7 Replies Latest reply on Feb 21, 2013 1:55 PM by wdfink

    ModuleClassLoader (JBoss AS7), interfaces and Remote EJB

    grubi

      Hi everybody,

       

      I tries to implement a maintenance notification system for our web applications based on EJB.

       

      We have a web framwork, which knows all maintenances for all applications we have. The application itself asks the framwork periodically for new maintenaces via an EJB call. The information about a maintenance is hold by the class MaintenanceInfo which implements IMaintenanceInfo. The interface is shared between the framework and the application but the implementation is only known by the framework.

       

      When the application ask for an update, it calls

      public interface IRemoteWebframeworkEJB {

          public List<IMaintenanceInfo> getMaintenances(int applicationId);

      }

      The call itself succeeds but as soon as I iterate over the list, I get a ClassCastException. After some time I was able to  get the Eclipse Debugger to give me the required information about what is going on. The framework sends instances of MaintenanceInfo and that class is loaded using the framework's ModuleClassLoader. The application receives those instances and tries to cast them to IMaintenanceInfo loaded by the application's ModuleClassLoader.

       

      Simple Question: Why does the EJB call does not work as desired? The EJB itself, which is based on an @Remote interface does not suffer from such a ClassCastException. Is there no possibility to implement such object transfer based on interfaces? Do I always need the concret implementation on both sides of the call?

       

      Thanks in advance.

        • 1. Re: ModuleClassLoader (JBoss AS7), interfaces and Remote EJB
          wdfink

          Often this is a issue where a class is passed by reference and not by value to a different application.

          Could you provide a bit more information about packaging and your lookup and EJB access code?

          • 2. Re: ModuleClassLoader (JBoss AS7), interfaces and Remote EJB
            grubi

            I will try it

             

            As I wrote in the first post, we have a WebFramework and many Applications, which get common information from the WebFramework (like users, auth, business data, ...). They are all packaged in a WAR and share a common library, where we provide interfaces and tools for EJB, CDI, JSF, ... .

             

             

            When the application server starts we first deploy the WebFramework and then all applications. Each application has a @Singleton @Stateless @Startup Bean which will, in this case, ask for the maintenance information from the WebFramework.

             

            Required classes / interfaces from the common library:

            IRemoteMaintenanceEJB (@Remote): This EJB is implemented in each application it either receives the information sent from the framework (hence the @Remote) or it ask itself for information. This is the mentioned @Singleton, ... Bean (when implemented).

            @Remote

            public interface IRemoteMaintenanceEJB {

                 public void maintenanceUpdate(List<IMaintenanceInfo> maintenances);

            }

             

            IRemoteWebFrameworkEJB (@Remote): Thie EJB is implemented in the WebFramework and provides access to all maintenances of an application.

            @Remote

            public interface IRemoteWebFrameworkEJB {

                 public List<IMaintenanceInfo> getMaintenances(int applicationId);

            }

             

            IMaintenanceInfo: The interfaces for the transferred maintenances (one instance per maintenance). It extends Serializable to enforce it.

            public interface IMaintenanceInfo extends Serializable {

                 // some getters for int, Date, String and a boolean

            }

             

            Required classes in the WebFramework:

            WebFrameworkEJBImpl (@Stateless): Thie is the implementation of IRemoteWebFrameworkEJB and simple fetches all maintenances from a database, instanciates a MaintenanceInfoImpl for each result and returns it as a java list (List<IMaintenanceInfo>).

            @Stateless

            public class WebFrameworkEJB implements IRemoteWebFrameworkEJB {

                 @Override

                 public List<IMaintenanceInfo> getMaintenances(int applicationID) {

                      // some black magic

                 }

            }

             

            MaintenanceInfoImpl: This is the implementation of IMaintenanceInfo which should be transferred from the WebFramework to the application.

            public class MaintenanceInfo implements IMaintenanceInfo {

                 private static final long serialVersionUID = ...;

             

                 // member variables and getters/setters for the int, Date, String and boolean

                 // overwrites equals and toString

            }

             

            Finally the required classes in the Application:

            MaintenanceEJBImpl: This is the implementation of IRemoteMaintenanceEJB.

            @Singleton

            @Startup

            @LocalBean

            @Named

            public class MaintenanceEJB implements IRemoteMaintenanceEJB {

                 @PostConstruct

                 public void initialize() {

                      // ask for maintenances on startup - see below

                 }

             

                

                @Override

                public void maintenanceUpdate(List<IMaintenanceInfo> maintenanceInfo) {

                      // Iterate over the list, perform some calculations on existing maintenances in this EJB and finally sort the list

                      // see below

                 }

            }

             

             

            As soon as the MaintenanceEJBImpl is instantiated it will execute the following code in @PostConstruct (without error handling)

            Context ctx = new InitialContext();

            IRemoteWebFrameworkEJB remoteEjb = (IRemoteWebFrameworkEJB) ctx.lookup(String.format("java:global/%s/%s!%s", appName, className, interfaceName));

            // appName = "WebFramework", className = "WebFrameworkEJBImpl", interfaceName = "package.IRemoteWebFrameworkEJB"

             

            maintenanceUpdate(remoteEjb.getMaintenances(applicationId));

             

            The ClassCastException occurres as soon as I iterate over this list (in maintenanceUpdate)

            for (IMaintenanceInfo maintenance : maintenanceInfo) { // class cast exception

                 // do something

            }

             

            When the WebFramework calls the maintenanceUpdate() via the remote instance (same lookup as above) of the IRemoteMaintenanceEJB it will result in the mentioned ClassNotFoundException.

            • 3. Re: ModuleClassLoader (JBoss AS7), interfaces and Remote EJB
              grubi

              Any ideas?

              • 4. Re: ModuleClassLoader (JBoss AS7), interfaces and Remote EJB
                grubi

                Still looking for a solution.

                 

                No EJB guru around?

                Or any other idea where I could ask for help?

                • 5. Re: ModuleClassLoader (JBoss AS7), interfaces and Remote EJB
                  wdfink

                  From what I understand you have different applications which all use the IMaintenanceInfo interface.

                  I suppose that you pack the Interface or the Imple into each application, right?

                  In this case it is not possible to work with 'call by reference' b/c the classloader's are different and you have such CCEx.

                  You may extract the common classes into a module and set a dependency, or you have to use remoteIF with call-by-value which might be a performance drawback (but is full spec compliant).

                  1 of 1 people found this helpful
                  • 6. Re: ModuleClassLoader (JBoss AS7), interfaces and Remote EJB
                    grubi

                    Thanks, that answer made it clear!

                     

                    The common classes are packed in each application through the common library in WEB-INF/lib.

                     

                    With "remoteIF " you mean "remote interface"?

                    I thought that I already use the remote interface of my EJBs b/c of the way I lookup the instance. If I'm wrong, what do I have to do to really use the remoteIF?

                     

                    call-by-value will be automatically used as soon as it is the remote interface?

                    • 7. Re: ModuleClassLoader (JBoss AS7), interfaces and Remote EJB
                      wdfink

                      Yes remoteIF mean remote interface.

                       

                      It depends on the lookup what type you get back.

                      I'm not 100% sure, but I suppose default is by-reference.

                       

                      Add the element to the ejb3 subsystem

                        <in-vm-remote-interface-invocationType pass-by-value="true"/>

                       

                      You might toggle true/false to see whether it has effect.