We have been running a JSF 1.2 application on Websphere 7 and 8 for years. We build our war with JSF bundled in it, and always set the classloader as PARENT LAST.
Having now upgraded to JSF 2.2 (and RF4 and PF4 - until migration is complete ), we are now facing issues deploying on the same server (WAS 8.0 as well as WAS 8.5).
We've now done a similar approach (with bundling JSF and PARENT LAST classloading). The application does start, it mentions initialization of Mojarra 2.2.11 , but on first page request, we get below error:
java.lang.reflect.UndeclaredThrowableException
at com.sun.proxy.$Proxy34.markResourceRendered(Unknown Source)
at org.richfaces.resource.ResourceFactoryImpl.createMappedResource(ResourceFactoryImpl.java:366)
at org.richfaces.resource.ResourceFactoryImpl.createResource(ResourceFactoryImpl.java:343)
at org.richfaces.resource.ResourceHandlerImpl.createResource(ResourceHandlerImpl.java:266)
at javax.faces.application.ResourceHandlerWrapper.createResource(ResourceHandlerWrapper.java:137)
at org.apache.myfaces.custom.captcha.CAPTCHAResourceHandlerWrapper.createResource(CAPTCHAResourceHandlerWrapper.java:83)
at org.apache.myfaces.tomahawk.resource.UncompressedResourceHandlerWrapper.createResource(UncompressedResourceHandlerWrapper.java:109)
at org.apache.myfaces.tomahawk.resource.UncompressedResourceHandlerWrapper.createResource(UncompressedResourceHandlerWrapper.java:61)
at com.sun.faces.renderkit.html_basic.ScriptRenderer.encodeEnd(ScriptRenderer.java:104)
at javax.faces.component.UIComponentBase.encodeEnd(UIComponentBase.java:919)
at javax.faces.component.UIComponent.encodeAll(UIComponent.java:1863)
Caused by: java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:60)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:37)
at java.lang.reflect.Method.invoke(Method.java:611)
at org.richfaces.application.ServiceTracker$1.invoke(ServiceTracker.java:153)
... 52 more
Caused by: java.lang.ExceptionInInitializerError
at org.richfaces.resource.external.ResourceTrackerForMyFaces.<init>(ResourceTrackerForMyFaces.java:58)
at org.richfaces.resource.external.ResourceTrackerImpl.getImplementation(ResourceTrackerImpl.java:86)
at org.richfaces.resource.external.ResourceTrackerImpl.markResourceRendered(ResourceTrackerImpl.java:67)
... 57 more
Caused by: java.lang.NoSuchMethodException: org.apache.myfaces.shared_impl.renderkit.html.util.ResourceUtils.isRenderedStylesheet(javax.faces.context.FacesContext, java.lang.String, java.lang.String)
at java.lang.Class.throwNoSuchMethodException(Class.java:356)
at java.lang.Class.getMethod(Class.java:1018)
at org.richfaces.resource.external.ResourceTrackerForMyFaces.<init>(ResourceTrackerForMyFaces.java:49)
... 59 more
I have obviously seen many suggestions of using a shared library, but I have similarly found that CDI is not supported when not using the default JSF implementation provided by websphere.
The preferred solution would obviously be to have a single deployment war, but I'm wondering if that's possible in websphere?
Also note that this application runs fine on weblogic and tomcat7
I've tracked this down to a bug in Richfaces, present in the most recent version 4.5.9, in class org.richfaces.resource.external.ResourceTrackerImpl
.
That class determines which ResourceTracker to use (there are different classes for either Mojarra and Myfaces), but simply checks if some class from MyFaces is on the classpath. That is the case, but JSF has initialized as Mojarra.
Here's the new method, in which I prevent a class lookup of MyFaces if the used JSF implementation is Mojarra.
private ResourceTracker getImplementation() {
ResourceTracker tracker = externalResourceTracker.get();
if (tracker == null) {
Class<?> myfacesResUtilClass = null;
if (!MOJARRA_IMPLTITLE.equals(FacesContext.class.getPackage().getImplementationTitle())) {
for (String myFacesResourceUtilsClass : MYFACES_RESOURCE_UTILS_CLASSES) {
try {
myfacesResUtilClass = this.getClass().getClassLoader().loadClass(myFacesResourceUtilsClass);
break;
} catch (Exception e) {
LOG.debug("could not load myfaces resource utils class: " + myFacesResourceUtilsClass, e);
}
}
}
if (myfacesResUtilClass != null) {
externalResourceTracker.compareAndSet(null, new ResourceTrackerForMyFaces(myfacesResUtilClass));
} else {
externalResourceTracker.compareAndSet(null, new ResourceTrackerForMojarra());
}
tracker = externalResourceTracker.get();
}
return tracker;
}
It's solved, but it disturbs me quite a lot that, apart from the bug, this class even checks on a websphere specific class, showing how MyFaces has actually been adapted to work on Websphere, instead of the other way around.