Axis
  1. Axis
  2. AXIS-2146

Different class loading used in attachment type mapping causing NoClassDefFoundError

    Details

    • Type: Bug Bug
    • Status: Open
    • Priority: Major Major
    • Resolution: Unresolved
    • Affects Version/s: 1.2.1
    • Fix Version/s: None
    • Labels:
      None
    • Environment:
      Windows 2000

      Description

      Driver: Axis 1.2.1

      The problem is that when the Eclipse WTP Web services wizard invokes the Java2WSDLAxisAnt task, the
      task itself will construct an AntClassLoader around the classpath that the WS
      wizard passes into the task.

      When creating Web service using Axis 1.2.1 runtime on a Tomcat 4.1 server,
      the classpath contains activation.jar and mail.jar.

      After the AntClassLoader is constructed, Axis will CACHE this classloader in a
      class call ClassUtils. Later on, when the TypeMappingRegistry is initialized,
      the TypeMappingRegistry will determine whether type mapping for attachment is
      needed. The way this is determined is by calling:

      ClassUtils.forName("javax.activiation.DataHandler");

      Of course, when creating a Web service on Axis using Tomcat 4.1,
      this returns true because ClassUtils uses the CACHED AntClassLoader,
      which has activation.jar and mail.jar on its classpath. So the
      TypeMappingRegistry will go ahead and initialize the type mapping for
      attachment. However, in the attachment type mapping's initialization method, it
      does a:

      Class.forName("javax.activiation.DataHandler");

      instead of a:

      ClassUtils.forName("javax.activiation.DataHandler");

      Since Class.forName("...") will go to the Eclipse class loader, which does not
      have activation.jar and mail.jar on its classpath. A NoClassDefFoundError is
      being thrown.

      This problem only starts happening with Axis 1.2.1. The same scenario works in Axis 1.1 and Axis 1.0.

      This problem does not occur when using Tomcat 5.0 since mail.jar and activation.jar is not in the classpath
      passed to Java2WSDLAxisAnt task.

      Here's the exception being thrown:

      — Nested Exception —
      java.lang.NoClassDefFoundError: javax/activation/DataSource
      at java.lang.Class.forName0(Native Method)
      at java.lang.Class.forName(Class.java:141)
      at org.apache.axis.encoding.ser.JAFDataHandlerSerializerFactory.class$(J
      AFDataHandlerSerializerFactory.java:37)
      at org.apache.axis.encoding.ser.JAFDataHandlerSerializerFactory.getSeria
      lizerClass(JAFDataHandlerSerializerFactory.java:46)
      at org.apache.axis.encoding.ser.JAFDataHandlerSerializerFactory.<init>(J
      AFDataHandlerSerializerFactory.java:34)
      at org.apache.axis.encoding.DefaultTypeMappingImpl.initMappings(DefaultT
      ypeMappingImpl.java:120)
      at org.apache.axis.encoding.DefaultTypeMappingImpl.<init>(DefaultTypeMap
      pingImpl.java:91)
      at org.apache.axis.encoding.DefaultTypeMappingImpl.getSingletonDelegate(
      DefaultTypeMappingImpl.java:85)
      at org.apache.axis.encoding.TypeMappingRegistryImpl.<init>(TypeMappingRe
      gistryImpl.java:155)
      at org.apache.axis.encoding.TypeMappingRegistryImpl.<init>(TypeMappingRe
      gistryImpl.java:149)
      at org.apache.axis.wsdl.fromJava.Emitter.<clinit>(Emitter.java:747)
      at org.apache.axis.tools.ant.wsdl.Java2WsdlAntTask.execute(Java2WsdlAntT
      ask.java:172)
      at org.eclipse.jst.ws.internal.axis.consumption.core.command.Java2WSDLCo
      mmand.executeAntTask(Java2WSDLCommand.java:144)
      at org.eclipse.jst.ws.internal.axis.consumption.core.command.Java2WSDLCo
      mmand.execute(Java2WSDLCommand.java:81)
      at org.eclipse.wst.command.internal.env.core.fragment.CommandFragmentEng
      ine.runCommand(CommandFragmentEngine.java:335)
      at org.eclipse.wst.command.internal.env.core.fragment.CommandFragmentEng
      ine.visitTop(CommandFragmentEngine.java:301)
      at org.eclipse.wst.command.internal.env.core.fragment.CommandFragmentEng
      ine.moveForwardToNextStop(CommandFragmentEngine.java:217)
      at org.eclipse.wst.command.internal.env.ui.widgets.SimpleCommandEngineMa
      nager$4.run(SimpleCommandEngineManager.java:208)
      at org.eclipse.jface.operation.ModalContext.runInCurrentThread(ModalCont
      ext.java:346)
      at org.eclipse.jface.operation.ModalContext.run(ModalContext.java:291)
      at org.eclipse.jface.wizard.WizardDialog.run(WizardDialog.java:830)
      at org.eclipse.wst.command.internal.env.ui.widgets.SimpleCommandEngineMa
      nager.runForwardToNextStop(SimpleCommandEngineManager.java:177)
      at org.eclipse.wst.command.internal.env.ui.widgets.WizardPageManager.run
      ForwardToNextStop(WizardPageManager.java:80)
      at org.eclipse.wst.command.internal.env.ui.widgets.WizardPageManager.get
      NextPage(WizardPageManager.java:119)
      at org.eclipse.wst.command.internal.env.ui.widgets.SimpleWizardPage.getN
      extPage(SimpleWizardPage.java:120)
      at org.eclipse.jface.wizard.WizardDialog.nextPressed(WizardDialog.java:7
      47)
      at org.eclipse.jface.wizard.WizardDialog.buttonPressed(WizardDialog.java
      :345)
      at org.eclipse.jface.dialogs.Dialog$2.widgetSelected(Dialog.java:556)
      at org.eclipse.swt.widgets.TypedListener.handleEvent(TypedListener.java:
      90)
      at org.eclipse.swt.widgets.EventTable.sendEvent(EventTable.java:66)
      at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:843)
      at org.eclipse.swt.widgets.Display.runDeferredEvents(Display.java:3080)
      at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:2713)
      at org.eclipse.jface.window.Window.runEventLoop(Window.java:809)
      at org.eclipse.jface.window.Window.open(Window.java:787)
      at org.eclipse.wst.command.internal.env.ui.widgets.popup.DynamicPopupWiz
      ard.run(DynamicPopupWizard.java:129)
      at org.eclipse.ui.internal.PluginAction.runWithEvent(PluginAction.java:2
      46)
      at org.eclipse.jface.action.ActionContributionItem.handleWidgetSelection
      (ActionContributionItem.java:538)
      at org.eclipse.jface.action.ActionContributionItem.access$2(ActionContri
      butionItem.java:488)
      at org.eclipse.jface.action.ActionContributionItem$5.handleEvent(ActionC
      ontributionItem.java:400)
      at org.eclipse.swt.widgets.EventTable.sendEvent(EventTable.java:66)
      at org.eclipse.swt.widgets.Widget.sendEvent(Widget.java:843)
      at org.eclipse.swt.widgets.Display.runDeferredEvents(Display.java:3080)
      at org.eclipse.swt.widgets.Display.readAndDispatch(Display.java:2713)
      at org.eclipse.ui.internal.Workbench.runEventLoop(Workbench.java:1699)
      at org.eclipse.ui.internal.Workbench.runUI(Workbench.java:1663)
      at org.eclipse.ui.internal.Workbench.createAndRunWorkbench(Workbench.jav
      a:367)
      at org.eclipse.ui.PlatformUI.createAndRunWorkbench(PlatformUI.java:143)
      at org.eclipse.ui.internal.ide.IDEApplication.run(IDEApplication.java:10
      3)
      at org.eclipse.core.internal.runtime.PlatformActivator$1.run(PlatformAct
      ivator.java:226)
      at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.ja
      va:376)
      at org.eclipse.core.runtime.adaptor.EclipseStarter.run(EclipseStarter.ja
      va:163)
      at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
      at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.
      java:39)
      at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAcces
      sorImpl.java:25)
      at java.lang.reflect.Method.invoke(Method.java:324)
      at org.eclipse.core.launcher.Main.invokeFramework(Main.java:334)
      at org.eclipse.core.launcher.Main.basicRun(Main.java:278)
      at org.eclipse.core.launcher.Main.run(Main.java:973)
      at org.eclipse.core.launcher.Main.main(Main.java:948)

      We had to workaround the problem by explicitely not passing in mail.jar and activation.jar (even though
      they are in the Tomcat 4.1 runtime library) when calling setClasspath for Java2WSDLAxisAnt task
      so that Axis determines that isAttachmentEnabled is false and thus not do further attachment
      type mapping processing.

      We were trying to see if there's a way to manually set "isAttachmentEnable" to be false but could not found one.
      It would be helpful if an API exist for the user to optionally disable attachment processing rather than having the Axis
      code "detects" it.

      Please let me know If you need any more information isolating the problem.

        Activity

        Hide
        Davanum Srinivas added a comment -

        Kathy,

        Could you please propose a fix (with a patch?)

        thanks,
        dims

        Show
        Davanum Srinivas added a comment - Kathy, Could you please propose a fix (with a patch?) thanks, dims
        Hide
        Kathy Chan added a comment -

        Sorry I don't have the environment set up for devloping and patching Axis code

        The project I'm working in (Eclipse Web Tools Project) is a user of Axis 1.2.1 and we found this inconsistent class loading behaviour while debugging one of our scenario. The main problem here is the Axis code thinks that attachment is enabled (since mail.jar and activation.jar is in the special AntClassLoader we set when calling Java2WSDLAxisAntTask), however, since activation.jar and mail.jar is not in the default classloader, further down in the code (it could be code that Axis is calling such as Log4j or Common-logging) when it's trying to do attachment support, it's trying to do

        Class.forName("javax.activiation.DataHandler");

        which fails with NoClassDefFoundError.

        One alternative that would solve our problem is to be able to set the boolean checkForAttachmentSupport via a setter in Java2WSDLAxisAntTask for us to expicitely disable attachment support, rather than relying on the code in JavaUtils.isAttachmentSupported().

        Here's what in JavaUtils currently:

        private static boolean checkForAttachmentSupport = true;

        public static synchronized boolean isAttachmentSupported() {

        if (checkForAttachmentSupport) {
        //aviod testing and possibly failing everytime.
        checkForAttachmentSupport = false;
        try

        { // Attempt to resolve DataHandler and MimeMultipart and // javax.xml.transform.Source, all necessary for full // attachment support ClassUtils.forName("javax.activation.DataHandler"); ClassUtils.forName("javax.mail.internet.MimeMultipart"); attachmentSupportEnabled = true; }

        catch (Throwable t) {
        }
        log.debug(Messages.getMessage("attachEnabled") + " " +
        attachmentSupportEnabled);
        if(!attachmentSupportEnabled)

        { log.warn(Messages.getMessage("attachDisabled")); }

        }

        return attachmentSupportEnabled;
        } // isAttachmentSupported

        Thanks you for your attention to this problem.

        Show
        Kathy Chan added a comment - Sorry I don't have the environment set up for devloping and patching Axis code The project I'm working in (Eclipse Web Tools Project) is a user of Axis 1.2.1 and we found this inconsistent class loading behaviour while debugging one of our scenario. The main problem here is the Axis code thinks that attachment is enabled (since mail.jar and activation.jar is in the special AntClassLoader we set when calling Java2WSDLAxisAntTask), however, since activation.jar and mail.jar is not in the default classloader, further down in the code (it could be code that Axis is calling such as Log4j or Common-logging) when it's trying to do attachment support, it's trying to do Class.forName("javax.activiation.DataHandler"); which fails with NoClassDefFoundError. One alternative that would solve our problem is to be able to set the boolean checkForAttachmentSupport via a setter in Java2WSDLAxisAntTask for us to expicitely disable attachment support, rather than relying on the code in JavaUtils.isAttachmentSupported(). Here's what in JavaUtils currently: private static boolean checkForAttachmentSupport = true; public static synchronized boolean isAttachmentSupported() { if (checkForAttachmentSupport) { //aviod testing and possibly failing everytime. checkForAttachmentSupport = false; try { // Attempt to resolve DataHandler and MimeMultipart and // javax.xml.transform.Source, all necessary for full // attachment support ClassUtils.forName("javax.activation.DataHandler"); ClassUtils.forName("javax.mail.internet.MimeMultipart"); attachmentSupportEnabled = true; } catch (Throwable t) { } log.debug(Messages.getMessage("attachEnabled") + " " + attachmentSupportEnabled); if(!attachmentSupportEnabled) { log.warn(Messages.getMessage("attachDisabled")); } } return attachmentSupportEnabled; } // isAttachmentSupported Thanks you for your attention to this problem.
        Hide
        Kathy Chan added a comment -

        Please note that this problem only occurs starting with Axis 1.2.1 but was not there in Axis 1.1 and Axis 1.0. Do you have any outlook on which release this problem will be addressed?

        One alternative that would solve our problem is to be able to set the boolean checkForAttachmentSupport via a setter in Java2WSDLAxisAntTask for us to expicitely disable attachment support, rather than relying on the code in JavaUtils.isAttachmentSupported().

        Would that be acceptable for the next release of Axis 1.2.x?

        Show
        Kathy Chan added a comment - Please note that this problem only occurs starting with Axis 1.2.1 but was not there in Axis 1.1 and Axis 1.0. Do you have any outlook on which release this problem will be addressed? One alternative that would solve our problem is to be able to set the boolean checkForAttachmentSupport via a setter in Java2WSDLAxisAntTask for us to expicitely disable attachment support, rather than relying on the code in JavaUtils.isAttachmentSupported(). Would that be acceptable for the next release of Axis 1.2.x?
        Hide
        Kathy Chan added a comment -

        Hi,

        More and more user of the Web Services wizard in WTP 1.0 are running into this problem:

        java.lang.NoClassDefFoundError: javax/activation/DataSource

        when the server (e.g. Geronimo 1.0 sever) they are targetting when creating Web services contains activation.jar in the server's path.

        Do you have any outlook on which release this problem will be addressed?

        Show
        Kathy Chan added a comment - Hi, More and more user of the Web Services wizard in WTP 1.0 are running into this problem: java.lang.NoClassDefFoundError: javax/activation/DataSource when the server (e.g. Geronimo 1.0 sever) they are targetting when creating Web services contains activation.jar in the server's path. Do you have any outlook on which release this problem will be addressed?
        Hide
        Kathy Chan added a comment -

        The problem can be solved by changing JavaUtils.isAttachmentSupported() from:

        ClassUtils.forName("javax.activation.DataHandler");
        ClassUtils.forName("javax.mail.internet.MimeMultipart");

        to:

        Class.forName("javax.activation.DataHandler");
        Class.forName("javax.mail.internet.MimeMultipart");

        Without using the special class loader in ClassUtils to load up DataHandler and MimeMultipart, the same class loader
        that's later on used for processing attachement is used in determining if attachment is supported. This way, we won't run
        the chance of ClassUtils thinking that attachment is supported but the Axis code handling type mapping was not able to load classes required by
        attachment support.

        I've tried patching the Axis 1.2.1 code and the fix works for us. Please consider putting it into the next Axis 1.x release.

        This problem is seriously affecting users of Axis Web services runtime in Eclispe Web Tools Project 1.0.

        Show
        Kathy Chan added a comment - The problem can be solved by changing JavaUtils.isAttachmentSupported() from: ClassUtils.forName("javax.activation.DataHandler"); ClassUtils.forName("javax.mail.internet.MimeMultipart"); to: Class.forName("javax.activation.DataHandler"); Class.forName("javax.mail.internet.MimeMultipart"); Without using the special class loader in ClassUtils to load up DataHandler and MimeMultipart, the same class loader that's later on used for processing attachement is used in determining if attachment is supported. This way, we won't run the chance of ClassUtils thinking that attachment is supported but the Axis code handling type mapping was not able to load classes required by attachment support. I've tried patching the Axis 1.2.1 code and the fix works for us. Please consider putting it into the next Axis 1.x release. This problem is seriously affecting users of Axis Web services runtime in Eclispe Web Tools Project 1.0.
        Hide
        Tom Jordahl added a comment -

        Wouldn't the change be for the attachement code to use the ClassUtils function instead?

        If I recall correctly, ClassUtils solves problems in class loading for various configurations such as App servers and the like.

        Show
        Tom Jordahl added a comment - Wouldn't the change be for the attachement code to use the ClassUtils function instead? If I recall correctly, ClassUtils solves problems in class loading for various configurations such as App servers and the like.
        Hide
        Kathy Chan added a comment -

        The problem can be solved by using the same classloader for both JavaUtils.isAttachmenSupported() and the attachment code. I thought it might be safer to change the JavaUtils.isAttachmentSupported() to not use ClassUtils.forName() rather than switching the attachment code to use ClassUtils (there will also be more places that had to be changed). If the Axis development team goes the route of changing attachment code to use ClassUtils.forName(may be because of "other problems in class loading for various configurations such as App servers and the like"), then you might also have to revisit possibly setting the AntClassLoader in Java2WSDLAntTask from:

        AntClassLoader cl = new AntClassLoader(getClass().getClassLoader(),
        getProject(),
        classpath == null ? createClasspath() : classpath,
        false);

        to:

        AntClassLoader cl = new AntClassLoader(getClass().getClassLoader(),
        getProject(),
        classpath == null ? createClasspath() : classpath,
        true);

        I think switching parentFirst to true might be necessary so that the loading behaviour is not changed too much by what's set through the classpath variable (in case the user is passing in different versions of JARs in the classpath).

        So, depending on what specific problem of not using ClassUtils.forName() will have on JavaUtils.isAttachmentSupport(), I think using the normal classloader in JavaUtils.isAttachmentSupport() would be safer than changing the loader behaviour in the attachment code. Also, it seems to make more sense to determine if attachment is supported by using what Axis could load from the lib directory (i.e. the normal class loader) rather than what the user passes in the classpath variable (the ClassUtils loader).

        Another point to note is this problem started to show up once we moved from Axis 1.1 to 1.2.1. This problem was not there in Axis 1.0 or Axis 1.1. So it might help to dig through the change history to see which piece of the class loader behaviour got changed in Axis 1.2.1 and switch that back as part of this fix.

        Show
        Kathy Chan added a comment - The problem can be solved by using the same classloader for both JavaUtils.isAttachmenSupported() and the attachment code. I thought it might be safer to change the JavaUtils.isAttachmentSupported() to not use ClassUtils.forName() rather than switching the attachment code to use ClassUtils (there will also be more places that had to be changed). If the Axis development team goes the route of changing attachment code to use ClassUtils.forName(may be because of "other problems in class loading for various configurations such as App servers and the like"), then you might also have to revisit possibly setting the AntClassLoader in Java2WSDLAntTask from: AntClassLoader cl = new AntClassLoader(getClass().getClassLoader(), getProject(), classpath == null ? createClasspath() : classpath, false); to: AntClassLoader cl = new AntClassLoader(getClass().getClassLoader(), getProject(), classpath == null ? createClasspath() : classpath, true); I think switching parentFirst to true might be necessary so that the loading behaviour is not changed too much by what's set through the classpath variable (in case the user is passing in different versions of JARs in the classpath). So, depending on what specific problem of not using ClassUtils.forName() will have on JavaUtils.isAttachmentSupport(), I think using the normal classloader in JavaUtils.isAttachmentSupport() would be safer than changing the loader behaviour in the attachment code. Also, it seems to make more sense to determine if attachment is supported by using what Axis could load from the lib directory (i.e. the normal class loader) rather than what the user passes in the classpath variable (the ClassUtils loader). Another point to note is this problem started to show up once we moved from Axis 1.1 to 1.2.1. This problem was not there in Axis 1.0 or Axis 1.1. So it might help to dig through the change history to see which piece of the class loader behaviour got changed in Axis 1.2.1 and switch that back as part of this fix.

          People

          • Assignee:
            Unassigned
            Reporter:
            Kathy Chan
          • Votes:
            4 Vote for this issue
            Watchers:
            3 Start watching this issue

            Dates

            • Created:
              Updated:

              Development