| HTTPClientInvoker.java |
/*
* JBoss, the OpenSource J2EE webOS
*
* Distributable under LGPL license.
* See terms of license at gnu.org.
*/
package org.jboss.remoting.transport.http;
import org.apache.commons.httpclient.HttpClient;
import org.apache.commons.httpclient.methods.PostMethod;
import org.jboss.logging.Logger;
import org.jboss.remoting.CannotConnectException;
import org.jboss.remoting.ConnectionFailedException;
import org.jboss.remoting.InvokerLocator;
import org.jboss.remoting.RemoteClientInvoker;
import org.jboss.remoting.marshal.Marshaller;
import org.jboss.remoting.marshal.UnMarshaller;
import org.jboss.remoting.marshal.http.HTTPMarshaller;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
/**
* @author <a href="mailto:tom@jboss.org">Tom Elrod</a>
*/
public class HTTPClientInvoker extends RemoteClientInvoker
{
protected final Logger log = Logger.getLogger(getClass());
public HTTPClientInvoker(InvokerLocator locator)
{
super(locator);
}
/**
*
* @param sessionId
* @param invocation
* @param marshaller
* @return
* @throws java.io.IOException
* @throws org.jboss.remoting.ConnectionFailedException
*
*/
protected Object transport(String sessionId, Object invocation, Map metadata,
Marshaller marshaller, UnMarshaller unmarshaller)
throws IOException, ConnectionFailedException
{
/**
* //TODO: -TME Need to fully javadoc.
* //TODO: -TME Need to think more on what the signature should be for this. Have to pass the marshaller
* to the actual transport implementation as will be up to the transport to figure out how
* it should get the data from the marshaller (streamed or one chunck). Am passing the invocation
* at this point, because don't know if will need to do anything with it later on down the call stack
* and currently, the marshaller does not have a reference to it (so HAVE to pass to marshaller at
* some point). Could change to pass invocation to MarshalFactory when getting Marshaller and
* add it to Marshaller constructor, but then not part of it's interface.
*/
String targetURL = getLocator().getOriginalURI();
//useApacheHttpClient(targetURL);
//useInnovationHttpClient(targetURL);
Object httpResponse = useHttpURLConnection(targetURL, invocation, metadata, marshaller, unmarshaller);
// Object httpResponse = useApacheHttpClient(targetURL, invocation, marshaller);
return httpResponse;
}
private Object useHttpURLConnection(String url, Object invocation, Map metadata,
Marshaller marshaller, UnMarshaller unmarshaller)
{
Object result = null;
try
{
URL externalURL = new URL(url);
HttpURLConnection conn = (HttpURLConnection) externalURL.openConnection();
// Get the request method type
boolean isPost = true;
if(metadata != null)
{
String type = (String) metadata.get("TYPE");
if(type != null && type.equals("GET"))
{
isPost = false;
}
// Set request headers
Map header = (Map) metadata.get("HEADER");
if(header != null)
{
Set keys = header.keySet();
Iterator itr = keys.iterator();
while(itr.hasNext())
{
String key = (String) itr.next();
String value = (String) header.get(key);
log.debug("Setting request header with " + key + " : " + value);
conn.setRequestProperty(key, value);
}
}
}
if(isPost)
{
//POST
conn.setDoOutput(true);
conn.setDoInput(true);
conn.setRequestMethod("POST");
//conn.setRequestProperty("Content-type", "application/soap+xml");
// TODO: -TME Does this really need to be set?
//conn.setRequestProperty("Content-length", String.valueOf(((String)invocation).getBytes().length));
//TODO: -TME How to set the SOAPAction header?
if(metadata != null)
{
String soapAction = (String)metadata.get("SOAPAction");
if (soapAction != null)
{
conn.setRequestProperty("SOAPAction", soapAction);
}
}
OutputStream stream = conn.getOutputStream();
marshaller.write(invocation, stream);
InputStream is = conn.getInputStream();
Map headers = conn.getHeaderFields();
result = unmarshaller.read(is, headers);
}
else
{
throw new Exception("HTTP GET opperation not currently supported.");
}
}
catch(Exception e)
{
log.debug("Error invoking http client invoker.", e);
throw new CannotConnectException("Can not connect http client invoker.", e);
}
return result;
}
/*
private void useInnovationHttpClient(String uri)
{
HTTPConnection conn = new HTTPConnection(uri);
HttpOutputStream output = new HttpOutputStream();
try
{
HTTPResponse response = conn.Post("", output);
byte[] bytes = new String("foobar").getBytes();
output.write(bytes);
output.flush();
System.out.println("response = " + response);
}
catch (IOException e)
{
e.printStackTrace(); //TODO: -TME Implement
}
catch (ModuleException e)
{
e.printStackTrace(); //TODO: -TME Implement
}
}
*/
private Object useApacheHttpClient(String url, Object invocation, Marshaller marshaller)
throws IOException
{
PostMethod post = new PostMethod(url);
post.setRequestHeader("Content-type", "application/soap+xml");
String body = (String) invocation;
post.setRequestContentLength(body.length());
post.setRequestBody(body);
HttpClient client = new HttpClient();
int status = client.executeMethod(post);
//System.out.println("POST returned status " + status);
return post.getResponseBodyAsString();
}
/**
* subclasses must implement this method to provide a hook to connect to the remote server, if this applies
* to the specific transport. However, in some transport implementations, this may not make must difference since
* the connection is not persistent among invocations, such as SOAP. In these cases, the method should
* silently return without any processing.
*
* @throws org.jboss.remoting.ConnectionFailedException
*
*/
protected void handleConnect() throws ConnectionFailedException
{
// NO OP as not statefull connection
}
/**
* subclasses must implement this method to provide a hook to disconnect from the remote server, if this applies
* to the specific transport. However, in some transport implementations, this may not make must difference since
* the connection is not persistent among invocations, such as SOAP. In these cases, the method should
* silently return without any processing.
*/
protected void handleDisconnect()
{
// NO OP as not statefull connection
}
/**
* Each implementation of the remote client invoker should have
* a default data type that is uses in the case it is not specified
* in the invoker locator uri.
*
* @return
*/
protected String getDefaultDataType()
{
return HTTPMarshaller.DATATYPE;
}
}| HTTPClientInvoker.java |