/** * 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.manifoldcf.agents.output.opensearchserver; import java.io.IOException; import java.io.StringReader; import java.io.Writer; import java.io.StringWriter; import java.io.Reader; import java.io.InputStreamReader; import java.io.InputStream; import java.io.InterruptedIOException; import java.nio.charset.Charset; import java.nio.charset.StandardCharsets; import java.util.Locale; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import javax.xml.xpath.XPath; import javax.xml.xpath.XPathExpression; import javax.xml.xpath.XPathExpressionException; import javax.xml.xpath.XPathFactory; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpRequestBase; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.util.EntityUtils; import org.apache.http.entity.ContentType; import org.apache.http.conn.ConnectTimeoutException; import org.apache.http.client.RedirectException; import org.apache.http.client.CircularRedirectException; import org.apache.http.NoHttpResponseException; import org.apache.http.HttpException; import org.apache.http.ParseException; import org.apache.manifoldcf.agents.interfaces.IOutputHistoryActivity; import org.apache.manifoldcf.core.interfaces.ManifoldCFException; import org.apache.manifoldcf.core.util.URLEncoder; import org.w3c.dom.Document; import org.xml.sax.InputSource; import org.xml.sax.SAXException; public class OpenSearchServerConnection { private String serverLocation; private String indexName; private String userName; private String apiKey; private String resultDescription; private String callUrlSnippet; private String response; private Document xmlResponse; private HttpClient httpClient; protected String xPathStatus = "/response/entry[@key='Status']/text()"; protected String xPathException = "/response/entry[@key='Exception']/text()"; public enum Result { OK, ERROR, UNKNOWN; } private Result result; private String resultCode; protected OpenSearchServerConnection(HttpClient client, OpenSearchServerConfig config) { this.httpClient = client; result = Result.UNKNOWN; response = null; xmlResponse = null; resultDescription = ""; callUrlSnippet = null; serverLocation = config.getServerLocation(); indexName = config.getIndexName(); userName = config.getUserName(); apiKey = config.getApiKey(); } protected StringBuffer getApiUrl(String command) throws ManifoldCFException { StringBuffer url = new StringBuffer(serverLocation); if (!serverLocation.endsWith("/")) url.append('/'); url.append(command); url.append("?use="); url.append(URLEncoder.encode(indexName)); callUrlSnippet = url.toString(); if (userName != null && apiKey != null && userName.length() > 0 && apiKey.length() > 0) { url.append("&login="); url.append(URLEncoder.encode(userName)); url.append("&key="); url.append(apiKey); } return url; } protected StringBuffer getApiUrlV2(String path) throws ManifoldCFException { StringBuffer url = new StringBuffer(serverLocation); if (!serverLocation.endsWith("/")) url.append('/'); url.append(path); callUrlSnippet = url.toString(); if (userName != null && apiKey != null && userName.length() > 0 && apiKey.length() > 0) { url.append("&login="); url.append(URLEncoder.encode(userName)); url.append("&key="); url.append(apiKey); } return url; } protected static class CallThread extends Thread { protected final HttpClient client; protected final HttpRequestBase method; protected int resultCode = -1; protected String response = null; protected Throwable exception = null; public CallThread(HttpClient client, HttpRequestBase method) { this.client = client; this.method = method; setDaemon(true); } @Override public void run() { try { try { HttpResponse resp = client.execute(method); resultCode = resp.getStatusLine().getStatusCode(); HttpEntity entity = resp.getEntity(); response = EntityUtils.toString(entity, StandardCharsets.UTF_8); } finally { method.abort(); } } catch (java.net.SocketTimeoutException e) { exception = e; } catch (InterruptedIOException e) { // Just exit } catch (Throwable e) { exception = e; } } public int getResultCode() { return resultCode; } public String getResponse() { return response; } public void finishUp() throws InterruptedException, HttpException, IOException { join(); Throwable t = exception; if (t != null) { if (t instanceof HttpException) throw (HttpException)t; else if (t instanceof IOException) throw (IOException)t; else if (t instanceof RuntimeException) throw (RuntimeException)t; else if (t instanceof Error) throw (Error)t; else throw new RuntimeException("Unexpected exception thrown: "+t.getMessage(),t); } } } protected void call(HttpRequestBase method) throws ManifoldCFException { CallThread ct = new CallThread(httpClient, method); try { ct.start(); try { ct.finishUp(); if (!checkResultCode(ct.getResultCode())) throw new ManifoldCFException(getResultDescription()); response = ct.getResponse(); } catch (InterruptedException e) { ct.interrupt(); throw new ManifoldCFException("Interrupted: "+e.getMessage(),e,ManifoldCFException.INTERRUPTED); } } catch (java.net.SocketTimeoutException e) { setResult(e.getClass().getSimpleName().toUpperCase(Locale.ROOT),Result.ERROR, e.getMessage()); throw new ManifoldCFException("SocketTimeoutException while calling " + method.getURI() +": " + e.getMessage(), e); } catch (InterruptedIOException e) { setResult(e.getClass().getSimpleName().toUpperCase(Locale.ROOT),Result.ERROR, e.getMessage()); throw new ManifoldCFException("Interrupted: "+e.getMessage(), e, ManifoldCFException.INTERRUPTED); } catch (HttpException e) { setResult(e.getClass().getSimpleName().toUpperCase(Locale.ROOT),Result.ERROR, e.getMessage()); throw new ManifoldCFException("HttpException while calling " + method.getURI() +": " + e.getMessage(), e); } catch (IOException e) { setResult(e.getClass().getSimpleName().toUpperCase(Locale.ROOT),Result.ERROR, e.getMessage()); throw new ManifoldCFException("IOException while calling " + method.getURI() +": " + e.getMessage(), e); } } private void readXmlResponse() throws ManifoldCFException { if (xmlResponse != null) return; StringReader sw = null; try { sw = new StringReader(response); DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); dbf.setNamespaceAware(true); // never forget this! DocumentBuilder builder; builder = dbf.newDocumentBuilder(); xmlResponse = builder.parse(new InputSource(sw)); } catch (ParserConfigurationException e) { throw new ManifoldCFException(e); } catch (SAXException e) { throw new ManifoldCFException(e); } catch (IOException e) { throw new ManifoldCFException(e); } finally { if (sw != null) { sw.close(); } } } protected String checkXPath(String xPathQuery) throws ManifoldCFException { try { readXmlResponse(); XPathFactory factory = XPathFactory.newInstance(); XPath xpath = factory.newXPath(); XPathExpression xPathExpr = xpath.compile(xPathQuery); return xPathExpr.evaluate(xmlResponse); } catch (XPathExpressionException e) { throw new ManifoldCFException(e); } } protected void setResult(String resultCode,Result res, String desc) { if (res != null) result = res; if (desc != null) if (desc.length() > 0) resultDescription = desc; setResultCode(resultCode); } public String getResultDescription() { return resultDescription; } protected String getResponse() { return response; } private boolean checkResultCode(int code) { switch (code) { case 0: setResult(IOutputHistoryActivity.HTTP_ERROR,Result.UNKNOWN, null); return false; case 200: setResult("OK",Result.OK, null); return true; case 404: setResult(IOutputHistoryActivity.HTTP_ERROR,Result.ERROR, "Server/page not found"); return false; default: setResult(IOutputHistoryActivity.HTTP_ERROR,Result.ERROR, null); return false; } } public Result getResult() { return result; } public String getCallUrlSnippet() { return callUrlSnippet; } public void setResultCode(String resultCode){ this.resultCode = resultCode; } public String getResultCode(){ return resultCode; } }