missing header in soap request java - java

I have created SOAP client in pure java. Also I have implemented SOAPHandler to trace the SOAP requests and responses. But when I see the sysouts the header part is missing in the request.
Note that I am calling an enterprise service and that requires a mandatory security header for the service to be called. I am getting proper response with my security header back in the response and also is being sysout.
What could be the issue for blank header trace from SOAPHandler ? Below is my handler code:
public class SOAPLoggingHandler implements SOAPHandler<SOAPMessageContext> {
private static final Logger log = LoggerFactory.getLogger(SOAPLoggingHandler.class);
public boolean handleMessage(SOAPMessageContext context) {
log.info("handleMessage");
logToSystemOut(context);
return true;
}
public boolean handleFault(SOAPMessageContext context) {
log.info("SOAP Fault Occur");
logToSystemOut(context);
return true;
}
public void close(MessageContext context) {
log.info("close");
}
public Set<QName> getHeaders() {
log.info("getHeaders");
return null;
}
protected void logToSystemOut(SOAPMessageContext smc) {
final Boolean outboundProperty = (Boolean) smc.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
final String message = !outboundProperty.booleanValue() ? "Web Service Response\n" : "Web Service Request\n";
logMessage(smc, message);
}
protected void logToSystemOut(SOAPMessageContext smc, String message) {
logMessage(smc, message);
}
private void logMessage(SOAPMessageContext smc, String message) {
try {
final ByteArrayOutputStream oStream = new ByteArrayOutputStream();
final Transformer transformer = TransformerFactory.newInstance().newTransformer();
transformer.setOutputProperty(OutputKeys.INDENT, "yes");
transformer.setOutputProperty("{http://xml.apache.org/xslt}indent-amount", "4");
transformer.transform(new DOMSource(smc.getMessage().getSOAPPart()), new StreamResult(oStream));
oStream.close();
log.info(message + new String(oStream.toByteArray()));
} catch (final Exception e) {
log.warn("Failed to log web service message", e);
}
//some custom logging going on below - could be ignored
SomeLogger someLoggerObj = SomeLogger.getInstance();
try {
someLoggerObj.logSomeMessage(smc, message);
} catch (SOAPException e) {
log.error("SOAP Exception occurred :", e);
} catch (TransformerException e) {
log.error("TransformerException Exception occurred :", e);
}
}
}
My Header is seen as:
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/" xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header/>

I've experienced this week exactly the same issue, I have a chain of 5 SOAP calls with also TLS and SAML, and a mix of services implemented with AXIS and CXF, running aunder the same Tomcat 9 on OpenJDK 11. The issue happened only on production server (RedHat server) and I was not able to reproduce it on my development machine, the header was completely dropped by the java client and it was not possible to debug on the server.
I ended up installing on the target server a dedicated Tomcat 8.5 on JDK 1.8 to run CXF service separated from AXIS ones.
Hope this helps if someone has such a complex configuration, it's not a solution but a workaround.

Related

How to send custom response message instead of Fault message in case of an exception with JAXWS?

In my JAXWS web service I need to send a specific message back to the client when an exception occurs, not the standard Fault message with the description of the exception.
How can this be done?
I am using jaxws-rt version 2.1.3
I have already tried to use exception mappers like this but without luck (some how they are not called, this could also be caused by a mistake in the configuration):
#Provider
public class ThrowableExceptionMapper implements ExceptionMapper<Throwable> {
public ThrowableExceptionMapper() {
// TODO Auto-generated constructor stub
}
#Override
public Response toResponse(Throwable throwable) {
if (throwable instanceof WebApplicationException) {
return ((WebApplicationException) throwable).getResponse();
} else {
return Response.serverError().entity("").build();
}
}
}
The server we use is JBoss EAP 6.4.
Edit:
The exception mapper approach is not suited for my JAXWS web service, because this is for JAX-RS (thanks SRINIVAS K).
Is there something similar available for JAXWS?
I managed to rewrite the response message with the help of this page:
http://www.java-tips.org/java-ee-tips-100042/156-java-api-for-xml-web-services/1958-writing-a-handler-in-jax-ws.html
And with some examples of this page:
http://www.programcreek.com/java-api-examples/index.php?api=javax.xml.ws.handler.MessageContext
I put together this class:
public class MyLogicalHandler implements LogicalHandler<LogicalMessageContext> {
private final String RejectionResponseBody = "<ns2:MessageControllerResponse xmlns:ns2=\"http://some.namespace.com/\"><return>SOMEDATA</return></ns2:MessageControllerResponse>";
#Override
public boolean handleMessage(LogicalMessageContext context) {
return true;
}
#Override
public boolean handleFault(LogicalMessageContext context) {
processMessage(context);
return true;
}
#Override
public void close(MessageContext context) {
}
private void processMessage(LogicalMessageContext context) {
Boolean outboundProperty = (Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
if (outboundProperty) {
LogicalMessage msg = context.getMessage();
msg.setPayload(new StreamSource(new ByteArrayInputStream(RejectionResponseBody.getBytes())));
}
}
}
Edit, additional information added:
You also need to add the HandlerChain annotation to the web service:
...
#HandlerChain(file = "handler-chain.xml")
public class MyWebService {
...
}
And create a handler-chain xml file:
<?xml version="1.0" encoding="UTF-8"?>
<handler-chains xmlns="http://java.sun.com/xml/ns/javaee">
<handler-chain>
<handler>
<handler-class>my.package.ws.jaxws.MyLogicalHandler</handler-class>
</handler>
</handler-chain>
</handler-chains>
And place this file in your resources folder of the web service, you need to use the same package structure as you did with the web service. So create the following package: my.package.ws in the resources folder if your web service class resides in the my.package.ws package.
Can you try using below?
String errorMessage = "this is custom error message";
return Response.status(e.getResponse().getStatus()).entity(errorMessage).build();
Can you check if ExceptionMapper works with generic exceptions like Throwable or Exception. I see some examples with custom defined exceptions that are configured with WebFault annotation.

Java web service : User defined meta-data

I have a SOAP web service implementation on Jboss 4.2.3. I want to add a version number check for the service. Whenever a client makes a call, I will pass the client version number. I will write an interceptor at the server that would check the client version number. If it is a client with a different version number, I would not process the request.
What I want to know is if there is a way to pass the version number from the client in some context parameter other than adding it in the web service method signature?
In general, if I want to pass some custom META-DATA from client to server, how do I do it ?
In general, if I want to pass some custom META-DATA from client to
server, how do I do it ?
This can be achieved through SOAP Message Handlers both side (Client and Server ) in Jax-WS .
Client Side:
The custom-meta-data , like version number, UUID , Signature information can be added via SOAP Headers.
1..Write a VersionNumberHandler as shown below.
public class VersionNumberHandler implements SOAPHandler<SOAPMessageContext> {
private static final String LoggerName = "ClientSideLogger";
private Logger logger;
private final boolean log_p = true; // set to false to turn off
public VersionNumberHandler() {
logger = Logger.getLogger(LoggerName);
}
public boolean handleMessage(SOAPMessageContext ctx) {
if (log_p)
logger.info("handleMessage");
// Is this an outbound message, i.e., a request?
Boolean request_p = (Boolean) ctx
.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
// Manipulate the SOAP only if it's a request
if (request_p) {
// Get the Version Number from some property file ,
// to place in the message header.
String versionNumber = "v1.0";
try {
SOAPMessage msg = ctx.getMessage();
SOAPEnvelope env = msg.getSOAPPart().getEnvelope();
SOAPHeader hdr = env.getHeader();
// Ensure that the SOAP message has a header.
if (hdr == null)
hdr = env.addHeader();
QName qname = new QName("http://ticket.example.com/",
"versionnumber");
SOAPHeaderElement helem = hdr.addHeaderElement(qname);
// In SOAP 1.2, setting the actor is equivalent to
// setting the role.
helem.setActor(SOAPConstants.URI_SOAP_ACTOR_NEXT);
helem.setMustUnderstand(true);
helem.addTextNode(versionNumber);
msg.saveChanges();
// For tracking, write to standard output.
msg.writeTo(System.out);
} catch (SOAPException e) {
System.err.println(e);
} catch (IOException e) {
System.err.println(e);
}
}
return true; // continue down the chain
}
public boolean handleFault(SOAPMessageContext ctx) {
if (log_p)
logger.info("handleFault");
try {
ctx.getMessage().writeTo(System.out);
} catch (SOAPException e) {
System.err.println(e);
} catch (IOException e) {
System.err.println(e);
}
return true;
}
public Set<QName> getHeaders() {
if (log_p)
logger.info("getHeaders");
return null;
}
public void close(MessageContext messageContext) {
if (log_p)
logger.info("close");
}
2..Mention this class in the Handler-Chain.xml.
<javaee:handler>
<javaee:handler-class>
com.example.client.handler.VersionNumberHandler
</javaee:handler-class>
</javaee:handler>
3..Add the handler-chain in the client (Stub) also.
#WebServiceClient(name = "TicketWSImplService", targetNamespace = "http://ticket.example.com/", wsdlLocation = "http://localhost:8080/ticket?wsdl")
#HandlerChain(file = "handler-chain.xml")
public class TicketWSImplService extends Service {
#WebMethod
public void method(){
}
Here, we are adding a new header element "versionnumber" and mustunderstand=true, which means the server/intermediaries has to process this element, otherwise Jax-WS-Runtime will throw SOAP Fault exception to the client. Now we need to write a Validator(SOAP Handler) at the server side to validate this version number which is being passed by the clients.
Server Side:
1..Write a VersionNumberValidator as shown below.
public class VersionNumberValidator implements SOAPHandler<SOAPMessageContext> {
#SuppressWarnings("unused")
#Override
public boolean handleMessage(SOAPMessageContext ctx) {
// Is this an inbound message, i.e., a request?
Boolean response_p = (Boolean) ctx
.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
// Manipulate the SOAP only if it's incoming.
if (!response_p) {
try {
SOAPMessage msg = ctx.getMessage();
SOAPEnvelope env = msg.getSOAPPart().getEnvelope();
SOAPHeader hdr = env.getHeader();
// Ensure that the SOAP message has a header.
if (hdr == null) {
generateSOAPFault(msg, "No message header.");
return true;
}
Iterator mustUnderstandHeaders = msg.getSOAPHeader()
.examineMustUnderstandHeaderElements(
"http://schemas.xmlsoap.org/soap/actor/next");
String value = null;
while (mustUnderstandHeaders.hasNext()) {
Node next = (Node) mustUnderstandHeaders.next();
System.out.println("mustUnderstandHeaders name:"
+ next.getValue());
if (next.getNodeName().equalsIgnoreCase("versionnumber"))
value = next.getValue();
if (value != null && !value.equalsIgnoreCase("v1.0")) {
generateSOAPFault(msg, "Version Number Mismatch");
}
}
// For tracking, write to standard output.
msg.writeTo(System.out);
} catch (SOAPException e) {
System.err.println(e);
} catch (IOException e) {
System.err.println(e);
}
}
return true; // continue down the chain
}
#Override
public boolean handleFault(SOAPMessageContext ctx) {
return true; // do continue down the chain
}
// For now, no-ops.
#Override
public Set<QName> getHeaders() {
Set<QName> headers = new HashSet<QName>();
QName qName = new QName("http://ticket.example.com/", "versionnumber");
headers.add(qName);
return headers;
}
#Override
public void close(MessageContext messageContext) {
}
private void generateSOAPFault(SOAPMessage msg, String reason) {
try {
SOAPBody body = msg.getSOAPBody();
SOAPFault fault = body.addFault();
QName fault_name = new QName(
SOAPConstants.URI_NS_SOAP_1_2_ENVELOPE, "UltimateReceiver");
fault.setFaultCode(fault_name);
fault.setFaultRole("http://ticket.example.com/versionNumber_validator");
fault.addFaultReasonText(reason, Locale.US);
} catch (SOAPException e) {
}
}
2..Mention this class in the Handler-Chain-server.xml.
<javaee:handler>
<javaee:handler-class>
com.example.client.handler.VersionNumberValidator
</javaee:handler-class>
</javaee:handler>
3..Publish the webservices.
Now, the every client request will be having "version number =v1.0", At the server side , you will be validating this value is correct or not. If it is not correct, SOAPFaultException will be thrown.
You could add it to the http-headers but that would mean your client would need to do this which also means they can change it and give you wrong numbers causing issues on the server. It's only as reliable as the messages being sent in.
Either way, this isn't the right way to restrict access to your Web Service, you should use http basic authentication or if it's version differences then you should create multiple version endpoints giving clients access to the versions they need.
Also, JBoss 4.2.3 is so old it might not even work. See [1]
Mus
[1] https://community.jboss.org/message/534711
It's a bad idea to try to add out-of-band metadata to a web service. Just pick a new URL for each version if the data structures are incompatible. If they are compatible, put the version number inside the request.
This way you can still support interoperation with all different libraries and not require your clients to find a new hoop to jump through for each toolkit.

calling some online service from GWT

I have this JavaScript code which is connecting with the service and sending back the result.
Now the requirement is to call the same service from Pure Java.
Below is the javascript code for calling the service.
If some one can guide me to convert this Javascript to Java in my GWT Application
Thanks
function verifyValidationSyntax(textToValidate)
{
var url = "https://validation-grammar.example.com/validation_grammar_service/rest/validation_step_validation";
var client = new XMLHttpRequest();
client.open("POST", url, false);
client.setRequestHeader("Content-Type", "text/plain");
client.send(textToValidate);
if (client.responseText==='true') {
return "true";
} else {
return "false";
}
}
I wont convert your code, But here is the sweetest example from docs
String url = "http://www.myserver.com/getData?type=3";
RequestBuilder builder = new RequestBuilder(RequestBuilder.GET, URL.encode(url));
try {
Request request = builder.sendRequest(null, new RequestCallback() {
public void onError(Request request, Throwable exception) {
// Couldn't connect to server (could be timeout, SOP violation, etc.)
}
public void onResponseReceived(Request request, Response response) {
if (200 == response.getStatusCode()) {
// Process the response in response.getText()
} else {
// Handle the error. Can get the status text from response.getStatusText()
}
}
});
} catch (RequestException e) {
// Couldn't connect to server
}
You may miss this in docs
To use the HTTP types in your application, you'll need to first inherit the GWT HTTP module by adding the following tag to your module XML file:
<inherits name="com.google.gwt.http.HTTP" />

WEBSERVICES : How to store mal-formed XML in webservices?

I am hosting a web service. I wanted to handle the scenario, in case the client sends a mal-formed XML
Here is the handler I have created
public boolean handleMessage(SOAPMessageContext smc)
{
Boolean outboundProperty =
(Boolean)smc.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
SOAPMessage message = null;
try
{
// This handling iss required in case a mal-formed XML is sent.
message = smc.getMessage();
}
catch(Throwable t )
{
// I want to log the XML in the database
// But the problem is I don't know how to get the XML
// as message is null.
}
}
I get to land into the catch(Throwable t) block where I have no information about the XML that was sent.
What I can log into the error log table is just that a mal-formed XML has been sent by client.
Actual Requirement:
To log and store the malformed XML for tracking purposes.
Please use the following code for getting the exact line number and exception in soap message for logging purposes:
public boolean handleMessage(SOAPMessageContext mc) {
try {
final SOAPMessage message = mc.getMessage();
String i = convertToString(message);
System.out.println(i);
return true;
} catch (Exception e) {
System.out.println(e.getMessage());
// e.printStackTrace();
return false;
}
}
This Code will take care of the any malformed SOAP Message

Add header to SOAP message

I need add custom soap header, like login
I do it in way like this
class Foo implements SOAPHandler<SOAPMessageContext> {
public boolean handleMessage(SOAPMessageContext context) {
try {
SOAPMessage soapMsg = context.getMessage();
SOAPEnvelope soapEnv = soapMsg.getSOAPPart().getEnvelope();
soapEnv.addHeader().addAttribute(new QName("login"), "bob");
soapMsg.writeTo(System.out);//tracing OUT
return true;
} catch (SOAPException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}
#HandlerChain(file="handler-chain.xml")//I describe Foo in this file
public class GreeterService
By tracing out I get message
<S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"><S:Header login="bob"/><S:Body><ns2:sayGoodbye xmlns:ns2="http://example.com/"><arg0>SOAP</arg0></ns2:sayGoodbye></S:Body></S:Envelope>
with header
<S:Header login="bob"/>
But server received it without any header
<?xml version="1.0" ?><S:Envelope xmlns:S="http://schemas.xmlsoap.org/soap/envelope/"><S:Body><ns2:sayGoodbye xmlns:ns2="http://example.com/"><arg0 xmlns="">SOAP</arg0></ns2:sayGoodbye></S:Body></S:Envelope>
What I make wrong?
I had the similar issue few days ago, there was a need to send user id by header.
I resolved this problem with special parameter - wsimport -XadditionalHeaders when generating code.

Categories

Resources