Archived

This forum has been archived. Please start a new discussion on GitHub.

Registering ObjectFactory for exceptions

Hi,

Is it possible to register object factory for exceptions?

I'm using Ice with Java. I registered object factory using Communicator.addObjectFactory(myFactory, "") and every time object is read from stream the factory is used to instantiate correct Ice.Object. Unfortunately this does not happen with exceptions.

The reason I would like to be able to register custom object factory is that I need to load classes instantiated by Ice using my own classloader. So my object factory loads classes using Class.forName(className, true, myClassLoader) and it works for parameters and return types. However BasicStream does not use object factory to load exceptions and tries to load them using Class.forName(className) with default classloader what results in ClassNotFoundException. (You can compare BasicStream.throwException() and BasicStream.readObject() methods). Is it possible to accomplish this in another way?

Thanks

Comments

  • There is no public API that would allow you to add a user exception factory. We never saw a need for this because all Slice exceptions are concrete types that can be instantiated without the need to call into application code (as is necessary for abstract classes).

    I don't see any other way to do this, short of changing the code in BasicStream.findClass().

    Cheers,

    Michi.
  • Michi,

    I have run across the same requirement. Has this been addresses in Ice 3.3.1? If not, if I modify BasicStream, can those changes be incorporated into subsequent builds? I am concerned that, once I make the modification, future updates of the Ice rpms will have to be ignored and all future installs will need to be made from source.

    Thanks,
    Steve
  • Hi Steve, could you outline your use case for this? I'm not averse to adding the feature, but I would like to understand the motivation for it.

    Thanks,

    Michi.
  • Michi,

    Our system has a tabbed pane. The individual tabs are contained in jar files that are specified at runtime via a config file. I have a tab that accesses an Ice Application acting as a database. In order for the exceptions to be accessed, I need to specify a ClassLoader for Ice.

    If you need more explanation, please let me know.

    Steve
  • Just to make sure I understand correctly... Suppose you have a Slice exception:
    exception E {
        // ...
    };
    
    When the client invokes an operation and gets the exception, what you want instantiated in the client is the actual generated exception E, not some exception that is derived from E?

    If so, can't you just put the generated code into a jar and load that jar in your client?

    The reason Ice has user-definable class factories is that, for a class with operations, the unmarshaling code must instantiate a type that is provided by the application; that type is derived from the generated class and isn't known at compile time. But Slice exceptions don't have operations, so the type is always known. Unless the application requires an exception to be instantiated that derives from the generated exception, I don't see the need for user exception factories.

    Cheers,

    Michi.
  • Michi,

    The problem I'm running across is in file IceInternal/BasicStream.java, method getConcreteClass. The current implementation is calling Class.forName, which doesn't work when the generated Ice exception's class is loaded from a jar file in my system. I've made a modification to supply a custom ClassLoader to the BasicStream class that is capable of loading classes from a jar file.

    I have a custom ClassLoader that, given a jar file, will load all of the class files contained in the jar file. If I use that ClassLoader (which has knowledge of the generated exception) as an argument to Class.forName, everything is okay.

    Steve
  • So the requirement here is not so much the ability to register a factory for user exceptions, but to have BasicStream use a custom class loader?

    Cheers,

    Michi.
  • That is correct. I was thinking more in terms of the beginning of the thread and the way that Objects are loaded.
  • mes
    mes California
    If we added the ability to supply a custom class loader for each communicator instance, would that work in your situation?

    Regards,
    Mark
  • I think it would. As long as BasicStream uses the class loader when loading exceptions my system will function.
  • Since this is ultimately a Java deployment issue, setting the classloader may still be necessary, but I was wondering if a generalized ExceptionHandler at the communucator-/proxy-level has ever been considered. Similar to the ObjectFactory/ExceptionFactory idea, but rather than solving instantiation it would solve mapping. Cheers, ~J.
  • mes
    mes California
    Hi Josh,

    I'm not sure I follow you. Can you be more specific?

    Thanks,
    Mark
  • None of OMERO's API consumers (I know of) allow the Ice-based exceptions to propagate up the stack. Inevitably there's code of the form:
    try {
       ...
    } catch (Exception e) {
       if (e instanceof UnknownLocalException) {
          ...
       } else if (...) {
       } else {
          bail();
       }
    }
    
    in everyone's client.

    With the context information that Ice has, this might could be made more efficient (though it may also be more trouble than it's worth):
    class ExceptionHandler extends Ice.ExceptionHandler {
    
        // similar to an AMI callback
        public void handle(Ice.ObjectPrx prx, string method, Exception e, Map<String, String> context) {
            // Here based on the proxy and the method do something sensible.
        }
    
    }
    
    initializationData.exceptionHandler = new ExceptionHandler();