Cross-application local bean invocations
Local EJB can be accessed by clients from the same application. But not only. The EJB specification admits that a local EJB can be accessed by any client from the same JVM. It is up to EJB Container provider if it allows such invocations. Fragment of EJB 3.1 specification:
Access to an enterprise bean through the local client view is only required to be supported for local clients packaged within the same application as the enterprise bean that provides the local client view. Compliant implementations of this specification may optionally support access to the local client view of an enterprise bean from a local client packaged in a different application. The configuration requirements for inter-application access to the local client view are vendor-specific and are outside the scope of this specification. Applications relying on inter-application access to the local client view are non-portable.
The fact, that EJB Container allows cross-application local invocations or not, has impact on application architectures. Cross-application local invocations has better performance, but has a security drawback. Better performance is achieved only if two communicating applications are located in the same JVM. Within a single server instance can be deployed many applications provided by different providers. Clients of local beans located in the same application are controlled by the application provider. But other clients located in the same JVM do not have to be controlled by the application provider. Thus the application should secure all its local beans, if not then malicious client can easily gain access to essential resources.
Example. A standalone EJB module localejbtest was deployed on JBoss 7.0 server. It contains EJB component with its local interface:
@Stateless
public class LocalTest implements LocalTestIntf {
public String test() {
return “test”;
}
}
@Local
public interface LocalTestIntf {
String test();
}
Also a standalone WEB module localejbclient was deployed. It contains a servlet acting as a ejb client:
@WebServlet(“/LocaTestClient”)
public class LocaTestClient extends HttpServlet {
protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
try {
InitialContext ctx = new InitialContext();
Object obj = ctx.lookup(“java:global/localejbtestnull/LocalTest!localtest.LocalTestIntf”);
response.getWriter().write(obj.getClass().getName());
} catch (Exception e) {
e.printStackTrace();
}
}
Test result is localtest.LocalTestIntf$$$view8 or similar. So the local bean is visible. We expect that each module have separate ClassLoader. So ClassLoader problems can appear. To see it we add interface LocalTestIntf to localejbclient module and modify client code:
InitialContext ctx = new InitialContext();
Object obj = ctx.lookup(“java:global/localejbtestnull/LocalTest!localtest.LocalTestIntf”);
LocalTestIntf intf = (LocalTestIntf) obj;
response.getWriter().write(intf.test());
An exception is raised: business interface LocalTestIntf cannot be cast to interface LocalTestIntf. Looks weird but actually that is how should it work. We do other way. Do not add this interface and use reflection:
InitialContext ctx = new InitialContext();
Object obj = ctx.lookup(“java:global/localejbtestnull/LocalTest!localtest.LocalTestIntf”);
Method method = obj.getClass().getMethod(“test”);
response.getWriter().write(“”+method.invoke(obj));
And it works! Thus local beans can be invoked always, by any client within the same JVM, even if client does not have interfaces. Probably there is a way to share interfaces via shared libraries or other mechanisms, and use them explicitly without reflection. One should consult the server provider, it is very vendor-specific.
When architecting an application containing local EJBs, check if your application server admits cross-application invocations.