CMIS

About 6 moths ago I was complaining about CMIS that it considers all requests which contain the same credentials (i.e. login and password are the same for all requests) as requests from the same client, and for all requests containing the same credentials CMIS uses the only one repository session, unfortunately we didn’t implement solution proposed in that blogpost – it is hard to maintain different passwords across clients, meanwhile we have started receiving concurrency-related errors, so, it was required to undertake something and I have found a solution – it is enough to replace just two classes in CMIS:

CMIS vs Weblogic

Two days ago my colleague faced with a next challenge: in Weblogic environment CMIS deployment fails with the following stacktrace:

weblogic.application.ModuleException: 
        at weblogic.servlet.internal.WebAppModule.startContexts(WebAppModule.java:1520)
        at weblogic.servlet.internal.WebAppModule.start(WebAppModule.java:484)
        at weblogic.application.internal.flow.ModuleStateDriver$3.next(ModuleStateDriver.java:425)
        at weblogic.application.utils.StateMachineDriver.nextState(StateMachineDriver.java:52)
        at weblogic.application.internal.flow.ModuleStateDriver.start(ModuleStateDriver.java:119)
        Truncated. see log file for complete stacktrace
Caused By: java.lang.IllegalArgumentException: com.sun.xml.internal.messaging.saaj.soap.LocalStrings != com.sun.xml.messaging.saaj.soap.LocalStrings
        at java.util.logging.Logger.getLogger(Logger.java:369)
        at com.sun.xml.messaging.saaj.soap.SAAJMetaFactoryImpl.<clinit>(SAAJMetaFactoryImpl.java:52)
        at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
        at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
        at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
        Truncated. see log file for complete stacktrace

The root cause of this error is following:

there are to classes which extend javax.xml.soap.SAAJMetaFactory:

  1. com.sun.xml.internal.messaging.saaj.soap.SAAJMetaFactoryImpl – part of rt.jar since Java6
  2. com.sun.xml.messaging.saaj.soap.SAAJMetaFactoryImpl – part of saaj-impl.jar which is shipped with emc-cmis-wls.ear/emc-cmis-weblogic.ear

both classes do following:

  protected static final Logger log = 
     Logger.getLogger("javax.xml.messaging.saaj.soap", 
      "com.sun.xml.internal.messaging.saaj.soap.LocalStrings");

and

  protected static final Logger log = 
     Logger.getLogger("javax.xml.messaging.saaj.soap", 
      "com.sun.xml.messaging.saaj.soap.LocalStrings");

java.util.logging.Logger prevents creating two loggers with the same name but different resource bundles:

    @CallerSensitive
    public static Logger getLogger(String name, String resourceBundleName) {
        Class<?> callerClass = Reflection.getCallerClass();
        Logger result = demandLogger(name, resourceBundleName, callerClass);

        if (result.resourceBundleName == null) {
            // We haven't set a bundle name yet on the Logger, so it's ok to proceed.

            // We have to set the callers ClassLoader here in case demandLogger
            // above found a previously created Logger.  This can happen, for
            // example, if Logger.getLogger(name) is called and subsequently
            // Logger.getLogger(name, resourceBundleName) is called.  In this case
            // we won't necessarily have the correct classloader saved away, so
            // we need to set it here, too.

            // Note: we may get a MissingResourceException here.
            result.setupResourceInfo(resourceBundleName, callerClass);
        } else if (!result.resourceBundleName.equals(resourceBundleName)) {
            // We already had a bundle name on the Logger and we're trying
            // to change it here which is not allowed.
            throw new IllegalArgumentException(result.resourceBundleName +
                                " != " + resourceBundleName);
        }
        return result;
    }

So, if Weblogic loads something SOAP-related (for example, by default weblogic loads wls-wsat application), instance of java.util.logging.Logger gets poisoned by com.sun.xml.internal.messaging.saaj.soap.SAAJMetaFactoryImpl class and you are unable to use different implementation of javax.xml.soap.SAAJMetaFactory.

The solution is to add -Dweblogic.wsee.wstx.wsat.deployed=false to weblogic’s startup parameters