MessageContext in SOAPHandler JAX-WS WebService - java

I have a JAX-WS 2.2 WebService and I must take the IP Address of each client that communicate with it. I write a SOAP protocol handler but I can't see the addresses because the handlers doesn't contain this information and using the mimeheaders I can't also see this information. The code of my handler is the follow:
public class AddressHandler implements SOAPHandler<SOAPMessageContext> {
private void takeIPAddress(SOAPMessageContext context) {
try {
SOAPMessage original = context.getMessage();
MimeHeaders mimeheaders = original.getMimeHeaders();
MimeHeader mimeheader = null;
Iterator<?> iter = mimeheaders.getAllHeaders();
for (; iter.hasNext();) {
mimeheader = (MimeHeader) iter.next();
System.out.println("name=" + mimeheader.getName() + ", value="
+ mimeheader.getValue());
}
} catch (Exception e) {
e.printStackTrace();
}
}
#Override
public void close(MessageContext arg0) {
// TODO Auto-generated method stub
}
#Override
public boolean handleFault(SOAPMessageContext arg0) {
// TODO Auto-generated method stub
return false;
}
#Override
public boolean handleMessage(SOAPMessageContext context) {
takeIPAddress(context);
return true;
}
#Override
public Set<QName> getHeaders() {
// TODO Auto-generated method stub
return null;
}
}
Now I'm seeing that would be possible to see the addresses using the following code:
SOAPMessageContext jaxwsContext = (SOAPMessageContext)wsContext.getMessageContext();
HttpServletRequest request = HttpServletRequest)jaxwsContext.get(SOAPMessageContext.SERVLET_REQUEST);
String ipAddress = request.getRemoteAddr();
But I can't import correctly the HttpServletRequest class. Do you have any ideas?
UPDATE
Thanks to A Nyar Thar, I've seen that exists another method to take address and I've implemented this in my code, that now is:
private void takeIPAddress(SOAPMessageContext context) {
HttpExchange exchange = (HttpExchange)context.get("com.sun.xml.ws.http.exchange");
InetSocketAddress remoteAddress = exchange.getRemoteAddress();
String remoteHost = remoteAddress.getHostName();
System.out.println(remoteHost);
}
But the code execution create this error (where row 39 is where I do exchange.getRemoteAddress()):
java.lang.NullPointerException
at server.AddressHandler.takeIPAddress(AddressHandler.java:39)
at server.AddressHandler.handleMessage(AddressHandler.java:80)
at server.AddressHandler.handleMessage(AddressHandler.java:1)
at com.sun.xml.internal.ws.handler.HandlerProcessor.callHandleMessage(HandlerProcessor.java:282)
at com.sun.xml.internal.ws.handler.HandlerProcessor.callHandlersRequest(HandlerProcessor.java:125)
at com.sun.xml.internal.ws.handler.ServerSOAPHandlerTube.callHandlersOnRequest(ServerSOAPHandlerTube.java:123)
at com.sun.xml.internal.ws.handler.HandlerTube.processRequest(HandlerTube.java:105)
at com.sun.xml.internal.ws.api.pipe.Fiber.__doRun(Fiber.java:626)
at com.sun.xml.internal.ws.api.pipe.Fiber._doRun(Fiber.java:585)
at com.sun.xml.internal.ws.api.pipe.Fiber.doRun(Fiber.java:570)
at com.sun.xml.internal.ws.api.pipe.Fiber.runSync(Fiber.java:467)
at com.sun.xml.internal.ws.server.WSEndpointImpl$2.process(WSEndpointImpl.java:299)
at com.sun.xml.internal.ws.transport.http.HttpAdapter$HttpToolkit.handle(HttpAdapter.java:593)
at com.sun.xml.internal.ws.transport.http.HttpAdapter.handle(HttpAdapter.java:244)
at com.sun.xml.internal.ws.transport.http.server.WSHttpHandler.handleExchange(WSHttpHandler.java:95)
at com.sun.xml.internal.ws.transport.http.server.WSHttpHandler.handle(WSHttpHandler.java:80)
at com.sun.net.httpserver.Filter$Chain.doFilter(Filter.java:77)
at sun.net.httpserver.AuthFilter.doFilter(AuthFilter.java:83)
at com.sun.net.httpserver.Filter$Chain.doFilter(Filter.java:80)
at sun.net.httpserver.ServerImpl$Exchange$LinkHandler.handle(ServerImpl.java:677)
at com.sun.net.httpserver.Filter$Chain.doFilter(Filter.java:77)
at sun.net.httpserver.ServerImpl$Exchange.run(ServerImpl.java:649)
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
at java.lang.Thread.run(Thread.java:744)
I think that the real problem is that I don't know how take WebServiceContext from my class AddressHandler. Do you have ideas?

For JAX-WS based webservice, you can access remote host info from javax.xml.ws.spi.http.HttpExchange, that can be accessed based on JAX-WS version,
JAX-WS 2.1
SOAPMessageContext soapContext = (SOAPMessageContext)wsContext.getMessageContext();
HttpExchange exchange = (HttpExchange)soapContext.get(JAXWSProperties.HTTP_EXCHANGE);
JAX-WS 2.2
SOAPMessageContext soapContext = (SOAPMessageContext)wsContext.getMessageContext();
HttpExchange exchange = (HttpExchange)soapContext.get("com.sun.xml.ws.http.exchange");
Note that wsContext.getMessageContext() will return MessageContext. If you want it, don't cast to SOAPMessageContext, like that,
MessageContext msgContext = wsContext.getMessageContext();
Finally you can access remote address info,
InetSocketAddress remoteAddress = exchange.getRemoteAddress();
String remoteHost = remoteAddress.getHostName();

Related

How to get SOAP fault message have no mapped in wsdl

I generated my client soap from wsimport JAX-WS, I have already consumed others webservice that it had fault message mapped, but the service current doesn't have.
When I call the service and it returns fault message I can't get the message in the Java, but if call from soapUI I can see the error.
The fault message is the same of the success, generated from JAX-WS.
My code:
//before I setter my request
try{
IPGApiOrderService iPGApiOrderService = new IPGApiOrderService();
IPGApiOrder client = iPGApiOrderService.getIPGApiOrderSoap11();
IPGApiOrderResponse response = client.ipgApiOrder(request)
}catch (SOAPFaultException soapEx) {
System.out.println("Fault ............. " + soapEx.getFault());
System.out.println("Detail ............ " + soapEx.getFault().getDetail());
System.out.println("FaultCode.......... " + soapEx.getFault().getFaultCode());
System.out.println("FaultActor......... " + soapEx.getFault().getFaultActor());
System.out.println("Message............ " + soapEx.getMessage());
soapEx.printStackTrace();
}
follow the out
Fault ............. [SOAP-ENV:Fault: null]
Detail ............ [detail: null]
FaultCode.......... SOAP-ENV:Client
FaultActor......... null
Message............ Client received SOAP Fault from server: ProcessingException Please see the server log to find more detail regarding exact cause of the failure.
com.sun.xml.internal.ws.fault.ServerSOAPFaultException: Client received SOAP Fault from server: ProcessingException Please see the server log to find more detail regarding exact cause of the failure.
at com.sun.xml.internal.ws.fault.SOAP11Fault.getProtocolException(SOAP11Fault.java:178)
at com.sun.xml.internal.ws.fault.SOAPFaultBuilder.createException(SOAPFaultBuilder.java:124)
at com.sun.xml.internal.ws.client.sei.StubHandler.readResponse(StubHandler.java:238)
at com.sun.xml.internal.ws.db.DatabindingImpl.deserializeResponse(DatabindingImpl.java:189)
at com.sun.xml.internal.ws.db.DatabindingImpl.deserializeResponse(DatabindingImpl.java:276)
at com.sun.xml.internal.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:104)
at com.sun.xml.internal.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:77)
at com.sun.xml.internal.ws.client.sei.SEIStub.invoke(SEIStub.java:147)
at com.sun.proxy.$Proxy36.ipgApiOrder(Unknown Source)
at com.firstdata.test.demo.MainTest.main(MainTest.java:53)
I resolved my problem with following steps.
Create SOAPHandler;
It'll be necessary implement 4 methods;
On method handleFault get SOAPMessageContext -> SOAPMessage -> SOAPBody -> Fault -> Detail -> add detail with xml error or some information do you want.
3.1 Fault you can put fault code, if API you was consuming always return one code error to API fault.
4. On exception you find that detail you set and work with it.
Code:
public class SOAPHandlerImpl implements SOAPHandler<SOAPMessageContext> {
public static final QName JSON_ERROR = new QName("json-error");
public boolean handleMessage(SOAPMessageContext smc) {
SOAPMessage message = smc.getMessage();
Boolean isOut = (Boolean) smc.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
return isOut;
}
#Override
public boolean handleFault(SOAPMessageContext context) {
SOAPMessage message = context.getMessage();
try {
StringOutputStream str = new StringOutputStream();
message.writeTo(str);
ErrorDTO dto = XmlUtil.buildErroDTO(str.toString());
Detail detail = message.getSOAPBody().getFault().getDetail();
Gson gson = new Gson();
String obj = gson.toJson(dto);
detail.addDetailEntry(JSON_ERROR).addTextNode(obj);
message.getSOAPBody().getFault().setFaultCode(String.valueOf(dto.getTransactionId()));
} catch (Exception e) {
System.out.println("Exception in handler: " + e);
}
return true;
}
#Override
public void close(MessageContext context) {
// TODO Auto-generated method stub
}
#Override
public Set<QName> getHeaders() {
// TODO Auto-generated method stub
return null;
}
}
Catch exception
} catch (SOAPFaultException sopex) {
ErrorDTO error = null;
Iterator childElements = sopex.getFault().getDetail().getChildElements();
while (childElements.hasNext()) {
DetailEntry next = (DetailEntry) childElements.next();
if (SOAPHandlerImpl.JSON_ERROR.getLocalPart().equals(next.getNodeName())) {
Gson gson = new Gson();
error = gson.fromJson(next.getValue(), ErrorDTO.class);
}
}
String message = null;
if(error.getProcessorResponseCode() != null) {
message = ErrorApiUtil.getInstance().getMessage(error.getProcessorResponseCode());
}else {
message = error.getMessage();
}
throw new BusinessException(message);
}

Requests and response from netty server hangs

I have the following code to create a netty web server based on http server created in the netty's example. My buisness logic is the following.
public class HttpServerHandler extends SimpleChannelInboundHandler<Object> {
private final static Logger LOG = LogManager
.getLogger(HttpServerHandler.class);
private WorkflowService workflowService;
private HttpRequest request;
private final StringBuffer buff = new StringBuffer();
private API avalancheApi;
public HttpServerHandler(WorkflowService workflowService) {
this.workflowService = workflowService;
this.avalancheApi = new API(this.workflowService);
}
#Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
LOG.debug("channelActive");
LOG.debug(ctx.toString());
};
#Override
public void channelReadComplete(ChannelHandlerContext ctx) {
ctx.flush();
}
#Override
public void channelRead0(ChannelHandlerContext ctx, Object msg)
throws IOException {
avalancheApi.setContext(ctx);
if (msg instanceof HttpRequest) {
HttpRequest request = this.request = (HttpRequest) msg;
if (HttpHeaders.is100ContinueExpected(request)) {
send100Continue(ctx);
}
String command = getCommand(request);
LOG.debug(command);
Map<String, List<String>> parameters = getParameters(request);
LOG.debug(parameters);
switch (command) {
case "/login":
ctx = avalancheApi.login(parameters);
break;
case "/test":
ctx = avalancheApi.test();
break;
default:
break;
}
}
if (msg instanceof LastHttpContent) {
LOG.debug("msg is of LastHttpContent");
}
if (!HttpHeaders.isKeepAlive(request)) {
// If keep-alive is off, close the connection once the content is
// fully written.
ctx.writeAndFlush(Unpooled.EMPTY_BUFFER).addListener(
ChannelFutureListener.CLOSE);
}
}
public class API {
private static final Logger LOG = LogManager.getLogger(API.class);
private ChannelHandlerContext ctx;
private HttpResponse response;
private WorkflowService workflowService;
public API(WorkflowService workflowService) {
this.workflowService = workflowService;
this.ctx = null;
}
public void setContext(ChannelHandlerContext ctx) {
this.ctx = ctx;
}
public ChannelHandlerContext login(Map<String, List<String>> parameters) {
boolean success;
String username = getUsername(parameters);
String password = getPassword(parameters);
User user = null;
user = workflowService.login(username, password);
success = validateLogin(user);
this.response = writeLoginResponse(success);
this.ctx.write(this.response);
writeLoginContext(success, response);
return this.ctx;
}
private void writeLoginContext(boolean success, HttpResponse response) {
JsonObject jsonResponseMessage = new JsonObject();
jsonResponseMessage.addProperty("result", success);
LOG.debug(jsonResponseMessage.toString());
this.ctx.write(Unpooled.copiedBuffer(jsonResponseMessage.toString(),
CharsetUtil.UTF_8));
this.response.headers().set(HttpHeaders.Names.CONTENT_LENGTH,
jsonResponseMessage.toString().length());
}
private HttpResponse writeLoginResponse(boolean success) {
if (success)
return createSuccessfullLoginResponse();
else
return createLoginFailureResponse();
}
private HttpResponse createLoginFailureResponse() {
return Response.loginFailureResponse();
}
private HttpResponse createSuccessfullLoginResponse() {
return Response.loginSuccessResponse();
}
}
Response class is only creating the response and the content_type which is of application/json. Content Length is set in the API class. Using python client with requests, results in the request made in http://localhost/login?username=name&password=pass works only once. The second time everything works, but it doesn't finish processing the request and send the response object. Api calls get executed normally, and I also get the message of LastHttpContext message getting print. The problem sometimes happens with browser too. Am I missing something? Maybe the content data and the content length doesn't match? Could it be that when making requests from python client, the content of the previous context isn't flushed and the content_length value of the header and content length of the context doesn't match?
Just wild guess
this.response.headers().set(HttpHeaders.Names.CONTENT_LENGTH,
jsonResponseMessage.toString().length());
Instead, shouldn't you be doing jsonResponseMessage.toString().getBytes().length ?? Sometimes, one character is not just one byte.
My guess is that you have overwritten the context in your API class, and as a result, are writing the response to the wrong context. Is your HttpServerHandler marked with #Shareable?

sip authorization header cannot be added

I have a question about authentication with jain sip library. I am using jain sip for registering sip accounts to Asterisk server.
As soon as I try to add AuthorizationHeader the following error message appears:
The method makeAuthHeader(HeaderFactory, Response, Request, String, String) is undefined for the type Utils
Here is the code snippet:
AuthorizationHeader authHeader = Utils.makeAuthHeader(
headerFactory, response, request, userId, password);
request.addHeader(authHeader);
It seems that cannot method makeAuthHeader() cannot be found.
Code SipClientServiceImpl.java:
#Service("clientService")
public class SipClientServiceImpl implements SipClientService, SipListener {
SipFactory sipFactory; // Used to access the SIP API.
SipStack sipStack; // The SIP stack.
SipProvider sipProvider; // Used to send SIP messages.
MessageFactory messageFactory; // Used to create SIP message factory.
HeaderFactory headerFactory; // Used to create SIP headers.
AddressFactory addressFactory; // Used to create SIP URIs.
ListeningPoint listeningPoint; // SIP listening IP address/port.
Properties properties; // Other properties.
// Objects keeping local configuration.
String ip; // The local IP address.
int port = 6060; // The local port.
String protocol = "udp"; // The local protocol (UDP).
int tag = (new Random()).nextInt(); // The local tag.
Address contactAddress; // The contact address.
ContactHeader contactHeader;
String asteriskServer = "10.0.0.0.0";
int asteriksPort = 5060;
String sipPasswordForAllAccounts = "1234";
Request request = null;
Response response = null;
private ClientTransaction inviteTid;
long invco = 1;
public void registerToAsterisk(String userId) throws ParseException,
InvalidArgumentException, PeerUnavailableException,
TransportNotSupportedException, ObjectInUseException,
TooManyListenersException {
init();
try {
// Get the destination address from the text field.
Address addressTo = addressFactory.createAddress("sip:" + userId
+ '#' + asteriskServer + ":" + asteriksPort);
// Create the request URI for the SIP message.
javax.sip.address.URI requestURI = addressTo.getURI();
// Create the SIP message headers.
// The "Via" headers.
ArrayList viaHeaders = new ArrayList();
ViaHeader viaHeader = this.headerFactory.createViaHeader(this.ip,
this.port, "udp", null);
viaHeaders.add(viaHeader);
// The "Max-Forwards" header.
MaxForwardsHeader maxForwardsHeader = this.headerFactory
.createMaxForwardsHeader(70);
// The "Call-Id" header.
CallIdHeader callIdHeader = this.sipProvider.getNewCallId();
// The "CSeq" header.
CSeqHeader cSeqHeader = this.headerFactory.createCSeqHeader(1L,
"REGISTER");
// The "From" header.
FromHeader fromHeader = this.headerFactory.createFromHeader(
this.contactAddress, String.valueOf(this.tag));
// The "To" header.
ToHeader toHeader = this.headerFactory.createToHeader(addressTo,
null);
// AuthorizationHeader authHeader = Utils.makeAuthHeader(
// headerFactory, response, request, userId,
// sipPasswordForAllAccounts);
// Create the REGISTER request.
Request request = this.messageFactory.createRequest(requestURI,
"REGISTER", callIdHeader, cSeqHeader, fromHeader, toHeader,
viaHeaders, maxForwardsHeader);
// Add the "Contact" header to the request.
request.addHeader(contactHeader);
// request.addHeader(authHeader);
// Send the request statelessly through the SIP provider.
this.sipProvider.sendRequest(request);
} catch (Exception e) {
// TODO: handle exception
}
// TODO Auto-generated method stub
}
public void processRequest(RequestEvent requestEvent) {
}
public void processResponse(ResponseEvent responseEvent) {
Response response = responseEvent.getResponse();
System.out.println(response);
ClientTransaction tid = responseEvent.getClientTransaction();
CSeqHeader cseq = (CSeqHeader) response.getHeader(CSeqHeader.NAME);
System.out.println("Response received : Status Code = "
+ response.getStatusCode() + " " + cseq);
// if (tid == null) {
// System.out.println("Stray response -- dropping ");
// return;
// }
try {
if (response.getStatusCode() == Response.PROXY_AUTHENTICATION_REQUIRED
|| response.getStatusCode() == Response.UNAUTHORIZED) {
AuthenticationHelper authenticationHelper = ((SipStackExt) sipStack)
.getAuthenticationHelper(new AccountManagerImpl(),
headerFactory);
inviteTid = authenticationHelper.handleChallenge(response, tid,
sipProvider, 5, false);
inviteTid.sendRequest();
invco++;
}
} catch (Exception ex) {
ex.printStackTrace();
System.exit(0);
}
}
public void processTimeout(TimeoutEvent timeoutEvent) {
// TODO Auto-generated method stub
}
public void processIOException(IOExceptionEvent exceptionEvent) {
// TODO Auto-generated method stub
}
public void processTransactionTerminated(
TransactionTerminatedEvent transactionTerminatedEvent) {
// TODO Auto-generated method stub
}
public void processDialogTerminated(
DialogTerminatedEvent dialogTerminatedEvent) {
// TODO Auto-generated method stub
}
public void init() {
// Get the local IP address.
try {
this.ip = InetAddress.getLocalHost().getHostAddress();
// Create the SIP factory and set the path name.
this.sipFactory = SipFactory.getInstance();
this.sipFactory.setPathName("gov.nist");
// Create and set the SIP stack properties.
this.properties = new Properties();
this.properties.setProperty("javax.sip.STACK_NAME", "stack");
// Create the SIP stack.
this.sipStack = this.sipFactory.createSipStack(this.properties);
// Create the SIP message factory.
this.messageFactory = this.sipFactory.createMessageFactory();
// Create the SIP header factory.
this.headerFactory = this.sipFactory.createHeaderFactory();
// Create the SIP address factory.
this.addressFactory = this.sipFactory.createAddressFactory();
// Create the SIP listening point and bind it to the local IP
// address, port and protocol.
this.listeningPoint = this.sipStack.createListeningPoint(this.ip,
this.port, this.protocol);
// Create the SIP provider.
this.sipProvider = this.sipStack
.createSipProvider(this.listeningPoint);
// Add our application as a SIP listener.
this.sipProvider.addSipListener(this);
// Create the contact address used for all SIP messages.
this.contactAddress = this.addressFactory.createAddress("sip:"
+ this.ip + ":" + this.port);
// Create the contact header used for all SIP messages.
this.contactHeader = this.headerFactory
.createContactHeader(contactAddress);
} catch (Exception e) {
e.printStackTrace();
}
}
}
Stack trace:
javax.sip.SipException: Unexpected exception
at gov.nist.javax.sip.clientauthutils.AuthenticationHelperImpl.handleChallenge(AuthenticationHelperImpl.java:298)
at com.musala.ving.voip.SipClientServiceImpl.processResponse(SipClientServiceImpl.java:152)
at gov.nist.javax.sip.EventScanner.deliverEvent(EventScanner.java:296)
at gov.nist.javax.sip.EventScanner.run(EventScanner.java:519)
at java.lang.Thread.run(Unknown Source)
Caused by: java.lang.NullPointerException
at gov.nist.javax.sip.clientauthutils.AuthenticationHelperImpl.handleChallenge(AuthenticationHelperImpl.java:149)
... 4 more
Any suggestion is appreciated!
Thank you!
Well, Utils is not part of the API and it simply doesn't have the method you are trying to use. The best way to do client auth is to use the example from https://svn.java.net/svn/jsip~svn/trunk/src/examples/authorization/ShootistAuth.java
This is the relevant part:
if (response.getStatusCode() == Response.PROXY_AUTHENTICATION_REQUIRED
|| response.getStatusCode() == Response.UNAUTHORIZED) {
AuthenticationHelper authenticationHelper =
((SipStackExt) sipStack).getAuthenticationHelper(new AccountManagerImpl(), headerFactory);
inviteTid = authenticationHelper.handleChallenge(response, tid, sipProvider, 5);
inviteTid.sendRequest();
invco++;
}
The class Utils doesn't own this method as you can see here:
http://grepcode.com/file/repo1.maven.org/maven2/javax.sip/jain-sip-ri/1.2.203/gov/nist/javax/sip/Utils.java
You have to use something different but I cannot find anything about what class/method to use.

How to get the response header in a RestEasy client?

i´m implementing a Restful service using Jax-RS 2.0 (Resteasy 3.0.7.Final) and share the interface between client and service.
The return value is void because ClientResponse is deprecated since RestEasy introduced JAX-RS 2.0 in version 3+.
To return the location of the new created object i inject the response, using the #Context annotation, and add the Content-Location header.
For example:
Shared Interface:
#Path("/")
#Consumes("application/xml")
#Produces("application/xml")
interface Resource {
#Path("createSomething")
void createSomething(AnyObject object);
...
}
Implementation class (The Service):
class ResourceImpl {
...
#Context org.jboss.resteasy.spi.HttpResponse response;
...
#Override
void createSomething(AnyObject object) throws AnyException {
String id = service.create(object);
response.getOutputHeaders().putSingle("Content-Location",
"/createSomething/" + id);
response.setStatus(Response.Status.CREATED.getStatusCode());
}
}
The client (build with the Resteasy Proxy Framework):
...
ResteasyClient client = new ResteasyClientBuilder().build();
ResteasyWebTarget target = client.target(baseUrl);
Resource resource = (Resource) target.proxy(Resource.class);
resource.createSomething(anyObject);
...
How can i retrieve Header information (and others, like Atom Links) which has been injected by the service?
Is it reasonable to use client side Filters and Interceptors?
Thank You
The best solution i found was to use a Filter to process the incoming response header.
public class HeaderFilter implements ClientResponseFilter {
private Map<String, String> headers = new HashMap<>();
private List<String> headerFilter = new ArrayList<>();
public final void addHeaderFilter(final String header) {
headerFilter.add(header);
}
public final void removeHeaderFilter(final String header) {
headerFilter.remove(header);
}
public final String getHeader(final String header) {
return headers.get(header);
}
#Override
public final void filter(final ClientRequestContext requestContext,
final ClientResponseContext responseContext)
throws IOException {
headers = new HashMap<>();
for (String headerToLookFor : headerFilter) {
String header = responseContext.getHeaderString(headerToLookFor);
if (header != null) {
headers.put(headerToLookFor, header);
} else {
...
}
}
}
}

How to add soap header when making a soap request using the java objects generated by wsdl

I generated client java objects using JAX-WS RI. I am trying to make a SOAP request to a web service. Service requires authentication in the header which looks like below:
<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/">
<soapenv:Header>
<xsd:authHeader>
<xsd:user>username#gmail.com</xsd:user>
<xsd:password>password1</xsd:password>
</xsd:authHeader>
</soapenv:Header>
<soapenv:Body>
<ns:searchAssetsParam>
<ns:includeSubfolders>true</ns:includeSubfolders>
<ns:resultsPage>2</ns:resultsPage>
</ns:searchAssetsParam>
</soapenv:Body>
</soapenv:Envelope>
The generated java objects have methods for calling the service, creating the objects and constructing the header. But, I am having trouble setting the header while making the call.
Here's the code that I am using:
IpsApiService service = new IpsApiService();
IpsApiPortType port = service.getIpsApiSoapPort();
SearchAssetsParam searchAssetsParam = buildSearchAssetsParam();
SearchAssetsReturn response = port.searchAssets(searchAssetsParam);
buildSearchAssetsParam() constructs the request object.
I created the header object as follows:
AuthHeader header = new AuthHeader();
header.setUser("username#gmail.com");
header.setPassword("password1");
How do I set this AuthHeader to the service request?
Thanks,
Venu
Once I had the same problem. I needed to modify the JAX-WS web service SOAP header at every request. To solve this problem I have created a handler like this:
public class MyHandler implements SOAPHandler<SOAPMessageContext> {
private static final Logger LOGGER = LoggerFactory.getLogger(MyHandler.class);
private String username;
private String password;
#Override
public boolean handleMessage(SOAPMessageContext context) {
try {
SOAPMessage message = context.getMessage();
SOAPHeader header = message.getSOAPHeader();
SOAPEnvelope envelope = message.getSOAPPart().getEnvelope();
if (header == null) {
header = envelope.addHeader();
}
QName qNameUserCredentials = new QName("https://your.target.namespace/", "UserCredentials");
SOAPHeaderElement userCredentials = header.addHeaderElement(qNameUserCredentials);
QName qNameUsername = new QName("https://your.target.namespace/", "Username");
SOAPHeaderElement username = header.addHeaderElement(qNameUsername );
username.addTextNode(this.username);
QName qNamePassword = new QName("https://your.target.namespace/", "Password");
SOAPHeaderElement password = header.addHeaderElement(qNamePassword);
password.addTextNode(this.password);
userCredentials.addChildElement(username);
userCredentials.addChildElement(password);
message.saveChanges();
//TODO: remove this writer when the testing is finished
StringWriter writer = new StringWriter();
message.writeTo(new StringOutputStream(writer));
LOGGER.debug("SOAP message: \n" + writer.toString());
} catch (SOAPException e) {
LOGGER.error("Error occurred while adding credentials to SOAP header.", e);
} catch (IOException e) {
LOGGER.error("Error occurred while writing message to output stream.", e);
}
return true;
}
//TODO: remove this class after testing is finished
private static class StringOutputStream extends OutputStream {
private StringWriter writer;
public StringOutputStream(StringWriter writer) {
this.writer = writer;
}
#Override
public void write(int b) throws IOException {
writer.write(b);
}
}
#Override
public boolean handleFault(SOAPMessageContext context) {
LOGGER.debug("handleFault has been invoked.");
return true;
}
#Override
public void close(MessageContext context) {
LOGGER.debug("close has been invoked.");
}
#Override
public Set<QName> getHeaders() {
LOGGER.debug("getHeaders has been invoked.");
return null;
}
public void setUsername(String username) {
this.username = username;
}
public void setPassword(String password) {
this.password = password;
}
}
It adds the needed parameters to my SOAP header and it is invoked on every request. All you need to do is to modify handleMessage method to suit your needs.
It works for me by overriding the public void setAttribute(String namespace, String localName, String value) method.
import javax.xml.namespace.QName;
import org.apache.axis.Constants;
import org.apache.axis.message.SOAPHeaderElement;
#SuppressWarnings("serial")
public class ADESHeaderElement extends SOAPHeaderElement
{
public ADESHeaderElement(QName qname, Object value)
{
super(qname, value);
}
#Override
public void setAttribute(String namespace, String localName, String value)
{
if (!Constants.ATTR_MUST_UNDERSTAND.equals(localName))
{ // Or any other attribute name you'd want to avoid
super.setAttribute(namespace, localName, value);
}
}
}
Create header element like this:
ADESHeaderElement custheader = new ADESHeaderElement(qname, clientserv);
custheader.setActor(null);
When you create your service from classess generated by cxf, add custom interceptor
Service service = new MyService(wsdlURL, new QName("http://myservice.com/MyService/", "MyService"));
MyPort port = service.getMyPort();
Client client = ClientProxy.getClient(port);
// adding interceptor programmatically
client.getOutInterceptors().add(new MyHeaderHandler());
Your can extend AbstractSoapInterceptor to implement your custom interceptor to handle message.
import javax.xml.bind.JAXBException;
import javax.xml.namespace.QName;
import org.apache.cxf.binding.soap.interceptor.AbstractSoapInterceptor;
import org.apache.cxf.headers.Header;
import org.apache.cxf.jaxb.JAXBDataBinding;
import org.apache.cxf.phase.Phase;
import com.rpc.core.utils.DomainContext;
public class MyHeaderHandler extends AbstractSoapInterceptor {
/**
* Constructor
*/
public MyHeaderHandler() {
super(Phase.PRE_LOGICAL);
}
#Override
public void handleMessage(org.apache.cxf.binding.soap.SoapMessage message) throws org.apache.cxf.interceptor.Fault {
try {
message.getHeaders().add(new Header(new QName("MyCustomHeader"),"value", new JAXBDataBinding(String.class)));
} catch (JAXBException e) {
e.printStackTrace();
}
};
}
}
Yes, I did the same that Rangappa Tungal, following this example:
Service w = new ServiceLocator();
ServiceSoap ws = new ServiceSoapStub(new URL(w.getServiceSoapAddress()),w); Stub mystub = (Stub) ws;
AuthHeader up = new AuthHeader("user","pass");
mystub.setHeader("namespace", "AuthHeader", up);
ws.get***();
Link to the example!

Categories