access remote session ejb on remote server

Discussions

EJB programming & troubleshooting: access remote session ejb on remote server

  1. access remote session ejb on remote server (9 messages)

    I have one session ejb deployed on serverA with jndi name: ejb/MySLSBRemoteHome

    I have one web client deployed on serverB with the following DD segment:

    Both are running weblogic 8.12.

    web.xml

    quote:
    --------------------------------------------------------------------------------
     <ejb-ref>
    <ejb-ref-name>test/myejb</ejb-ref-name>
    <ejb-ref-type>Session</ejb-ref-type>
    <home>test.MySLSBHome</home>
    <remote>test.MySLSBRemote</remote>
    </ejb-ref>

    --------------------------------------------------------------------------------

    weblogic.xml

    quote:
    --------------------------------------------------------------------------------
     <reference-descriptor>
    <ejb-reference-description>
    <ejb-ref-name>test/myejb</ejb-ref-name>
    <jndi-name>ejb/MySLSBRemoteHome</jndi-name>
    </ejb-reference-description>
    </reference-descriptor>

    --------------------------------------------------------------------------------

    index.jsp

    quote:
    --------------------------------------------------------------------------------
     Properties prop = new Properties();
    prop.put(Context.INITIAL_CONTEXT_FACTORY,"weblogic.jndi.WLInitialContextFactory");
    prop.put(Context.PROVIDER_URL,"t3://severA:7001");

    Context initial = new InitialContext(prop);
    Object objref = initial.lookup("java:comp/env/test/myejb");

    MySLSBHome home =
    (MySLSBHome)PortableRemoteObject.narrow(objref,
    MySLSBHome.class);

    MySLSBRemote bean = home.create();

    --------------------------------------------------------------------------------

    Now the problem is that i get an exception:

    javax.naming.LinkException: . Root exception is javax.naming.NameNotFoundExcept
    ion: Unable to resolve 'ejb/MySLSBRemoteHome' Resolved ejb; remaining name 'MySLSBRemoteHome'

    But when i change the lookup to initial.lookup("ejb/MySLSBRemoteHome"); it will work. But i am supposed to use "java:comp/env/test/myejb", right?

    Can anyone of you help me out? Thanks in advance
  2. When i change the lookup to initial.lookup("ejb/MySLSBRemoteHome"); it will work. But i am supposed to use "java:comp/env/test/myejb", right?Can anyone of you help me out?
    You can only use "java:comp/env" JNDI names for EJBs on the same server. For remote EJB's, you use the "real" JNDI name (the same one that a client would use).
  3. When i change the lookup to initial.lookup("ejb/MySLSBRemoteHome"); it will work. But i am supposed to use "java:comp/env/test/myejb", right?Can anyone of you help me out?
    You can only use "java:comp/env" JNDI names for EJBs on the same server. For remote EJB's, you use the "real" JNDI name (the same one that a client would use).
    Then why can't i use the coded name as in jeb-ref-name, test/myejb, instead of the real jndi name? Because in real case, web application developer will not be able to know the exact jndi name of a specific ejb deployed.

    Of course i can alternatively specify this jndi name as servlet init param to avoid hard coding the jndi into the web application.
  4. Then why can't i use the coded name as in ejb-ref-name, test/myejb, instead of the real jndi name?
    You server has no way to correlate an ejb-ref-name to the real JNDI name of a remote EJB. It can only do so for a local EJB. This is because the server uses some configuration data to match ejb-ref-names to JNDI names, and this data is only available within the same server.
    Of course i can alternatively specify this jndi name as servlet init param to avoid hard coding the jndi into the web application.
    I suggest you do something like this, or use some other kind of configuration. Personally, I feel that the whole ejb-ref-name approach is not sophisticated enough to hide to EJB location information from the rest of the program. Try looking at the Service Locator pattern for a more advanced approach.
  5. I suggest you do something like this, or use some other kind of configuration. Personally, I feel that the whole ejb-ref-name approach is not sophisticated enough to hide to EJB location information from the rest of the program. Try looking at the Service Locator pattern for a more advanced approach.
    But anyway we have to pass these properties to the ServiceLocator for initialcontext initialization, so what do you think is the best way to do so in a web application:

    1. servlet init param: retrive in servlet, then pass to BusinessDelegate and subsequently pass to ServiceLocator
    2. env entry: lookup in BusinessDelegate and pass to ServiceLocator
    3. env entry: lookup and use in ServiceLocator

    Or you could suggest alternatives and comment on the pros and cons of each method.

    Really appreciate your effort in answering my questions :)
  6. 1. servlet init param: retrive in servlet, then pass to BusinessDelegate and subsequently pass to ServiceLocator
    2. env entry: lookup in BusinessDelegate and pass to ServiceLocator
    3. env entry: lookup and use in ServiceLocator
    I don't use any of the above. I create my own configuration files (usually custom XML but sometimes properties files) and manage configuration data that way.

    The reason is this: I find that configuration data is often needed in a variety of circumstances, not just in a particular application layer. Any configuration data you put in the web.xml and ejb-jar.xml file is only available in the web layer or the EJB layer, and requires some pretty complex lookup logic.

    On the other hand, if you manage your own configuration, it is pretty easy to use the same config files for all application layers using a classpath-based lookup via Class.getResource() method. That is my preferred approach.

    There is one downside to this approach I should warn you about, though. Most J2EE servers provide some mechanism for remotely administering configuration data in the web.xml or ejb-jar.xml. If you do classpath-based configuration, generally the only way to update configuration files is to upload a new jar with the updated configuration XML file.

    I handle this kind of issue by distinguishing between application data and configuration data. Data that changes rarely if ever (including JNDI and server names) I handle through custom XML files in the jars. Data that may change regularly I treat as application data and store in the database, with some sort of administrative interface.

    I admit I am re-inventing the wheel, here, but classpath-based configuration is not hard, and I find J2EE configuration files too limiting. I only use the J2EE configuration to configure the servlets, filters and EJBs themselves (because I have no choice).

    So ... I would use a ServiceLocator with a method something like this:

    public interface EJBHomeLocator {
      EJBHome locate(Class class);
    }

    You would pass the class of the home interface. The locator would have an XML configuration file that match EJB homes to JNDI names. It would do the lookup, and return the home.

    BTW, I would also include a ContextLocator to separate the InitialContext lookup, for additional isolation:

    public class ContextLocator {
      public static InitialContext locate() ...
    }

    Your flow would go like this:

    Client --> Business Delegate --> Service Locator --> ContextLocator --> Remote Server

    1) The client is isolated from the EJB layer by the Business Delegate.

    2) The Business Delegate is isolated from the JNDI names by the service locator (which can also do home caching).

    3) The Service Locator is isolated from the remote machine address by the ContextLocator, since machine location is only specified by the lookup for the InitialContext. The ContextLocator can also pool InitialContext objects, if necessary.

    4) The delegates and locators are independent of the client environment, so they can be reused for web clients, GUI clients or even for EJB-to-EJB server communication.
  7. Oh, one more thing. Almost all of the above code delegate and locator logic is 100% boilerplate, and can be produced by code generation.
  8. By using custom xml configuration files, we have to the xml parsing right? Why not just use property files?

    BTW, is this the right sequence of operations?

    1. URL url = Class.getResource("configXMLLocationOnTheClasspath");
    2. Inputstream in = url.openStream();
    3. XML parsing on 'in' to get those params


    As for auto code generation, what do you use? What are the common choices? Up to now i type in every byte of my program, though with the help of weblogic workshop.
  9. By using custom xml configuration files, we have to the xml parsing right? Why not just use property files?
    A property file works just fine (and I use them when I am feeling lazy). There is an advantage to XML, though: You can use a DTD/schema to specify the structure of your config file. This is especially helpful if someone else will maintain the configuration.
    BTW, is this the right sequence of operations?

    1. URL url = Class.getResource("configXMLLocationOnTheClasspath");
    2. Inputstream in = url.openStream();
    3. XML parsing on 'in' to get those params
    Hmm. I may have given you bad advice earlier. This is what I normally do:

    1. InputStream is = Class.getResourceAsStream("configLocationOnClasspath");
    2. Load properties/parse XML using the stream.

    I find that this approach works better if your config files are inside JARs (often the case for J2EE applications).
    As for auto code generation, what do you use? What are the common choices? Up to now i type in every byte of my program, though with the help of weblogic workshop.
    I usually put together my own code-generation programs using some sort of simple scripting language as templates. I tend to use Velocity. It helps a lot if you can invoke the script from Java. The Doclet API is a useful way to retrieve data about Java classes, which you can use for further code generation.

    Code generation is not really all that difficult. After all, the only thing that a code generator does is to produce a text file. How hard is it to write a program to produce a text file?

    My rule of thumb is: if a class is (a) boilerplate and (b) you are going to have more than 10 examples of it, then I consider using code generation for that class. Writing the generator will take about a week, and once you have it, creating those classes takes practically no time.

    For Stateless Session Beans, I usually use the EJB class as a baseline. I assume that all public methods that don't begin with "ejb" are the methods for the Remote Interface. I then use Doclet and Velocity to generate the Remote and Home Interfaces, the ejb-jar.xml file, custom config files and the Business Delegate. The Context and Service Locator classes are "generic", so they don't need to be generated.

    You do have to make some assumptions (like "every method has a transaction attribute of Required" and "the JNDI name always matches the home interface name"), but if you have to break those assumptions, it is not too hard to update the generated config files.
  10. Thanks a lot, Paul.

    I really appreciate your way of isolating jndi, context dependences, and more importantly, your enthusiasm in answering my chain of questions. :)