/* 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.catalog.arcims;
import com.esri.gpt.framework.security.codec.Base64;
import com.esri.gpt.framework.security.codec.Digest;
import com.esri.gpt.framework.security.credentials.Credentials;
import com.esri.gpt.framework.security.credentials.UsernamePasswordCredentials;
import com.esri.gpt.framework.util.Val;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import java.io.UnsupportedEncodingException;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* Provides a basic client for out-bound ArcIMS HTTP communication.
*
*/
public class ImsHttpClient extends ImsClient {
// class variables =============================================================
private static Logger LOGGER = Logger.getLogger(ImsHttpClient.class.getName());
// instance variables ==========================================================
private Credentials _credentials = null;
private String _responseContentEncoding = "";
private long _responseContentLength = 0;
private String _responseContentType = "";
private String _url = "";
// constructors ================================================================
/** Default constructor. */
public ImsHttpClient() {
super();
}
// properties ==================================================================
/**
* Gets the credentials for the user.
* @return the credentials
*/
public Credentials getCredentials() {
return _credentials;
}
/**
* Sets the credentials for the user.
* @param credentials the credentials
*/
public void setCredentials(Credentials credentials) {
_credentials = credentials;
}
/**
* Gets the response content encoding.
* @return the response content encoding
*/
public String getResponseContentEncoding() {
return _responseContentEncoding;
}
/**
* Sets the response content encoding.
* @param encoding the response content encoding
*/
protected void setResponseContentEncoding(String encoding) {
_responseContentEncoding = Val.chkStr(encoding);
}
/**
* Gets the response content length.
* @return the response content length
*/
public long getResponseContentLength() {
return _responseContentLength;
}
/**
* Sets the response content length.
* @param length the response content length
*/
protected void setResponseContentLength(long length) {
_responseContentLength = length;
}
/**
* Gets the response content type.
* @return the response content type
*/
public String getResponseContentType() {
return _responseContentType;
}
/**
* Sets the response content type.
* @param type the response content type
*/
protected void setResponseContentType(String type) {
_responseContentType = Val.chkStr(type);
}
/**
* Gets the server url.
* @return the server url
*/
public String getUrl() {
return _url;
}
/**
* Sets the server url.
* @param url the server url
*/
public void setUrl(String url) {
_url = Val.chkStr(url);
}
// methods =====================================================================
/**
* Executes the sending of the HTTP request.
* @throws MalformedURLException if the URL was not properly specified
* @throws IOException if a communication exception occurs
*/
private void executeSend()
throws MalformedURLException, IOException {
resetResponse();
HttpURLConnection httpCon = null;
InputStream responseStream = null;
if (LOGGER.isLoggable(Level.FINER)) {
StringBuffer sb = new StringBuffer();
sb.append("Sending ArcIMS HTTP request\n");
sb.append(" url=").append(getUrl());
sb.append("\n").append(getAxlRequest());
LOGGER.finer(sb.toString());
}
try {
// set-up the connection
String sMethod = "GET";
boolean bSendData = false;
if (getAxlRequest().length() > 0) {
sMethod = "POST";
bSendData = true;
}
// if (getUrl().startsWith("https://")) {
// boolean allowSetDefault = true;
// // check security manager first for net permission to perform 'setDefault'
// try {
// SecurityManager security = System.getSecurityManager();
// if (security!=null) {
// security.checkPermission(
// new java.net.NetPermission("setDefaultAuthenticator"));
// }
// } catch (SecurityException ex) {
// allowSetDefault = false;
// }
// // perform 'setDefault' if allowed
// if (allowSetDefault) {
// if (getCredentials() instanceof UsernamePasswordCredentials) {
// final UsernamePasswordCredentials credentials =
// (UsernamePasswordCredentials)getCredentials();
// Authenticator.setDefault(
// new Authenticator() {
// @Override
// protected PasswordAuthentication getPasswordAuthentication() {
// return new PasswordAuthentication(
// credentials.getUsername(), credentials.getPassword().toCharArray());
// }
// });
// }
// }
// }
// open connection
httpCon = openConnection(sMethod, bSendData);
// setup basic credentials
setupBasicCredentials(getCredentials(), httpCon);
// send data if required
if (bSendData) {
sendData(httpCon);
}
// read the response
setResponseCode(httpCon.getResponseCode());
setResponseCodeText(httpCon.getResponseMessage());
// not authenticated; setup digest authentication and resend request
if (getResponseCode() == 401) {
Digest digResp = Digest.extractFrom(httpCon);
if (digResp.isValid()) {
// reconnect
httpCon.disconnect();
httpCon = openConnection(sMethod, bSendData);
// setup credentials
digResp.injectTo(httpCon,(UsernamePasswordCredentials)getCredentials());
// send data if required
if (bSendData) {
sendData(httpCon);
}
// read the response
setResponseCode(httpCon.getResponseCode());
setResponseCodeText(httpCon.getResponseMessage());
}
}
if ((getResponseCode() < 200) || (getResponseCode() > 299)) {
throw new IOException("Request failed: HTTP " + getResponseCode());
}
setResponseContentEncoding(httpCon.getContentEncoding());
setResponseContentType(httpCon.getContentType());
setResponseContentLength(httpCon.getContentLength());
responseStream = httpCon.getInputStream();
setAxlResponse(readCharacters(responseStream).toString());
if (LOGGER.isLoggable(Level.FINER)) {
StringBuffer sb = new StringBuffer();
sb.append("Read ArcIMS HTTP response\n");
sb.append(" url=").append(getUrl());
sb.append(" responseCode=").append(getResponseCode());
sb.append(" responseContentType=").append(getResponseContentType());
sb.append(" responseContentEncoding=").append(getResponseContentEncoding());
sb.append("\n").append(getAxlResponse());
LOGGER.finer(sb.toString());
}
} finally {
try {
if (responseStream != null) responseStream.close();
} catch (Exception ef) {}
}
}
/**
* Creates an open HTTP connection.
* @param sMethod method ("GET" or "POST")
* @param bSendData <code>true</code> if any data to send
* @return connection
* @throws java.net.MalformedURLException if invalid URL
* @throws java.io.IOException if error opening connection
*/
private HttpURLConnection openConnection(String sMethod, boolean bSendData)
throws MalformedURLException, IOException {
URL url = new URL(getUrl());
HttpURLConnection httpCon = (HttpURLConnection) url.openConnection();
httpCon.setRequestMethod(sMethod);
httpCon.setConnectTimeout(getTimeoutMillisecs());
httpCon.setDoInput(true);
httpCon.setDoOutput(bSendData);
httpCon.setUseCaches(false); // turn off document caching
httpCon.setRequestProperty("Connection", "Close"); // Disable keep-alive
return httpCon;
}
/**
* Sends request to the opened HTTP connection.
* @param httpCon HTTP connection
* @throws java.io.IOException if sending data failed
*/
private void sendData(HttpURLConnection httpCon)
throws IOException {
OutputStream sendStream = null;
try {
httpCon.setRequestProperty("Content-Type","text/xml; charset=UTF-8");
httpCon.setRequestProperty("Content-Length",""+getAxlRequest().length());
sendStream = httpCon.getOutputStream();
sendStream.write(getAxlRequest().getBytes("UTF-8"));
sendStream.flush();
} finally {
try {
if (sendStream != null) {
sendStream.close();
}
} catch (Exception ef) {
}
}
}
/**
* Fully reads the characters from an InputStream.
* @param strm the InputStream
* @return the characters read
* @throws IOException if an exception occurs
*/
protected StringBuffer readCharacters(InputStream strm)
throws IOException {
StringBuffer sb = new StringBuffer();
BufferedReader br = null;
InputStreamReader ir = null;
try {
char cbuf[] = new char[2048];
int n = 0;
int nLen = cbuf.length;
ir = new InputStreamReader(strm, "UTF-8");
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;
}
/**
* Resets the response.
*/
protected void resetResponse() {
setAxlResponse("");
setResponseCode(0);
setResponseCodeText("");
setResponseContentEncoding("");
setResponseContentLength(0);
setResponseContentType("");
}
/**
* Sends the HTTP request.
* @throws MalformedURLException if the URL was not properly specified
* @throws IOException if a communication exception occurs
*/
public void sendRequest()
throws MalformedURLException, IOException {
executeSend();
}
/**
* Sets up HTTP header basic authorization.
* @param credentials the associated credentials
* @param urlCon the URLConnection
*/
private void setupBasicCredentials(Credentials credentials,
URLConnection urlCon) {
// Currently we are only handling Basic scheme username/password encoding
if ((credentials != null) && (credentials instanceof UsernamePasswordCredentials)) {
UsernamePasswordCredentials upCredentials =
(UsernamePasswordCredentials) credentials;
String sUsername = upCredentials.getUsername();
String sPassword = upCredentials.getPassword();
if ((sUsername.length() > 0) || (sPassword.length() > 0)) {
String sUserPwd = sUsername + ":" + sPassword;
String sEncodedUserPwd = "";
try {
sEncodedUserPwd = Base64.encode(sUserPwd, null);
} catch (UnsupportedEncodingException eun) {
}
urlCon.setRequestProperty("Authorization", "Basic " + sEncodedUserPwd);
}
}
}
}