I need to create a Cookie with a specific name to be sent across in my web service calls to another network which has a routing logic based on it.
When i try to set to the HTTP header in my SOAP handler using
headers.put("Cookie", Collections.singletonList(cookiename + "='" + cookieValue + "'"));
it works for the first time.
The response for this comes with a Set-Cookie for JSESSIONID.
My subsequent requests hold that JSESSIONID and it's value in the cookie and ignores setting my custom cookie.
Is there a way to make sure that my cookie gets set by default in all my requests?
We also needed to support JSESSIONID with SOAP service recently and this is what we came up with after reading StackOverflow and referring to an example of an SSO client on the IBM site.
We extended SOAPHandler:
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import java.util.List;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.handler.soap.SOAPHandler;
import javax.xml.ws.handler.soap.SOAPMessageContext;
import com.sun.istack.internal.Nullable;
public class SoapMessageHandler implements SOAPHandler<SOAPMessageContext> {
private String sessionCookie = "";
@Override
public void close(MessageContext arg0) { }
@SuppressWarnings({ "rawtypes", "unchecked" })
@Override
public Set getHeaders() {
return null;
}
@Override
public boolean handleFault(SOAPMessageContext context) {
return false;
}
@Override
public boolean handleMessage(SOAPMessageContext soapMessageContext) {
if ((Boolean) soapMessageContext.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY)) {
// Add header to outbound request (set cookie in HTTP client header)
// Set the Cookie
Map<String, List<String>> headers = (Map<String, List<String>>)soapMessageContext.get(MessageContext.HTTP_REQUEST_HEADERS);
if (headers == null) {
headers = new HashMap<String, List<String>>();
soapMessageContext.put(MessageContext.HTTP_REQUEST_HEADERS, headers);
}
List<String> cookie = headers.get("Cookie");
if (cookie == null) {
cookie = new ArrayList<String>();
headers.put("Cookie", cookie);
}
cookie.add(sessionCookie);
} else {
// Read header from request (read cookie from server's HTTP headers)
Map<String, List<String>> map = (Map<String, List<String>>) soapMessageContext.get(MessageContext.HTTP_RESPONSE_HEADERS);
List<String> contentType = getHTTPHeader(map, "Set-Cookie");
// Note, only grabs last cookie value!
// If you need to present more than one cookie you could make
// sessionCookie a List<String> and modify this class accordingly.
if (contentType != null) {
StringBuffer strBuf = new StringBuffer();
for (String type : contentType) {
strBuf.append(type);
}
sessionCookie = strBuf.toString();
}
}
return true;
}
private @Nullable List<String> getHTTPHeader(Map<String, List<String>> headers, String header) {
for (Map.Entry<String, List<String>> entry : headers.entrySet()) {
String name = entry.getKey();
if (header != null && name !=null) {
if (name.equalsIgnoreCase(header))
return entry.getValue();
}
}
return null;
}
}
This also requires HandlerResolver:
import java.util.ArrayList;
import java.util.List;
import javax.xml.ws.handler.Handler;
import javax.xml.ws.handler.HandlerResolver;
import javax.xml.ws.handler.PortInfo;
public class SoapHandlerResolver implements HandlerResolver {
@SuppressWarnings("unchecked")
public List<Handler> getHandlerChain(PortInfo portInfo) {
List<Handler> handlerChain = new ArrayList<Handler>();
handlerChain.add( new SoapMessageHandler() );
return handlerChain;
}
}
The extended HandlerResolver is then invoked when calling the SOAP service like so:
ExampleService exampleService = new ExampleService();
exampleService.setHandlerResolver( new SoapHandlerResolver() );
Example example = exampleService.getExampleServicePort();
example.myMethod();
This worked for us, with Java 6, with the limitation of only supporting one Cookie header (though could be trivially modified to support multiple Cookie headers).
NB: If, like us, you have to pass the same session cookie between multiple services (as if cookies on a SOAP service weren't bad enough) instead of this:
private String sessionCookie = "";
You could just do this:
static private String sessionCookie = "";
Which is super hacky, and may or may not work for you depending on how the service (and your code) works and how may sessions you can have on the remote service, so I'd suggest something more sophisticated than using a static in production.