SOAP Web service configuration

IHE actors' endpoint

This section of the documentation gives some indication about how to create a SOAP 1.2 endpoint which matches the IHE specifications. Those constraints have to be followed when implementing an IHE actor acting as a webservice responder.

The next sections refer to the code snippet below (extract from PatientManager tool) which defines the PDQ Supplier service (PDQV3)

@Stateless
@Name("PDQSupplierService")
@WebService(portName = "PDQSupplier_Port_Soap12", name = "PDQSupplier_PortType", targetNamespace = "urn:ihe:iti:pdqv3:2007", serviceName = "PDQSupplier_Service")
@SOAPBinding(parameterStyle = ParameterStyle.BARE)
@Addressing(enabled = true, required = true)
@BindingType(javax.xml.ws.soap.SOAPBinding.SOAP12HTTP_BINDING)
@RespectBinding(enabled = true)
@GenerateInterface(value = "PDQSupplierServiceRemote", isLocal = false, isRemote = true)
@HandlerChain(file = "soap-handler.xml")
public class PDQSupplierService implements PDQSupplierServiceRemote {

	private static Logger log = LoggerFactory.getLogger(PDQSupplierService.class);
	private static final String HL7_NS = "urn:hl7-org:v3";

	@Resource
	private WebServiceContext context;

	@WebMethod(operationName = "PDQSupplier_PRPA_IN201305UV02", action = "urn:hl7-org:v3:PRPA_IN201305UV02")
	@WebResult(name = "PRPA_IN201306UV02", partName = "Body", targetNamespace = HL7_NS)
	@Action(input = "urn:hl7-org:v3:PRPA_IN201305UV02", output = "urn:hl7-org:v3:PRPA_IN201306UV02")
	public PRPAIN201306UV02Type findCandidatesQuery(
			@WebParam(name = "PRPA_IN201305UV02", partName = "Body", targetNamespace = HL7_NS) PRPAIN201305UV02Type request){
		PDQV3QueryHandler queryHandler = new PDQV3QueryHandler(getDomainForPDQ(),
				Actor.findActorWithKeyword("PDS"), Actor.findActorWithKeyword("PDC"),
				Transaction.GetTransactionByKeyword("ITI-47"), getRemoteHostFromContext());
		try {
			return queryHandler.handlePRPAIN201305UV02(request);
		} catch (Exception e) {
			log.error(e.getMessage(), e);
			return null;
		}
	}
}

Service, Port and binding

Java code WSDL Value in the example
serviceName attribute of @Webservice

definitions@name

service@name

PDQSupplier_Service
targetNamespace attribute of @Webservice definitions@targetNamespace urn:ihe:iti:pdqv3:2007 (prefixed as ns1 in the generated wsdl)
name attribute of @Webservice

portType@name

bindings@type

PDQSupplier_PortType
portName attribute of @Webservice service/port@name PDQSupplier_Port_Soap12


You can use the RespectBindingFeature to control whether a JAX-WS implementation is required to respect the contents of a Web Services Description Language (WSDL) binding that is associated with an endpoint. In that case, use annotation @RespectBinding(enabled="true")

Messages

Java code WSDL Value in example

name attribute of @WebResult

name attribute of @WebParam

message/part@element PRPA_IN201305UV02

partName attribute of @WebResult

partName attribute of @WebParam

message/part@name body (default)

targetNamespace attribute of @WebResult

targetNamespace attribute of @WebParam

used as namespace in message/part@element urn:hl7-org:v3

 

You can also use header attribute of @WebParam if the parameter is expected in the header of the SOAP envelop.

Note: ns1 is the namespace prefix for urn:hl7-org:v3

 

<wsdl:message name="PDQSupplier_QUQI_IN000003UV01_ContinueResponse">
<wsdl:part element="ns1:PRPA_IN201306UV02" name="body"></wsdl:part>
</wsdl:message>
<wsdl:message name="PDQSupplier_QUQI_IN000003UV01_Continue">
<wsdl:part element="ns1:QUQI_IN000003UV01" name="body"></wsdl:part>
</wsdl:message>
<wsdl:message name="PDQSupplier_QUQI_IN000003UV01_CancelResponse">
<wsdl:part element="ns1:MCCI_IN000002UV01" name="body"></wsdl:part>
</wsdl:message>
<wsdl:message name="PDQSupplier_PRPA_IN201305UV02">
<wsdl:part element="ns1:PRPA_IN201305UV02" name="Body"></wsdl:part>
</wsdl:message>
<wsdl:message name="PDQSupplier_QUQI_IN000003UV01_Cancel">
<wsdl:part element="ns1:QUQI_IN000003UV01_Cancel" name="body"></wsdl:part>
</wsdl:message>
<wsdl:message name="PDQSupplier_PRPA_IN201305UV02Response">
<wsdl:part element="ns1:PRPA_IN201306UV02" name="Body"></wsdl:part>
</wsdl:message>

 

Operations and bindings

Typically, you will need to create one method per operation.

Java code WSDL Value in example
operationName attribute of @WebMethod

portType/operation@name

binding/operation@name

PDQSupplier_PRPA_IN201305UV02
action attribute of @WebMethod

binding/operation/operation@soapAction

urn:hl7-org:v3:PRPA_IN201305UV02
input attribute of @Action

portType/operation/input@wsam:Action

 

portType/operation/input@wsaw:Action

urn:hl7-org:v3:PRPA_IN201305UV02
output attribute of @Action

portType/operation/output@wsam:Action

portType/operation/output@wsaw:Action

urn:hl7-org:v3:PRPA_IN201306UV02

 

 

<wsdl:portType name="PDQSupplier_PortType">
<wsdl:operation name="PDQSupplier_QUQI_IN000003UV01_Continue">
<wsdl:input message="tns:PDQSupplier_QUQI_IN000003UV01_Continue" name="PDQSupplier_QUQI_IN000003UV01_Continue" wsam:Action="urn:hl7-org:v3:QUQI_IN000003UV01_Continue" wsaw:Action="urn:hl7-org:v3:QUQI_IN000003UV01_Continue"></wsdl:input>
<wsdl:output message="tns:PDQSupplier_QUQI_IN000003UV01_ContinueResponse" name="PDQSupplier_QUQI_IN000003UV01_ContinueResponse" wsam:Action="urn:hl7-org:v3:PRPA_IN201306UV02" wsaw:Action="urn:hl7-org:v3:PRPA_IN201306UV02"></wsdl:output>
</wsdl:operation>
<wsdl:operation name="PDQSupplier_PRPA_IN201305UV02">
<wsdl:input message="tns:PDQSupplier_PRPA_IN201305UV02" name="PDQSupplier_PRPA_IN201305UV02" wsam:Action="urn:hl7-org:v3:PRPA_IN201305UV02" wsaw:Action="urn:hl7-org:v3:PRPA_IN201305UV02"></wsdl:input>
<wsdl:output message="tns:PDQSupplier_PRPA_IN201305UV02Response" name="PDQSupplier_PRPA_IN201305UV02Response" wsam:Action="urn:hl7-org:v3:PRPA_IN201306UV02" wsaw:Action="urn:hl7-org:v3:PRPA_IN201306UV02"></wsdl:output>
</wsdl:operation>
<wsdl:operation name="PDQSupplier_QUQI_IN000003UV01_Cancel">
<wsdl:input message="tns:PDQSupplier_QUQI_IN000003UV01_Cancel" name="PDQSupplier_QUQI_IN000003UV01_Cancel" wsam:Action="urn:hl7-org:v3:QUQI_IN000003UV01_Cancel" wsaw:Action="urn:hl7-org:v3:QUQI_IN000003UV01_Cancel"></wsdl:input>
<wsdl:output message="tns:PDQSupplier_QUQI_IN000003UV01_CancelResponse" name="PDQSupplier_QUQI_IN000003UV01_CancelResponse" wsam:Action="urn:hl7-org:v3:MCCI_IN000002UV01" wsaw:Action="urn:hl7-org:v3:MCCI_IN000002UV01"></wsdl:output>
</wsdl:operation>
</wsdl:portType>

Addressing

If the addressing tag can be present in the inbound message, add the @Addressing annotation and set its enabled attribute to "true".

If mustUnderstand="true" is expected, set the required attribute to "true".

Handlers

In our example, we use the @HandlerChain annotation the one references an XML file. In the Java project, this file is located in EJBModule resources: resources/net/ihe/gazelle/simulator/pdqv3/pds/soap-hander.xml. It is import that the folder hierarchy matches the package where the Java class is defined (here net.ihe.gazelle.simulator.pdqv3.pds).

Below is its content:

<?xml version="1.0" encoding="UTF-8" standalone="yes"?>
<javaee:handler-chains
		xmlns:javaee="http://java.sun.com/xml/ns/javaee">
	<javaee:handler-chain>
		<javaee:handler>
			<javaee:handler-class>net.ihe.gazelle.simulator.common.ihewsresp.WSAddressingHandler</javaee:handler-class>
		</javaee:handler>
	</javaee:handler-chain>
</javaee:handler-chains>

 

The WSAddressingHandler class referenced here is used to explicit the content of the addressing element in the SOAP header. This is required when you force the addressing using @Addressing(enabled="true", required="true").

Faults

You can define SOAP faults that will be returned by your webservice in specific use cases.

Add the following in the @Action annotation (example):

fault = {
			@FaultAction(className = NAVFault.class, value = "NAV"),
			@FaultAction(className = VERUNKFault.class, value = "VERUNK") }

 

You can declare as many @FaultAction as you need. The classes returned for those faults (NAVFault and VERUNKFault in our case) shall

  • be thrown by your web method
  • extend SoapFaultException

Below, as example, is the implementation of the NAVFault Class.

@WebFault(name = "NAV", targetNamespace = "urn:ihe:iti:svs:2008")
	public class NAVFault extends SOAPFaultException {

		/**
		 * 
		 */
		private static final long serialVersionUID = 1L;

		public NAVFault(SOAPFault fault) {
			super(fault);
			try {
				getFault().setFaultCode(new QName("http://www.w3.org/2003/05/soap-envelope", "Sender"));
				getFault().appendFaultSubcode(new QName(SVS_NS, "NAV"));
				getFault().addFaultReasonText("Unknown value set", Locale.ENGLISH);
			} catch (SOAPException e) {
				log.error("Unable to build NAV SOAPFault");
				e.getMessage();
			}
		}
	}

 

Java code WSDL Value in example

value attribute of @FaultAction

name attribyte of @WebFault

portType/operation/fault@Action NAV
className attribute of @FaultAction portType/operation/fault@name NAVFault
targetNamespace attribute of @WebFault used as namespace in message/part/element urn:ihe:iti:svs:2008

 Handler chains

In the same way as we use an handler to make the addressing header understandable by Jboss, we can define other handlers for operations to be performed

  • before processing of the request by the @WebService class
  • after generation of the response by the @WebService class (and thus before sending to the requester)

It allows you to perform some operations on the entire SOAP message.

Once your handler is ready, you can declare it in the handler.xml file. You can add as many <java:handlier-chain> elements as you need.

The easier way is to

  • extend the SOAPRequestHandler class (from org.jboss.seam.webservice) if you want the operations to be applied only on requests
  • implement the SOAPHandler<SOAPMessageContext> interface for operations to be applied on requests and responses

The handle{Message|Fault|Inbound|Outbound} methods return a boolean indicating if the message shall be processed by the @WebService class. If the message shall not be processed and you want to send a Fault to the end user, simply throw a RuntimeException, its message will be used as fault reason in the returned response.

Examples:

 

Jboss 5.1.0 Configuration

In order to make sure that the wsdl is correct and displays a URL in soap12:address/@location which is correct and reachable by the requester, the following changes shall be brought to the configuration (to be performed on each server inside a jboss installation):

In file  ${JBOSS_HOME}/server/${JBOSS_SERVER}/deployers/jbossws.deployer/META-INF/stack-agnostic-jboss-beans.xml, replace

<property name="webServiceHost">${jboss.bind.address}</property>

by the following

<property name="webServiceHost">jbossws.undefined.host</property>

And make sure that the modifySOAPAddress property is set to true:

<property name="modifySOAPAddress">true</property>

You must restart your Jboss server to take the changes into account.

 

jboss 7.X Configuration

In order to make sure that the wsdl is correct and displays a URL in soap12:address/@location which is correct and reachable by the requester, the following changes shall be brought to the configuration (to be performed on each server inside a jboss installation):

In file  standalone.xml of the jboss that you are running (file located at configuration/standalone.xml)

<wsdl-host>${jboss.bind.address}:0.0.0.0</wsdl-host>

by the following

<wsdl-host>jbossws.undefined.host</wsdl-host>

And make sure that the following property is set to true:

<modify-wsdl-address>true</modify-wsdl-address>

You must restart your Jboss server to take the changes into account.