Remove invalid characters from soap response in JAX-WS - java

I am trying to get the lists present on a sharepoint site using SP webservice.
Lists listsSevice = new Lists(new URL(spSiteURL + "/_vti_bin/Lists.asmx?wsdl"));
listsSevice.setHandlerResolver(new SPHandlerResolver());
spListsServiceIfx = listsSevice.getListsSoap();
// Calling the List Web Service
GetListItemsResponse.GetListItemsResult result = spListsServiceIfx .getListItems(listName, viewName, query, viewFields, rowLimit, queryOptions, webID);
However, I get this error because of some invalid character present in soap response.
com.sun.xml.ws.encoding.soap.DeserializationException: Failed to read a response: javax.xml.bind.UnmarshalException
- with linked exception:
[com.ctc.wstx.exc.WstxParsingException: Illegal character entity: expansion character (code 0x15 at [row,col {unknown-source}]: [1125,122]]
I tried to modify the SOAPMessage to remove invalid characters from response.
public class SOAPMessageHandler implements SOAPHandler<SOAPMessageContext> {
public boolean handleMessage(SOAPMessageContext smc) {
System.out.println("in handleMessage");
Boolean outboundProperty = (Boolean) smc.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
System.out.println("outboundProperty: " + outboundProperty);
try {
if (outboundProperty.booleanValue()) {
System.out.println(" SOAP Request ");
} else {
System.out.println(" SOAP Response ");
SOAPMessage message = smc.getMessage();
message.writeTo(System.out);
ByteArrayOutputStream out = new ByteArrayOutputStream();
message.writeTo(out);
String messageAsString = new String(out.toByteArray());
/*smc.setMessage(new SOAPMessage(
stripNonValidXMLCharacters(message.getSOAPPart().toString())));*/
}
} catch (SOAPException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
System.out.println("in soap msg handler..." + e.getMessage());
e.printStackTrace();
}
System.out.println("");
return true;
}
But I get an exception at
SOAPMessage message = smc.getMessage();
The stack trace is:
javax.xml.ws.WebServiceException: javax.xml.soap.SOAPException: org.xml.sax.SAXParseException; lineNumber: 1125; columnNumber: 122; Illegal character entity: expansion character (code 0x15
at [row,col {unknown-source}]: [1125,122]
at com.sun.xml.ws.handler.SOAPMessageContextImpl.getMessage(SOAPMessageContextImpl.java:86)
at com.cah.ecm.sharepoint.migrator.util.SOAPMessageHandler.handleMessage(SOAPMessageHandler.java:25)
at com.cah.ecm.sharepoint.migrator.util.SOAPMessageHandler.handleMessage(SOAPMessageHandler.java:1)
at com.sun.xml.ws.handler.HandlerProcessor.callHandleMessageReverse(HandlerProcessor.java:341)
at com.sun.xml.ws.handler.HandlerProcessor.callHandlersResponse(HandlerProcessor.java:214)
at com.sun.xml.ws.handler.ClientSOAPHandlerTube.callHandlersOnResponse(ClientSOAPHandlerTube.java:163)
at com.sun.xml.ws.handler.HandlerTube.processResponse(HandlerTube.java:164)
at com.sun.xml.ws.api.pipe.Fiber.__doRun(Fiber.java:651)
at com.sun.xml.ws.api.pipe.Fiber._doRun(Fiber.java:600)
at com.sun.xml.ws.api.pipe.Fiber.doRun(Fiber.java:585)
at com.sun.xml.ws.api.pipe.Fiber.runSync(Fiber.java:482)
at com.sun.xml.ws.client.Stub.process(Stub.java:323)
at com.sun.xml.ws.client.sei.SEIStub.doProcess(SEIStub.java:161)
at com.sun.xml.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:113)
at com.sun.xml.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:93)
at com.sun.xml.ws.client.sei.SEIStub.invoke(SEIStub.java:144)
at com.sun.proxy.$Proxy28.getListItems(Unknown Source)
at com.cah.ecm.sharepoint.migrator.sharepoint.client.SharepointClient.getListItemNodes(SharepointClient.java:292)
at com.cah.ecm.sharepoint.migrator.sharepoint.client.SharepointClient.getListItems(SharepointClient.java:389)
at com.cah.ecm.sp.jde.main.TestIterateAllSPFiles.main(TestIterateAllSPFiles.java:35)
Please help me with where I am wrong and if there is an alternate way to remove invalid characters from SOAP response.
Thanks!

One option is to implement your own SAAJMetaFactory that will create custom MessageFactory. Like this:
import java.io.IOException;
import java.io.InputStream;
import javax.xml.soap.MessageFactory;
import javax.xml.soap.MimeHeaders;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPMessage;
import com.sun.xml.internal.messaging.saaj.soap.SAAJMetaFactoryImpl;
public class OwnSAAJMetaFactoryImpl extends SAAJMetaFactoryImpl {
#Override
protected MessageFactory newMessageFactory(String protocol) throws SOAPException {
final MessageFactory f = super.newMessageFactory(protocol);
return new MessageFactory() {
#Override
public SOAPMessage createMessage(MimeHeaders headers, InputStream in) throws IOException, SOAPException {
in = doCleaingStuff(in);
return createMessage(headers, in);
}
#Override
public SOAPMessage createMessage() throws SOAPException {
return f.createMessage();
}
};
}
private InputStream doCleaingStuff(InputStream in) {
// TODO implement it
return null;
}
}
According to SAAJMetaFactory#getInstance() documentation your OwnSAAJMetaFactoryImpl can be exposed through system property
System.setProperty("javax.xml.soap.MetaFactory", "own.package.OwnSAAJMetaFactoryImpl");
or any of this way
Use the javax.xml.soap.MetaFactory system property.
Use the properties file "lib/jaxm.properties" in the JRE directory. This configuration file is in standard java.util.Properties format and
contains the fully qualified name of the implementation class with the
key being the system property defined above.
Use the Services API (as detailed in the JAR specification), if available, to determine the classname. The Services API will look for
a classname in the file META-INF/services/javax.xml.soap.MetaFactory
in jars available to the runtime.
Default to com.sun.xml.messaging.saaj.soap.SAAJMetaFactoryImpl.

Related

Namespace error while validation schema with StAXSource

I'm try to validate an XML using StAX and javax Validator however I'm getting the following cast error:
org.xml.sax.SAXException: java.lang.ClassCastException: org.codehaus.stax2.ri.evt.NamespaceEventImpl cannot be cast to java.lang.String
javax.xml.transform.TransformerException: java.lang.ClassCastException: org.codehaus.stax2.ri.evt.NamespaceEventImpl cannot be cast to java.lang.String
The basic idea is that I need to parse an XML using StAX and I'm attempting to reuse the event reader I'll be using for parsing and creating a StAXSource to perform the validation.
I was able to debug the error and trace the cast exception to the class com.sun.org.apache.xalan.internal.xsltc.trax.StAXEvent2SAX, line 341, where there is a loop through an iterator and a cast to a String when in fact the iterator has the type NamespaceEventImpl (snippet code of the portion of code below).
// end namespace bindings
for( Iterator i = event.getNamespaces(); i.hasNext();) {
String prefix = (String)i.next();
if( prefix == null ) { // true for default namespace
prefix = "";
}
_sax.endPrefixMapping(prefix);
}
The following is the content of the iterator "i" while performing the logic I'm referring to:
iterator content
Below is a snippet of code describing how I'm doing it.
public void validateRequest(RequestMessage message) {
try {
XMLInputFactory factory = XMLInputFactory.newInstance();
XMLEventReader eventReader = factory.createXMLEventReader(new ByteArrayInputStream(message.getMessage().getBytes()));
this.validateSchema(eventReader);
if(this.isSchemaValid()) {
// parse through XML
}
} catch(Exception e) {
LOGGER.error(e.getMessage(), e);
}
}
private void validateSchema(XMLEventReader eventReader) {
try {
StAXErrorHandler errorHandler = new StAXErrorHandler();
this.validator.setErrorHandler(errorHandler);
this.validator.validate(new StAXSource(eventReader));
} catch (SAXException | IOException | XMLStreamException e) {
LOGGER.error(e.getMessage(), e);
}
}
I was wondering if someone faced this issue before and if it is a limitation of using StAXSource with the Validator itself.

Removing XML declaration in JAX-WS message

I'm trying to invoke a webservice using Java code.
So I used JAX-WS and JAXB to generate my object from wsdl file.
When I invoke the webservice it respond with this error:
Exception in thread "main" javax.xml.ws.soap.SOAPFaultException: The [javax.xml.transform.TransformerException] occurred during XSLT transformation: javax.xml.transform.TransformerException: org.xml.sax.SAXParseException: The XML declaration must end with "?>".
Exception in thread "main" javax.xml.ws.soap.SOAPFaultException: The [javax.xml.transform.TransformerException] occurred during XSLT transformation: javax.xml.transform.TransformerException: org.xml.sax.SAXParseException: The XML declaration must end with "?>".
at com.sun.xml.ws.fault.SOAP11Fault.getProtocolException(SOAP11Fault.java:189)
at com.sun.xml.ws.fault.SOAPFaultBuilder.createException(SOAPFaultBuilder.java:122)
at com.sun.xml.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:119)
at com.sun.xml.ws.client.sei.SyncMethodHandler.invoke(SyncMethodHandler.java:89)
at com.sun.xml.ws.client.sei.SEIStub.invoke(SEIStub.java:118)
So with wireshark I analysed the xml message that is being sent. And tried to resend it with soapUI.
And found out that my xml contains the xml declaration
<?xml version='1.0' encoding='UTF-8'?>
When I remove it from SoapUI and resend it. The message goes ok.
My java code goes like this:
public static Data receiveSIBS(webserviceclient.Data input) {
webserviceclient.Starter service = new webserviceclient.Starter();
webserviceclient.PortType port = service.getSOAPEventSource();
BindingProvider bp = (BindingProvider) port;
bp.getRequestContext().put(BindingProvider.ENDPOINT_ADDRESS_PROPERTY, endpoint);
return port.receiveSIBS(input);
}
How can I generate my message in Java without this xml declaration?
because the xml message is all generated with JAX-WS and JAXB.
Thanks in advanced!
Found my own solution!
First, as referred in other post, I implemented a SOAPHandler to edit this two properties:
soapMsg.setProperty(SOAPMessage.CHARACTER_SET_ENCODING, "UTF-16");
soapMsg.setProperty(SOAPMessage.WRITE_XML_DECLARATION, "false");
But although this two properties change message instance inside handleMessage() method, it won't be sent like it, and message with default xml declaration is sent.
Instead of setting this properties the solution was to set this two NamespaceDeclaration:
SOAPEnvelope env = sp.getEnvelope();
env.addNamespaceDeclaration("xsd", "http://www.w3.org/2001/XMLSchema");
env.addNamespaceDeclaration("xsi", "http://www.w3.org/2001/XMLSchema-instance");
I don't understand why we get "The XML declaration must end with "?>"" error. Because my solution didn't removed xml declaration. Might be related to xml structure (but I don't have enough knowledge to confirm it).
I need to refer http://blog.jdevelop.eu/?p=67 post that let me to this solution, and some debug code is from this post.
Following I put my complete CustomHandler class so it can held anyone.
import java.io.ByteArrayOutputStream;
import java.util.Set;
import javax.xml.namespace.QName;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPMessage;
import javax.xml.soap.SOAPPart;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.handler.soap.SOAPHandler;
import javax.xml.ws.handler.soap.SOAPMessageContext;
/**
*
* #author Daniel Chang Yan
*/
public class CustomHandler implements SOAPHandler<SOAPMessageContext> {
public boolean handleMessage(SOAPMessageContext context) {
Boolean isOutbound
= (Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
if (isOutbound != null && isOutbound) {
SOAPMessage soapMsg = context.getMessage();
try {
//Properties always rewritten by jaxws, no matter what is set here
//soapMsg.setProperty(SOAPMessage.CHARACTER_SET_ENCODING, "UTF-16");
//soapMsg.setProperty(SOAPMessage.WRITE_XML_DECLARATION, "false");
// get SOAP-Part
SOAPPart sp = soapMsg.getSOAPPart();
//edit Envelope
SOAPEnvelope env = sp.getEnvelope();
env.addNamespaceDeclaration("xsd", "http://www.w3.org/2001/XMLSchema");
env.addNamespaceDeclaration("xsi", "http://www.w3.org/2001/XMLSchema-instance");
} catch (SOAPException e) {
throw new RuntimeException(e);
}
// print SOAP-Message
System.out.println("Direction=outbound (handleMessage)...");
dumpSOAPMessage(soapMsg);
} else {
// INBOUND
System.out.println("Direction=inbound (handleMessage)...");
SOAPMessage msg = ((SOAPMessageContext) context).getMessage();
dumpSOAPMessage(msg);
}
return true;
}
public Set<QName> getHeaders() {
return null;
}
public boolean handleFault(SOAPMessageContext context) {
System.out.println("ServerSOAPHandler.handleFault");
boolean outbound = (Boolean) context.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY);
if (outbound) {
System.out.println("Direction=outbound (handleFault)...");
} else {
System.out.println("Direction=inbound (handleFault)...");
}
if (!outbound) {
try {
SOAPMessage msg = ((SOAPMessageContext) context).getMessage();
dumpSOAPMessage(msg);
if (context.getMessage().getSOAPBody().getFault() != null) {
String detailName = null;
try {
detailName = context.getMessage().getSOAPBody().getFault().getDetail().getFirstChild().getLocalName();
System.out.println("detailName=" + detailName);
} catch (Exception e) {
}
}
} catch (SOAPException e) {
e.printStackTrace();
}
}
return true;
}
public void close(MessageContext mc) {
}
/**
* Dump SOAP Message to console
*
* #param msg
*/
private void dumpSOAPMessage(SOAPMessage msg) {
if (msg == null) {
System.out.println("SOAP Message is null");
return;
}
//System.out.println("");
System.out.println("--------------------");
System.out.println("DUMP OF SOAP MESSAGE");
System.out.println("--------------------");
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
msg.writeTo(baos);
System.out.println(baos.toString(getMessageEncoding(msg)));
// show included values
String values = msg.getSOAPBody().getTextContent();
System.out.println("Included values:" + values);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* Returns the message encoding (e.g. utf-8)
*
* #param msg
* #return
* #throws javax.xml.soap.SOAPException
*/
private String getMessageEncoding(SOAPMessage msg) throws SOAPException {
String encoding = "utf-8";
if (msg.getProperty(SOAPMessage.CHARACTER_SET_ENCODING) != null) {
encoding = msg.getProperty(SOAPMessage.CHARACTER_SET_ENCODING).toString();
}
return encoding;
}
}

How to create MIME-atachment text/xml in Java?

How can I create mime-atachment text/xml for my SOAPMessage?
I have a function, which sends binary file of XML. But I don't know how can I do it.
Use a DataHandler/DataSource to push the binary data into the message on the client side.
On the server side, you need to create a DataContentHandler implementation and register it with the activation framework.
Step 1 - Adding the binary attachment
Implement a simple DataSource for getting the data:
import javax.activation.*;
class BinaryDataSource implements DataSource {
InputStream _is;
public BinaryDataSource(InputStream is) {
_is = is;
}
public String getContentType() { return "application/binary"; }
public InputStream getInputStream() throws IOException { return _is; }
public String getName() { return "some file"; }
public OutputStream getOutputStream() throws IOException {
throw new IOException("Cannot write to this file");
}
}
Now use this code to add the attachment:
InputStream data = ...
SOAPMessage msg = ...
DataHandler dh = new DataHandler(new BinaryDataSource(data));
AttachmentPart attachment = msg.createAttachmentPart(dh);
msg.addAttachmentPart(attachment);
Step 2 - Setup the server side
[Note: this worked for me]
Create a DataContentHandler which handles the incoming attachment of type "application/binary".
import javax.activation.*;
import java.io.*;
public class BinaryDataHandler implements DataContentHandler {
/** Creates a new instance of BinaryDataHandler */
public BinaryDataHandler() {
}
/** This is the key, it just returns the data uninterpreted. */
public Object getContent(javax.activation.DataSource dataSource) throws java.io.IOException {
System.out.println("BinaryDataHandler: getContent called with: " + dataSource);
return dataSource.getInputStream();
}
public Object getTransferData(java.awt.datatransfer.DataFlavor dataFlavor,
javax.activation.DataSource dataSource)
throws java.awt.datatransfer.UnsupportedFlavorException,
java.io.IOException {
return null;
}
public java.awt.datatransfer.DataFlavor[] getTransferDataFlavors() {
return new java.awt.datatransfer.DataFlavor[0];
}
public void writeTo(Object obj, String str, java.io.OutputStream outputStream)
throws java.io.IOException {
// You would need to implement this to have
// the conversion done automatically based on
// mime type on the client side.
}
}
Now, you can use this code to get the data of the attachment:
SOAPMessage msg = ... //received message
Iterator ats = msg.getAttachments();
if( ats.hasNext() ){
AttachmentPart attachment = (AttachmentPart)ats.next();
InputStream contents = (InputStream)attachment.getContent();
}
Finally, you need to register your DataContentHandler so that the activation framework will use it. There are a couple of ways (see MailcapCommandMap in the activation framework javadocs). What I did was to create a file called "mailcap" in the lib directory used by my "java" interpreter.
This file looks like this:
application/binary; BinaryDataHandler
application/binary;; x-java-content-handler=BinaryDataHandler
This tells the activation framework to use your handler for the indicated
MIME type.

How can I make Spring WebServices log all SOAP requests?

I need all SOAP requests logged in the CommonLogFormat (see http://en.wikipedia.org/wiki/Common_Log_Format), plus the duration (the amount of time it takes to process the request).
What's the best way to do this? It looks like it's possible to configure log4j for Spring WebServices but will it log all the values I'm interested in?
http://pijava.wordpress.com/2009/12/04/spring-webservice-soap-requestresponse-logging-with-log4j/
EDIT: We're actually using SLF4J, not Log4j. Also, it looks like it's possible to do this by configuring the PayloadLoggingInterceptor:
http://static.springsource.org/spring-ws/site/reference/html/server.html#server-endpoint-interceptor
But I am not sure where the log messages will go. I added that interceptor to our interceptors and I don't see any log messages.
For Spring Boot project adding below in application.properties worked for me:
logging.level.org.springframework.web=DEBUG
logging.level.org.springframework.ws.client.MessageTracing.sent=DEBUG
logging.level.org.springframework.ws.server.MessageTracing.sent=DEBUG
logging.level.org.springframework.ws.client.MessageTracing.received=TRACE
logging.level.org.springframework.ws.server.MessageTracing.received=TRACE
You can use this to log the raw payload of incoming and outgoing web service calls.. I'm not sure how to log how long the webservice communication took.
<!-- Spring Web Service Payload Logging-->
<logger name="org.springframework.ws.client.MessageTracing">
<level value="TRACE"/>
</logger>
<logger name="org.springframework.ws.server.MessageTracing">
<level value="TRACE"/>
</logger>
Additional details can be found at http://static.springsource.org/spring-ws/site/reference/html/common.html#logging
If you have your own Logging system the following interceptor can be an alternative to log the SOAP messages.
setInterceptors(new ClientInterceptor[]{new ClientInterceptor() {
#Override
public boolean handleResponse(MessageContext messageContext) throws WebServiceClientException {
System.out.println("### SOAP RESPONSE ###");
try {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
messageContext.getResponse().writeTo(buffer);
String payload = buffer.toString(java.nio.charset.StandardCharsets.UTF_8.name());
System.out.println(payload);
} catch (IOException e) {
throw new WebServiceClientException("Can not write the SOAP response into the out stream", e) {
private static final long serialVersionUID = -7118480620416458069L;
};
}
return true;
}
#Override
public boolean handleRequest(MessageContext messageContext) throws WebServiceClientException {
System.out.println("### SOAP REQUEST ###");
try {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
messageContext.getRequest().writeTo(buffer);
String payload = buffer.toString(java.nio.charset.StandardCharsets.UTF_8.name());
System.out.println(payload);
} catch (IOException e) {
throw new WebServiceClientException("Can not write the SOAP request into the out stream", e) {
private static final long serialVersionUID = -7118480620416458069L;
};
}
return true;
}
#Override
public boolean handleFault(MessageContext messageContext) throws WebServiceClientException {
System.out.println("### SOAP FAULT ###");
try {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
messageContext.getResponse().writeTo(buffer);
String payload = buffer.toString(java.nio.charset.StandardCharsets.UTF_8.name());
System.out.println(payload);
} catch (IOException e) {
throw new WebServiceClientException("Can not write the SOAP fault into the out stream", e) {
private static final long serialVersionUID = 3538336091916808141L;
};
}
return true;
}
}});
In each handle method you can easily use payload to obtain raw soap messages.
This worked for me. It logs the request message sent and the response received. You could work out the total time taken from the log.
log4j.logger.org.springframework.ws.client.MessageTracing.sent=TRACE
log4j.logger.org.springframework.ws.client.MessageTracing.received=TRACE
First, SLF4J is just a simple facade. It means you still need a logging framework(e.g. java.util.logging, logback, log4j).
Second, Spring-ws uses Commons Logging interface that is another simple facade like SLF4J.
Finally, you can use below setting to enable Spring-ws message logging functionality.
log4j.logger.org.springframework.ws.client.MessageTracing.sent=DEBUG
log4j.logger.org.springframework.ws.client.MessageTracing.received=TRACE
log4j.logger.org.springframework.ws.server.MessageTracing.sent=DEBUG
log4j.logger.org.springframework.ws.server.MessageTracing.received=TRACE
Include the following in the log4j.properties file...
To log all server-side messages:
log4j.logger.org.springframework.ws.server.MessageTracing=DEBUG
To log all client-side messages:
log4j.logger.org.springframework.ws.client.MessageTracing=TRACE
On the DEBUG level - only the payload root element is logged
On the TRACE level - the entire message content is logged
Lastly to log only the sent or received messages use the .sent or .received at the end of the configurations.
ex : log4j.logger.org.springframework.ws.server.MessageTracing.received=DEBUG
logs the client-side received massages payload root element
returning :
DEBUG WebServiceMessageReceiverHandlerAdapter:114 - Accepting incoming [org.springframework.ws.transport.http.HttpServletConnection#51ad62d9] to [http://localhost:8080/mock-platform/services]
For more info
Add a servlet filter to the spring ws (to move with org.springframework.web.servlet.DispatcherServlet) in web.xml
you can find a filter here
http://www.wetfeetblog.com/servlet-filer-to-log-request-and-response-details-and-payload/431
inside the filter you can log as you wish
. . .
package com.example.Soap;
import org.springframework.ws.client.WebServiceClientException;
import org.springframework.ws.client.support.interceptor.ClientInterceptor;
import org.springframework.ws.context.MessageContext;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
public class LoggingVonfig implements ClientInterceptor {
#Override
public boolean handleResponse(MessageContext messageContext) throws WebServiceClientException {
System.out.println("### SOAP RESPONSE ###");
try {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
messageContext.getResponse().writeTo(buffer);
String payload = buffer.toString(java.nio.charset.StandardCharsets.UTF_8.name());
System.out.println(payload);
} catch (IOException e) {
throw new WebServiceClientException("Can not write the SOAP response into the out stream", e) {
private static final long serialVersionUID = -7118480620416458069L;
};
}
return true;
}
#Override
public boolean handleRequest(MessageContext messageContext) throws WebServiceClientException {
System.out.println("### SOAP REQUEST ###");
try {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
messageContext.getRequest().writeTo(buffer);
String payload = buffer.toString(java.nio.charset.StandardCharsets.UTF_8.name());
System.out.println(payload);
} catch (IOException e) {
throw new WebServiceClientException("Can not write the SOAP request into the out stream", e) {
private static final long serialVersionUID = -7118480620416458069L;
};
}
return true;
}
#Override
public boolean handleFault(MessageContext messageContext) throws WebServiceClientException {
System.out.println("### SOAP FAULT ###");
try {
ByteArrayOutputStream buffer = new ByteArrayOutputStream();
messageContext.getResponse().writeTo(buffer);
String payload = buffer.toString(java.nio.charset.StandardCharsets.UTF_8.name());
System.out.println(payload);
} catch (IOException e) {
throw new WebServiceClientException("Can not write the SOAP fault into the out stream", e) {
private static final long serialVersionUID = 3538336091916808141L;
};
}
return true;
}
#Override
public void afterCompletion(MessageContext messageContext, Exception e) throws WebServiceClientException {
}
}
. . .
This is logging Configuration class
. . .
package com.example.Soap;
import com.example.Soap.com.example.Soap.Add;
import com.example.Soap.com.example.Soap.AddResponse;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.ws.client.core.support.WebServiceGatewaySupport;
import org.springframework.ws.client.support.interceptor.ClientInterceptor;
import org.springframework.ws.soap.client.core.SoapActionCallback;
public class CalculatorClient extends WebServiceGatewaySupport {
private static Logger log = LoggerFactory.getLogger(CalculatorClient.class);
public com.example.Soap.com.example.Soap.AddResponse getaddition(com.example.Soap.com.example.Soap.Add addrequest){
com.example.Soap.com.example.Soap.Add add = new com.example.Soap.com.example.Soap.Add();
add.setIntB(addrequest.getIntB());
add.setIntA(addrequest.getIntA());
log.info("----------------------------------------------"+"Inbound Request"+"-----------------------");
com.example.Soap.com.example.Soap.AddResponse addResponse = (com.example.Soap.com.example.Soap.AddResponse) getWebServiceTemplate().marshalSendAndReceive("http://www.dneonline.com/calculator.asmx?wsdl",add,new SoapActionCallback("http://tempuri.org/Add"));
return addResponse;
}
public com.example.Soap.com.example.Soap.SubtractResponse getSubtract(com.example.Soap.com.example.Soap.Subtract subreq){
com.example.Soap.com.example.Soap.Subtract subtract=new com.example.Soap.com.example.Soap.Subtract();
subtract.setIntA(subreq.getIntA());
subtract.setIntB(subreq.getIntB());
com.example.Soap.com.example.Soap.SubtractResponse subtractResponse=(com.example.Soap.com.example.Soap.SubtractResponse) getWebServiceTemplate().marshalSendAndReceive("http://www.dneonline.com/calculator.asmx?wsdl",subtract,new SoapActionCallback("http://tempuri.org/Subtract"));
return subtractResponse;
}
public com.example.Soap.com.example.Soap.MultiplyResponse getMultiply(com.example.Soap.com.example.Soap.Multiply multiply)
{
com.example.Soap.com.example.Soap.Multiply multiply1=new com.example.Soap.com.example.Soap.Multiply();
multiply1.setIntA(multiply.getIntA());
multiply1.setIntB(multiply.getIntB());
com.example.Soap.com.example.Soap.MultiplyResponse multiplyResponse=(com.example.Soap.com.example.Soap.MultiplyResponse) getWebServiceTemplate().marshalSendAndReceive("http://www.dneonline.com/calculator.asmx?wsdl",multiply1,new SoapActionCallback("http://tempuri.org/Multiply"));
return multiplyResponse;
}
public com.example.Soap.com.example.Soap.DivideResponse getDivide(com.example.Soap.com.example.Soap.Divide divide){
com.example.Soap.com.example.Soap.Divide divide1=new com.example.Soap.com.example.Soap.Divide();
divide1.setIntA(divide.getIntA());
divide1.setIntB(divide.getIntB());
com.example.Soap.com.example.Soap.DivideResponse divideResponse=(com.example.Soap.com.example.Soap.DivideResponse) getWebServiceTemplate().marshalSendAndReceive("http://www.dneonline.com/calculator.asmx?wsdl",divide1,new SoapActionCallback("http://tempuri.org/Divide"));
return divideResponse;
}
public void MySoapClient() {
this.setInterceptors(new ClientInterceptor[] { new LoggingVonfig() });
}
}
. . .
This is my client class
. . .
package com.example.Soap;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.oxm.jaxb.Jaxb2Marshaller;
import org.springframework.ws.client.core.WebServiceTemplate;
#Configuration
public class CalculatorConfig {
#Bean
public Jaxb2Marshaller marshaller(){
Jaxb2Marshaller jaxb2Marshaller = new Jaxb2Marshaller();
// jaxb2Marshaller.setPackagesToScan("com.example.Soap.com.example.Soap");
jaxb2Marshaller.setContextPath("com.example.Soap.com.example.Soap"); // this will serilaize and unserialize it
return jaxb2Marshaller;
}
#Bean
public CalculatorClient calculatorClient(Jaxb2Marshaller jaxb2Marshaller){
WebServiceTemplate wsTemplate = new WebServiceTemplate();
CalculatorClient calculatorClient = new CalculatorClient();
calculatorClient.setDefaultUri("http://www.dneonline.com");
calculatorClient.setMarshaller(jaxb2Marshaller);
calculatorClient.setUnmarshaller(jaxb2Marshaller);
return calculatorClient;
}
}
. . .
configuration file
. . .
package com.example.Soap;
import com.example.Soap.com.example.Soap.Add;
import com.example.Soap.com.example.Soap.AddResponse;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
#SpringBootApplication
#RestController
public class SoapApplication {
#Autowired
private CalculatorClient calculatorClient;
#PostMapping(value = "/add")
public com.example.Soap.com.example.Soap.AddResponse addelements(#RequestBody com.example.Soap.com.example.Soap.Add add){
return calculatorClient.getaddition(add);
}
#PostMapping(value = "/subtract")
public com.example.Soap.com.example.Soap.SubtractResponse addelements(#RequestBody com.example.Soap.com.example.Soap.Subtract subreq){
return calculatorClient.getSubtract(subreq);
}
#PostMapping(value = "/multiply")
public com.example.Soap.com.example.Soap.MultiplyResponse addelements(#RequestBody com.example.Soap.com.example.Soap.Multiply multiply){
return calculatorClient.getMultiply(multiply);
}
#PostMapping(value = "/divide")
public com.example.Soap.com.example.Soap.DivideResponse addelements(#RequestBody com.example.Soap.com.example.Soap.Divide divide){
return calculatorClient.getDivide(divide);
}
public static void main(String[] args) {
SpringApplication.run(SoapApplication.class, args);
}
}
. . .
These are my classes but still, I can't able to log all requests and responses in my console. I'm not getting where I have done wrong.
I implemented Client configuration too.
An easiest way is adding attribute into your security config (securityPolicy.xml):
<xwss:SecurityConfiguration xmlns:xwss="http://java.sun.com/xml/ns/xwss/config" dumpMessages="true">
No additional settings inside application.properties required.
Check that link to understanding security policy file.

SAX parsing problem in Android... empty elements?

I am using SAX to parse an XML file I'm pulling from the web. I've extended DefaultHandler with code similar to:
public class ArrivalHandler extends DefaultHandler {
#Override
public void startElement(String namespaceUri, String localName, String qualifiedName, Attributes attributes) throws SAXException {
if (qualifiedName.equalsIgnoreCase("resultSet")) {
System.out.println("got a resultset");
} else if (qualifiedName.equalsIgnoreCase("location")) {
System.out.println("got a location");
} else if (qualifiedName.equalsIgnoreCase("arrival")) {
System.out.println("got an arrival");
} else {
System.out.println("There was an unknown XML element encountered: '" + qualifiedName + "'");
}
}
#Override
public void endElement(String namespaceUri, String localName, String qualifiedName) throws SAXException {
// we'll just ignore this for now
}
#Override
public void characters(char[] chars, int startIndex, int length) throws SAXException {
// ignore this too
}
}
The problem I'm having is that I'm just getting a series of empty elements. The log reads:
There was an unknown XML element encountered: ''
There was an unknown XML element encountered: ''
There was an unknown XML element encountered: ''
etc
This worked fine when I was just passing parser.parse a local file, but now I'm pulling it from the web with:
HttpClient httpClient = new DefaultHttpClient();
resp = httpClient.execute("http://example.com/whatever");
SAXParserFactory saxFactory = SAXParserFactory.newInstance();
ArrivalHandler handler = new ArrivalHandler();
SAXParser parser = saxFactory.newSAXParser();
parser.parse(resp.getEntity().getContent(), handler);
and I get the (apparently) empty results described above.
What I've looked into so far:
I converted the InputStream from resp.getEntity().getContent() to a string and dumped it out and it looks like I'm getting the XML from the server correctly.
There are no exceptions thrown but there is a warning that reads "W/ExpatReader(232): DTD handlers aren't supported.".
Any other ideas for what I'm doing incorrectly or how to debug this?
From the docs for ContentHandler.startElement:
the qualified name is required when
the namespace-prefixes property is
true, and is optional when the
namespace-prefixes property is false
(the default).
So, do you have the namespace-prefixes property set to true?
Can you just cope with the uri and localName instead?

Categories