Adding SOAP Header generated by JAXB(wsimport)
- Get link
- X
- Other Apps
Adding SOAP Header generated by JAXB(wsimport)
Introduction
Recently, I've been working with Exact Web Service and needed to add SOAP header entry from the source files generated by wsimport tool. To access Globe database, I needed to add database server name and database name from SOAP Header.
I tried to find out lots of article and this is the way to add headers into SOAP.
Reference
There was one excellent site, but I couldn't find it any more. If I find it, I will update here.
The steps
- Add jaxws-api (2.2.12) to POM file
- Add jaxws-maven-plugin to POM file to generate java code from WSDL
- Add SOAPHanlder class to intercept during sending messages
- To add SOAPHandler, get handler from JAXB service
- Call Service
1. Add jaxws-api
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.8.8</version>
</dependency>
<dependency>
<groupId>javax.xml.ws</groupId>
<artifactId>jaxws-api</artifactId>
<version>2.2.12</version>
</dependency>
</dependencies>
2. jaxws-maven-plugin
<build>
<plugins>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>jaxws-maven-plugin</artifactId>
<version>2.4.1</version>
<executions>
<execution>
<id>ExactSynergyMetadataWSDL</id>
<phase>generate-sources</phase>
<goals>
<goal>wsimport</goal>
</goals>
<configuration>
<wsdlUrls>
<wsdlUrl>http://globe_webservice_server:8010/services/Exact.Entity.EG?singleWsdl</wsdlUrl>
</wsdlUrls>
<packageName>com.alexjoh.exact.ws.globe.entity</packageName>
<vmArgs>
<vmArg>-Djavax.xml.accessExternalSchema=all</vmArg>
<!-- <vmArg>-XadditionalHeaders</vmArg> -->
<vmArg>-Djaxws.sourceDestDir=${basedir}/src/main/java/com/alexjoh/exact/ws/globe/entity</vmArg>
</vmArgs>
<keep>true</keep>
<sourceDestDir>${basedir}/src/main/java/</sourceDestDir>
<bindingDirectory>src/main/resources/wsdl</bindingDirectory>
<bindingFiles>
<bindingFile>jaxb_binding.xml</bindingFile>
</bindingFiles>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
To remove JAXBElement datatype, I am using following jaxb_binding.xml file
<jaxb:bindings version="2.0"
xmlns:jaxb="http://java.sun.com/xml/ns/jaxb">
<jaxb:bindings>
<jaxb:globalBindings generateElementProperty="false">
</jaxb:globalBindings>
</jaxb:bindings>
</jaxb:bindings>
3. Add SOAPHanlder class to intercept during sending messages
package com.flairpackaging.exact.ws.globe.common;
import java.util.Set;
import javax.xml.namespace.QName;
import javax.xml.soap.SOAPElement;
import javax.xml.soap.SOAPEnvelope;
import javax.xml.soap.SOAPException;
import javax.xml.soap.SOAPHeader;
import javax.xml.soap.SOAPMessage;
import javax.xml.ws.handler.MessageContext;
import javax.xml.ws.handler.soap.SOAPHandler;
import javax.xml.ws.handler.soap.SOAPMessageContext;
public class GlobeSOAPHeaderHandler implements SOAPHandler<SOAPMessageContext>{
private String serverName;
private String dbName;
public GlobeSOAPHeaderHandler(String serverName, String dbName) {
this.serverName = serverName;
this.dbName = dbName;
}
public boolean handleMessage(SOAPMessageContext messageContext) {
SOAPMessage msg = messageContext.getMessage();
if ((Boolean) messageContext.get(MessageContext.MESSAGE_OUTBOUND_PROPERTY)) {
try {
SOAPEnvelope envelope = msg.getSOAPPart().getEnvelope();
// error handling: Can't add a header when one is already present
if (envelope.getHeader() != null) {
envelope.getHeader().detachNode();
}
SOAPHeader header = envelope.addHeader();
SOAPElement el = header.addChildElement(
envelope.createName("DatabaseName", "", "urn:exact.services.entitymodel.backoffice:v1"));
el.setValue(dbName);
el = header
.addChildElement(envelope.createName("ServerName", "", "urn:exact.services.entitymodel.backoffice:v1"));
el.setValue(serverName);
msg.saveChanges();
} catch (SOAPException e) {
return false;
}
}
return true;
}
public boolean handleFault(SOAPMessageContext context) {
// TODO Auto-generated method stub
return false;
}
public void close(MessageContext context) {
// TODO Auto-generated method stub
}
public Set<QName> getHeaders() {
// TODO Auto-generated method stub
return null;
}
}
4. To add SOAPHandler, get handler from JAXB service
package com.flairpackaging.exact.ws.globe.common;
import java.net.Authenticator;
import java.util.List;
import javax.xml.ws.Binding;
import javax.xml.ws.BindingProvider;
import javax.xml.ws.handler.Handler;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.flairpackaging.exact.security.NTLMAuthenticator;
import com.flairpackaging.exact.ws.globe.entity.Entity;
import com.flairpackaging.exact.ws.globe.entity.EntityWinService;
public class GlobeSOAPService {
protected Authenticator authenticator;
protected EntityWinService entityLocator;
protected Entity entity;
protected Binding binding;
protected ObjectMapper objMapper = new ObjectMapper();
public GlobeSOAPService(String serverName, String dbName) {
// this is for AD authentication. For this, please refer another my blog post about AD authentication from web
authenticator = new NTLMAuthenticator("AD User Name", "AD Password");
Authenticator.setDefault(authenticator);
// Get JAXB service from generated source
entityLocator = new EntityWinService();
// get Stub from generated source. This entity will provide all opertational functions
entity = entityLocator.getPort(Entity.class);
// casting WS stub to add handler
binding = ((BindingProvider) entity).getBinding();
// BindingProvider bindingProvider = (BindingProvider)entity;
List<Handler> handlerChain = binding.getHandlerChain();
// Adding handler created from #4 step.
handlerChain.add(new GlobeSOAPHeaderHandler(serverName, dbName));
binding.setHandlerChain(handlerChain);
}
}
5. Call Service
@Test
public void GlobeWSLibraryRetrieveTest () {
GlobeEntityRetrieve globeRetrieve = new GlobeEntityRetrieve("sql server", "globe db name");
ArrayOfPropertyData propList = new ArrayOfPropertyData();
PropertyData propData = new PropertyData();
propData.setName("ItemCode");
propData.setNoRights(false);
propData.setValue("10000002");
propList.getPropertyData().add(propData);
globeRetrieve.setEntityName("Item");
globeRetrieve.setPropertyDataList(propList);
EntityData result = null;
try {
result = globeRetrieve.Retrieve();
System.out.println(objMapper.writeValueAsString(result));
} catch (JsonProcessingException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Assert.assertNotNull(result);
}
GlobeEntityRetrieve.java file
package com.flairpackaging.exact.ws.globe.common;
import com.flairpackaging.exact.ws.globe.entity.ArrayOfPropertyData;
import com.flairpackaging.exact.ws.globe.entity.EntityData;
public class GlobeEntityRetrieve extends GlobeSOAPService {
private String entityName;
private String serverName;
private String dbName;
private ArrayOfPropertyData propertyDataList;
public String getEntityName() {
return entityName;
}
public void setEntityName(String entityName) {
this.entityName = entityName;
}
public ArrayOfPropertyData getPropertyDataList() {
return propertyDataList;
}
public void setPropertyDataList(ArrayOfPropertyData propertyDataList) {
this.propertyDataList = propertyDataList;
}
public GlobeEntityRetrieve(String serverName, String dbName, String entityName, ArrayOfPropertyData propertyDataList) {
super(serverName, dbName);
this.entityName = entityName;
this.propertyDataList = propertyDataList;
this.serverName = serverName;
this.dbName = dbName;
}
public GlobeEntityRetrieve(String serverName, String dbName) {
super(serverName, dbName);
this.serverName = serverName;
this.dbName = dbName;
}
public EntityData Retrieve() {
EntityData entityData = new EntityData();
EntityData entityDataResult = null;
entityData.setEntityName(entityName);
entityData.setProperties(propertyDataList);
try {
entityDataResult = entity.retrieve(entityData);
System.out.println(objMapper.writeValueAsString(entityDataResult));
// EntityData requestData =
// populated.getEntities().getRequestData().get(0);
// EntityData populatedRequest = entity.retrieve(requestData);
// System.out.println(populatedRequest);
} catch (Exception e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
return entityDataResult;
}
}
GlobeSOAPService.java
package com.flairpackaging.exact.ws.globe.common;
import java.net.Authenticator;
import java.util.List;
import javax.xml.ws.Binding;
import javax.xml.ws.BindingProvider;
import javax.xml.ws.handler.Handler;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.flairpackaging.exact.security.NTLMAuthenticator;
import com.flairpackaging.exact.ws.globe.entity.Entity;
import com.flairpackaging.exact.ws.globe.entity.EntityWinService;
public class GlobeSOAPService {
protected Authenticator authenticator;
protected EntityWinService entityLocator;
protected Entity entity;
protected Binding binding;
protected ObjectMapper objMapper = new ObjectMapper();
public GlobeSOAPService(String serverName, String dbName) {
authenticator = new NTLMAuthenticator("AD Username", "AD Password");
Authenticator.setDefault(authenticator);
entityLocator = new EntityWinService();
entity = entityLocator.getPort(Entity.class); // equivalent of
// getPort();
binding = ((BindingProvider) entity).getBinding();
// BindingProvider bindingProvider = (BindingProvider)entity;
List<Handler> handlerChain = binding.getHandlerChain();
handlerChain.add(new GlobeSOAPHeaderHandler(serverName, dbName));
binding.setHandlerChain(handlerChain);
}
}
Troubleshooting and tracing
Use Wireshark to see the messages and use SOAPUI program to check the data
Sample of Envelop for Exact Globe Web Service
<s:Envelope xmlns:s="http://schemas.xmlsoap.org/soap/envelope/">
<s:Header>
<ServerName xmlns="urn:exact.services.entitymodel.backoffice:v1">database server name</ServerName>
<DatabaseName xmlns="urn:exact.services.entitymodel.backoffice:v1">globe database name</DatabaseName>
</s:Header>
<s:Body>
<Retrieve xmlns="http://www.exactsoftware.com/services/entities/">
<data xmlns:a="http://www.exactsoftware.com/schemas/entities/" xmlns:i="http://www.w3.org/2001/XMLSchema-instance">
<a:EntityName>Resource</a:EntityName>
<a:Properties>
<a:PropertyData>
<a:Name>ID</a:Name>
<a:NoRights>false</a:NoRights>
<a:Value i:type="b:string" xmlns:b="http://www.w3.org/2001/XMLSchema">1</a:Value>
</a:PropertyData>
</a:Properties>
</data>
</Retrieve>
</s:Body>
</s:Envelope>
Summary
If you want to manupulate any SOAP header or SOAP body, this should be done from the SOAPHandler event. I hope this could help someone to struggle to manupulate SOAP messages which I spent hugh amount of hours. If you like it, please click AD to raise tiny money.
- Get link
- X
- Other Apps
Comments
Hello Alex.
ReplyDeleteI am following this post to send a header in my SOAP request, but I am stuck in the forth step because idk what is the code inside this package 'com.flairpackaging.exact'.
Could you please provide more details about the classes that are contained in that package?
Thanks in advance!