Java tutorial
/** * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.apache.solr.servlet; import java.io.File; import java.io.IOException; import java.io.InputStream; import java.io.UnsupportedEncodingException; import java.net.URL; import java.net.URLDecoder; import java.util.ArrayList; import java.util.Collection; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Locale; import java.util.Map; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.servlet.http.HttpServletRequest; import org.apache.commons.fileupload.FileItem; import org.apache.commons.fileupload.disk.DiskFileItemFactory; import org.apache.commons.fileupload.servlet.ServletFileUpload; import org.apache.solr.common.SolrException; import org.apache.solr.common.params.CommonParams; import org.apache.solr.common.params.MultiMapSolrParams; import org.apache.solr.common.params.SolrParams; import org.apache.solr.common.util.ContentStream; import org.apache.solr.common.util.ContentStreamBase; import org.apache.solr.core.Config; import org.apache.solr.core.SolrCore; import org.apache.solr.request.ServletSolrParams; import org.apache.solr.request.SolrQueryRequest; import org.apache.solr.request.SolrQueryRequestBase; public class SolrRequestParsers { final Logger log = LoggerFactory.getLogger(SolrRequestParsers.class); // Should these constants be in a more public place? public static final String MULTIPART = "multipart"; public static final String RAW = "raw"; public static final String SIMPLE = "simple"; public static final String STANDARD = "standard"; private HashMap<String, SolrRequestParser> parsers; private boolean enableRemoteStreams = false; private boolean handleSelect = true; private StandardRequestParser standard; /** * Pass in an xml configuration. A null configuration will enable * everythign with maximum values. */ public SolrRequestParsers(Config globalConfig) { long uploadLimitKB = 1048; // 2MB default if (globalConfig == null) { uploadLimitKB = Long.MAX_VALUE; enableRemoteStreams = true; handleSelect = true; } else { uploadLimitKB = globalConfig.getInt("requestDispatcher/requestParsers/@multipartUploadLimitInKB", (int) uploadLimitKB); enableRemoteStreams = globalConfig.getBool("requestDispatcher/requestParsers/@enableRemoteStreaming", false); // Let this filter take care of /select?xxx format handleSelect = globalConfig.getBool("requestDispatcher/@handleSelect", handleSelect); } MultipartRequestParser multi = new MultipartRequestParser(uploadLimitKB); RawRequestParser raw = new RawRequestParser(); standard = new StandardRequestParser(multi, raw); // I don't see a need to have this publicly configured just yet // adding it is trivial parsers = new HashMap<String, SolrRequestParser>(); parsers.put(MULTIPART, multi); parsers.put(RAW, raw); parsers.put(SIMPLE, new SimpleRequestParser()); parsers.put(STANDARD, standard); parsers.put("", standard); } public SolrQueryRequest parse(SolrCore core, String path, HttpServletRequest req) throws Exception { SolrRequestParser parser = standard; // TODO -- in the future, we could pick a different parser based on the request // Pick the parser from the request... ArrayList<ContentStream> streams = new ArrayList<ContentStream>(1); SolrParams params = parser.parseParamsAndFillStreams(req, streams); SolrQueryRequest sreq = buildRequestFrom(core, params, streams); // Handlers and login will want to know the path. If it contains a ':' // the handler could use it for RESTful URLs sreq.getContext().put("path", path); return sreq; } public SolrQueryRequest buildRequestFrom(SolrCore core, SolrParams params, Collection<ContentStream> streams) throws Exception { // The content type will be applied to all streaming content String contentType = params.get(CommonParams.STREAM_CONTENTTYPE); // Handle anything with a remoteURL String[] strs = params.getParams(CommonParams.STREAM_URL); if (strs != null) { if (!enableRemoteStreams) { throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "Remote Streaming is disabled."); } for (final String url : strs) { ContentStreamBase stream = new ContentStreamBase.URLStream(new URL(url)); if (contentType != null) { stream.setContentType(contentType); } streams.add(stream); } } // Handle streaming files strs = params.getParams(CommonParams.STREAM_FILE); if (strs != null) { if (!enableRemoteStreams) { throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "Remote Streaming is disabled."); } for (final String file : strs) { ContentStreamBase stream = new ContentStreamBase.FileStream(new File(file)); if (contentType != null) { stream.setContentType(contentType); } streams.add(stream); } } // Check for streams in the request parameters strs = params.getParams(CommonParams.STREAM_BODY); if (strs != null) { for (final String body : strs) { ContentStreamBase stream = new ContentStreamBase.StringStream(body); if (contentType != null) { stream.setContentType(contentType); } streams.add(stream); } } SolrQueryRequestBase q = new SolrQueryRequestBase(core, params) { }; if (streams != null && streams.size() > 0) { q.setContentStreams(streams); } return q; } /** * Given a standard query string map it into solr params */ public static MultiMapSolrParams parseQueryString(String queryString) { Map<String, String[]> map = new HashMap<String, String[]>(); if (queryString != null && queryString.length() > 0) { try { for (String kv : queryString.split("&")) { int idx = kv.indexOf('='); if (idx > 0) { String name = URLDecoder.decode(kv.substring(0, idx), "UTF-8"); String value = URLDecoder.decode(kv.substring(idx + 1), "UTF-8"); MultiMapSolrParams.addParam(name, value, map); } else { String name = URLDecoder.decode(kv, "UTF-8"); MultiMapSolrParams.addParam(name, "", map); } } } catch (UnsupportedEncodingException uex) { throw new SolrException(SolrException.ErrorCode.SERVER_ERROR, uex); } } return new MultiMapSolrParams(map); } public boolean isHandleSelect() { return handleSelect; } public void setHandleSelect(boolean handleSelect) { this.handleSelect = handleSelect; } } //----------------------------------------------------------------- //----------------------------------------------------------------- // I guess we don't really even need the interface, but i'll keep it here just for kicks interface SolrRequestParser { public SolrParams parseParamsAndFillStreams(final HttpServletRequest req, ArrayList<ContentStream> streams) throws Exception; } //----------------------------------------------------------------- //----------------------------------------------------------------- /** * The simple parser just uses the params directly */ class SimpleRequestParser implements SolrRequestParser { public SolrParams parseParamsAndFillStreams(final HttpServletRequest req, ArrayList<ContentStream> streams) throws Exception { return new ServletSolrParams(req); } } /** * Wrap an HttpServletRequest as a ContentStream */ class HttpRequestContentStream extends ContentStreamBase { private final HttpServletRequest req; public HttpRequestContentStream(HttpServletRequest req) throws IOException { this.req = req; contentType = req.getContentType(); // name = ??? // sourceInfo = ??? String v = req.getHeader("Content-Length"); if (v != null) { size = Long.valueOf(v); } } public InputStream getStream() throws IOException { return req.getInputStream(); } } /** * Wrap a FileItem as a ContentStream */ class FileItemContentStream extends ContentStreamBase { private final FileItem item; public FileItemContentStream(FileItem f) { item = f; contentType = item.getContentType(); name = item.getName(); sourceInfo = item.getFieldName(); size = item.getSize(); } public InputStream getStream() throws IOException { return item.getInputStream(); } } /** * The raw parser just uses the params directly */ class RawRequestParser implements SolrRequestParser { public SolrParams parseParamsAndFillStreams(final HttpServletRequest req, ArrayList<ContentStream> streams) throws Exception { // The javadocs for HttpServletRequest are clear that req.getReader() should take // care of any character encoding issues. BUT, there are problems while running on // some servlet containers: including Tomcat 5 and resin. // // Rather than return req.getReader(), this uses the default ContentStreamBase method // that checks for charset definitions in the ContentType. streams.add(new HttpRequestContentStream(req)); return SolrRequestParsers.parseQueryString(req.getQueryString()); } } /** * Extract Multipart streams */ class MultipartRequestParser implements SolrRequestParser { private long uploadLimitKB; public MultipartRequestParser(long limit) { uploadLimitKB = limit; } public SolrParams parseParamsAndFillStreams(final HttpServletRequest req, ArrayList<ContentStream> streams) throws Exception { if (!ServletFileUpload.isMultipartContent(req)) { throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "Not multipart content! " + req.getContentType()); } MultiMapSolrParams params = SolrRequestParsers.parseQueryString(req.getQueryString()); // Create a factory for disk-based file items DiskFileItemFactory factory = new DiskFileItemFactory(); // Set factory constraints // TODO - configure factory.setSizeThreshold(yourMaxMemorySize); // TODO - configure factory.setRepository(yourTempDirectory); // Create a new file upload handler ServletFileUpload upload = new ServletFileUpload(factory); upload.setSizeMax(uploadLimitKB * 1024); // Parse the request List items = upload.parseRequest(req); Iterator iter = items.iterator(); while (iter.hasNext()) { FileItem item = (FileItem) iter.next(); // If its a form field, put it in our parameter map if (item.isFormField()) { MultiMapSolrParams.addParam(item.getFieldName(), item.getString(), params.getMap()); } // Add the stream else { System.out.println(item.getFieldName() + "===" + item.getSize()); streams.add(new FileItemContentStream(item)); } } return params; } } /** * The default Logic */ class StandardRequestParser implements SolrRequestParser { MultipartRequestParser multipart; RawRequestParser raw; StandardRequestParser(MultipartRequestParser multi, RawRequestParser raw) { this.multipart = multi; this.raw = raw; } public SolrParams parseParamsAndFillStreams(final HttpServletRequest req, ArrayList<ContentStream> streams) throws Exception { String method = req.getMethod().toUpperCase(Locale.ENGLISH); if ("GET".equals(method) || "HEAD".equals(method)) { return new ServletSolrParams(req); } if ("POST".equals(method)) { String contentType = req.getContentType(); if (contentType != null) { int idx = contentType.indexOf(';'); if (idx > 0) { // remove the charset definition "; charset=utf-8" contentType = contentType.substring(0, idx); } if ("application/x-www-form-urlencoded".equals(contentType.toLowerCase(Locale.ENGLISH))) { return new ServletSolrParams(req); // just get the params from parameterMap } if (ServletFileUpload.isMultipartContent(req)) { return multipart.parseParamsAndFillStreams(req, streams); } } return raw.parseParamsAndFillStreams(req, streams); } throw new SolrException(SolrException.ErrorCode.BAD_REQUEST, "Unsupported method: " + method); } }