The Holy Java

Building the right thing, building it right, fast

Posts Tagged ‘aapserver’

Access EJB on JBoss from outside

Posted by Jakub Holý on April 10, 2006

How to acces an enterprise java bean (EJB) running on JBoss from a standalone application running outside JBoss?

  1. In the code you must, among others:
    1. Set properties for a naming context and create one to be able to look the EJB up
    2. Authenticate by JBoss by means of JAAS
  2. To run the application:
    1. Set the classpath (-cp …): it must contain jbosssx.jar (ClientLoginModule), jboss-common.jar and jnpserver.jar (naming stuff) from <jboss home>/server/default/lib
    2. Create the JAAS configuration file sample_jaas.config containing:
      jboss_jaas { org.jboss.security.ClientLoginModule required; };
      

      If you ever wanted to run the application from JBoss, replace the JAAS config file by the following entry in <JBoss home>/server/default/conf/login-config.ml (application-policy name must be the same name as the one passed to the constructor of a LoginContext):

      <application-policy name = "tap_experiments">
             <authentication>
                <login-module code = "org.jboss.security.ClientLoginModule"  flag = "required"></login-module>
             </authentication>
          </application-policy>
      
    3. Pass the file to the JVM: -Djava.security.auth.login.config=sample_jaas.config
    4. Set a security manager by passing the following options to the JVM:
      -Djava.security.manager -Djava.security.policy="<jboss home>\server\default\conf\server.policy"
import java.rmi.RemoteException;
import java.util.Properties;

import javax.ejb.CreateException;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.rmi.PortableRemoteObject;
import javax.security.auth.callback.Callback;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.callback.NameCallback;
import javax.security.auth.callback.PasswordCallback;
import javax.security.auth.callback.UnsupportedCallbackException;
import javax.security.auth.login.LoginContext;
import javax.security.auth.login.LoginException;

import com.teradata.tap.system.query.ejb.QueryEngineRemote;
import com.teradata.tap.system.query.ejb.QueryEngineRemoteHome;

/**
 * Call a business method of an EJB running on JBoss
 */
public class ExternalCallEjbSample {

        public static void main(String[] args) {
                // 1: Get the naming Context
                // Required JARs (in jboss/server/default/lib): jboss-common.jar, jnpserver.jar 
                Properties props = new Properties();
                //      Matches the java.naming.factory.initial property in jndi.properties
                props.put(Context.INITIAL_CONTEXT_FACTORY,
                                "org.jnp.interfaces.NamingContextFactory");
                //      Matches the java.naming.provider.url property in jndi.properties
                props.put(Context.PROVIDER_URL, "jnp://localhost:1099");
                props.put(Context.URL_PKG_PREFIXES,
                                "org.jboss.naming:org.jnp.interfaces");
                QueryEngineRemoteHome queryEngineHome = null;

                try {

                        Context ctx = new InitialContext(props);

                        /*/ Print all entries in the JNDI
                         NamingEnumeration ne = ctx.list("java:");
                         while (ne.hasMore()) {
                         System.out.println("A: " + ne.next().toString());
                         } //*/

                        // Look up and instantiate the home interface of the EJB
                        // IMPORTANT: It fails if no SecurityManager specified for RMI class loader will be disabled
                        // -> add these options to the JVM:
                        // -Djava.security.manager -Djava.security.policy=" home>\server\default\conf\server.policy"
                        String beanName = QueryEngineRemoteHome.JNDI_NAME;
                        System.out.println("Looking up '" + beanName + "'");
                        Object lookup = ctx.lookup(beanName);

                        queryEngineHome = (QueryEngineRemoteHome) PortableRemoteObject
                                        .narrow(lookup, QueryEngineRemoteHome.class);

                } catch (NamingException e) {
                        System.out.println("new InitialContext failed:" + e);
                }

                // 2. Instantiate the (remote) EJB and call its business method(s)
                // 2.1 I have to authenticate unless security allows anybody to call create on the EJB
                //      Otherwise an EJBException: checkSecurityAssociation will be thrown.
                // TODO: JVM option -Djava.security.auth.login.config==sample_jaas.config - use org.jboss.security.ClientLoginModule
                // and have  home>\server\default\lib\jbosssx.jar on the path (class ClientLoginModule)
                // Listing of sample_jaas.config:
                //      jboss_jaas { org.jboss.security.ClientLoginModule required debug=true; };
                LoginContext loginContext = null;
                boolean loggedIn = false;
                try {
                        CallbackHandler handler = new MyPresetCallbackHandler("tapdev","tapdev");
                        // jboss_jaas - name of a configuration in the jaas config file 
                        loginContext = new LoginContext("jboss_jaas", handler);
                        System.out.println("Created LoginContext");
                        loginContext.login(); // throws LoginException
                        System.out.println("Logged in.");
                        loggedIn = true;
                } catch (LoginException le) {
                        System.out.println("Login failed");
                        le.printStackTrace();
                }

                // Create & use the EJB:
                if (loggedIn && queryEngineHome != null) {
                        try {
                                QueryEngineRemote queryEngine = queryEngineHome.create();
                                System.out.println("queryEngine remote created.");
                                // TODO: call business method(s)
                        } catch (RemoteException e1) {
                                e1.printStackTrace();
                        } catch (CreateException e1) {
                                e1.printStackTrace();
                        }
                }

                // Log out
                if (loggedIn && loginContext != null) {
                        try {
                                loginContext.logout();
                        } catch (LoginException e) {
                                System.out.println("Logout failed:" + e);
                        }
                }

                System.out.println("## DONE! ##");
        } // main

        /** Authentication CallbackHandler with preset username/password. */
        static class MyPresetCallbackHandler implements CallbackHandler {
                String username;

                char[] password;

                public MyPresetCallbackHandler(String username, String password) {
                        this.username = username;
                        this.password = password.toCharArray();
                }

                public void handle(Callback[] callbacks) throws java.io.IOException,
                                UnsupportedCallbackException {
                        for (int i = 0; i < callbacks.length; i++) {
                                Callback callback = callbacks[i];
                                if (callback instanceof NameCallback) {
                                        ((NameCallback) callback).setName(username);
                                } else if (callback instanceof PasswordCallback) {
                                        ((PasswordCallback) callback).setPassword(password);
                                } else {
                                        throw new UnsupportedCallbackException(callback,
                                                        "Unrecognized Callback");
                                }
                        }
                }// handle 
        }// MyPresetCallbackHandler
}

See EjbLocator.java
and EjbLocatorException.java.
With them, you can replace all above with QueryEngineRemote queryEngine = (QueryEngineRemote) EjbLocator.getInstance().locate( QueryEngineRemoteHome.JNDI_NAME );

Posted in j2ee | Tagged: , , , | Comments Off