001/*
002 * Licensed to the Apache Software Foundation (ASF) under one or more
003 * contributor license agreements.  See the NOTICE file distributed with
004 * this work for additional information regarding copyright ownership.
005 * The ASF licenses this file to You under the Apache License, Version 2.0
006 * (the "License"); you may not use this file except in compliance with
007 * the License.  You may obtain a copy of the License at
008 *
009 *     http://www.apache.org/licenses/LICENSE-2.0
010 *
011 * Unless required by applicable law or agreed to in writing, software
012 * distributed under the License is distributed on an "AS IS" BASIS,
013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014 * See the License for the specific language governing permissions and
015 * limitations under the License.
016 */
017
018package org.apache.lucene.demo.xmlparser;
019
020import java.io.BufferedReader;
021import java.io.IOException;
022import java.io.InputStream;
023import java.io.InputStreamReader;
024import java.nio.charset.StandardCharsets;
025import java.util.Enumeration;
026import java.util.Properties;
027import java.util.StringTokenizer;
028
029import javax.servlet.RequestDispatcher;
030import javax.servlet.ServletConfig;
031import javax.servlet.ServletException;
032import javax.servlet.http.HttpServlet;
033import javax.servlet.http.HttpServletRequest;
034import javax.servlet.http.HttpServletResponse;
035
036import org.apache.lucene.analysis.Analyzer;
037import org.apache.lucene.analysis.standard.StandardAnalyzer;
038import org.apache.lucene.document.Document;
039import org.apache.lucene.document.Field;
040import org.apache.lucene.document.FieldType;
041import org.apache.lucene.document.TextField;
042import org.apache.lucene.index.DirectoryReader;
043import org.apache.lucene.index.IndexReader;
044import org.apache.lucene.index.IndexWriter;
045import org.apache.lucene.index.IndexWriterConfig;
046import org.apache.lucene.queryparser.xml.CorePlusExtensionsParser;
047import org.apache.lucene.queryparser.xml.QueryTemplateManager;
048import org.apache.lucene.search.IndexSearcher;
049import org.apache.lucene.search.Query;
050import org.apache.lucene.search.ScoreDoc;
051import org.apache.lucene.search.TopDocs;
052import org.apache.lucene.store.RAMDirectory;
053import org.apache.lucene.util.Version;
054
055/**
056 * Example servlet that uses the XML queryparser.
057 * <p>
058 * NOTE: you must provide CSV data in <code>/WEB-INF/data.tsv</code>
059 * for the demo to work!
060 */
061public class FormBasedXmlQueryDemo extends HttpServlet {
062
063  private QueryTemplateManager queryTemplateManager;
064  private CorePlusExtensionsParser xmlParser;
065  private IndexSearcher searcher;
066  private Analyzer analyzer = new StandardAnalyzer(org.apache.lucene.util.Version.LUCENE_CURRENT);
067
068  /** for instantiation by the servlet container */
069  public FormBasedXmlQueryDemo() {}
070
071  @Override
072  public void init(ServletConfig config) throws ServletException {
073    super.init(config);
074    try {
075      openExampleIndex();
076
077      //load servlet configuration settings
078      String xslFile = config.getInitParameter("xslFile");
079      String defaultStandardQueryParserField = config.getInitParameter("defaultStandardQueryParserField");
080
081
082      //Load and cache choice of XSL query template using QueryTemplateManager
083      queryTemplateManager = new QueryTemplateManager(
084          getServletContext().getResourceAsStream("/WEB-INF/" + xslFile));
085
086      //initialize an XML Query Parser for use by all threads
087      xmlParser = new CorePlusExtensionsParser(defaultStandardQueryParserField, analyzer);
088    } catch (Exception e) {
089      throw new ServletException("Error loading query template", e);
090    }
091  }
092
093  @Override
094  protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
095    //Take all completed form fields and add to a Properties object
096    Properties completedFormFields = new Properties();
097    Enumeration<?> pNames = request.getParameterNames();
098    while (pNames.hasMoreElements()) {
099      String propName = (String) pNames.nextElement();
100      String value = request.getParameter(propName);
101      if ((value != null) && (value.trim().length() > 0)) {
102        completedFormFields.setProperty(propName, value);
103      }
104    }
105
106    try {
107      //Create an XML query by populating template with given user criteria
108      org.w3c.dom.Document xmlQuery = queryTemplateManager.getQueryAsDOM(completedFormFields);
109
110      //Parse the XML to produce a Lucene query
111      Query query = xmlParser.getQuery(xmlQuery.getDocumentElement());
112
113      //Run the query
114      TopDocs topDocs = searcher.search(query, 10);
115
116      //and package the results and forward to JSP
117      if (topDocs != null) {
118        ScoreDoc[] sd = topDocs.scoreDocs;
119        Document[] results = new Document[sd.length];
120        for (int i = 0; i < results.length; i++) {
121          results[i] = searcher.doc(sd[i].doc);
122          request.setAttribute("results", results);
123        }
124      }
125      RequestDispatcher dispatcher = getServletContext().getRequestDispatcher("/index.jsp");
126      dispatcher.forward(request, response);
127    }
128    catch (Exception e) {
129      throw new ServletException("Error processing query", e);
130    }
131  }
132
133  private void openExampleIndex() throws IOException {
134    //Create a RAM-based index from our test data file
135    RAMDirectory rd = new RAMDirectory();
136    IndexWriterConfig iwConfig = new IndexWriterConfig(Version.LUCENE_CURRENT, analyzer);
137    IndexWriter writer = new IndexWriter(rd, iwConfig);
138    InputStream dataIn = getServletContext().getResourceAsStream("/WEB-INF/data.tsv");
139    BufferedReader br = new BufferedReader(new InputStreamReader(dataIn, StandardCharsets.UTF_8));
140    String line = br.readLine();
141    final FieldType textNoNorms = new FieldType(TextField.TYPE_STORED);
142    textNoNorms.setOmitNorms(true);
143    while (line != null) {
144      line = line.trim();
145      if (line.length() > 0) {
146        //parse row and create a document
147        StringTokenizer st = new StringTokenizer(line, "\t");
148        Document doc = new Document();
149        doc.add(new Field("location", st.nextToken(), textNoNorms));
150        doc.add(new Field("salary", st.nextToken(), textNoNorms));
151        doc.add(new Field("type", st.nextToken(), textNoNorms));
152        doc.add(new Field("description", st.nextToken(), textNoNorms));
153        writer.addDocument(doc);
154      }
155      line = br.readLine();
156    }
157    writer.close();
158
159    //open searcher
160    // this example never closes it reader!
161    IndexReader reader = DirectoryReader.open(rd);
162    searcher = new IndexSearcher(reader);
163  }
164}