Build React Native App (4) - Redux, Jest, and NativeBase

Image
From this blog, typescript feature will be added. There are couple of ways to implement static type checking like; flow from facebook, PropTypes and Typescript. Typescript is well integrated with Visual Studio Code and supports better linter, error messages, and intellisense. Reference site Github Sample Ex4 Currnet version D:\GitRepo\reactnative>npm --version 6.3.0 D:\GitRepo\reactnative>react-native --version react-native-cli: 2.0.1 react-native: n/a - not inside a React Native project directory D:\GitRepo\reactnative>yarn --version 1.9.4 Creating React Native App $ react-native init ex4 If you want to specify the version, add "--version 0.57.3" at the end. Add NativeBase to React Native $ npm install native-base --save ... + native-base@2.8.1 added 71 packages from 42 contributors, removed 50 packages, updated 829 packages and audited 34989 packages in 138.542s found 0 vulnerabilities $ $ yarn yarn install v1.9.4 warning package-lock.json found. You...

Adding SOAP Header generated by JAXB(wsimport)

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

  1. Add jaxws-api (2.2.12) to POM file
  2. Add jaxws-maven-plugin to POM file to generate java code from WSDL
  3. Add SOAPHanlder class to intercept during sending messages
  4. To add SOAPHandler, get handler from JAXB service
  5. 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.

Comments

  1. Hello Alex.

    I 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!

    ReplyDelete

Post a Comment

Popular posts from this blog

Build React Native App (4) - Redux, Jest, and NativeBase

Replacing text in PDF file using iTextSharp

Using GIT(Bitbucket), Visual Studio Code