Access EJB on JBoss from outside
How to acces an enterprise java bean (EJB) running on JBoss from a standalone application running outside JBoss?
- In the code you must, among others:
- Set properties for a naming context and create one to be able to look the EJB up
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>
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 outif (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 );