You are viewing an old version of this page. View the current version.

Compare with Current View Page History

« Previous Version 9 Next »

What's My Bean's JNDI Name?

There are two things to keep in mind before you start reading:

  1. OpenEJB provides a default JNDI name to your EJB.
  2. You can customize the JNDI name.

    Default JNDI name

    The default JNDI name is in the following format:
    {deploymentId}{interfaceType.annotationName}
    
    Lets try and understand the above format. Each of deploymentId, interfaceType and annotationName are pre-defined variables. There are other pre-defined variables available which you could use to customize the JNDI name format. Its just that OpenEJB uses the above three variables to determine the default JNDI name. Lets see what each variable means:
  • deploymentId: The EJB's ejb-name
  • *interfaceType.annotationName: *

JNDI Name Formatting

variable

description

moduleId

Typically the name of the ejb-jar file or the <ejb-jar id=""> id value if specified

ejbType

STATEFUL, STATELESS, BMP_ENTITY, CMP_ENTITY, or MESSAGE_DRIVEN

ejbClass

for a class named org.acme.superfun.WidgetBean results in org.acme.superfun.WidgetBean

ejbClass.simpleName

for a class named org.acme.superfun.WidgetBean results in WidgetBean

ejbClass.packageName

for a class named org.acme.superfun.WidgetBean results in org.acme.superfun

ejbName

The ejb-name as specified in xml or via the 'name' attribute in an @Stateful, @Stateless, or @MessageDriven annotation

deploymentId

The unique system id for the ejb. Typically the ejbName unless specified in the openejb-jar.xml or via changing the openejb.deploymentId.format

interfaceType

see interfaceType.annotationName

interfaceType.annotationName

Following the EJB 3 annotations @RemoteHome, @LocalHome, @Remote and @Local

  • RemoteHome (EJB 2 EJBHome)
  • LocalHome (EJB 2 EJBLocalHome)
  • Remote (EJB 3 Business Remote)
  • Local (EJB 3 Business Local)
  • Endpoint (EJB webservice endpoint)

interfaceType.xmlName

Following the ejb-jar.xml descriptor elements <home>, <local-home>, <business-remote>, <business-local>, and <service-endpoint>:

  • home (EJB 2 EJBHome)
  • local-home (EJB 2 EJBLocalHome)
  • business-remote (EJB 3 Business Remote)
  • business-local (EJB 3 Business Local)
  • service-endpoint (EJB webservice endpoint)

interfaceType.xmlNameCc

Camel-case version of interfaceType.xmlName:

  • Home (EJB 2 EJBHome)
  • LocalHome (EJB 2 EJBLocalHome)
  • BusinessRemote (EJB 3 Business Remote)
  • BusinessLocal (EJB 3 Business Local)
  • ServiceEndpoint (EJB webservice endpoint)

interfaceType.openejbLegacyName

type.getOpenejbLegacy()

Following the OpenEJB 1.0 hard-coded format:

  • (empty string) (EJB 2 EJBHome)
  • Local (EJB 2 EJBLocalHome)
  • BusinessRemote (EJB 3 Business Remote)
  • BusinessLocal (EJB 3 Business Local)
  • ServiceEndpoint (EJB webservice endpoint)

interfaceClass

for a class named org.acme.superfun.WidgetRemote results in org.acme.superfun.WidgetRemote

interfaceClass.simpleName

for a class named org.acme.superfun.WidgetRemote results in WidgetRemote

interfaceClass.packageName

for a class named org.acme.superfun.WidgetRemote results in org.acme.superfun

BACK IT UP

The short answer is:

  • {deploymentId}/{interfaceClass.simpleName}

And typically, deploymentId will be your bean's ejb-name unless you've explicitly set it to something else via an openejb-jar.xml or set the openejb.deploymentId.format to something else.

So if you have a bean like such:

<session>
      <ejb-name>Calculator</ejb-name>
      <home>org.acme.CalculatorRemoteHome</home>
      <remote>org.acme.CalculatorRemote</remote>
      <local-home>org.acme.CalculatorLocalHome</local-home>
      <local>org.acme.CalculatorLocal</local>
      <ejb-class>org.acme.CalculatorImpl</ejb-class>
      <business-local>org.acme.CalculatorBusinessLocal</business-local>
      <business-local>org.acme.CalculatorBusinessLocalTwo</business-local>
      <business-remote>org.acme.CalculatorBusinessRemote</business-remote>
      <business-remote>org.acme.CalculatorBusinessRemoteTwo</business-remote>
    </session>

The following names will be bound into JNDI and accessible via the LocalInitialContextFactory:

  • Calculator/CalculatorRemote
  • Calculator/CalculatorLocal
  • Calculator/CalculatorBusinessLocal
  • Calculator/CalculatorBusinessLocalTwo
  • Calculator/CalculatorBusinessRemote
  • Calculator/CalculatorBusinessRemoteTwo

And these would be available via the RemoteInitialContextFactory

  • Calculator/CalculatorRemote
  • Calculator/CalculatorBusinessRemote
  • Calculator/CalculatorBusinessRemoteTwo

This is the same list minus any interfaces of a local nature as they aren't accessible over a network.

Changing the JNDI name format

The JNDI name format can actually be changed. At current date this can be done on a server-wide basis, but in the future it will be changeable on an application and individual bean basis.

To set it for the server, there is a system property called openejb.jndiname.format which understands the following variables:

  • moduleId - typically the file name of the ear or of the ejb jar if it's not in an ear.
  • ejbType - STATEFUL, STATELESS, BMP_ENTITY, CMP_ENTITY, or MESSAGE_DRIVEN
  • ejbClass - ((Class)ejbClass).getName()
  • ejbClass.simpleName - ((Class)ejbClass).getSimpleName());
  • ejbName - ejb-name as it is in the xml
  • deploymentId - the bean's deployment Id
  • interfaceType - EJB_OBJECT, EJB_LOCAL, BUSINESS_LOCAL, or BUSINESS_REMOTE
  • interfaceClass - ((Class)interfce).getName()
  • interfaceClass.simpleName - ((Class)interfce).getSimpleName()

More variables will be added in the future, such as prettier varieties of ejbType and interfaceType. If there are any you'd like added, feel free to write the dev list.

With this you can create a layout for the ejbs in global jndi namespace how ever you like. A couple examples could be:

  • {interfaceClass.simpleName}
  • {ejbName}{interfaceClass.simpleName}
  • ejb/{interfaceClass.simpleName}
  • ejb/{interfaceClass}
  • {deploymentId}-{interfaceType}
  • app/{moduleId}/ejb/{ejbName}/{interfaceClass}
  • {deploymentId}.{interfaceClass}

You are responsible for ensuring the names don't conflict. I.e. if you used something as simple as just "{interfaceClass.simpleName}" for your format it would only work as long as you didn't reuse the interface for any other beans in your app or any other app deployed in the server. If you used "{ejbName}{interfaceClass.simpleName}" you could reuse the interface in other beans but you'd have to guarantee that the ejbName is not already used by another bean in a different app.

The default of "{deploymentId}/{interfaceClass.simpleName}" is a pretty safe bet as deploymentId is guaranteed to be globally unique across all apps and beans, however the use of simpleName could cause conflicts if the bean had two interfaces like org.package1.Foo and org.package2.Foo. The safest bet, though not the default as we wanted something short, is to use the fully qualified name of the interface "{deploymentId}/{interfaceClass}".

JNDI Name Defaults

More on the jndi name issue as it relates to proxies.

You may recall our discussions[1][2][3] on what do to about all-in-one proxies and the fact that some spec compliant beans may have business interfaces that conflict[4] and therefore can't be all-in-one proxies requiring us to also support a one-proxy-per-interface approach.
What we ended up with is for each bean we create an all-in-one proxy and bind it into jndi, then for each of that bean's business interfaces we create a proxy with just that interface in it (the one-proxy-per-interface approach) and bind each proxy into jndi as well. So a bean with four remote business interfaces, for example, gets 1 all-in-one "business remote" proxy and 4 single-interface proxies, one for each remote business interface.  The same algorithm would apply to local business interfaces.  We still do not support an all-in-one proxy that implements both local business interfaces and remote business interfaces.

This is the part that has changed.  *Now* we no longer have two separate approaches (all-in-one-proxy vs single-interface-proxy) we have a sort of hybrid approach.  In the new approach we still create one proxy per each business interface, but we *also* include all the other business interfaces implemented by the bean class provided none of them conflict.  So a bean with four business interfaces gets 4 proxies, each possibly containing all four business interfaces. Recap: each proxy has all the business interfaces your bean implements (provided no conflicts are found), plus the interface the proxy is dedicated to (regardless if the bean implemented it).  We create one such proxy for each business interface you have.

So what are these conflicts?  Business interfaces extending java.rmi.Remote.  If you do not have any business interfaces extending java.rmi.Remote *and* you implemented all your business interfaces in your bean class, you are good to go and do not need to be concerned; all your proxies will be guaranteed to be 'all in one' proxies you can cast it to any of the other business interfaces of the same type (type=local vs remote) that bean implements.

What's the deal with java.rmi.Remote?  The specific issue with java.rmi.Remote interfaces is that per spec rules many runtime exceptions (container or connection related) are thrown to clients as java.rmi.RemoteException which is not a runtime exception and must be throwable via the proxy. For example it's legal for a bean to implement two conflicting methods such as these:
      InterfaceA: void doIt() throws Foo;
      InterfaceB: void doIt() throws RemoteException;

by leaving out exceptions from the throws clause that aren't declared in both interfaces methods.       Implementation:  void doIt(){}

This is fine for a bean class as it isn't going to need to throw RemoteException.  However if we create a proxy from these two interfaces it will also wind up with a 'doIt(){}' method that cannot throw RemoteException.  This is very bad as the container does need to throw RemoteException per spec rules to any business interfaces extending java.rmi.Remote.  If the container attempts to throw a RemoteException from the proxies 'doIt(){}' method, it will result in an UndeclaredThrowableException thrown by the VM.  The only way to guarantee the proxy has the 'doIt() throws RemoteException {}' method of InterfaceB is to cut out InterfaceA when we create the proxy dedicated to InterfaceB.  When we create the proxy dedicated to InterfaceA, InterfaceB is cut out.
Hope this helps describe how we deal with proxies and the strange edge case that may occur.

The important thing to remember is that if you implement all your business interfaces and do not use java.rmi.Remote, your life is super easy.
The only real issue in all of this java.rmi.Remote business is if you decide to use an openejb.jndiname.format[5] that results in you getting one proxy per bean (format="{deploymentId}" for example) or one "business remote" proxy per bean (format="{deploymentId}
{interfaceType}", my preference) instead of one proxy per each interface of a bean (format={deploymentId}/ {interfaceClass.simpleName}, the default).  

  • No labels