/* See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * Esri Inc. 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 com.esri.gpt.server.csw.client; import com.esri.gpt.framework.http.ContentProvider; import com.esri.gpt.framework.http.CredentialProvider; import com.esri.gpt.framework.http.HttpClientRequest; import com.esri.gpt.framework.http.HttpClientRequest.MethodName; import com.esri.gpt.framework.http.StringProvider; import com.esri.gpt.framework.util.Val; import java.io.*; import java.util.logging.Level; import java.util.logging.Logger; import javax.xml.parsers.DocumentBuilder; import javax.xml.parsers.DocumentBuilderFactory; import javax.xml.parsers.ParserConfigurationException; import org.apache.commons.httpclient.HttpClient; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.xml.sax.SAXException; /** * CswClient class is used to submit CSW search request. * * CswClient is a wrapper class of .NET HttpWebRequest and HttpWebResponse. * It basically submits a HTTP request then return a text response. */ public class CswClient { // class variables ============================================================= /** Class Logger **/ private static Logger LOG = Logger .getLogger(CswClient.class.getCanonicalName()); /** The REQUES Timeout parameter. */ public static int DEFAULT_REQUEST_TIMEOUT = -1; // instance variables ========================================================== /**Connection timeout for query **/ private int connectTimeout = DEFAULT_REQUEST_TIMEOUT; private int readTimeOut = DEFAULT_REQUEST_TIMEOUT; // constructor ================================================================= private HttpClient batchHttpClient; /** * use static variable to be thread safe * (FROM C# CODE: MAY BE REMOVED LATER) * */ // private static CookieContainer _cookieContainer; // private CredentialCache _credentialCache; /** * Constructor */ public CswClient() { } // properties ================================================================== public void setBatchHttpClient(HttpClient batchHttpClient) { this.batchHttpClient = batchHttpClient; } public HttpClient getBatchHttpClient() { return batchHttpClient; } /** * Gets the timeout. * * @return the timeout */ public int getConnectTimeout() { return this.connectTimeout; } /** * Sets the timeout. * * @param timeout the new timeout */ public void setConnectTimeout(int timeout) { this.connectTimeout = timeout; } /** * Gets the timeout. * * @return the timeout */ public int getReadTimeout() { return this.readTimeOut; } /** * Sets the timeout. * * @param timeout the new timeout */ public void setReadTimeout(int timeout) { this.readTimeOut = timeout; } // methods ===================================================================== /** * Encode PostBody * * Encode special characters (such as %, space, <, >, \, and &) to percent * values. * @return Encoded text. * * @param postbody Text to be encoded */ public String encodePostbody(String postbody) { String strOutput = postbody; strOutput = replaceSubString(strOutput, "&amp;", "&"); strOutput = replaceSubString(strOutput, "&", "&"); strOutput = replaceSubString(strOutput, "<", "<"); strOutput = replaceSubString(strOutput, "'", "'"); strOutput = replaceSubString(strOutput, """, "\""); strOutput = replaceSubString(strOutput, "-", "-"); return strOutput; } /** * Replace sub string. * * @param source the source * @param pattern the pattern * @param replace the replace * * @return the replaced string */ public static String replaceSubString(String source, String pattern, String replace) { if (source != null) { int len = pattern.length(); StringBuffer sb = new StringBuffer(); int found = -1; int start = 0; while ((found = source.indexOf(pattern, start)) != -1) { sb.append(source.substring(start, found)); sb.append(replace); start = found + len; } sb.append(source.substring(start)); return sb.toString(); } else return null; } /** * Submit HTTP Request * * @return Response in plain text * * @param method HTTP Method. for example "POST", "GET" * @param url URL to send HTTP Request to * @param postdata Data to be posted * @throws IOException */ public InputStream submitHttpRequest(String method, String url, String postdata) throws IOException { return submitHttpRequest(method, url, postdata, "", ""); } /** * Submit HTTP Request (Both GET and POST). Return InputStream object from the response * * Submit an HTTP request. * @return Response in plain text. * * @param method HTTP Method. for example "POST", "GET" * @param urlString URL to send HTTP Request to * @param postdata Data to be posted * @param usr Username * @param pwd Password * @throws IOException in IOException * @throws java.net.SocketTimeoutException if connect or read timeout */ public InputStream submitHttpRequest(String method, String urlString, String postdata, String usr, String pwd) throws IOException { if (LOG.isLoggable(Level.FINER)) { LOG.finer("Data being sent. URL = " + urlString + "\n Data = " + postdata); } urlString = Utils.chkStr(urlString); urlString = urlString.replaceAll("\\n", ""); urlString = urlString.replaceAll("\\t", ""); urlString = urlString.replaceAll("\\r", ""); urlString = urlString.replaceAll(" ", ""); HttpClientRequest client = HttpClientRequest.newRequest(); client.setBatchHttpClient(getBatchHttpClient()); client.setUrl(urlString); client.setRetries(1); usr = Val.chkStr(usr); pwd = Val.chkStr(pwd); if (usr.length() > 0 || pwd.length() > 0) { CredentialProvider provider = new CredentialProvider(usr, pwd); client.getCredentialProvider(); client.setCredentialProvider(provider); } if (this.getReadTimeout() > 0) { client.setResponseTimeOutMs(this.getReadTimeout()); } if (this.getConnectTimeout() > 0) { client.setConnectionTimeMs(this.getConnectTimeout()); } // Send a request if (Val.chkStr(method).equalsIgnoreCase("post")) { ContentProvider contentProvider = new StringProvider(postdata, "text/xml"); client.setContentProvider(contentProvider); } else { client.setMethodName(MethodName.GET); } String response = client.readResponseAsCharacters(); LOG.finer(" CSW Response : " + response); return new ByteArrayInputStream(response.getBytes("UTF-8")); } /** * Returns content encoding value from content type * @param contentType content type * @return last content encoding */ private String getLastContentEncoding(String contentType){ if(contentType != null){ contentType = contentType.trim(); String[] contentTypes = contentType.split(";"); for(String c:contentTypes){ if (c != null) { int index = c.trim().toLowerCase().indexOf("charset="); if(index == 0) return c.trim().substring(index+8).trim(); } } } return "UTF-8"; } /** * Fully reads the characters from an input stream. * @param stream the input stream * @param charset the encoding of the input stream * @return the characters read * @throws IOException if an exception occurs */ private String readCharacters(InputStream stream, String charset) throws IOException { StringBuffer sb = new StringBuffer(); BufferedReader br = null; InputStreamReader ir = null; try { if ((charset == null) || (charset.trim().length() == 0)) charset = "UTF-8"; char cbuf[] = new char[4096]; int n = 0; int nLen = cbuf.length; ir = new InputStreamReader(stream,charset); br = new BufferedReader(ir); while ((n = br.read(cbuf,0,nLen)) >= 0) sb.append(cbuf,0,n); } finally { try {if (br != null) br.close();} catch (Exception ef) {} try {if (ir != null) ir.close();} catch (Exception ef) {} } return sb.toString(); } /** * submit HTTP Request (Both GET and POST). Parse the response into an xml document element. * @param method * @param urlString * @param postdata * @param usr * @param pwd * @return response * @throws IOException * @throws ParserConfigurationException * @throws SAXException */ public Element submitHttpRequestAndGetDom(String method, String urlString, String postdata, String usr, String pwd) throws IOException, ParserConfigurationException, SAXException { InputStream inStream = null; Element response; try { inStream = submitHttpRequest(method, urlString, postdata, "", ""); // Get a response DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); DocumentBuilder docBuilder = factory.newDocumentBuilder(); Document doc = docBuilder.parse(inStream); response = doc.getDocumentElement(); response.normalize(); } finally { Utils.close(inStream); } return response; } }