Admin console login page is corrupted after a while in JBoss EAP 5.x
Environment
- Red Hat JBoss Enterprise Application Platform (EAP)
- 5.1.2
- 5.2
Issue
After EAP has been running for 30 minutes or more, the username and password fields on the login page of the admin console disappear. This is accompanied by a stack trace like the following in the logs:
java.lang.RuntimeException: Failed to initialize ZipWrapper: /opt/jboss/jboss-as/servers/myconfig/deployers/jbossws.deployer/spring-core.jar/META-INF/
at org.jboss.virtual.plugins.context.zip.ZipEntryContext.getZipSource(ZipEntryContext.java:286)
at org.jboss.virtual.plugins.context.zip.ZipEntryContext.ensureEntries(ZipEntryContext.java:638)
at org.jboss.virtual.plugins.context.zip.ZipEntryContext.checkIfModified(ZipEntryContext.java:786)
at org.jboss.virtual.plugins.context.zip.ZipEntryContext.getChildren(ZipEntryContext.java:858)
at org.jboss.virtual.plugins.context.AbstractVFSContext.visit(AbstractVFSContext.java:337)
at org.jboss.virtual.plugins.context.AbstractVFSContext.visit(AbstractVFSContext.java:307)
at org.jboss.virtual.VFS.visit(VFS.java:468)
at org.jboss.virtual.VirtualFile.visit(VirtualFile.java:448)
at com.sun.facelets.util.VFSClasspath.search(VFSClasspath.java:49)
at com.sun.facelets.util.Classpath.search(Classpath.java:63)
at com.sun.facelets.compiler.TagLibraryConfig.loadImplicit(TagLibraryConfig.java:428)
at com.sun.facelets.compiler.Compiler.initialize(Compiler.java:87)
at com.sun.facelets.compiler.Compiler.compile(Compiler.java:104)
We are seeing this error in JBoss Enterprise Portal 5.2.1 :
SEVERE [facelets.viewhandler] (ajp-host-127.0.0.1-8009-1) Error Rendering View[/index.xhtml]
java.lang.RuntimeException: Failed to initialize ZipWrapper: /var/jboss/jboss-epp-5.1/server/deploy/application.ear/lib/asm-3.3.1.jar/META-INF/
at org.jboss.virtual.plugins.context.zip.ZipEntryContext.getZipSource(ZipEntryContext.java:286)
at org.jboss.virtual.plugins.context.zip.ZipEntryContext.ensureEntries(ZipEntryContext.java:638)
...
at org.jboss.virtual.VirtualFile.visit(VirtualFile.java:448)
at com.sun.facelets.util.VFSClasspath.search(VFSClasspath.java:49)
...
at com.sun.facelets.FaceletViewHandler.renderView(FaceletViewHandler.java:567)
at org.ajax4jsf.application.ViewHandlerWrapper.renderView(ViewHandlerWrapper.java:100)
...
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:206)
at org.jboss.seam.servlet.SeamFilter$FilterChainImpl.doFilter(SeamFilter.java:83)
...
Caused by: java.lang.IllegalArgumentException: Cannot find entry: java.io.FileInputStream@4ac2a314, META-INF
at org.jboss.virtual.plugins.context.zip.ZipEntryContext.findEntry(ZipEntryContext.java:429)
at org.jboss.virtual.plugins.context.zip.ZipEntryContext.createZipSource(ZipEntryContext.java:362)
at org.jboss.virtual.plugins.context.zip.ZipEntryContext.getZipSource(ZipEntryContext.java:282)
... 66 more
Resolution
Patches are available for This content is not included.EAP 5.1.2 and This content is not included.EAP 5.2.
A workaround is to add the relevant directory (deployers in the stack above) as a permanent root in $JBOSS_HOME/server/$CONFIG/conf/bootstrap/vfs.xml
If symlinks are involved, the directory still needs to be present in vfs.xml, but -Djboss.vfs.forceCanonical=true should be used when starting the server. However, if the platform is EAP 5.1.2, the patch must be applied for this to work.
Root Cause
Starting with EAP 5.1.2, the facelets implementation had a change to classpath scanning that better integrated it with JBoss VFS. It requests all resources containing META-INF/ from the current classloader and then requests the underlying VirtualFiles for them.
IF JBossWS-CXF is installed, obviously its files are added to the installation. Two to note are $JBOSS_HOME/server/$CONFIG/deployers/jbossws.deployer/spring-core.jar and $JBOSS_HOME/common/lib/asm.jar
These are noteworthy because they were created without entries for directories. This means that, while they contain an entry for a file like META-INF/MANIFEST.MF, they don't actually contain an entry for the META-INF/ directory itself.
If zip is used to create a jar by invoking zip -D, zip --no-dir-entries, or by setting the environment variable ZIPOPT to either of those properties when zip is executed, then the jar will be created without directory entries.
Now, when EAP starts, VFS is configured in $JBOSS_HOME/server/$CONFIG/conf/bootstrap/vfs.xml with a set of roots that are permanently cached. These roots are like top level mount points and provide roots for an hierarchy of structures that represent different types of resources in the virtual file system. For instance, $JBOSS_HOME/server/$CONFIG/deploy/ is a root. If a WAR is deployed there, since it is not a regular file, another VFS context that knows how to deal with it will be constructed and attached to the deploy root. Jars it contains will have their own roots and will be attached to the WAR context, and so on. In this way, resources anywhere along the path can be retrieved in principle by navigating the hierarchy of contexts.
When looking for the context of a resource, VFS first checks the permanent cache for some context either matching the resource or that is some parent of the resource. If it can at least find a parent, it can create a new context and attach it to that parent. If no such context is found in the permanent cache, a temp cache is consulted in the same way.
What if a VirtualFile is retrieved that does not belong to a context existing in some hierarchy terminating in a root that belongs to either the permanent or temp cache? Then a context is created for the resource itself and stored in the VFS temp cache. This cache times out after 30 minutes.
The above is important because $JBOSS_HOME/server/$CONFIG/deployers is not a permanent root. However, it is accessed during EAP boot, and its context is stored in the temp cache. Then subcontexts for its children are attached to it as described above. In this way, on boot, the context for spring-core.jar is initialized and attached to a parent.
However, after the temp cache times out, the root context of deployers is kicked out of it along with all the children attached to it, and subsequent accesses of it or its children contexts will require reinitialization of the contexts representing their backing resources.
Since the facelets code above is requesting META-INF from all VirtualFiles it can see, it eventually requests it from spring-core.jar. After waiting long enough, this jar will no longer have a context representing it, so one is created and put into the temp cache. However, the initialization of this context as a root itself is different from its initialization as a child of some other context (previously deployers). It's this reinitialization of the jar itself as a root that causes the problem because it doesn't properly deal with missing directory entries.
This situation also can occur if a deployment contains jars that don't have directory entries and the deploy directory is not configured as a permanent root in vfs.xml. This situation always is seen in circumstances where a custom deploy directory has been added to profile.xml but not vfs.xml, or some directory (possibly deploy) is a symlink to a directory outside of a VFS permanent root.
This solution is part of Red Hat’s fast-track publication program, providing a huge library of solutions that Red Hat engineers have created while supporting our customers. To give you the knowledge you need the instant it becomes available, these articles may be presented in a raw and unedited form.