How to expose an EJB via IIOP and call it in JBoss EAP 7 / 6
Environment
- JBoss Enterprise Application Platform (EAP)
- 7.x
- 6.x
Issue
- Could you provide me some samples or documentation how to call an EJB using iiop ( jboss jacorb )?
- Can you clarify if calling EJB 2 EJB using iiop is supported?
- Do you have any documentation related RMI over IIOP implemented in JBoss EAP 6 with respect to EJB?
- How to call an EJB in JBoss EAP from Tomcat?
- How to connect JBoss EAP and Websphere?
Resolution
JBoss EAP 6/7 supports CORBA/IIOP-based access to EJB deployed on JBoss EAP, as explained on EAP 7.3 Development Guide. However, when running in a containerised environment it is unsupported.
To expose an EJB via IIOP
- Create a jboss-ejb3.xml in the META-INF directory of the ejb jar.
- Specify the EJB names you want exposed via IIOP or use a * for all EJBs in the ejb jar
<?xml version="1.0" encoding="UTF-8"?>
<jboss:ejb-jar xmlns:jboss="http://www.jboss.com/xml/ns/javaee"
xmlns="http://java.sun.com/xml/ns/javaee"
xmlns:iiop="urn:iiop"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.jboss.com/xml/ns/javaee http://www.jboss.org/j2ee/schema/jboss-ejb3-2_0.xsd
http://java.sun.com/xml/ns/javaee http://www.jboss.org/j2ee/schema/jboss-ejb3-spec-2_0.xsd
urn:iiop jboss-ejb-iiop_1_0.xsd"
version="3.1"
impl-version="2.0">
<assembly-descriptor>
<iiop:iiop>
<ejb-name>*</ejb-name>
</iiop:iiop>
</assembly-descriptor>
</jboss:ejb-jar>
The EJB needs a RemoteHome interface, for example:
public interface HelloRemote extends javax.ejb.EJBObject {
String hello(String name) throws java.rmi.RemoteException;
}
public interface HelloRemoteHome extends javax.ejb.EJBHome {
public HelloRemote create() throws java.rmi.RemoteException;
}
@javax.ejb.Stateless
@javax.ejb.RemoteHome(HelloRemoteHome.class)
public class HelloSessionBean {
public String hello(String name) {
return "Hello " + name;
}
}
To call the EJB via IIOP using from a standalone JVM client using com.sun.jndi.cosnaming.CNCtxFactory
import java.rmi.RMISecurityManager;
import java.util.Hashtable;
import javax.naming.Context;
import javax.naming.InitialContext;
import javax.naming.NamingException;
import javax.rmi.PortableRemoteObject;
public class JDKClient {
public static void main(String[] args) throws Exception {
// The java security manager can be enabled via system property in the standalone java application or by setting it on the command line: -Djava.security.manager
// Setup security for stub downloading. See conf/security.policy in
// this project as well as this project's build.xml 'run' target for
// additional required configuration.
// Note this can be removed and use -Djava.security.manager instead when running the
// standalone java client
if ( System.getSecurityManager() == null ) {
System.setSecurityManager(new RMISecurityManager());
}
// system property must be used by remote clients to dynamically generate the stubs
System.setProperty("com.sun.CORBA.ORBUseDynamicStub", "true");
// get initial context
Hashtable<String,String> env = new Hashtable<String,String>();
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.cosnaming.CNCtxFactory");
env.put(Context.PROVIDER_URL, "corbaloc::localhost:3528/JBoss/Naming/root");
Context ctx = new InitialContext(env);
// lookup the IIOP EJB
Object iiopObj = ctx.lookup("HelloSessionBean");
// narrow down to the RemoteHome interface
HelloRemoteHome ejbHome = (HelloRemoteHome) PortableRemoteObject.narrow(iiopObj, HelloRemoteHome.class);
// create the remote interface
HelloRemote remote = ejbHome.create();
// invoke business methods on the remote interface
System.out.println(remote.hello("JBoss"));
}
}
Standalone JDK Client Notes
If you need to specify a java security policy allowing the standalone client access, by adding this system property:
-Djava.security.policy=java.policy
Where java.policy grants access, below is just an example granting all permissions. If you are using a java security policy, you would need to grant the permissions needed for the client app to download the stubs from the remote server.
grant {
// Allow everything for now
permission java.security.AllPermission;
};
Also, you can remove, the code from the client setting the security manager if you set the system property -Djava.security.manager instead when launching the standalone client.
if ( System.getSecurityManager() == null )
System.setSecurityManager(new RMISecurityManager());
To call an EJB running in another application server from a client running in JBoss EAP 6
Change the InitialContext factory & lookup to be:
// get initial context
InitialContext ctx = new InitialContext(new Hashtable<String,String>());
String ejbLookupPath = "HelloSessionBean";
String lookup = "corbaname:iiop:" + host + ":" + port +"#" + ejbLookupPath;
// lookup the IIOP EJB
Object iiopObj = ctx.lookup(lookup);
HelloRemoteHome ejbHome = (HelloRemoteHome) PortableRemoteObject.narrow(iiopObj, HelloRemoteHome.class);
HelloRemote remote = ejbHome.create();
System.out.println(remote.hello("JBoss"));
...
To enable authorization
Add the ior-security-config to the jboss-ejb3.xml for the EJBs you want to enable security upon, for example an EJB named HelloSessionBean below:
<?xml version="1.0" encoding="UTF-8"?>
<jboss:jboss xmlns:jboss="http://www.jboss.com/xml/ns/javaee" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://www.jboss.com/xml/ns/javaee http://www.jboss.org/j2ee/schema/jboss_5_0.xsd http://java.sun.com/xml/ns/javaee http://www.jboss.org/j2ee/schema/jboss-ejb3-spec-2_0.xsd urn:security jboss-ejb-security_1_0.xsd urn:security-role jboss-ejb-security-role_1_0.xsd" version="3.1" impl-version="2.0">
<assembly-descriptor xmlns="http://java.sun.com/xml/ns/javaee">
<iiop xmlns:xalan="http://xml.apache.org/xalan" xmlns:s="urn:security" xmlns:ext="xalan://org.jboss.ts.lib.porting.EjbJarHandler" xmlns:sr="urn:security-role" xmlns="urn:iiop">
<ejb-name xmlns="http://java.sun.com/xml/ns/javaee">HelloSessionBean</ejb-name>
<binding-name>HelloSessionBean</binding-name>
<ior-security-config>
<transport-config>
<integrity>supported</integrity>
<confidentiality>supported</confidentiality>
<establish-trust-in-target>supported</establish-trust-in-target>
<establish-trust-in-client>supported</establish-trust-in-client>
</transport-config>
<as-context>
<auth-method>username_password</auth-method>
<realm>default</realm>
<required>false</required>
</as-context>
<sas-context>
<caller-propagation>supported</caller-propagation>
</sas-context>
</ior-security-config>
</iiop>
</assembly-descriptor>
</jboss:jboss>
Create an appclientlogin.conf containing:
csi {
org.jboss.security.ClientLoginModule required debug=false;
};
Create a JAAS CallbackHandler for example:
static class SimpleCallbackHandler implements CallbackHandler
{
String username;
char[] password;
public SimpleCallbackHandler(String username, String password)
{
this.username = username;
this.password = password.toCharArray();
}
@Override
public void handle(Callback[] callbacks) throws IOException, UnsupportedCallbackException
{
for (Callback callback : callbacks)
{
if (callback instanceof NameCallback)
{
NameCallback nameCallback = (NameCallback) callback;
nameCallback.setName(this.username);
}
else if (callback instanceof PasswordCallback)
{
PasswordCallback passCallback = (PasswordCallback) callback;
passCallback.setPassword(this.password);
}
else
throw new UnsupportedCallbackException(callback);
}
}
}
Login the JAAS LoginContext before looking up the EJB in the client code:
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;
// set the client security context.
LoginContext loginContext = new LoginContext(configName, new SimpleCallbackHandler(username, password));
loginContext.login();
// get initial context
Hashtable<String,String> env = new Hashtable<String,String>();
env.put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.cosnaming.CNCtxFactory");
env.put(Context.PROVIDER_URL, "corbaloc::localhost:3528/JBoss/Naming/root");
Context ctx = new InitialContext(env);
...
Make sure your standalone client is run with the following JVM arguments:
-Djava.security.policy=java.policy -Djava.security.auth.login.config=appclientlogin.conf -Djava.security.manager -Dcom.sun.CORBA.ORBUseDynamicStub=true -Dorg.omg.CORBA.ORBClass=org.jacorb.orb.ORB -Dorg.omg.CORBA.ORBSingletonClass=org.jacorb.orb.ORBSingleton -Dorg.omg.PortableInterceptor.ORBInitializerClass.org.jboss.as.jacorb.csiv2.SASClientInitializer
- This setting grants access to download the dynamic stubs from the server
-Djava.security.policy=java.policy
- This settings tells it where to load the JAAS client configuration
-Djava.security.auth.login.config=appclientlogin.conf
- This setting enables the java security manager
-Djava.security.manager
- These settings tell it to use the jacorb implementation (ships with JBoss EAP 6) instead of the JDK ORB
-Dcom.sun.CORBA.ORBUseDynamicStub=true
-Dorg.omg.CORBA.ORBClass=org.jacorb.orb.ORB
-Dorg.omg.CORBA.ORBSingletonClass=org.jacorb.orb.ORBSingleton
- This enables the security interceptor to pass along the security credentials
-Dorg.omg.PortableInterceptor.ORBInitializerClass.org.jboss.as.jacorb.csiv2.SASClientInitializer
Examples
See attached eap6-client-calls-eap5-iiop-ejb.zip , this example has a client that runs in JBoss EAP 6 and calls an EJB exposed by IIOP running in JBoss EAP 5.
Related Solutions:
- How to configure EJB IIOP bindings to include the fully qualified path in JBoss EAP 7 / 6
- How to list the objects bound in the IIOP context in JBoss EAP 7 / 6
- WFNAM00007: Invalid URL scheme name "iiop" in JBoss EAP 7
- How to enable EJB IIOP in JBoss EAP 7 / 6
- NullPointerException when trying to use org.wildfly.iiop.openjdk.naming.jndi.CNCtxFactory in standalone java client to connect to JBoss EAP 7 IIOP
- org.omg.CosNaming.NamingContextPackage.NotFound trying to look up an EJB via IIOP in JBoss EAP 7 / 6
Diagnostic Steps
- Ensure the JBoss EAP server is running one of the full based profiles otherwise IIOP will not be enabled on the server.
- Ensure the EJB application specifies the EJBs to enable IIOP on within the
jboss-ejb3.xml
This solution is part of Red Hat’s fast-track publication program, providing a huge library of solutions that Red Hat engineers have created while supporting our customers. To give you the knowledge you need the instant it becomes available, these articles may be presented in a raw and unedited form.