[[SOAP_over_JMS]]
= SOAP over JMS

JBoss Web Services allows communication over the _JMS_ transport. The
functionality comes from Apache CXF support for the
http://www.w3.org/TR/soapjms/[SOAP over Java Message Service 1.0]
specification, which is aimed at a set of standards for interoperable
transport of _SOAP_ messages over _JMS_.

On top of Apache CXF functionalities, the JBossWS integration allows
users to deploy WS archives containing both _JMS_ and _HTTP_ endpoints
the same way as they do for basic _HTTP_ WS endpoints (in _war_
archives). The webservices layer of WildFly takes care of looking for
_JMS_ enpdoints in the deployed archive and starts them delegating to
the Apache CXF core similarly as with _HTTP_ endpoints.

[[configuring-soap-over-jms]]
== Configuring SOAP over JMS

As per specification, the _SOAP over JMS_ transport configuration is
controlled by proper elements and attributes in the `binding` and
`service` elements of the WSDL contract. So a _JMS_ endpoint is usually
developed using a contract-first approach.

The http://cxf.apache.org/docs/soap-over-jms-10-support.html[Apache CXF
documentation] covers all the details of the supported configurations.
The minimum configuration implies:

* setting a proper JMS URI in the `soap:address` `location` [1]
* providing a JNDI connection factory name to be used for connecting to
the queues [2]
* setting the transport binding [3]

[source,xml,options="nowrap"]
----
<wsdl:definitions name="HelloWorldService" targetNamespace="http://org.jboss.ws/jaxws/cxf/jms"
  xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
  xmlns:tns="http://org.jboss.ws/jaxws/cxf/jms"
  xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
  xmlns:soapjms="http://www.w3.org/2010/soapjms/"
  xmlns:xsd="http://www.w3.org/2001/XMLSchema">
...
 
<wsdl:binding name="HelloWorldServiceSoapBinding" type="tns:HelloWorld">
  <soap:binding style="document" transport="http://www.w3.org/2010/soapjms/"/> <!-- 3 -->
  <wsdl:operation name="echo">
    <soap:operation soapAction="" style="document"/>
    <wsdl:input name="echo">
      <soap:body use="literal"/>
    </wsdl:input>
    <wsdl:output name="echoResponse">
      <soap:body use="literal"/>
    </wsdl:output>
  </wsdl:operation>
</wsdl:binding>
<wsdl:service name="HelloWorldService">
  <soapjms:jndiConnectionFactoryName>java:/ConnectionFactory</soapjms:jndiConnectionFactoryName> <!-- 2 -->
  <wsdl:port binding="tns:HelloWorldServiceSoapBinding" name="HelloWorldImplPort">
    <soap:address location="jms:queue:testQueue"/> <!-- 1 -->
  </wsdl:port>
</wsdl:service>
----

Apache CXF takes care of setting up the JMS transport for endpoint
implementations whose `@WebService` annotation points to a port declared
for JMS transport as explained above.

[NOTE]

JBossWS currently supports POJO endpoints only for JMS transport use.
The endpoint classes can be deployed as part of _jar_ or _war_ archives.

The _web.xml_ descriptor in _war_ archives doesn't need any entry for
JMS endpoints.

[[examples-soap-over-jms]]
== Examples

[[jms-endpoint-only-deployment]]
=== JMS endpoint only deployment

In this example we create a simple endpoint relying on _SOAP over JMS_
and deploy it as part of a jar archive.

The endpoint is created using wsconsume tool from a WSDL contract such
as:

[source,xml,options="nowrap"]
----
<?xml version='1.0' encoding='UTF-8'?>
<wsdl:definitions name="HelloWorldService" targetNamespace="http://org.jboss.ws/jaxws/cxf/jms"
  xmlns:ns1="http://schemas.xmlsoap.org/soap/http"
  xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
  xmlns:tns="http://org.jboss.ws/jaxws/cxf/jms"
  xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
  xmlns:soapjms="http://www.w3.org/2010/soapjms/"
  xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <wsdl:types>
<xs:schema elementFormDefault="unqualified" targetNamespace="http://org.jboss.ws/jaxws/cxf/jms" version="1.0" xmlns:tns="http://org.jboss.ws/jaxws/cxf/jms" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="echo" type="tns:echo"/>
<xs:element name="echoResponse" type="tns:echoResponse"/>
<xs:complexType name="echo">
    <xs:sequence>
      <xs:element minOccurs="0" name="arg0" type="xs:string"/>
    </xs:sequence>
  </xs:complexType>
<xs:complexType name="echoResponse">
    <xs:sequence>
      <xs:element minOccurs="0" name="return" type="xs:string"/>
    </xs:sequence>
  </xs:complexType>
</xs:schema>
  </wsdl:types>
  <wsdl:message name="echoResponse">
    <wsdl:part element="tns:echoResponse" name="parameters">
    </wsdl:part>
  </wsdl:message>
  <wsdl:message name="echo">
    <wsdl:part element="tns:echo" name="parameters">
    </wsdl:part>
  </wsdl:message>
  <wsdl:portType name="HelloWorld">
    <wsdl:operation name="echo">
      <wsdl:input message="tns:echo" name="echo">
    </wsdl:input>
      <wsdl:output message="tns:echoResponse" name="echoResponse">
    </wsdl:output>
    </wsdl:operation>
  </wsdl:portType>
  <wsdl:binding name="HelloWorldServiceSoapBinding" type="tns:HelloWorld">
    <soap:binding style="document" transport="http://www.w3.org/2010/soapjms/"/>
    <wsdl:operation name="echo">
      <soap:operation soapAction="" style="document"/>
      <wsdl:input name="echo">
        <soap:body use="literal"/>
      </wsdl:input>
      <wsdl:output name="echoResponse">
        <soap:body use="literal"/>
      </wsdl:output>
    </wsdl:operation>
  </wsdl:binding>
  <wsdl:service name="HelloWorldService">
    <soapjms:jndiConnectionFactoryName>java:jms/RemoteConnectionFactory</soapjms:jndiConnectionFactoryName>
    <soapjms:jndiInitialContextFactory>org.jboss.naming.remote.client.InitialContextFactory</soapjms:jndiInitialContextFactory>
    <soapjms:jndiURL>http-remoting://myhost:8080</soapjms:jndiURL>
    <wsdl:port binding="tns:HelloWorldServiceSoapBinding" name="HelloWorldImplPort">
      <soap:address location="jms:queue:testQueue"/>
    </wsdl:port>
  </wsdl:service>
  <wsdl:service name="HelloWorldServiceLocal">
    <soapjms:jndiConnectionFactoryName>java:/ConnectionFactory</soapjms:jndiConnectionFactoryName>
    <wsdl:port binding="tns:HelloWorldServiceSoapBinding" name="HelloWorldImplPort">
      <soap:address location="jms:queue:testQueue"/>
    </wsdl:port>
  </wsdl:service>
</wsdl:definitions>
----

[IMPORTANT]

The _HelloWorldImplPort_ here is meant for using the _testQueue_ that
has to be created before deploying the endpoint.

At the time of writing, _java:/ConnectionFactory_ is the default
connection factory JNDI location on WildFly

For allowing remote JNDI lookup of the connection factory, a specific
service ( `HelloWorldService`) for remote clients is added to the WSDL.
The _java:jms/RemoteConnectionFactory_ is the JNDI location of the same
connection factory mentioned above, except it's exposed for remote
lookup. The `soapjms:jndiInitialContextFactory` and `soap:jmsjndiURL`
complete the remote connection configuration, specifying the initial
context factory class to use and the JNDI registry address.

[IMPORTANT]

Have a look at the application server domain for finding out the
configured connection factory JNDI locations.

The endpoint implementation is a basic JAX-WS POJO using @WebService
annotation to refer to the consumed contract:

[source,java,options="nowrap"]
----
package org.jboss.test.ws.jaxws.cxf.jms;
 
import javax.jws.WebService;
 
@WebService
(
   portName = "HelloWorldImplPort",
   serviceName = "HelloWorldServiceLocal",
   wsdlLocation = "META-INF/wsdl/HelloWorldService.wsdl",
   endpointInterface = "org.jboss.test.ws.jaxws.cxf.jms.HelloWorld",
   targetNamespace = "http://org.jboss.ws/jaxws/cxf/jms"
)
public class HelloWorldImpl implements HelloWorld
{
   public String echo(String input)
   {
      return input;
   }
}
----

[NOTE]

The endpoint implementation references the `HelloWorldServiceLocal` wsdl
service, so that the local JNDI connection factory location is used for
starting the endpoint on server side.

That's pretty much all. We just need to package the generated service
endpoint interface, the endpoint implementation and the WSDL file in a
_jar_ archive and deploy it:

....
alessio@inuyasha /dati/jbossws/stack/cxf/trunk $ jar -tvf ./modules/testsuite/cxf-tests/target/test-libs/jaxws-cxf-jms-only-deployment.jar
     0 Thu Jun 23 15:18:44 CEST 2011 META-INF/
   129 Thu Jun 23 15:18:42 CEST 2011 META-INF/MANIFEST.MF
     0 Thu Jun 23 15:18:42 CEST 2011 org/
     0 Thu Jun 23 15:18:42 CEST 2011 org/jboss/
     0 Thu Jun 23 15:18:42 CEST 2011 org/jboss/test/
     0 Thu Jun 23 15:18:42 CEST 2011 org/jboss/test/ws/
     0 Thu Jun 23 15:18:42 CEST 2011 org/jboss/test/ws/jaxws/
     0 Thu Jun 23 15:18:42 CEST 2011 org/jboss/test/ws/jaxws/cxf/
     0 Thu Jun 23 15:18:42 CEST 2011 org/jboss/test/ws/jaxws/cxf/jms/
   313 Thu Jun 23 15:18:42 CEST 2011 org/jboss/test/ws/jaxws/cxf/jms/HelloWorld.class
  1173 Thu Jun 23 15:18:42 CEST 2011 org/jboss/test/ws/jaxws/cxf/jms/HelloWorldImpl.class
     0 Thu Jun 23 15:18:40 CEST 2011 META-INF/wsdl/
  3074 Thu Jun 23 15:18:40 CEST 2011 META-INF/wsdl/HelloWorldService.wsdl
....

[NOTE]

A dependency on `org.hornetq` module needs to be added in MANIFEST.MF
when deploying to WildFly.

....
Manifest-Version: 1.0

Ant-Version: Apache Ant 1.7.1

Created-By: 17.0-b16 (Sun Microsystems Inc.)

Dependencies: org.hornetq
....

A JAX-WS client can interact with the JMS endpoint the usual way:

[source,java,options="nowrap"]
----
URL wsdlUrl = ...
//start another bus to avoid affecting the one that could already be assigned to the current thread - optional but highly suggested
Bus bus = BusFactory.newInstance().createBus();
BusFactory.setThreadDefaultBus(bus);
try
{
   QName serviceName = new QName("http://org.jboss.ws/jaxws/cxf/jms", "HelloWorldService");
   Service service = Service.create(wsdlUrl, serviceName);
   HelloWorld proxy = (HelloWorld) service.getPort(new QName("http://org.jboss.ws/jaxws/cxf/jms", "HelloWorldImplPort"), HelloWorld.class);
   setupProxy(proxy);
   proxy.echo("Hi");
}
finally
{
   bus.shutdown(true);
}
----

[IMPORTANT]

The WSDL location URL needs to be retrieved in a custom way, depending
on the client application. Given the endpoint is JMS only, there's no
automatically published WSDL contract.

in order for performing the remote invocation (which internally goes
through remote JNDI lookup of the connection factory), the calling user
credentials need to be set into the Apache CXF JMSConduit:

[source,java,options="nowrap"]
----
private void setupProxy(HelloWorld proxy) {
   JMSConduit conduit = (JMSConduit)ClientProxy.getClient(proxy).getConduit();
   JNDIConfiguration jndiConfig = conduit.getJmsConfig().getJndiConfig();
   jndiConfig.setConnectionUserName("user");
   jndiConfig.setConnectionPassword("password");
   Properties props = conduit.getJmsConfig().getJndiTemplate().getEnvironment();
   props.put(Context.SECURITY_PRINCIPAL, "user");
   props.put(Context.SECURITY_CREDENTIALS, "password");
}
----

[IMPORTANT]

Have a look at the WildFly domain and messaging configuration for
finding out the actual security requirements. At the time of writing, a
user with `guest` role is required and that's internally checked using
the `other` security domain.

Of course once the endpoint is exposed over JMS transport, any plain JMS
client can also be used to send messages to the webservice endpoint. You
can have a look at the SOAP over JMS spec details and code the client
similarly to

[source,java,options="nowrap"]
----
Properties env = new Properties();
env.put(Context.INITIAL_CONTEXT_FACTORY, "org.jboss.naming.remote.client.InitialContextFactory");
env.put(Context.PROVIDER_URL, "http-remoting://myhost:8080");
env.put(Context.SECURITY_PRINCIPAL, "user");
env.put(Context.SECURITY_CREDENTIALS, "password");
InitialContext context = new InitialContext(env);
QueueConnectionFactory connectionFactory = (QueueConnectionFactory)context.lookup("jms/RemoteConnectionFactory");
Queue reqQueue = (Queue)context.lookup("jms/queue/test");
Queue resQueue = (Queue)context.lookup("jms/queue/test");
QueueConnection con = connectionFactory.createQueueConnection("user", "password");
QueueSession session = con.createQueueSession(false, Session.AUTO_ACKNOWLEDGE);
QueueReceiver receiver = session.createReceiver(resQueue);
ResponseListener responseListener = new ResponseListener(); //a custom response listener...
receiver.setMessageListener(responseListener);
con.start();
TextMessage message = session.createTextMessage(reqMessage);
message.setJMSReplyTo(resQueue);
 
//setup SOAP-over-JMS properties...
message.setStringProperty("SOAPJMS_contentType", "text/xml");
message.setStringProperty("SOAPJMS_requestURI", "jms:queue:testQueue");
 
QueueSender sender = session.createSender(reqQueue);
sender.send(message);
sender.close();
 
...
----

[[jms-and-http-endpoints-deployment]]
=== JMS and HTTP endpoints deployment

In this example we create a deployment containing an endpoint that
serves over both HTTP and JMS transports.

We from a WSDL contract such as below (please note we've two `binding` /
`portType` for the same `service`):

[source,xml,options="nowrap"]
----
<?xml version='1.0' encoding='UTF-8'?>
<wsdl:definitions name="HelloWorldService" targetNamespace="http://org.jboss.ws/jaxws/cxf/jms"
  xmlns:ns1="http://schemas.xmlsoap.org/soap/http"
  xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
  xmlns:tns="http://org.jboss.ws/jaxws/cxf/jms"
  xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
  xmlns:soapjms="http://www.w3.org/2010/soapjms/"
  xmlns:xsd="http://www.w3.org/2001/XMLSchema">
  <wsdl:types>
<xs:schema elementFormDefault="unqualified" targetNamespace="http://org.jboss.ws/jaxws/cxf/jms" version="1.0"
  xmlns:tns="http://org.jboss.ws/jaxws/cxf/jms" xmlns:xs="http://www.w3.org/2001/XMLSchema">
<xs:element name="echo" type="tns:echo"/>
<xs:element name="echoResponse" type="tns:echoResponse"/>
<xs:complexType name="echo">
    <xs:sequence>
      <xs:element minOccurs="0" name="arg0" type="xs:string"/>
    </xs:sequence>
  </xs:complexType>
<xs:complexType name="echoResponse">
    <xs:sequence>
      <xs:element minOccurs="0" name="return" type="xs:string"/>
    </xs:sequence>
  </xs:complexType>
</xs:schema>
  </wsdl:types>
  <wsdl:message name="echoResponse">
    <wsdl:part element="tns:echoResponse" name="parameters">
    </wsdl:part>
  </wsdl:message>
  <wsdl:message name="echo">
    <wsdl:part element="tns:echo" name="parameters">
    </wsdl:part>
  </wsdl:message>
  <wsdl:portType name="HelloWorld">
    <wsdl:operation name="echo">
      <wsdl:input message="tns:echo" name="echo">
    </wsdl:input>
      <wsdl:output message="tns:echoResponse" name="echoResponse">
    </wsdl:output>
    </wsdl:operation>
  </wsdl:portType>
  <wsdl:binding name="HelloWorldServiceSoapBinding" type="tns:HelloWorld">
    <soap:binding style="document" transport="http://www.w3.org/2010/soapjms/"/>
    <wsdl:operation name="echo">
      <soap:operation soapAction="" style="document"/>
      <wsdl:input name="echo">
        <soap:body use="literal"/>
      </wsdl:input>
      <wsdl:output name="echoResponse">
        <soap:body use="literal"/>
      </wsdl:output>
    </wsdl:operation>
  </wsdl:binding>
  <wsdl:binding name="HttpHelloWorldServiceSoapBinding" type="tns:HelloWorld">
    <soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http"/>
    <wsdl:operation name="echo">
      <soap:operation soapAction="" style="document"/>
      <wsdl:input name="echo">
        <soap:body use="literal"/>
      </wsdl:input>
      <wsdl:output name="echoResponse">
        <soap:body use="literal"/>
      </wsdl:output>
    </wsdl:operation>
  </wsdl:binding>
  <wsdl:service name="HelloWorldService">
    <soapjms:jndiConnectionFactoryName>java:jms/RemoteConnectionFactory</soapjms:jndiConnectionFactoryName>
    <soapjms:jndiInitialContextFactory>org.jboss.naming.remote.client.InitialContextFactory</soapjms:jndiInitialContextFactory>
    <soapjms:jndiURL>http-remoting://localhost:8080</soapjms:jndiURL>
    <wsdl:port binding="tns:HelloWorldServiceSoapBinding" name="HelloWorldImplPort">
      <soap:address location="jms:queue:testQueue"/>
    </wsdl:port>
    <wsdl:port binding="tns:HttpHelloWorldServiceSoapBinding" name="HttpHelloWorldImplPort">
      <soap:address location="http://localhost:8080/jaxws-cxf-jms-http-deployment"/>
    </wsdl:port>
  </wsdl:service>
  <wsdl:service name="HelloWorldServiceLocal">
    <soapjms:jndiConnectionFactoryName>java:/ConnectionFactory</soapjms:jndiConnectionFactoryName>
    <wsdl:port binding="tns:HelloWorldServiceSoapBinding" name="HelloWorldImplPort">
      <soap:address location="jms:queue:testQueue"/>
    </wsdl:port>
</wsdl:definitions>
----

The same considerations of the previous example regarding the JMS queue
and JNDI connection factory still apply. +
Here we can implement the endpoint in multiple ways, either with a
common implementation class that's extended by the JMS and HTTP ones, or
keep the two implementation classes independent and just have them
implement the same service endpoint interface:

[source,java,options="nowrap"]
----
package org.jboss.test.ws.jaxws.cxf.jms_http;
 
import javax.jws.WebService;
 
@WebService
(
   portName = "HelloWorldImplPort",
   serviceName = "HelloWorldServiceLocal",
   wsdlLocation = "WEB-INF/wsdl/HelloWorldService.wsdl",
   endpointInterface = "org.jboss.test.ws.jaxws.cxf.jms_http.HelloWorld",
   targetNamespace = "http://org.jboss.ws/jaxws/cxf/jms"
)
public class HelloWorldImpl implements HelloWorld
{
   public String echo(String input)
   {
      System.out.println("input: " + input);
      return input;
   }
}
----

[source,java,options="nowrap"]
----
package org.jboss.test.ws.jaxws.cxf.jms_http;
 
import javax.jws.WebService;
 
@WebService
(
   portName = "HttpHelloWorldImplPort",
   serviceName = "HelloWorldService",
   wsdlLocation = "WEB-INF/wsdl/HelloWorldService.wsdl",
   endpointInterface = "org.jboss.test.ws.jaxws.cxf.jms_http.HelloWorld",
   targetNamespace = "http://org.jboss.ws/jaxws/cxf/jms"
)
public class HttpHelloWorldImpl implements HelloWorld
{
   public String echo(String input)
   {
      System.out.println("input (http): " + input);
      return "(http) " + input;
   }
}
----

Both classes are packaged together the service endpoint interface and
the WSDL file in a _war_ archive:

....
alessio@inuyasha /dati/jbossws/stack/cxf/trunk $ jar -tvf ./modules/testsuite/cxf-spring-tests/target/test-libs/jaxws-cxf-jms-http-deployment.war
     0 Thu Jun 23 15:18:44 CEST 2011 META-INF/
   129 Thu Jun 23 15:18:42 CEST 2011 META-INF/MANIFEST.MF
     0 Thu Jun 23 15:18:44 CEST 2011 WEB-INF/
   569 Thu Jun 23 15:18:40 CEST 2011 WEB-INF/web.xml
     0 Thu Jun 23 15:18:44 CEST 2011 WEB-INF/classes/
     0 Thu Jun 23 15:18:42 CEST 2011 WEB-INF/classes/org/
     0 Thu Jun 23 15:18:42 CEST 2011 WEB-INF/classes/org/jboss/
     0 Thu Jun 23 15:18:42 CEST 2011 WEB-INF/classes/org/jboss/test/
     0 Thu Jun 23 15:18:42 CEST 2011 WEB-INF/classes/org/jboss/test/ws/
     0 Thu Jun 23 15:18:42 CEST 2011 WEB-INF/classes/org/jboss/test/ws/jaxws/
     0 Thu Jun 23 15:18:42 CEST 2011 WEB-INF/classes/org/jboss/test/ws/jaxws/cxf/
     0 Thu Jun 23 15:18:42 CEST 2011 WEB-INF/classes/org/jboss/test/ws/jaxws/cxf/jms_http/
   318 Thu Jun 23 15:18:42 CEST 2011 WEB-INF/classes/org/jboss/test/ws/jaxws/cxf/jms_http/HelloWorld.class
  1192 Thu Jun 23 15:18:42 CEST 2011 WEB-INF/classes/org/jboss/test/ws/jaxws/cxf/jms_http/HelloWorldImpl.class
  1246 Thu Jun 23 15:18:42 CEST 2011 WEB-INF/classes/org/jboss/test/ws/jaxws/cxf/jms_http/HttpHelloWorldImpl.class
     0 Thu Jun 23 15:18:40 CEST 2011 WEB-INF/wsdl/
  3068 Thu Jun 23 15:18:40 CEST 2011 WEB-INF/wsdl/HelloWorldService.wsdl
....

A trivial web.xml descriptor is also included to trigger the HTTP
endpoint publish:

[source,xml,options="nowrap"]
----
<?xml version="1.0" encoding="UTF-8"?>
<web-app xmlns="http://java.sun.com/xml/ns/j2ee"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://java.sun.com/xml/ns/j2ee http://java.sun.com/xml/ns/j2ee/web-app_2_4.xsd"
  version="2.4">
  <servlet>
    <servlet-name>EndpointServlet</servlet-name>
    <servlet-class>org.jboss.test.ws.jaxws.cxf.jms_http.HttpHelloWorldImpl</servlet-class>
  </servlet>
  <servlet-mapping>
    <servlet-name>EndpointServlet</servlet-name>
    <url-pattern>/*</url-pattern>
  </servlet-mapping>
</web-app>
----

[IMPORTANT]

Here too the MANIFEST.MF needs to declare a dependency on _org.hornetq_
module when deploying to WildFly.

Finally, the JAX-WS client can ineract with both JMS and HTTP endpoints
as usual:

[source,java,options="nowrap"]
----
//start another bus to avoid affecting the one that could already be assigned to current thread - optional but highly suggested
Bus bus = BusFactory.newInstance().createBus();
BusFactory.setThreadDefaultBus(bus);
try
{
   QName serviceName = new QName("http://org.jboss.ws/jaxws/cxf/jms", "HelloWorldService");
   Service service = Service.create(wsdlUrl, serviceName);
 
   //JMS test
   HelloWorld proxy = (HelloWorld) service.getPort(new QName("http://org.jboss.ws/jaxws/cxf/jms", "HelloWorldImplPort"), HelloWorld.class);
   setupProxy(proxy);
   proxy.echo("Hi");
   //HTTP test
   HelloWorld httpProxy = (HelloWorld) service.getPort(new QName("http://org.jboss.ws/jaxws/cxf/jms", "HttpHelloWorldImplPort"), HelloWorld.class);
   httpProxy.echo("Hi");
}
finally
{
   bus.shutdown(true);
}
----

[[use-of-endpoint.publish-api]]
=== Use of Endpoint.publish() API

An alternative to deploying an archive containing JMS endpoints is in
starting them directly using the JAX-WS `Endpoint.publish(..)` API.

That's as easy as doing:

[source,java,options="nowrap"]
----
Object implementor = new HelloWorldImpl();
Endpoint ep = Endpoint.publish("jms:queue:testQueue", implementor);
try
{
   //use or let others use the endpoint
}
finally
{
   ep.stop();
}
----

where `HelloWorldImpl` is a POJO endpoint implementation referencing a
JMS _port_ in a given WSDL contract, as explained in the previous
examples.

The main difference among the deployment approach is in the direct
control and responsibility over the endpoint lifecycle ( _start/publish_
and _stop_).
