Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 package org.apache.xmlrpc.client;
00020
00021 import java.io.BufferedOutputStream;
00022 import java.io.FilterOutputStream;
00023 import java.io.IOException;
00024 import java.io.InputStream;
00025 import java.io.OutputStream;
00026
00027 import org.apache.commons.httpclient.Credentials;
00028 import org.apache.commons.httpclient.Header;
00029 import org.apache.commons.httpclient.HttpClient;
00030 import org.apache.commons.httpclient.HttpException;
00031 import org.apache.commons.httpclient.HttpMethod;
00032 import org.apache.commons.httpclient.HttpStatus;
00033 import org.apache.commons.httpclient.HttpVersion;
00034 import org.apache.commons.httpclient.URI;
00035 import org.apache.commons.httpclient.URIException;
00036 import org.apache.commons.httpclient.UsernamePasswordCredentials;
00037 import org.apache.commons.httpclient.auth.AuthScope;
00038 import org.apache.commons.httpclient.methods.PostMethod;
00039 import org.apache.commons.httpclient.methods.RequestEntity;
00040 import org.apache.commons.httpclient.params.HttpMethodParams;
00041 import org.apache.xmlrpc.XmlRpcException;
00042 import org.apache.xmlrpc.XmlRpcRequest;
00043 import org.apache.xmlrpc.common.XmlRpcStreamConfig;
00044 import org.apache.xmlrpc.common.XmlRpcStreamRequestConfig;
00045 import org.apache.xmlrpc.util.HttpUtil;
00046 import org.apache.xmlrpc.util.XmlRpcIOException;
00047 import org.xml.sax.SAXException;
00048
00049
00053 public class XmlRpcCommonsTransport extends XmlRpcHttpTransport {
00057 private static final int MAX_REDIRECT_ATTEMPTS = 100;
00058
00059 protected final HttpClient client;
00060 private static final String userAgent = USER_AGENT + " (Jakarta Commons httpclient Transport)";
00061 protected PostMethod method;
00062 private int contentLength = -1;
00063 private XmlRpcHttpClientConfig config;
00064
00068 public XmlRpcCommonsTransport(XmlRpcCommonsTransportFactory pFactory) {
00069 super(pFactory.getClient(), userAgent);
00070 HttpClient httpClient = pFactory.getHttpClient();
00071 if (httpClient == null) {
00072 httpClient = newHttpClient();
00073 }
00074 client = httpClient;
00075 }
00076
00077 protected void setContentLength(int pLength) {
00078 contentLength = pLength;
00079 }
00080
00081 protected HttpClient newHttpClient() {
00082 return new HttpClient();
00083 }
00084
00085 protected void initHttpHeaders(XmlRpcRequest pRequest) throws XmlRpcClientException {
00086 config = (XmlRpcHttpClientConfig) pRequest.getConfig();
00087 method = newPostMethod(config);
00088 super.initHttpHeaders(pRequest);
00089
00090 if (config.getConnectionTimeout() != 0)
00091 client.getHttpConnectionManager().getParams().setConnectionTimeout(config.getConnectionTimeout());
00092
00093 if (config.getReplyTimeout() != 0)
00094 client.getHttpConnectionManager().getParams().setSoTimeout(config.getReplyTimeout());
00095
00096 method.getParams().setVersion(HttpVersion.HTTP_1_1);
00097 }
00098
00099 protected PostMethod newPostMethod(XmlRpcHttpClientConfig pConfig) {
00100 return new PostMethod(pConfig.getServerURL().toString());
00101 }
00102
00103 protected void setRequestHeader(String pHeader, String pValue) {
00104 method.setRequestHeader(new Header(pHeader, pValue));
00105 }
00106
00107 protected boolean isResponseGzipCompressed() {
00108 Header h = method.getResponseHeader( "Content-Encoding" );
00109 if (h == null) {
00110 return false;
00111 } else {
00112 return HttpUtil.isUsingGzipEncoding(h.getValue());
00113 }
00114 }
00115
00116 protected InputStream getInputStream() throws XmlRpcException {
00117 try {
00118 checkStatus(method);
00119 return method.getResponseBodyAsStream();
00120 } catch (HttpException e) {
00121 throw new XmlRpcClientException("Error in HTTP transport: " + e.getMessage(), e);
00122 } catch (IOException e) {
00123 throw new XmlRpcClientException("I/O error in server communication: " + e.getMessage(), e);
00124 }
00125 }
00126
00127 protected void setCredentials(XmlRpcHttpClientConfig pConfig) throws XmlRpcClientException {
00128 String userName = pConfig.getBasicUserName();
00129 if (userName != null) {
00130 String enc = pConfig.getBasicEncoding();
00131 if (enc == null) {
00132 enc = XmlRpcStreamConfig.UTF8_ENCODING;
00133 }
00134 client.getParams().setParameter(HttpMethodParams.CREDENTIAL_CHARSET, enc);
00135 Credentials creds = new UsernamePasswordCredentials(userName, pConfig.getBasicPassword());
00136 AuthScope scope = new AuthScope(null, AuthScope.ANY_PORT, null, AuthScope.ANY_SCHEME);
00137 client.getState().setCredentials(scope, creds);
00138 client.getParams().setAuthenticationPreemptive(true);
00139 }
00140 }
00141
00142 protected void close() throws XmlRpcClientException {
00143 method.releaseConnection();
00144 }
00145
00146 protected boolean isResponseGzipCompressed(XmlRpcStreamRequestConfig pConfig) {
00147 Header h = method.getResponseHeader( "Content-Encoding" );
00148 if (h == null) {
00149 return false;
00150 } else {
00151 return HttpUtil.isUsingGzipEncoding(h.getValue());
00152 }
00153 }
00154
00155 protected boolean isRedirectRequired() {
00156 switch (method.getStatusCode()) {
00157 case HttpStatus.SC_MOVED_TEMPORARILY:
00158 case HttpStatus.SC_MOVED_PERMANENTLY:
00159 case HttpStatus.SC_SEE_OTHER:
00160 case HttpStatus.SC_TEMPORARY_REDIRECT:
00161 return true;
00162 default:
00163 return false;
00164 }
00165 }
00166
00167 protected void resetClientForRedirect()
00168 throws XmlRpcException {
00169
00170 Header locationHeader = method.getResponseHeader("location");
00171 if (locationHeader == null) {
00172 throw new XmlRpcException("Invalid redirect: Missing location header");
00173 }
00174 String location = locationHeader.getValue();
00175
00176 URI redirectUri = null;
00177 URI currentUri = null;
00178 try {
00179 currentUri = method.getURI();
00180 String charset = currentUri.getProtocolCharset();
00181 redirectUri = new URI(location, true, charset);
00182 method.setURI(redirectUri);
00183 } catch (URIException ex) {
00184 throw new XmlRpcException(ex.getMessage(), ex);
00185 }
00186
00187
00188 method.getHostAuthState().invalidate();
00189 }
00190
00191 protected void writeRequest(final ReqWriter pWriter) throws XmlRpcException {
00192 method.setRequestEntity(new RequestEntity(){
00193 public boolean isRepeatable() { return true; }
00194 public void writeRequest(OutputStream pOut) throws IOException {
00195 try {
00196
00197
00198
00199 OutputStream ostream;
00200 if (isUsingByteArrayOutput(config)) {
00201
00202 ostream = new FilterOutputStream(pOut){
00203 public void close() throws IOException {
00204 flush();
00205 }
00206 };
00207 } else {
00208 ostream = new BufferedOutputStream(pOut){
00209 public void close() throws IOException {
00210 flush();
00211 }
00212 };
00213 }
00214 pWriter.write(ostream);
00215 } catch (XmlRpcException e) {
00216 throw new XmlRpcIOException(e);
00217 } catch (SAXException e) {
00218 throw new XmlRpcIOException(e);
00219 }
00220 }
00221 public long getContentLength() { return contentLength; }
00222 public String getContentType() { return "text/xml"; }
00223 });
00224 try {
00225 int redirectAttempts = 0;
00226 for (;;) {
00227 client.executeMethod(method);
00228 if (!isRedirectRequired()) {
00229 break;
00230 }
00231 if (redirectAttempts++ > MAX_REDIRECT_ATTEMPTS) {
00232 throw new XmlRpcException("Too many redirects.");
00233 }
00234 resetClientForRedirect();
00235 }
00236 } catch (XmlRpcIOException e) {
00237 Throwable t = e.getLinkedException();
00238 if (t instanceof XmlRpcException) {
00239 throw (XmlRpcException) t;
00240 } else {
00241 throw new XmlRpcException("Unexpected exception: " + t.getMessage(), t);
00242 }
00243 } catch (IOException e) {
00244 throw new XmlRpcException("I/O error while communicating with HTTP server: " + e.getMessage(), e);
00245 }
00246 }
00247
00254 private void checkStatus(HttpMethod pMethod) throws XmlRpcHttpTransportException {
00255 final int status = pMethod.getStatusCode();
00256
00257
00258 if (status < 200 || status > 299) {
00259 throw new XmlRpcHttpTransportException(status, pMethod.getStatusText());
00260 }
00261 }
00262 }