package lux.solr; import java.io.File; import java.io.IOException; import java.io.UnsupportedEncodingException; import java.net.URI; import java.net.URISyntaxException; import java.net.URLEncoder; import java.util.HashMap; import java.util.Map; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletRequestWrapper; import org.apache.solr.request.SolrQueryRequest; import org.apache.solr.request.SolrRequestHandler; import org.apache.solr.response.SolrQueryResponse; import org.apache.solr.servlet.SolrDispatchFilter; /** * rewrite URLs of the form: * * [/core-name]/[appserver][/xquery-path]?query-string * * TO * * [/core-name]/[appserver]?query-string&lux.xquery=[/xquery-path] * */ public class LuxDispatchFilter extends SolrDispatchFilter { private String baseURI; private String[] baseURIArr; @Override public void init(FilterConfig filterConfig) throws ServletException { super.init(filterConfig); baseURI = filterConfig.getInitParameter("base-uri"); URI uri; if (baseURI == null) { String path = filterConfig.getServletContext().getRealPath("/"); if (path == null) { // unexploded war: load resources from classpath root. um. path = "resource:/"; } else if (File.separatorChar == '\\') { path = "///" + path.replace('\\', '/'); } else { path = "//" + path; } // Create a URI since that is supposed to handle quoting of non-URI // characters in the path (like spaces) try { uri = new URI("file", path, null); } catch (URISyntaxException e) { throw new ServletException("Malformed URI for path: " + path, e); } } else { try { uri = new URI(baseURI); } catch (URISyntaxException e) { throw new ServletException( "Malformed URI for path: " + baseURI, e); } } baseURI = uri.toString(); baseURIArr = new String[] { baseURI }; // Arrange for initialization of EXPath repository by setting the // appropriate system property, if a path is configured using JNDI: String expathRepo = filterConfig .getInitParameter("org.expath.pkg.saxon.repo"); if (expathRepo != null) { System.setProperty("org.expath.pkg.saxon.repo", expathRepo); } } @Override public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException { if (request instanceof HttpServletRequest) { HttpServletRequest req = (HttpServletRequest) request; Request wrapper = new Request(req); String path = req.getServletPath(); String[] pc = path.split("/", 4); if (path.contains(".xq") && pc.length > 2) { String coreName, handlerName, xquery; if (pc.length > 3) { coreName = pc[1]; handlerName = pc[2]; xquery = pc[3]; } else { coreName = "collection1"; // FIXME get default core name handlerName = pc[1]; xquery = pc[2]; } wrapper.setServletPath('/' + coreName + '/' + handlerName); String qs = req.getQueryString(); HashMap<String, String[]> params = null; if (req.getMethod().equals("GET")) { Map<String, String[]> requestParams = req.getParameterMap(); params = new HashMap<String, String[]>(requestParams); } // Solr 4 actually implements its own query string parsing, so // we need to // add our parameters to the query string in addition to setting // the parameter map // handle URLs like /core/foo.xqy/path/info int pathInfoOffset = xquery.indexOf(".xqy/"); if (pathInfoOffset >= 0) { pathInfoOffset += ".xqy/".length(); String pathInfo = xquery.substring(pathInfoOffset); xquery = xquery.substring(0, pathInfoOffset - 1); if (params != null) { params.put(XQueryComponent.LUX_PATH_INFO, new String[] { pathInfo }); } qs = appendToQueryString(qs, XQueryComponent.LUX_PATH_INFO, pathInfo); } // add lux.query and lux.base-uri to the query parameter map if (params != null) { params.put(XQueryComponent.LUX_XQUERY, new String[] { xquery }); params.put("lux.serverBaseUri", baseURIArr); } qs = appendToQueryString(qs, XQueryComponent.LUX_XQUERY, xquery); qs = appendToQueryString(qs, "lux.serverBaseUri", baseURI); // set the modified query string and parameter map on a request // wrapper wrapper.setQueryString(qs); wrapper.setParameterMap(params); } wrapper.setAttribute(SolrQueryContext.LUX_HTTP_SERVLET_RESPONSE, response); super.doFilter(wrapper, response, chain); return; } super.doFilter(request, response, chain); } @Override protected void execute(HttpServletRequest req, SolrRequestHandler handler, SolrQueryRequest sreq, SolrQueryResponse rsp) { // Make the raw request available to the XQueryComponent and // LuxResponseWriter sreq.getContext().put(SolrQueryContext.LUX_HTTP_SERVLET_REQUEST, req); super.execute(req, handler, sreq, rsp); } private String appendToQueryString(String qs, String param, String value) throws UnsupportedEncodingException { // swizzle the queryString here: if (qs == null) { return param + '=' + URLEncoder.encode(value, "UTF-8"); } else { return qs + '&' + param + '=' + URLEncoder.encode(value, "utf-8"); } } public class Request extends HttpServletRequestWrapper { private Map<String, String[]> parameterMap; private String pathInfo; private String servletPath; private String queryString; public Request(HttpServletRequest req) { super(req); } @Override public String getServletPath() { return servletPath == null ? super.getServletPath() : servletPath; } @Override public String getPathInfo() { return pathInfo == null ? super.getPathInfo() : pathInfo; } @Override public Map<String, String[]> getParameterMap() { return parameterMap == null ? super.getParameterMap() : parameterMap; } @Override public String getQueryString() { return queryString == null ? super.getQueryString() : queryString; } public void setParameterMap(Map<String, String[]> map) { parameterMap = map; } public void setServletPath(String path) { servletPath = path; } public void setPathInfo(String path) { pathInfo = path; } public void setQueryString(String queryString) { this.queryString = queryString; } } }