J2EE Integration  Locate

Overview  Locate

WSO2 SOA Enablement Server 6.5.4 supports these J2EE features:

  • JNDI over SOAP

  • EJB as a Web service access

  • JTA over SOAP

  • Support for narrowing

  • JMS transport, which allows SOAP messages to be sent over JMS topics and queues

JNDI Over SOAP  Locate

Figure 26. JNDI Over SOAP Illustrated

JNDI Over SOAP Illustrated

With WSO2 SOA Enablement Server for Java 6.5.4, you can turn existing communication between a J2EE server and a client into SOAP. In most cases, the only thing a client has to do to access its existing business logic via SOAP with WSO2 SOA Enablement Server for Java 6.5.4 is to change its JNDI properties. You need to install the JNDI connector component to do so.

Deploy the component WASP_HOME/conf/porting/dist/j2ee_jndi_connector.jar on the WSO2 SOA Enablement Server that has the accessible JNDI context you want to expose. If you use the J2eeIntegrate tool and you installed J2EE Support during the installation process, it will be done automatically.

On the client side, you must include the component WASP_HOME/lib/j2ee_jndi_connector_client.jar into the classpath of your J2EE client. Then simply replace the original JNDI context with com.idoox.jndi.InitialContextFactoryImpl (usually done by changing the value of the property java.naming.factory.initial) and set the property java.naming.provider.url according to the following rules :

Setting the Value of java.naming.provider.url  Locate

If java.naming.provider is only a URL pointing to a running WSO2 SOA Enablement Server, like http://localhost:8080/wso2/server, it defaults to http://localhost:8080/wso2/server/internal/jndi-dl/wsdl. A Web service running at this endpoint implements the server side of the JNDI connector, which is accessible over document/literal SOAP operations.

If you specify a URL that ends with wsdl or / (http://localhost:8080/wso2/server/internal/jndi-dl/wsdl) or (http://localhost:8080/wso2/server/internal/jndi-dl/), we assume that you are pointing directly to the server side of the JNDI connector. By default, you can use two locations in the URL - /internal/jndi/ or /internal/jndi-dl/. If you use /jndi-dl/, (default) document/literal will be used instead. If you use /jndi/, the JNDI connector will run using RPC/encoded SOAP operations.

JNDI Connector Service  Locate

The WSO2 SOA Enablement Server for Java implementation of JNDI context (JNDI Connector) connects to a JNDI connector service that exposes either the whole or a restricted JNDI namespace. The service has two endpoints, which differ in SOAP operation styles. The endpoint running at location /internal/jndi-dl/ uses document/literal SOAP operation, while the endpoint running at location /internal/jndi/ uses rpc/encoded SOAP operation.

Securing the JNDI Connector  Locate

You can also run a JNDI connector using a secured connection (see the Web Services Security book). On the client, you can pass credentials using three properties:

  • java.naming.security.principal to pass the username

  • java.naming.security.credentials to pass the password

  • java.naming.security.protocol to pass the name of the security provider (HttpBasic, HttpDigest, Kerberos or WS-Security).

The security provider on the client must be accepted by the service that the property java.naming.provider.url points to. To ensure this, you usually need to configure JNDIService with location /internal/jndi/ or JNDIService.dl with location /internal/jndi-dl/.

Configuring the JNDI Connector  Locate

You can prohibit the exposure of an object from the JNDI namespace in the configuration of the JNDI connector:

<!-- Copyright WSO2 Inc. All rights reserved. 
     Use is subject to license terms. -->
<!--    ...   -->
<JNDIServiceConfig name="jndi_connector">
    <include>ejb/MyAccount</include>
    <exclude>MyBank</exclude>
    <exclude>ejb/*</include>
</JNDIServiceConfig>
<!--    ...   -->

JNDIServiceConfig may contain property tags holding properties used when WSO2 SOA Enablement Server creates an instance of InitialContext as shown in Example 268. If they are present, they initialize a hash table passed to the constructor of the InitialContext used to lookup objects from the JNDI namespace. If they are not present, the InitialContext is created using a default constructor without any parameter.

Example 268. JNDIServiceConfig With Property Tags

<JNDIServiceConfig name="jndi_connector">
    <property propertyName="java.naming.factory.initial"
              propertyValue="..."/>
    <property propertyName="java.naming.provider.url"
              propertyValue="..."/>
    <include>ejb/MyAccount</include>
    <exclude>MyBank</exclude>
    <exclude>ejb/*</include>
</JNDIServiceConfig>
[Note]Note

When accessing EJBs using the JNDI connector, WSO2 SOA Enablement Server must have the home and remote interfaces of the EJBs in the classpath. When WSO2 SOA Enablement Server runs as a servlet, this is usually done by adding them to the WEB-INF/classes of the web application containing WSO2 SOA Enablement Server.

JNDI over SOAP Lookup on RMI-IIOP Application Servers  Locate

The javax.naming.IntialContext.lookup() method usually does not directly return an EJB object implementing the EJB remote and home interfaces in the RMI-IIOP based application servers. The user must call the method javax.rmi.PortableRemoRmethteObject.narrow(...) to get the real EJB object. The method's first parameter is the pointer obtained through the lookup method. The second parameter is the interface class. If it is possible, the pointer will be cast to the interface.

The WSO2 SOA Enablement Server implementation of the javax.naming.IntialContext.lookup() method delegates the call to the application server, and returns a remote reference to the object obtained by the lookup. In the case of an RMI-IIOP based application server, it does not return directly a remote reference to the EJB object. The returned reference must be narrowed to the requested class.

A common implementation of javax.rmi.PortableRemoteObject delegates calls to the class determined by the javax.rmi.CORBA.PortableRemoteObjectClass JVM property. WSO2 SOA Enablement Server includes its own implementation of the delegate object: the class com.idoox.wasp.jndi.PortableRemoteObjectDelegate. It delegates all calls performed on the javax.rmi.PortableRemoteObject to the original delegate class with one exception, the narrow() method.

The method is implemented as follows:

  1. Check whether the object is an instance of the requested class. If it is, a pointer to the object is returned.

  2. Call the narrow method, over SOAP, on some application server. If it returns null, the third step is performed; otherwise, the remote reference pointer is returned.

  3. The call is delegated to the original delegate.

For more information see Sun's Enterprise JavaBeans documentation.

Configuring the javax.rmi.PortableRemoteObject   Locate

To delegate javax.rmi.PortableRemote calls to WSO2 SOA Enablement Server for Java's PortableRemoteObjectDelegate, the client's JVM must run with the parameter:

-Djavax.rmi.PortableRemoteObject.narrow=com.idoox.wasp.jndi.PortableRemoteObjectDelegate

This parameter causes the JVM to perform the following:

  1. It checks whether the JVM property wasp.jndi.portableRemoteObjectDelegate is set. If it is set, it creates its instance and uses it as the delegate.

  2. If the property is not present, the JVM looks at the WSO2 SOA Enablement Server client config and reads the main JNDIServiceConfig tag. It gets the value of the attribute portableRemoteObjectDelegate and uses it as the class name for the delegate.

  3. If all else fails, the JVM tries to create the delegate as an instance of com.sun.corba.se.internal.javax.rmi.PortableRemoteObject

Performance Issue: Serializing java.sql.ResultSet  Locate

To get data from java.sql.ResultSet we usually call the java.sql.ResultSet.next() method plus a number of its getXXX() methods in the cycle. Such cycles are ineffective if two or more pairs of SOAP messages are sent in a round. To solve this problem, WSO2 SOA Enablement Server provides a cached ResultSet. This caches data so that most of the calls are performed on locally-stored data on the client side.

EJB over SOAP Example  Locate

The WSO2 SOA Enablement Server distribution includes an EJB demo in which we show how to run an EJB client over SOAP. To run this demo, WSO2 SOA Enablement Server must be ported in some application server and the server must be running. (To learn how to port WSO2 SOA Enablement Server, see the porting guide.) To run the demo, just enter ./run.sh make_client , ./run.sh run_client (for UNIX-type systems) or run make_client, run run_client (for Windows) on the command line in the demo directory. For more information about the demo, see readme.txt file in the demo directory.

The piece of code in Example 269 shows how to get EJB interfaces over SOAP. It is a regular J2EE client run with JNDI properties.

Example 269. EJB Over SOAP

// Copyright WSO2 Inc. All rights reserved.
// Use is subject to license terms.
package example.applicationIntegration.j2eeIntegration;

import demo.advanced.jndiOverSoap.Account;
import demo.advanced.jndiOverSoap.AccountHome;

import javax.naming.InitialContext;

import javax.rmi.PortableRemoteObject;


public class Ejb {
    public static void main(String[] args) throws Exception {
        Object obj = (new InitialContext()).lookup("beanPerson.PersonHome");
        AccountHome accountHome =
            (AccountHome) PortableRemoteObject.narrow(obj, AccountHome.class);
        Account a = accountHome.create();
    }
}

Web Services Implemented by EJBs  Locate

To enable this feature, you must deploy the component WASP_HOME/conf/porting/dist/j2ee_ejb_webservice.jar on the WSO2 SOA Enablement Server that has the accessible JNDI context you want to expose. If you use the J2eeIntegrate tool and you installed J2EE Support during the installation process, it will be done automatically.

There is a deprecated mechanism for implementing EJBs for versions of WSO2 SOA Enablement Server prior to 4.5. This is provided in the Appendix.

In most cases, WSO2 SOA Enablement Server handles Web services implemented by EJB in the same way as it handles other Web services. The deployment of a common Web service usually starts with the creation of a package containing the deployment descriptor of the Web service and its implementing classes.

For Web services implemented by EJB, the only change is that you pass a class name to the WaspPackager tool in the form jndi:JNDI_NAME where JNDI_NAME is the JNDI name of the deployed EJB. When WaspPackager processes a Web service with this class name, it handles it in a special way. It does not create a WSDL and the deployment descriptor does not contain any information about the WSDL in the corresponding service-endpoint element.

The following command creates a package with a Web service, with the JNDI name AccountBean, implemented by EJB:

WaspPackager --package EjbWS --output EjbWS.jar --service-name EJB_webservice --class jndi:AccountBean --uri /ejb-ws/

Although WaspPackager does not create the WSDL, you can pass your own WSDL to the WaspPackager. For a stateful session or entity EJB, this WSDL should reflect the home interface. For a stateless session EJB, it should reflect the remote interface. You can generate it in the standard way using the Java2WSDL tool.

When a package containing a Web service implemented by EJB is deployed and the package does not include a WSDL, a default one is created on the server side. You can customize its creation by setting the target namespace of the WSDL and name of the service in the deployment descriptor:

Example 270. Deployment Descriptor for a Web Service Implemented by EJB

<?xml version="1.0" encoding="UTF-8"?>
<package name="EjbWS" targetNamespace="http://wso2.com/demos/ejb-ws/"
    version="1.1" 
    xmlns="http://wso2.com/wasp/package/1.0" 
    xmlns:tns="http://wso2.com/demos/ejb-ws/">

    <service-endpoint name="EJB_webservice" path="/ejb-ws/"
        processing="tns:Ejb-ws_Processing" 
        service-instance="tns:Ejb-ws_Instance">
        <wsdl service="wsdls:AccountEjbService" 
            xmlns:wsdls="http://wso2.com/test/"/>
    </service-endpoint>
    <service-instance implementation-class="jndi:AccountBean" 
        name="Ejb-ws_Instance"/>
    <!-- message processing, serialization etc. -->
    <processing name="Ejb-ws_Processing"/>
    <processing name="EJBRemoteWSDLService_processing"/>
</package>

All options and settings related to a Web service can be used for a Web service implemented by EJB.

When an EJBModule is initialized, it creates an InitialContext the same way as one is created when configuring JNDI. However, the initialization of the properties is done from the element called EJBServiceConfig. This element contains the option javaMappingExtension, which if set to true adds custom WSDL extensions to the WSDL, which can describe either remote or local EJB interfaces:

Example 271. EJBServiceConfig with property Tags

<?xml version="1.0" encoding="UTF-8"?>
<EJBServiceConfig javaMappingExtension="true" name="ejb_webservice" 
   xmlns="http://wso2.com/wasp/package/j2ee_ejb_webservice">
    <property propertyName="java.naming.factory.initial" propertyValue="..."/>
    <property propertyName="java.naming.provider.url" propertyValue="..."/>
</EJBServiceConfig>

On the client side, you access a Web service implemented by EJB in the standard way:

Example 272. Client for a Web Service Implemented by EJB

// Copyright WSO2 Inc. All rights reserved.
// Use is subject to license terms.
package example.applicationIntegration.j2eeIntegration;

import demo.advanced.jndiOverSoap.Account;
import demo.advanced.jndiOverSoap.AccountHome;

import org.systinet.wasp.webservice.LookupException;
import org.systinet.wasp.webservice.Registry;


public class EjbWsExample {
    public static void main(String[] args) throws Exception {
        // Account home is the home interface of the EJB
        AccountHome accountHome = null;

        try {
            // Lookup the web service implemented by EJB
            accountHome =
                (AccountHome) Registry.lookup("http://localhost:7001/ejb-ws/",
                    AccountHome.class);
        } catch (LookupException e) {
            e.printStackTrace();
        }

        // Create a new statefull session bean
        Account account = accountHome.create();

        // Call methods
        account.deposit(new Integer(100));
        System.out.println(account.getBalance());
    }
}
[Note]Note

When exposing EJBs or deploying Web services implemented by EJBs, WSO2 SOA Enablement Server must have home and remote interfaces of the EJBs in the classpath. When WSO2 SOA Enablement Server runs as a servlet, this us usually done by adding them to the WEB-INF/classes of the web application containing WSO2 SOA Enablement Server.

Securing J2EE Integration  Locate

For SOAP communication between the J2EE client and the WSO2 SOA Enablement Server server, you can apply any security supported by WSO2 SOA Enablement Server, as with any regular Web service. The same is true when you expose an EJB as a web service (please see Web Services Implemented by EJBs). This means you can set up, for example, the HttpDigest security provider on a JNDI service to secure communication with this service (please see Security Guide). (Of course, you must provide credentials on the client side. Please read the section on JNDI Connector to see how to do it).

Consider the communication between client and WSO2 SOA Enablement Server from the security point of view. The WSO2 SOA Enablement Server functions as a bridge between the J2EE application server and clients. The client side is fundamentally a WSO2 SOA Enablement Server Client regardless of the type of integration. If you use JNDI connector, your J2EE client runs over the WSO2 SOA Enablement Server implementation of JNDI context, which transforms calls into SOAP communication with the JNDI connector service. From the perspective of the JNDI connector service, the client is an ordinary Web service client. If you expose your EJB as a Web service, it is simplest to use such an ordinary Web service client to access it.

The drawback of the solution described in the previous paragraphs is that there is no relation between the identity passed from the client to the WSO2 SOA Enablement Server and the identity under which the WSO2 SOA Enablement Server server performs a call in the environment of the application server. The call is always made under the identity of the WSO2 SOA Enablement Server running within the application server, regardless of the identity received in the SOAP call from the client. The rest of the Securing J2EE Integration section discusses propagation of the caller identity to the hosting J2EE environment and related issues.

JAAS Login Modules  Locate

Because of the flexibility of JAAS, we use JAAS login modules to authenticate calls against the J2EE environment. Currently, the WSO2 SOA Enablement Server distribution contains login modules for BEA WebLogic version 7.0 and higher and IBM WebSphere version 4.0 and higher. You can replace authentication against the identities stored in WSO2 SOA Enablement Server UserStore with authentication against the user database maintained by the application server by changing the JAAS configuration, as follows:

  • Replace the login module that authenticates against the identities in WSO2 SOA Enablement Server UserStore, com.idoox.security.jaas.NamePasswordLoginModule, with two login modules:

  1. com.idoox.security.jaas.NamePasswordLoginModuleNoAuth, which adds WSO2 SOA Enablement Server principals used by WSO2 SOA Enablement Server authorization framework to the JAAS subject.

  2. An application server specific login module, com.idoox.security.jaas.WlNamePasswordLoginModule or com.idoox.security.jaas.WasNamePasswordLoginModule, which performs authentication against the user database maintained by the application server.

When a WSO2 SOA Enablement Server is hosted by an application server, it reuses its modified JAAS configuration. The modification is done during the porting process, when you are instructed to modify the JAAS configuration with the J2eeIntegrate tool. Perform the modifications described in the following sections to the same file.

BEA WebLogic  Locate

On BEA WebLogic 7.x and 8.x the JAAS configuration file is set in the startup scripts to WASP_HOME/conf/jaas.config by default. To modify the HttpBasic authentication, change the original configuration entry in this file from

NamePasswordAN{
   com.idoox.security.jaas.NamePasswordLoginModule required debug=true;
          };

to

NamePasswordAN{
   com.idoox.security.jaas.WlNamePasswordLoginModule required
   debug=true; com.idoox.security.jaas.NamePasswordLoginModuleNoAuth
   required debug=true;
  };
IBM WebSphere  Locate

On IBM WebSphere 5.x the JAAS configuration is stored in WAS_HOME/config/cells/DOMAIN_NAME/security.xml. Change the entry:

<example>
    <entries alias="NamePasswordAN" xmi:id="WaspNamePasswordAN">
        <loginModules authenticationStrategy="REQUIRED"
            moduleClassName="com.idoox.security.jaas.NamePasswordLoginModule" 
            xmi:id="NamePasswordAN">
            <options name="debug" value="true" xmi:id="debug_property_7"/>
        </loginModules>
    </entries>
</example>

to

<example>
  <entries alias="NamePasswordAN" xmi:id="WaspNamePasswordAN">
    <loginModules authenticationStrategy="REQUIRED"
      moduleClassName="com.idoox.security.jaas.NamePasswordLoginModuleNoAuth"
      xmi:id="NamePasswordAN">
      <options name="debug" value="true" xmi:id="debug_property_x"/>
    </loginModules>
    <loginModules authenticationStrategy="REQUIRED"
      moduleClassName="com.idoox.security.jaas.WasNamePasswordLoginModule" 
      xmi:id="NamePasswordAN">
      <options name="debug" value="true" xmi:id="debug_property_x"/>
    </loginModules>
  </entries>
</example>

On IBM WebSphere 4.x the JAAS configuration file is referenced by default from file WAS_HOME/java/jre/lib/security/java.security to WASP_HOME/conf/jaas.config. Modify the jaas.config file by changing the entry

NamePasswordAN{
          com.idoox.security.jaas.NamePasswordLoginModule required debug=true;
          };

to

NamePasswordAN{
     com.idoox.security.jaas.WasNamePasswordLoginModule required
     debug=true;
     com.idoox.security.jaas.NameLoginModuleNoAuth required
     debug=true;
    };
Impact on WSO2 SOA Enablement Server Authorization Framework Mapping  Locate

The WSO2 SOA Enablement Server authorization framework maintains mapping between users and roles. If you change authentication to use the user database maintained by the application server, the mapping becomes invalid.

To correct this issue, you must add dummy users to the WSO2 SOA Enablement Server UserStore and assign them appropriate roles. Use the Authorization Policy tool for this. The username of the 'dummy' user must correspond to the username of the user in the application server's user database. For example, if you have a WebLogic server user with the username system and you want to grant him unrestricted access to the WSO2 SOA Enablement Server administration console:

  1. Start the WSO2 SOA Enablement Server Authorization Policy tool.

  2. Add a user with the username system.

  3. Grant him the Role Assignment permission with the name administrator.

JNDI Connector Setup  Locate

To secure JNDI connector, you must set the accepting security provider to its appropriate endpoint and pass security properties to the WSO2 SOA Enablement Server JNDI context.

JNDI Connector Service Setup  Locate

You can set up the HttpBasic security provider for the JNDI service endpoint (either /internal/jndi-dl/ or /internal/jndi-/) using either WSO2 SOA Enablement Server Administration Console or the ProvidersManager command line tool (a GUI version is available as well):

ProvidersManager -t http//host]:[port]//wasp

ProvidersManager -t http//[host]:[ port]//WSO2 SOA Enablement Server -b /internal/jndi-dl/ -a HttpBasic

JNDI Connector Client Setup  Locate

If your J2EE client program uses WSO2 SOA Enablement Server JNDI context implementation, the only thing you need to secure the SOAP communication is to specify two properties:

  1. java.naming.security.principal, which will be the username.

  2. java.naming.security.credentials, which will be the password.

You can specify the properties either on the command line, with java -Djava.naming.security.principal=asUsername -Djava.naming.security.credentials=asPassword ... or in the code:

Hashtable env = new Hashtable();
        env.put(java.naming.provider.url,
        http://[host]:[port]/WSO2 SOA Enablement Server);
        env.put(java.naming.security.principal,
        asUsername);
        env.put(java.naming.security.credentials,
        asPassword); InitialContext initialContext = new
        InitialContext(env);
[Note]Note

asUsername and asPassword stand for a real username and password of the identity within the application server. WASP_HOME stands for you WSO2 SOA Enablement Server installation home directory.

Securing the jndiOverSoap Demo  Locate

The jndiOverSoap demo shows the use of JNDI Connector. No security mechanisms are used in this demo, by default. To set up HttpBasic authentication against the application server's user database for this demo, follow these steps:

  1. Change the source code of the demo's EJB, at WASP_HOME/demo/advanced/j2eeIntegration/src/demo/advanced/jndiOverSoap/BankBean.java so the create method prints the caller principal, as shown in Example 273 :

    Example 273. BankBeanSession Modified to Print Caller Principal

    /*
     * Generated file - Do not edit!
     */
    package demo.advanced.jndiOverSoap;
    
    import java.lang.*;
    
    import java.security.Principal;
    
    import java.util.Vector;
    
    import javax.ejb.CreateException;
    import javax.ejb.EJBException;
    
    import javax.naming.InitialContext;
    import javax.naming.NamingException;
    
    
    /**
     * Session layer for BankBean.
     * This version prints in the method ejbCreate caller principal on 
     * the standard output.
     */
    public class BankBeanSession extends demo.advanced.jndiOverSoap.BankBean
        implements javax.ejb.SessionBean {
        static final long serialVersionUID = 406790000992848677L;
        javax.ejb.SessionContext ctx = null;
    
        public void ejbActivate() {
        }
    
        public void ejbPassivate() {
        }
    
        public void setSessionContext(javax.ejb.SessionContext ctx) {
            this.ctx = ctx;
        }
    
        public void unsetSessionContext() {
        }
    
        public void ejbRemove() {
        }
    
        public void ejbCreate() throws javax.ejb.CreateException {
            if (this.ctx != null) {
                Principal principal = this.ctx.getCallerPrincipal();
    
                if (principal == null) {
                    System.err.println("Principal is null");
                } else {
                    System.err.println("Caller principal name : "
                        + principal.getName());
                }
            }
    
            super.ejbCreate();
        }
    }
    
  2. Redeploy WSO2 SOA Enablement Server into the application server using the J2eeIntegrate tool. To do so, run deployWithEJBs.bat j2eeIntegrate from the directory WASP_HOME/demo/advanced/j2eeIntegration.

  3. Set up JAAS login modules within the application server you use ( please see JAAS Login Modules.

  4. Set up JNDI Connector.

  5. Edit the run file (run.bat on Windows or run.sh on Unix). Modify the command that invokes the demo by adding these properties:

    • -Djava.naming.security.credentials=asUsername

    • -Djava.naming.security.principal=asPassword

    • -Djava.security.auth.login.config=WASP_HOME/conf/jaas.config

    We recommend adding these properties after -Djava.naming.factory.initial.

  6. Add WASP_HOME/lib/security_providers_client.jar to the demo classpath. To do so, modify the system variable RUN_CLIENT_CLASSPATH by adding WASP_HOME/lib/security_providers_client.jar.

  7. Run the client. In the stdout log of the application server you should see the username of the authenticated user.

Securing EJBs Exposed as Web Services  Locate
Securing the Web Service  Locate

You can set up HttpBasic security provider for your service endpoint using either WSO2 SOA Enablement Server Administration Console or the ProvidersManager command line tool (a GUI version is also available), as follows:

ProvidersManager -t http://[host]:[port]/WSO2 SOA Enablement Server -b [your_ejb_webservice_endpoint] -a HttpBasic

Securing the Client  Locate

Because the client of the EJB Web service is a regular web service client, you can set up security in the usual way. For example, you can call the following sequence of commands in your code:

org.systinet.wasp.webservice.ServiceClient myEJBServiceClient =
    org.systinet.wasp.webservice.ServiceClient.create(
        "http://[host]:[port]/myEJBServiceLocation");

org.idoox.security.Credentials credentials = 
    WaspSecurity.acquireClientCredentials(username, password, "HttpBasic");

WaspSecurity.setCredentials(myEJBServiceClient, credentials);

WaspSecurity.setInitiatingProvider(myEJBServiceClient, "HttpBasic");
Demo  Locate

The following instructions show you how to secure a Web service implemented by the BankBean EJB and modify the demo so it performs a secure call of the BankBean EJB. You can secure any Web service implemented by EJBs this way.

  1. Change the source code of the demo's EJB, at WASP_HOME/demo/advanced/j2eeIntegration/src/demo/advanced/jndiOverSoap/BankBean.java so the create method prints the caller principal, as shown in Example 273

  2. Add authentication to the client code. Replace the code in WASP_HOME/demo/advanced/j2eeIntegration/ejbWebservice/src/demo/advanced/ejbWebservice/WsClient.java with the code in Example 274 .

    Example 274. WsClient with Authentication

    // Copyright WSO2 Inc. All rights reserved.
    // Use is subject to license terms.
    package demo.advanced.ejbWebservice;
    
    import demo.advanced.jndiOverSoap.Account;
    import demo.advanced.jndiOverSoap.AccountHome;
    import demo.advanced.jndiOverSoap.Bank;
    import demo.advanced.jndiOverSoap.BankHome;
    import demo.advanced.jndiOverSoap.Calc;
    import demo.advanced.jndiOverSoap.CalcHome;
    import org.idoox.security.Credentials;
    import org.idoox.wasp.WaspSecurity;
    import org.systinet.wasp.webservice.Registry;
    import org.systinet.wasp.webservice.ServiceClient;
    
    import java.util.Vector;
    
    
    /**
     * Wasp client for the EJB web service demo
     */
    public class WsClient {
        private static AccountHome accountHome = null;
        private static BankHome bankHome = null;
        private static CalcHome calcHome = null;
        private static final String CALC_WSDL_LOCATION =
            "/demo/ejbWebservice/CalcBean/wsdl";
        private static final String BANK_WSDL_LOCATION =
            "/demo/ejbWebservice/BankBean/wsdl";
        private static final String ACCOUNT_WSDL_LOCATION =
            "/demo/ejbWebservice/AccountBean";
    
        public static void main(String[] args) throws Exception {
            String serverURL =
                System.getProperty("wso2.demo.server.url",
                    "http://localhost:6060");
    
            // setup default security
            Credentials credentials = WaspSecurity.acquireClientCredentials("asUsername", 
                "asPassword", "HttpBasic");
            WaspSecurity.setCredentials((ServiceClient) null, new Credentials[]{credentials});
            WaspSecurity.setInitiatingProvider((ServiceClient) null, "HttpBasic");
    
            accountHome =
                (AccountHome) Registry.lookup(serverURL + ACCOUNT_WSDL_LOCATION,
                    AccountHome.class);
            bankHome =
                (BankHome) Registry.lookup(serverURL + BANK_WSDL_LOCATION,
                    BankHome.class);
    
            Calc calc =
                (Calc) Registry.lookup(serverURL + CALC_WSDL_LOCATION, Calc.class);
            System.out.println(
                "Creating a new bank (Statefull session EJB) : bank_1");
    
            Bank bank_1 = bankHome.create();
            bank_1.setName("bank_1");
            System.out.println("Creating a new account (Entity EJB) : account_1");
    
            Account account_1 = accountHome.create();
            account_1.setName("account_1");
            account_1.setBalance(new Integer(0));
            System.out.println("Adding an account id of account_1 to the bank");
            bank_1.addAccountId(account_1.getId());
            System.out.println("Creating a new account (Entity EJB) : account_2");
    
            Account account_2 = accountHome.create();
            account_2.setName("account_2");
            account_2.setBalance(new Integer(0));
            System.out.println("Adding an account id of account_2 to the bank");
            bank_1.addAccountId(account_2.getId());
            System.out.println("Depositing $2000 to the account_1");
            account_1.deposit(new Integer(2000));
            System.out.println("Depositing $4000 to the account_2");
            account_2.deposit(new Integer(4000));
    
            Vector accounts = bank_1.getAccountIds();
            printAccounts(accounts);
            System.out.print("Calculating sum of accounts in bank_1 : $");
            System.out.println(calc.sumAccountIds(accounts));
            calc.sumAccountIds(accounts);
            System.out.println("Removing account_1");
            account_1.remove();
            System.out.println("Removing account_2");
            account_2.remove();
            System.out.println("Removing bank_1");
            bank_1.remove();
        }
    
        private static void printAccounts(Vector v) throws Exception {
            System.out.println("Accounts : ");
    
            for (int i = 0; i < v.size(); i++) {
                Integer accountId = (Integer) v.elementAt(i);
                Account account = accountHome.findByPrimaryKey(accountId);
                System.out.println(account.getName() + " $" + account.getBalance());
            }
        }
    }
    
  3. Redeploy WSO2 SOA Enablement Server into the application server using the J2eeIntegrate tool. To do so, run deployWithEJBs.bat j2eeIntegrate from the directory WASP_HOME/demo/advanced/j2eeIntegration.

  4. Deploy the demo Web service to the WSO2 SOA Enablement Server by running the command run deploy_service in the root directory of the demo.

  5. Set the security on the endpoint representing the BankBean EJB by running the following command from the WASP_HOME/bin directory:

    • If you run BEA WebLogic: ProvidersManager -t http://localhost:7001/WSO2 SOA Enablement Server -b /demo/ejbWebservice/BankBean -a HttpBasic

    • If you run IBM WebSphere: ProvidersManager -t http://localhost:9080/WSO2 SOA Enablement Server -b /demo/ejbWebservice/BankBean -a HttpBasic

  6. Set up JAAS login modules within the application server you use (please see JAAS Login Modules).

  7. Add WASP_HOME/lib/security_providers_client.jar to the demo classpath. To do so, modify the system variable RUN_CLIENT_CLASSPATH by adding WASP_HOME/lib/security_providers_client.jar.

  8. Edit the run file (run.bat on Windows or run.sh on Unix). Modify the command that starts the client by adding the property -Djava.security.auth.login.config=WASP_HOME/conf/jaas.config.

    We recommend inserting this property after -Didoox.debug.level=1.

  9. Restart the application server and run the client. In the stdout log of your application server you should see the username of the authenticated user.

JMS Transport  Locate

JMS (Java Message Service) is part of the J2EE specification. You can send SOAP messages over JMS using WSO2 SOA Enablement Server. For more information see JMS Transport in Message Processing.

JTA Over SOAP  Locate

To call JTA transactions over SOAP, you must deploy the component WASP_HOME/conf/porting/dist/j2ee_jta.jar on the WSO2 SOA Enablement Server that has the accessible JNDI context you want to expose. If you use the J2eeIntegrate tool and you installed J2EE Support during the installation process, it will be done automatically.

On the client side, you must include the component WASP_HOME/lib/j2ee_jndi_connector_client.jar into the classpath of your J2EE client. Note please, that we use the interface javax.transaction.TransactionManager to handle JTA transactions on the server side. The implementation of this interface is usually accessible in the JNDI namespace.

To set this interface to correspond to your application server, edit the deployment descriptor of the component WASP_HOME/conf/porting/dist/j2ee_jta.jar and replace the string [jndi_name] with the JNDI name of the transaction manager before you deploy it.

Please note that this component is dependent on the JNDI connector on the client side - you must have WASP_HOME/lib/j2ee_jndi_connector_client.jar in the classpath.

Most application servers provide JTA's java.transaction.UserTransaction interface. The J2EE client program may use this interface to demarcate transactions by calling its begin(), commit() or rollback() methods. The client program may obtain a reference to the interface through JNDI lookup. In the WSO2 SOA Enablement Server Server's java.naming.InitialContext implementation, the UserTransaction interface may be obtained through the JNDI name java:comp/UserTransaction.

[Note]Note

For the sake of backward compatibility, the user transaction can be still obtained using the old JNDI name 'wasp.userTransaction'.

When you call the UserTransaction.begin() method, the following takes place:

  1. On the client side, UserTransaction.begin() creates a unique transaction id.

  2. The call is sent over SOAP to the WSO2 SOA Enablement Server.

  3. On the server side, UserTransaction.begin() creates a new transaction associated with the unique id. This transaction begins but is immediately suspended.

All subsequent Web service calls (including JDBC, JMS and EJB over SOAP calls) from the client's thread that called the begin() method are associated with the newly-started transaction.

The new transaction sits in suspended state on the server until an associated Web service method call is made, at which point the following happens:

  1. The SOAP header processors on the client side add the transaction id to the SOAP message containing the method call.

  2. On the server side, the transaction id is obtained from the SOAP header.

  3. The suspended transaction is resumed. The subsequent Web service method call is made in the transaction context.

  4. When the method finishes, the transaction is suspended again.

This process repeats with all subsequent Web service method calls until the commit() or rollback() method is called.

Example 275 shows a piece of code that uses the UserTransaction interface.

Example 275. JTA Over SOAP

// Copyright WSO2 Inc. All rights reserved.
// Use is subject to license terms.
package example.applicationIntegration.j2eeIntegration;

import demo.advanced.jndiOverSoap.Account;
import demo.advanced.jndiOverSoap.AccountHome;

import javax.naming.InitialContext;

import javax.transaction.UserTransaction;


public class Jta {
    public static void main(String[] args) throws Exception {
        InitialContext context = new InitialContext();
        AccountHome accountHome = (AccountHome) context.lookup("AccountBean");
        UserTransaction userTransaction =
            (UserTransaction) context.lookup("java:comp/UserTransaction");

        // Create new entity bean
        Account account = accountHome.findByPrimaryKey(new Integer(123456));
        account.setName("account_1");

        // Begin transaction
        userTransaction.begin();
        account.deposit(new Integer(25000));

        // Rollback the transaction - no new entity bean is created
        userTransaction.rollback();
    }
}

We provide two demos that show WSO2 SOA Enablement Server's ability to handle user transactions.

The first is the JTA Over SOAP demo. More information about it is in the readme.txt file within the demo directory.

The second is the EJB Under JTA demo. This demo uses Microsoft SOAP Toolkit to access Enterprise JavaBeans under JTA transaction from the Microsoft Excel worksheet.

Integration with Existing Application Servers  Locate

Supported application servers, and notes about each of them, are described in the Release Notes. For information about porting WSO2 SOA Enablement Server on the application server, please see Porting WSO2 SOA Enablement Server Overview.