JBoss Community

Re: IIOP Subsystem Issues

created by David Lloyd in JBoss AS7 Development - View the full discussion

I'll answer the issues inline.

 

Stefan Guilhen wrote:

 

Issue 1 - JacORB configuration file

 

When bootstraping the ORB, jacorb.properties must be loaded by the ORB service. My initial approach was to place the jacorb.properties file under standalone/configuration (along with the logging.properties file), inject the jboss.server.config.dir into the ORB service and then read the configuration file as a regular file. Although this approach works in standalone mode, it fails in the domain mode because jboss.server.config.dir points to the configuration dir of each server and not to domain/configuration. As a result, the file can't be loaded and the ORB doesn't start as it should.

 

In a nutshell, this initial approach doesn't look like the right thing to do. What would be the right way for reading jacorb.properties? If the file was immutable I could probably place it in the META-INF dir of the IIOP module and load it via class loader. However, jacorb.properties must be available for easy editing - users might, for example, enable SSL socket factories for IIOP by setting the appropriate option in jacorb.properties. So where should this file be placed and how do we load it?

The file should not really be anywhere.  We need a better way to configure the ORB - either by hooking into its configuration mechanism or in the worst case feeding it a programmatically generated properties file.  It is very important that all of these config items be configurable via the central configuration mechanism.

 

 

Stefan Guilhen wrote:

 

Issue 2 - ORB related classes are instantiated via context classloader

 

The ORB is created by calling the static ORB.init(String[], Hashtable) method. This method attempts to instantiate the ORB class and all its initializers by using the Thread context classloader. As a result, if we don't set the context classloader before calling init we get CNFEs. So here's what I did to get around it:

 

       ClassLoader loader = SecurityActions.getThreadContextClassLoader();
       try {           SecurityActions.setThreadContextClassLoader(SecurityActions.getClassLoader(this.getClass()));
           this.orb = ORB.init(new String[0], properties);
       } finally {           // restore the thread context classloader.           SecurityActions.setThreadContextClassLoader(loader);
       }

 

I temporarily set the thread context classloader to use the same classloader of the IIOP subsystem module. This way all classes are successfully loaded and the ORB is initialized without errors. Does this look ok or do do you have any other suggestions for doing this?

 

That's the right way to work around this type of problem.  I think ultimately though we want to fix these issues in the upstream projects, pushing those fixes upstream if possible.  The rule is, if the project is loading its own implementation classes they should usally be loaded directly using its own class loader by default.  It also usually makes sense to have a variant which accepts a class loader argument as well.

 

 

Stefan Guilhen wrote:

 

Issue 3 - The ORB must run in a dedicated thread

 

The ORB.run() method must be placed in a dedicated thread as this call blocks the current thread for the lifetime of the ORB. This means the service thread that is starting the ORB service would block until the ORB receives a shutdown message. What I'm currently doing is creating a new Thread and setting a runnable that runs the ORB but this is clearly not the right way to do this . I imagine the server has some control over its threads and a service shouldn't be creating new threads like this. Is there a thread service I can call to create a thread that is managed by the server?

 

If a service requires a dedicated thread, then creating a thread is exactly the right thing to do.  To do this from MSC properly though, you should:

  1. Make sure you have a proper thread name which is descriptive.
  2. Your start method should return when it is clear that the service started successfully. When you start up a thread this gets tricky though because the thread could start up and then a failure could become known only from within the thread! Since blocking in start() is a huge no-no, you cannot use conditions or latches or anything like that to verify your thread start. Instead you will probably have to use the asynchronous start mechanism. I'd recommend that you call context.asynchronous() early in the start method, call context.complete() or context.failed() from the thread once you know everything is OK (or not), and judiciously employ try/finally in start() to ensure that either the thread starts successfully or context.failed() is called.
  3. Your stop method, like start(), cannot block.  This means that it must do the following:
    1. Upon entry, call context.asynchronous().
    2. Signal the thread that it must terminate, passing the context to it in a deterministic fashion.
    3. The thread must call context.complete() when the ORB is known to be stopped (see the thread pool services for an example of this behavior).
  4. Make sure that there is no code path that would allow start() or stop() to be called without complete() or failed(), else the container may hang.

 

 

It does raise a question about thread services - if we end up needing more than one of these, we may want to explore a generalized ThreadService base class which creates and manages a thread, or something like that.  But for now let's just do it the simple way.

 

 

Stefan Guilhen wrote:

 

Issue 4 - JacORB has linkage problems with JDK classes

 

If you inspect the code, you will notice that the CORBA naming service is not being installed (see the commented out code in IIOPSubsystemAdd). That's because calling methods on the running ORB results in a VerifyError:

 

16:42:40,285 ERROR [org.jboss.msc.service.fail] (MSC service thread 1-15) MSC00001: Failed to start service jboss.iiop.naming-service: org.jboss.msc.service.StartException in service jboss.iiop.naming-service: Failed to start service
    at org.jboss.msc.service.ServiceControllerImpl$StartTask.run(ServiceControllerImpl.java:1696)
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886) [:1.6.0_24]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908) [:1.6.0_24]
    at java.lang.Thread.run(Thread.java:662) [:1.6.0_24]
Caused by: java.lang.VerifyError: (class: org/jacorb/orb/Delegate, method: getReference signature: (Lorg/jacorb/poa/POA;)Lorg/omg/CORBA/portable/ObjectImpl;) Incompatible object argument for function call
    at org.jacorb.orb.ORB.getReference(Unknown Source)
    at org.jacorb.poa.POA.getReference(Unknown Source)
    at org.jacorb.poa.POA.create_reference_with_id(Unknown Source)
    at org.jboss.as.iiop.service.CorbaNamingService.start(CorbaNamingService.java:77)
    at org.jboss.msc.service.ServiceControllerImpl$StartTask.run(ServiceControllerImpl.java:1675)
    ... 3 more

 

Setting the -noverify option in standalone.conf shows the following:

 

16:44:48,280 ERROR [org.jboss.msc.service.fail] (MSC service thread 1-14) MSC00001: Failed to start service jboss.iiop.naming-service: org.jboss.msc.service.StartException in service jboss.iiop.naming-service: Failed to start service
    at org.jboss.msc.service.ServiceControllerImpl$StartTask.run(ServiceControllerImpl.java:1696)
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:886) [:1.6.0_24]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:908) [:1.6.0_24]
    at java.lang.Thread.run(Thread.java:662) [:1.6.0_24]
Caused by: java.lang.AbstractMethodError: org.omg.CORBA.portable.ObjectImpl._set_delegate(Lorg/omg/CORBA/portable/Delegate;)V
    at org.jacorb.orb.Delegate.getReference(Unknown Source)
    at org.jacorb.orb.ORB.getReference(Unknown Source)
    at org.jacorb.poa.POA.getReference(Unknown Source)
    at org.jacorb.poa.POA.create_reference_with_id(Unknown Source)
    at org.jboss.as.iiop.service.CorbaNamingService.start(CorbaNamingService.java:77)
    at org.jboss.msc.service.ServiceControllerImpl$StartTask.run(ServiceControllerImpl.java:1675)
    ... 3 more

 

The JacORB and JDK classes are being mixed up even though I've removed the org/omg API from the javax.api module and introduced an org.omg.api module with JacORB's API. After messing around for a while I found out that some JacORB classes were causing the module loader to ask the bootstrap class loader to load the org.omg classes instead of loading the version of these classes from jacorb.jar.

 

After trying to add jacorb to the JRE endorsed dir with no results, I tried regenerating the JacORB jar in a way that it used its own org.omg classes as it seemed to me that JacORB's classes had references to the JDK classes. Setting the Xbootclasspath or the endorsed dirs when compiling JacORB didn't make any difference, so I went a bit extreme and removed the org.omg classes from the rt.jar - that forced JacORB to use its own version of the org.omg classes and the resulting jar fixes the VerifyError.

 

The CORBA naming service can be tested by uncommenting the line that prevents the service from being installed in IIOPSubsystemAdd and replacing the jar in the jacorb module for the jar I'm attaching here.

 

As I'm not a classloading expert I would like other's opinions on this issue.

 

First I would verify that the "system" module is not among the list of imports for the jacorb module or any of its transitives; this is the simplest possible explanation for the problem you see.  Using endorsed is definitely not something we want to do.  I'm pretty sure though that the problem you're seeing is due to using the "system" module.  Removing org.omg and its children from javax.api and adding an new org.omg.api module is definitely the right thing to do.

Reply to this message by going to Community

Start a new discussion in JBoss AS7 Development at Community