package lux.solr; import java.io.File; import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.net.URL; import org.apache.commons.io.IOUtils; import org.apache.commons.lang.StringUtils; import org.apache.solr.common.SolrException; import org.apache.solr.common.SolrException.ErrorCode; import org.apache.solr.common.params.SolrParams; import org.apache.solr.handler.component.ResponseBuilder; import org.apache.solr.request.SolrQueryRequest; import org.slf4j.LoggerFactory; /** * This component supplies a level of indirection, reading the query from a * location specified in the lux.xquery parameter. When the queries are in * a directory, this functions like an xquery application service. * * TODO: merge w/XQueryComponent. The only distinction is that one gets its query from the "q" * parameter and interprets it as the query body, and the other gets the location of a query document * from the "lux.xquery" parameter. Having two separate components causes us to create two Compilers, * two Processors, etc. * * TODO: add extended support for accessing HTTP request and controlling HTTP response via xquery; * eg for redirects, binary responses, file upload, etc. */ public class AppServerComponent extends XQueryComponent { private static final String RESOURCE_SCHEME = "resource:"; private static final String CONTEXT_SCHEME = "context:"; @Override public void prepare(ResponseBuilder rb) throws IOException { SolrQueryRequest req = rb.req; SolrParams params = req.getParams(); if (rb.getQueryString() == null) { queryPath = rb.req.getParams().get(LUX_XQUERY); if (! StringUtils.isBlank(queryPath)) { String baseUri; String contextBase = (String) params.get("lux.serverBaseUri"); if (params.get("lux.baseUri") != null) { baseUri = (String) params.get("lux.baseUri"); } else if (params.get("lux.serverBaseUri") != null) { baseUri = contextBase; } else { baseUri = ""; } if (File.separatorChar == '\\') { baseUri = baseUri.replace('\\', '/'); } if (! baseUri.endsWith("/")) { // add trailing slash baseUri = baseUri + '/'; } if (baseUri.startsWith("/") || (File.separatorChar == '\\' && baseUri.matches("^[A-Za-z]:/.*$"))) { baseUri = "file://" + baseUri; } //System.out.println ("BASE URI = " + baseUri); String resourceBase=null; if (baseUri.startsWith (RESOURCE_SCHEME)) { resourceBase = baseUri.substring(RESOURCE_SCHEME.length()); } else if (baseUri.startsWith(CONTEXT_SCHEME)) { baseUri = contextBase + baseUri.substring(CONTEXT_SCHEME.length()); } String contents = null; if (resourceBase != null) { InputStream in = AppServerComponent.class.getResourceAsStream(resourceBase + queryPath); queryPath = baseUri + queryPath; if (in == null) { throw new SolrException (ErrorCode.NOT_FOUND, queryPath + " not found"); } else { try { contents = IOUtils.toString(in); } catch (IOException e) { LoggerFactory.getLogger(AppServerComponent.class).error("An error occurred while reading " + queryPath, e); } IOUtils.closeQuietly(in); } } else { // url provided with scheme queryPath = baseUri + queryPath; URL url = new URL (queryPath); String scheme = url.getProtocol(); if (scheme.equals("lux")) { // TODO implement lux: uri resolution throw new SolrException (ErrorCode.NOT_FOUND, queryPath + " not found (actually lux: scheme is not implemented)"); } else { InputStream in = null; try { if (url.getProtocol().equals("file")) { File f = new File(url.getPath()); if (!f.exists()) { throw new SolrException (ErrorCode.NOT_FOUND, f + " not found"); } if (f.isDirectory() || ! f.canRead()) { throw new SolrException (ErrorCode.FORBIDDEN, "access to " + f + " denied by rule"); } in = new FileInputStream(f); } else { // in = url.openStream(); LoggerFactory.getLogger(AppServerComponent.class).error("URL scheme not supported: " + url.getProtocol()); } contents = IOUtils.toString(in); } catch (IOException e) { LoggerFactory.getLogger(AppServerComponent.class).error("An error occurred while reading " + url, e); } if (in != null) { IOUtils.closeQuietly(in); } } } rb.setQueryString(contents); } } super.prepare(rb); } @Override public String getDefaultSerialization () { return "html"; } /** * ignores start and len query parameters */ @Override public void process(ResponseBuilder rb) throws IOException { evaluateQuery(rb, -1, -1); } } /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this file, * You can obtain one at http://mozilla.org/MPL/2.0/. */