Issue Details (XML | Word | Printable)

Key: GLASSFISH-9165
Type: Improvement Improvement
Status: Open Open
Priority: Major Major
Assignee: Sanjeeb Sahoo
Reporter: Alexis MP
Votes: 0
Watchers: 3
Operations

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

Application bundling Jersey 1.0 is forced to use GF's copy of Jersey

Created: 18/Aug/09 11:14 PM   Updated: 07/Jan/13 07:24 PM
Component/s: classloader
Affects Version/s: V3
Fix Version/s: not determined

Time Tracking:
Not Specified

File Attachments: 1. Text File artifactory-delegate-false.txt (20 kB) 19/Aug/09 02:57 PM - Alexis MP
2. Text File artifactory-delegate-true.txt (16 kB) 19/Aug/09 02:57 PM - Alexis MP
3. Zip Archive mavenproject5.zip (6 kB) 03/Sep/09 05:41 AM - sandoz

Environment:

Operating System: All
Platform: All


Issuezilla Id: 9,165
Tags:
Participants: Alexis MP, dochez, Jakub Podlesak, sandoz, Sanjeeb Sahoo and Tom Mueller


 Description  « Hide

Dropping the artifactory.war [1] in v3's autodeploy directory triggers the following scan error documented at http://forums.java.net/jive/thread.jspa?
messageID=360993.

This is a case of an application being forced to use Jersey 1.1 bundled in GlassFish v3 instead of the 1.0 library that it ships with.
Even with class loader delegation set to false Jersey 1.0 will look in META-INF/services of jersey installed in GF.

Of course it would be nice to have Jersey 1.0 apps run unmodified on 1.1 but only strict adherence to the JAX-RS specification offers compatibility
between 1.0 and 1.1 releases.

Removing jersey from the GFv3 distro sounds like a bad solution (glassfish-management depends on it).

An application should be able to ship and use its own set of libraries with some sort of "ignore system/GlassFish libraries" isolation at deploy time.

[1]: http://downloads.sourceforge.net/project/artifactory/artifactory/2.0/artifactory-2.0.7.war



Alexis MP added a comment - 18/Aug/09 11:16 PM

adding Sahoo to CC list


Sanjeeb Sahoo added a comment - 19/Aug/09 02:54 AM

Alexis,

It is kind of strange that jersey 1.1 is not compatible with 1.0. Anyway, that's
a separate issue altogether. But, it is a bit too much to expect that a
traditional Java EE application can override a server implementation module by
just including it in itself. Given all the spec requirements and implementation
challenge, it is quite impossible to support this.

On the other hand, these are the kind of things I expect an OSGi enabled
application [1] to be able to solve. Skip the step of downloading an extra jar
and copying it to autodeploy-bundles directory, as osgi-web-container.jar is now
part of modules/. So, I gave try like this:
$ start GlassFish
$ telnet localhost 6666
-> install webbundle:file:///tmp/artifactory-2.0.7.war
-> start 205 (where 205 is the bundle id reported by install command)

I am seeing an exception like this:
Caused by: org.springframework.beans.factory.BeanCreationException: Error
creating bean with name
'org.springframework.transaction.interceptor.TransactionAttributeSourceAdvisor#0'
defined in class path resource [META-INF/spring/applicationContext.xml]: Cannot
resolve reference to bean 'txInterceptor' while setting bean property
'transactionInterceptor'; nested exception is
org.springframework.beans.factory.BeanCreationException: Error creating bean
with name 'txInterceptor' defined in class path resource
[META-INF/spring/applicationContext.xml]: Cannot resolve reference to bean
'transactionManager' while setting bean property 'transactionManager'; nested
exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No
bean named 'transactionManager' is defined

I don't know enough about Spring to debug further. When does this error occur?
Can the submitter try it out and explain what's going wrong.

May be we need a simpler test case that just bundles jersey-1.0 jar and first
see if it can be handled or not.

Sahoo

[1] http://weblogs.java.net/blog/ss141213/archive/2009/06/osgi_enabled_we.html


sandoz added a comment - 19/Aug/09 03:10 AM

Jersey's implementation of JAX-RS 1.1 is backwards compatible with 1.0. So if
you just depend on JAX-RS 1.0 features the same app should work with JAX-RS 1.1
(a long as you do not have both 1.0 and 1.1 JAX-RS implementations in the class
path!). I do agree that the version naming is confusing because we currently
include the JAX-RS version as the major/minor Jersey version.

I suspect the Spring-related error is due to class loading restrictions.

I agree with you about OSGi. Note that we do plan to make jersey fully
OSGi-enabled, i am not sure if that will help or not in this case.

A simpler test case would be most useful to verify it is works, we could use the
following sample:

http://download.java.net/maven/2/com/sun/jersey/samples/helloworld-webapp/1.0.3.1/helloworld-webapp-1.0.3.1-project.zip

when built there will be a war with the Jersey 1.0.3.1 jars present in WEB-INF/lib.


Sanjeeb Sahoo added a comment - 19/Aug/09 04:29 AM

sandoz:
If jersey 1.1 is both a jersey 1.0 and 1.1 implementation, then why does things
not work if you just deploy a web app even if it bundles jersey-1.0.jar inside
it. After all, jersey-1.1.jar, which is provided by the server, should shadow
the bundled version and there is no need to even switch of classloader
delegation. I guess, I am missing something. What it is.

alexismp:
Do you know anything about the Spring framework error that I observed?

sandoz:
I tried using the simple test case you pointed to. I got the following error:
java.lang.NoSuchMethodError:
com.sun.jersey.server.impl.container.servlet.JSPTemplateProcessor.<init>(Lcom/sun/jersey/api/core/ResourceConfig;Ljava/lang/ThreadLocal;Ljava/lang/ThreadLocal;)V
at
com.sun.jersey.spi.container.servlet.WebComponent.configure(WebComponent.java:414)
at
com.sun.jersey.spi.container.servlet.ServletContainer$InternalWebComponent.configure(ServletContainer.java:235)
at
com.sun.jersey.spi.container.servlet.WebComponent.load(WebComponent.java:448)
at
com.sun.jersey.spi.container.servlet.WebComponent.init(WebComponent.java:169)
at
com.sun.jersey.spi.container.servlet.ServletContainer.init(ServletContainer.java:281)
at
com.sun.jersey.spi.container.servlet.ServletContainer.init(ServletContainer.java:442)
at javax.servlet.GenericServlet.init(GenericServlet.java:242)
...

What does this mean? I don't have the time to debug it, so I am asking you. May
be you know if this bundle is seeing some class incorrectly. May be we need to
adjust the OSGi metadata of the bundle as opposed to relying on the metadata
generated by the server. So, try adding OSGi metadata to the war file depending
on what this bundle imports/exports and see how it goes.

Sahoo


Alexis MP added a comment - 19/Aug/09 05:04 AM

Sorry, my Spring knowledge is too limited. Class-loader visibility seems like the most likely cause.
Maybe repackaging the application to use Spring DM (the OSGi version of the Spring framework) would
help but that's beyond what would be a reasonable solution to the problem.


sandoz added a comment - 19/Aug/09 05:10 AM

Jersey 1.1.x supports JAX-RS 1.0 and 1.1. Jersey currently does guarantee to
support two different versions of Jersey in the same VM unless they are fully
isolated by some external mechanism.

The main problem is that Jersey loads components declared in META-INF/service
files. Those files will be present in multiple jersey jars/modules of the same
version.

When two versions of Jersey, 1.0 and 1.1.0 say, are present, the version of
Jersey that gets initiated, say 1.0, will also attempt to load components
declared by 1.1.0 jars because of the way Classloader.getResources works.

Re the Spring exception: can you attach the full exception log, if any more, to
know what caused the NoSuchBeanDefinitionException.

Re the NoSuchMethodError: the error indicates that the JSPTemplateProcessor
class is being loaded from the Jersey version distributed with GF and not Jersey
version distributed in the war.

The relevant code in 1.0.3.1 is:

rc.getSingletons().add(new JSPTemplateProcessor(
resourceConfig,
requestInvoker.getThreadLocal(),
responseInvoker.getThreadLocal()));

public class JSPTemplateProcessor implements TemplateProcessor {
@Context HttpContext hc;

@Context ServletContext servletContext;

@Context UriInfo ui;

private final ThreadLocal<HttpServletRequest> requestInvoker;

private final ThreadLocal<HttpServletResponse> responseInvoker;

private final String basePath;

public JSPTemplateProcessor(
ResourceConfig resourceConfig,
ThreadLocal<HttpServletRequest> requestInvoker,
ThreadLocal<HttpServletResponse> responseInvoker) {

The JSPTemplateProcessor in Jersey 1.1.x is:

public class JSPTemplateProcessor implements TemplateProcessor {
private @Context HttpContext hc;

private @Context ServletContext servletContext;

private @Context ThreadLocal<HttpServletRequest> requestInvoker;

private @Context ThreadLocal<HttpServletResponse> responseInvoker;

private final String basePath;

public JSPTemplateProcessor(
@Context ResourceConfig resourceConfig) {

Note that the sample i pointed you to is not an OSGi-based sample, it will just
create a vanilla war file with jersey 1.0.3.1 jars included in the WEB-INF/lib.

My OSGi knowledge is very limited and Jakub (our resident Jersey expert is on
holiday this week) so i really do not know where to start.


Sanjeeb Sahoo added a comment - 19/Aug/09 05:52 AM

sandoz:
In the case of traditional war, jersey-1.1 is higher up in the classloader
hierarchy, so why does jersey-1.0 get initiated in the first place?

Yes, later on when I looked at jersey-gf-bundle.jar, I realized that
JSPTemplateProcessor was getting picked up from jersey-1.1 implementation. That
leads me to think this class is exported by jersey-gf-bundle. Why? Is it not an
implementation artifact?

I think we should wait for Jakub to be back and then may be he needs to look at
two things:
1. OSGi metadata of Jersey bundle.
2. OSGi metadata of the test bundle to be able to use a bundled jersey
implementation.

Sahoo


sandoz added a comment - 19/Aug/09 06:55 AM

The example i presented would apply for <class-loader delegate="false"/>.

However, the problem would still occur for <class-loader delegate="true"/> would
it not when the following applies?

When two versions of Jersey, 1.0 and 1.1.0 say, are present, the version of
Jersey that gets initiated, say 1.1.0, will also attempt to load components
declared by 1.0 jars because of the way Classloader.getResources works.


Sanjeeb Sahoo added a comment - 19/Aug/09 07:54 AM

OK, I understand why things won't work when delegate=false.

When delegate=true, what is the problem with ClassLoader.getResources. It would
return META-INF/services found in both 1.1 and 1.0 jar, but 1.1 ones would be
ahead of 1.0 ones in the enumeration. How do you select a particular one?
Actually, does the code call getResources or getResource? getResource should
only return 1.1 resource.

Sahoo


sandoz added a comment - 19/Aug/09 08:27 AM

For certain services Jersey selects all classes registered. It then tries to
instantiate them and ignore ones it cannot, reporting the instantiation errors,
and continues processing (a "keep on trucking" strategy).

Alexis said that for class loader <class-loader delegate="false"/> other errors
occurred but i do not know what they were. Alexis?
It is likely that Jersey 1.0 may not be as robust in ignoring certain errors
when attempting to instantiate components. Perhaps a move to Jersey 1.0.3.1 may
help?

Note that a META-INF/services file in say Jersey 1.0 may refer to a class that
still exists in say Jersey 1.1.x but that class is now abstract and is not
referred to in the META-INF/services file of Jersey 1.1.x. And, if course,
similar occurrences are possible if Jersey 1.1.x is loaded before Jersey 1.0.
Errors will be reported and processing will continue but it confuses the heck
out of developers because the situation i described has actually occurred
between 1.1.0 and 1.1.1 and we got some bemused questions.

The issue with including successfully instantiated components from different
versions is that there could be some subtle errors introduced. JAX-RS/Jersey
attempts to ensure that components registered before other components that
intersect in terms of "functionality" have priority. But, i cannot say for sure
whether some really subtle issues may result in the future e.g. an old component
get registered and instantiated successfully that is no longer relevant but yet
causes functional change.

All in all META-INF/services is a PITA! and is not suitable for a version-based
runtime module system where two or more versions of may co-exist in the same VM.

Perhaps we need a way to say in the sun-web.xml "please do include modules X, Y
and Z" in the classpath or a way to declare OSGi dependencies in the sun-web.xml
or at deployment (so the war does not require modification).


Alexis MP added a comment - 19/Aug/09 09:20 AM

sandoz said:
> Alexis said that for class loader <class-loader delegate="false"/> other errors occurred but i do not know what they were. Alexis?

Let me attach files to this case with the full logs for both cases (class-loader delegate set to true or false).
With <class-loader delegate="false"/>, here's the stacktrace :

com.sun.jersey.spi.service.ServiceConfigurationError: com.sun.jersey.spi.HeaderDelegateProvider: The class
com.sun.jersey.core.impl.provider.header.LocaleProvider implementing provider interface com.sun.jersey.spi.HeaderDelegateProvider could not
be instantiated: null
at com.sun.jersey.spi.service.ServiceFinder.fail(ServiceFinder.java:413)
at com.sun.jersey.spi.service.ServiceFinder.access$600(ServiceFinder.java:146)
at com.sun.jersey.spi.service.ServiceFinder$LazyObjectIterator.hasNext(ServiceFinder.java:707)
at com.sun.jersey.impl.provider.RuntimeDelegateImpl.<init>(RuntimeDelegateImpl.java:79)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
at java.lang.Class.newInstance0(Class.java:355)
at java.lang.Class.newInstance(Class.java:308)
at javax.ws.rs.ext.FactoryFinder.newInstance(FactoryFinder.java:65)
at javax.ws.rs.ext.FactoryFinder.find(FactoryFinder.java:117)
at javax.ws.rs.ext.RuntimeDelegate.findDelegate(RuntimeDelegate.java:105)
at javax.ws.rs.ext.RuntimeDelegate.getInstance(RuntimeDelegate.java:91)
at javax.ws.rs.core.EntityTag.<clinit>(EntityTag.java:35)
at java.lang.Class.forName0(Native Method)
at java.lang.Class.forName(Class.java:169)
at $Proxy156.<clinit>(Unknown Source)
at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
at java.lang.reflect.Constructor.newInstance(Constructor.java:513)
at java.lang.reflect.Proxy.newProxyInstance(Proxy.java:588)
at com.sun.jersey.impl.application.WebApplicationImpl.createProxy(WebApplicationImpl.java:953)
at com.sun.jersey.impl.application.WebApplicationImpl.<init>(WebApplicationImpl.java:199)
at com.sun.jersey.impl.container.WebApplicationProviderImpl.createWebApplication(WebApplicationProviderImpl.java:52)
at com.sun.jersey.spi.container.WebApplicationFactory.createWebApplication(WebApplicationFactory.java:63)
at com.sun.jersey.spi.container.servlet.ServletContainer.create(ServletContainer.java:548)
at com.sun.jersey.spi.container.servlet.ServletContainer.load(ServletContainer.java:536)
at com.sun.jersey.spi.container.servlet.ServletContainer.init(ServletContainer.java:197)
at org.apache.catalina.core.StandardWrapper.initServlet(StandardWrapper.java:1410)
at org.apache.catalina.core.StandardWrapper.load(StandardWrapper.java:1213)
at org.apache.catalina.core.StandardContext.loadOnStartup(StandardContext.java:4941)
at org.apache.catalina.core.StandardContext.start(StandardContext.java:5296)
at com.sun.enterprise.web.WebModule.start(WebModule.java:509)
at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:928)
at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:912)
at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:694)
at com.sun.enterprise.web.WebContainer.loadWebModule(WebContainer.java:1796)
at com.sun.enterprise.web.WebContainer.loadWebModule(WebContainer.java:1485)
at com.sun.enterprise.web.WebApplication.start(WebApplication.java:93)
at org.glassfish.internal.data.EngineRef.start(EngineRef.java:126)
at org.glassfish.internal.data.ModuleInfo.start(ModuleInfo.java:223)
at org.glassfish.internal.data.ApplicationInfo.start(ApplicationInfo.java:193)
at com.sun.enterprise.v3.server.ApplicationLifecycle.deploy(ApplicationLifecycle.java:295)
at com.sun.enterprise.v3.server.ApplicationLifecycle.deploy(ApplicationLifecycle.java:175)
at org.glassfish.deployment.admin.DeployCommand.execute(DeployCommand.java:270)
at com.sun.enterprise.v3.admin.CommandRunnerImpl$4.execute(CommandRunnerImpl.java:427)
at com.sun.enterprise.v3.admin.CommandRunnerImpl.doCommand(CommandRunnerImpl.java:437)
at com.sun.enterprise.v3.admin.CommandRunnerImpl.doCommand(CommandRunnerImpl.java:524)
at com.sun.enterprise.v3.admin.CommandRunnerImpl.doCommand(CommandRunnerImpl.java:157)
at org.glassfish.deployment.autodeploy.AutoOperation.run(AutoOperation.java:121)
at org.glassfish.deployment.autodeploy.AutoDeployer.deploy(AutoDeployer.java:529)
at org.glassfish.deployment.autodeploy.AutoDeployer.deployAll(AutoDeployer.java:415)
at org.glassfish.deployment.autodeploy.AutoDeployer.run(AutoDeployer.java:347)
at org.glassfish.deployment.autodeploy.AutoDeployer.run(AutoDeployer.java:332)
at org.glassfish.deployment.autodeploy.AutoDeployService$1.run(AutoDeployService.java:200)
at java.util.TimerThread.mainLoop(Timer.java:512)
at java.util.TimerThread.run(Timer.java:462)
Caused by: java.lang.ClassCastException
at java.lang.Class.cast(Class.java:2990)
at com.sun.jersey.spi.service.ServiceFinder$LazyObjectIterator.hasNext(ServiceFinder.java:665)
... 56 more


sandoz added a comment - 19/Aug/09 01:10 PM

I have just tried deploying 1.0 and 1.0.3.1 helloworld web app samples on GF v3
build 59:

http://download.java.net/maven/2/com/sun/jersey/samples/helloworld-webapp/1.0/helloworld-webapp-1.0-project.zip

http://download.java.net/maven/2/com/sun/jersey/samples/helloworld-webapp/1.0.3.1/helloworld-webapp-1.0.3.1-project.zip

I do not get the same error from within initiation of the JAX-RS RuntimeDelegate.

For 1.0.3.1 i get the following error:

java.lang.ClassCastException
at java.lang.Class.cast(Class.java:2990)
at
com.sun.jersey.core.spi.component.ProviderServices.getProvidersAndServices(ProviderServices.java:122)
at
com.sun.jersey.server.impl.model.parameter.multivalued.StringReaderFactory.init(StringReaderFactory.java:57)
at
com.sun.jersey.server.impl.application.WebApplicationImpl.initiate(WebApplicationImpl.java:597)
at
com.sun.jersey.server.impl.application.WebApplicationImpl.initiate(WebApplicationImpl.java:414)
at
com.sun.jersey.spi.container.servlet.ServletContainer.initiate(ServletContainer.java:377)
at
com.sun.jersey.spi.container.servlet.ServletContainer$InternalWebComponent.initiate(ServletContainer.java:242)
at com.sun.jersey.spi.container.servlet.WebComponent.load(WebComponent.java:449)
at com.sun.jersey.spi.container.servlet.WebComponent.init(WebComponent.java:169)
at
com.sun.jersey.spi.container.servlet.ServletContainer.init(ServletContainer.java:281)
at
com.sun.jersey.spi.container.servlet.ServletContainer.init(ServletContainer.java:442)
at javax.servlet.GenericServlet.init(GenericServlet.java:242)

The error is occuring when Jersey 1.0.3.1 is finding and instantiating instances
of StringReaderProvider implementatons registered in
META-INF/services/com.sun.jersey.spi.StringReaderProvider.

The following classes are registered in 1.0.3.1:

com.sun.jersey.server.impl.model.parameter.multivalued.StringReaderProviders$TypeValueOf
com.sun.jersey.server.impl.model.parameter.multivalued.StringReaderProviders$StringConstructor
com.sun.jersey.server.impl.model.parameter.multivalued.StringReaderProviders$DateProvider
com.sun.jersey.server.impl.model.parameter.multivalued.JAXBStringReaderProviders$RootElementProvider

The following classes are registered in 1.1.1-ea:

com.sun.jersey.server.impl.model.parameter.multivalued.StringReaderProviders$TypeFromStringEnum
com.sun.jersey.server.impl.model.parameter.multivalued.StringReaderProviders$TypeValueOf
com.sun.jersey.server.impl.model.parameter.multivalued.StringReaderProviders$TypeFromString
com.sun.jersey.server.impl.model.parameter.multivalued.StringReaderProviders$StringConstructor
com.sun.jersey.server.impl.model.parameter.multivalued.StringReaderProviders$DateProvider
com.sun.jersey.server.impl.model.parameter.multivalued.JAXBStringReaderProviders$RootElementProvider

I think i can explain this behaviour as follows;

1) When 1.0.3.1 loads a class from a META-INF/services file that is present in
1.0.3.1 it uses class loader, A say.

2) When 1.0.3.1 loads a class from a META-INF/services file that is only
present in 1.1.1-ea it uses class loader, B say.

Class loader A and B will load two different Class instances of
StringReaderProvider, hence the class cast exception: a sub-class of
StringReaderProvider loaded by class loader B cannot be cast to the class of
StringReaderProvder loaded by class loader A.

I think this just re-enforces the requirement to correctly isolate the web app
using an appropriate feature of GF.


sandoz added a comment - 19/Aug/09 01:31 PM

I forgot to state i deployed the samples using <class-loader delegate="false"/>.


Alexis MP added a comment - 19/Aug/09 02:57 PM

Created an attachment (id=3108)
Log for artifactory deployment with class-loader delegate set to "true"


Alexis MP added a comment - 19/Aug/09 02:57 PM

Created an attachment (id=3109)
Log for artifactory deployment with class-loader delegate set to "false"


sandoz added a comment - 20/Aug/09 02:18 AM

1.0 META-INF/services/com.sun.jersey.spi.HeaderDelegateProvider

com.sun.jersey.impl.provider.header.LocaleProvider
com.sun.jersey.impl.provider.header.EntityTagProvider
com.sun.jersey.impl.provider.header.MediaTypeProvider
com.sun.jersey.impl.provider.header.CacheControlProvider
com.sun.jersey.impl.provider.header.NewCookieProvider
com.sun.jersey.impl.provider.header.CookieProvider
com.sun.jersey.impl.provider.header.URIProvider
com.sun.jersey.impl.provider.header.DateProvider
com.sun.jersey.impl.provider.header.StringProvider

1.1.1-ea META-INF/services/com.sun.jersey.spi.HeaderDelegateProvider

com.sun.jersey.core.impl.provider.header.LocaleProvider
com.sun.jersey.core.impl.provider.header.EntityTagProvider
com.sun.jersey.core.impl.provider.header.MediaTypeProvider
com.sun.jersey.core.impl.provider.header.CacheControlProvider
com.sun.jersey.core.impl.provider.header.NewCookieProvider
com.sun.jersey.core.impl.provider.header.CookieProvider
com.sun.jersey.core.impl.provider.header.URIProvider
com.sun.jersey.core.impl.provider.header.DateProvider
com.sun.jersey.core.impl.provider.header.StringProvider

Note that Jersey 1.0 is attempting to instantiate an instance of
"com.sun.jersey.core.impl.provider.header.LocaleProvider" that is declared in
Jersey 1.1.1-ea.

It is the same error that i described previously with StringReaderProvider. In
this case two different Class instances of HeaderDelegateProvider are created by
two different class loaders.


Jakub Podlesak added a comment - 02/Sep/09 02:20 AM

Sahoo: could you please explain a bit, what
install webbundle:file:///tmp/artifactory-2.0.7.war
should do. The jersey jars bundled in the war do not contain any OSGi headers,
and also the jersey (OSGified) jars installed into GlassFish are missing any
version information. How is this supposed to work?


Sanjeeb Sahoo added a comment - 02/Sep/09 03:45 AM

japod:
When you run
install webbundle:file:///tmp/artifactory-2.0.7.war
there is a built in URL handler in the server which will try to add some OSGi
metadata to the war file and the modified war file is installed in the OSGi
framework. You can configure the OSGi metadata by use of URL query parameters.
To see the default OSGi metadata that's generated, perform the above step and
see the OSGi metadata using "headers [bundle-id]" command.

To all:
I think it will help to have a conference call to understand why things don't
work wih the original war file with classloader delegation=true. I am still not
clear despite all the explanations provided by Paul.


sandoz added a comment - 03/Sep/09 05:41 AM

Created an attachment (id=3165)
Simple web-based project reproducing the issues


sandoz added a comment - 03/Sep/09 06:06 AM

I have attached a simple project that shows the cause of the problem and
hopefully that will help in understanding what is going on.

It loads service classes from

META-INF/services/com.sun.jersey.spi.HeaderDelegateProvider

and prints information from each entry like this, when a class is loaded from
the service file present in the war:

Class com.sun.jersey.impl.provider.header.LocaleProvider is assignable to
interface com.sun.jersey.spi.HeaderDelegateProvider
FIND: com.sun.jersey.spi.HeaderDelegateProvider
com/sun/jersey/spi/HeaderDelegateProvider.class
Class loader of class

jar:file:/Users/paulsandoz/Applications/GlassFish/glassfish-v3-preview-b61/glassfishv3/glassfish/domains/domain1/applications/mavenproject5/WEB-INF/lib/jersey-core-1.0.jar!/com/sun/jersey/spi/HeaderDelegateProvider.class
Context class loader

jar:file:/Users/paulsandoz/Applications/GlassFish/glassfish-v3-preview-b61/glassfishv3/glassfish/domains/domain1/applications/mavenproject5/WEB-INF/lib/jersey-core-1.0.jar!/com/sun/jersey/spi/Header

and:

Class com.sun.jersey.core.impl.provider.header.LocaleProvider is NOT assignable
to interface com.sun.jersey.spi.HeaderDelegateProvider
FIND: com.sun.jersey.spi.HeaderDelegateProvider
com/sun/jersey/spi/HeaderDelegateProvider.class
Class loader of class
bundle://6.0:1/com/sun/jersey/spi/HeaderDelegateProvider.class
Context class loader

jar:file:/Users/paulsandoz/Applications/GlassFish/glassfish-v3-preview-b61/glassfishv3/glassfish/domains/domain1/applications/mavenproject5/WEB-INF/lib/jersey-core-1.0.jar!/com/sun/jersey/spi/HeaderDelegateProvider.class

Notice that this shows that two HeaderDelegateProvider classes have been loaded,
one from the jar in the war, and one from GF.


sandoz added a comment - 03/Sep/09 07:31 AM

Note that i forgot to add that i could fix for future releases by performing
isAssignable checks at appropriate places in Jersey's ServiceFinder. This, of
course, is not something that is immediately obvious to do unless one has some
hindsight

However, this may just result in pushing errors somewhere else. What we really
require is a way to isolate the web applications from certain modules
distributed with GF.


Sanjeeb Sahoo added a comment - 03/Sep/09 09:51 AM

OK, I looked at your simplified test case. What you are seeing is a direct
result of switching of classloader delegation by setting delagation=false in
sun-web.xml. I have said this before, I understand why things won't work as
expected when delegation is switched off. Switching off delegation must be a
developer's last resort, as it can lead to all kinds of class constraint
violations.

Run your simple test case with delegation=true (this is the default value) and
tell me what you see. Do you see two versions of
com.sun.jersey.spi.HeaderDelegateProvider.class?


sandoz added a comment - 03/Sep/09 11:48 PM

Class loader delegation set to true works, but... I feel we may be going around
in circles

The war depends Jersey 1.0 APIs in Jersey 1.0 jars to function correctly,
which is why class loader delegation was set to false, so that the Jersey 1.0
jars take precedence.

The war depends on the Jersey Spring integration. Which is why when class loader
delegation is set to true for the war the following exception is thrown:

SEVERE: WebModule[/artifactory]StandardWrapper.Throwable
java.lang.NoSuchMethodError:
com.sun.jersey.spi.container.WebApplication.initiate(Lcom/sun/jersey/api/core/ResourceConfig;Lcom/sun/jersey/spi/service/ComponentProvider;)V
at
org.artifactory.rest.servlet.ArtifactoryRestServlet.initiate(ArtifactoryRestServlet.java:51)
at
com.sun.jersey.spi.container.servlet.ServletContainer$InternalWebComponent.initiate(ServletContainer.java:242)
at com.sun.jersey.spi.container.servlet.WebComponent.load(WebComponent.java:455)
at com.sun.jersey.spi.container.servlet.WebComponent.init(WebComponent.java:178)
at
com.sun.jersey.spi.container.servlet.ServletContainer.init(ServletContainer.java:281)
at
com.sun.jersey.spi.container.servlet.ServletContainer.init(ServletContainer.java:442)
at javax.servlet.GenericServlet.init(GenericServlet.java:242)

(See the attachment that Alexis added).

The ArtifactoryRestServlet is extending the Jersey 1.0 ServletContainer, but in
Jersey 1.1.x the ServletContainer class has changed.

The only way this war will work on GF is if:

1) Jersey in GF is removed; or

2) They developers upgrade their app to the same version as in GF.

I fear are going to run into this issue again and again when GF is released
and potentialy in the future as well, if refactoring of service impl classes
occurs in later versions.

Unfortunately this the Java equivalent of DLL hell. Again, we need a way of
cleanly isolating web app deployments.


dochez added a comment - 25/Sep/09 10:02 PM

providing a complete application isolation is not a supported feature of V3, public libraries should not
break public APIs during a .dot release. We should provide a solution for this problem in the next release.


Tom Mueller added a comment - 06/Mar/12 09:57 PM

Bulk update to change fix version to "not determined" for all issues still open but with a fix version for a released version.


Tom Mueller added a comment - 07/Jan/13 07:24 PM

Assigning to the classloader component for evaluation.