Issue Details (XML | Word | Printable)

Key: AXIS-2146
Type: Bug Bug
Status: Open Open
Priority: Major Major
Assignee: Unassigned
Reporter: Kathy Chan
Votes: 4
Watchers: 3
Operations

If you were logged in you would be able to see more operations.
Axis

Different class loading used in attachment type mapping causing NoClassDefFoundError

Created: 28/Jul/05 08:54 AM   Updated: 27/Jan/06 01:49 AM
Return to search
Component/s: Serialization/Deserialization
Affects Version/s: 1.2.1
Fix Version/s: None

Time Tracking:
Not Specified

Environment: Windows 2000


 Description  « Hide
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.

 All   Comments   Work Log   Change History   Subversion Commits      Sort Order: Ascending order - Click to sort in descending order
Davanum Srinivas added a comment - 01/Aug/05 12:07 PM
Kathy,

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

thanks,
dims

Kathy Chan added a comment - 18/Aug/05 12:58 AM
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.

Kathy Chan added a comment - 11/Nov/05 07:05 AM
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?

Kathy Chan added a comment - 24/Jan/06 01:56 AM
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?


Kathy Chan added a comment - 26/Jan/06 08:15 AM
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.

Tom Jordahl added a comment - 27/Jan/06 12:34 AM
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.

Kathy Chan added a comment - 27/Jan/06 01:49 AM
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.