dev@javaserverfaces.java.net

Seeking Review JAVASERVERFACES-1856

From: Ed Burns <edward.burns_at_oracle.com>
Date: Fri, 18 Mar 2011 22:40:57 -0700

Account for the fact that the zip file spec does not require "directory entries" http://java.net/jira/browse/JAVASERVERFACES-1856


SECTION: Modified Files
----------------------------
M jsf-ri/src/main/java/com/sun/faces/application/resource/ClasspathResourceHelper.java

- in findLibrary(), first use

+ Set<String> resourcePaths = ctx.getExternalContext().getResourcePaths("/" + libraryName + "/");

  to look for the library. This should work if GLASSFISH-16229 is
  fixed. Failing that, use this new class, ZipDirectoryEntryScanner, to
  see if the library exists.

  I tested the dynamic reload case to ensure a new instance of this
  class is given to the ResourceManager each time, thus causing the scan
  to re-execute. That works, but I see an exception. I've logged
  http://java.net/jira/browse/JAVASERVERFACES-2001.

M jsf-ri/src/main/java/com/sun/faces/config/JavaClassScanningAnnotationScanner.java

- Make this class public, not package private. This is related to
  JAVASERVERFACES-1995.

M jsf-test/build.xml

- add regression test

A jsf-ri/src/main/java/com/sun/faces/application/resource/ZipDirectoryEntryScanner.java

- New class that scans jar entries for resource libraries upon instantiation.

A jsf-test/JAVASERVERFACES-1856
A jsf-test/JAVASERVERFACES-1856/i_jsf_1856
A jsf-test/JAVASERVERFACES-1856/i_jsf_1856/src
A jsf-test/JAVASERVERFACES-1856/i_jsf_1856/src/main
A jsf-test/JAVASERVERFACES-1856/i_jsf_1856/src/main/webapp
A jsf-test/JAVASERVERFACES-1856/i_jsf_1856/src/main/webapp/WEB-INF
A jsf-test/JAVASERVERFACES-1856/i_jsf_1856/src/main/webapp/WEB-INF/faces-config.xml
A jsf-test/JAVASERVERFACES-1856/i_jsf_1856/src/main/webapp/WEB-INF/lib
A + jsf-test/JAVASERVERFACES-1856/i_jsf_1856/src/main/webapp/WEB-INF/lib/i_jsf_1856.jar

- this jar has had its directory entries stripped.
  http://chowhound.chow.com/topics/707713

A + jsf-test/JAVASERVERFACES-1856/i_jsf_1856/src/main/webapp/i_jsf_1856-using.xhtml
A jsf-test/JAVASERVERFACES-1856/i_jsf_1856/pom.xml
A jsf-test/JAVASERVERFACES-1856/build.xml
D jsf-ri/systest/src/com/sun/faces/systest/composite/JarPackagedCompositeComponentTestCase.java
D jsf-ri/systest/web/composite/i_jsf_1856-using.xhtml
D jsf-ri/systest/web/WEB-INF/lib/i_jsf_1856.jar

- move this jar to the regression test area.


SECTION: Diffs
----------------------------
Index: jsf-ri/src/main/java/com/sun/faces/application/resource/ZipDirectoryEntryScanner.java
===================================================================
--- jsf-ri/src/main/java/com/sun/faces/application/resource/ZipDirectoryEntryScanner.java (revision 0)
+++ jsf-ri/src/main/java/com/sun/faces/application/resource/ZipDirectoryEntryScanner.java (revision 0)
@@ -0,0 +1,125 @@
+
+/*
+ * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+ *
+ * Copyright (c) 1997-2010 Oracle and/or its affiliates. All rights reserved.
+ *
+ * The contents of this file are subject to the terms of either the GNU
+ * General Public License Version 2 only ("GPL") or the Common Development
+ * and Distribution License("CDDL") (collectively, the "License"). You
+ * may not use this file except in compliance with the License. You can
+ * obtain a copy of the License at
+ * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
+ * or packager/legal/LICENSE.txt. See the License for the specific
+ * language governing permissions and limitations under the License.
+ *
+ * When distributing the software, include this License Header Notice in each
+ * file and include the License file at packager/legal/LICENSE.txt.
+ *
+ * GPL Classpath Exception:
+ * Oracle designates this particular file as subject to the "Classpath"
+ * exception as provided by Oracle in the GPL Version 2 section of the License
+ * file that accompanied this code.
+ *
+ * Modifications:
+ * If applicable, add the following below the License Header, with the fields
+ * enclosed by brackets [] replaced by your own identifying information:
+ * "Portions Copyright [year] [name of copyright owner]"
+ *
+ * Contributor(s):
+ * If you wish your version of this file to be governed by only the CDDL or
+ * only the GPL Version 2, indicate your decision by adding "[Contributor]
+ * elects to include this software in this distribution under the [CDDL or GPL
+ * Version 2] license." If you don't indicate a single choice of license, a
+ * recipient has the option to distribute your version of this file under
+ * either the CDDL, the GPL Version 2 or to extend the choice of license to
+ * its licensees as provided above. However, if you add GPL Version 2 code
+ * and therefore, elected the GPL Version 2 license, then the option applies
+ * only if the new code is made subject to such option by the copyright
+ * holder.
+ */
+
+package com.sun.faces.application.resource;
+
+import com.sun.faces.util.FacesLogger;
+import java.io.IOException;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+import javax.faces.context.ExternalContext;
+import javax.faces.context.FacesContext;
+
+
+
+class ZipDirectoryEntryScanner {
+
+ private static final Logger LOGGER = FacesLogger.RESOURCE.getLogger();
+ private Set<String> webInfLibJars;
+ private static final String prefix = "META-INF/resources";
+ private static final int prefixLen = prefix.length();
+ Map<String, Boolean> resourceLibraries;
+
+
+ ZipDirectoryEntryScanner() {
+ ExternalContext extContext = FacesContext.getCurrentInstance().getExternalContext();
+ webInfLibJars = extContext.getResourcePaths("/WEB-INF/lib");
+ resourceLibraries = new ConcurrentHashMap<String, Boolean>();
+ ZipInputStream zis = null;
+ ZipEntry ze = null;
+ String entryName = null;
+ for (String cur : webInfLibJars) {
+ zis = new ZipInputStream(extContext.getResourceAsStream(cur));
+ try {
+ while (null != (ze = zis.getNextEntry())) {
+ entryName = ze.getName();
+ if (entryName.startsWith(prefix)) {
+ if (prefixLen < entryName.length()) {
+ entryName = entryName.substring(prefixLen + 1);
+ if (!entryName.endsWith("/")) {
+ // Assume this code is only reached if the zip entry
+ // is NOT a 'directory' entry.
+ int i = entryName.lastIndexOf("/");
+ if (-1 != i) {
+ entryName = entryName.substring(0, i);
+ if (!resourceLibraries.containsKey(entryName)) {
+ resourceLibraries.put(entryName, Boolean.TRUE);
+ }
+ }
+ }
+
+ }
+ }
+ }
+
+ } catch (IOException ioe) {
+ if (LOGGER.isLoggable(Level.SEVERE)) {
+ LOGGER.log(Level.SEVERE, "Unable to inspect resource library " + cur, ioe);
+ }
+ }
+ }
+
+ // remove the optional local prefix entries
+ List<String> toRemove = new ArrayList<String>();
+ for (String cur : resourceLibraries.keySet()) {
+ if (cur.contains("/")) {
+ toRemove.add(cur);
+ }
+ }
+ for (String cur : toRemove) {
+ resourceLibraries.remove(cur);
+ }
+ }
+
+ boolean libraryExists(String libraryName) {
+ return resourceLibraries.containsKey(libraryName);
+ }
+
+
+
+}
Index: jsf-ri/src/main/java/com/sun/faces/application/resource/ClasspathResourceHelper.java
===================================================================
--- jsf-ri/src/main/java/com/sun/faces/application/resource/ClasspathResourceHelper.java (revision 8930)
+++ jsf-ri/src/main/java/com/sun/faces/application/resource/ClasspathResourceHelper.java (working copy)
@@ -40,6 +40,7 @@
 
 package com.sun.faces.application.resource;
 
+import java.util.Set;
 import java.io.IOException;
 import java.io.InputStream;
 import java.net.URL;
@@ -64,6 +65,7 @@
 
     private static final String BASE_RESOURCE_PATH = "META-INF/resources";
     private boolean cacheTimestamp;
+ private ZipDirectoryEntryScanner libraryScanner;
 
 
     // ------------------------------------------------------------ Constructors
@@ -73,6 +75,7 @@
 
         WebConfiguration webconfig = WebConfiguration.getInstance();
         cacheTimestamp = webconfig.isOptionEnabled(CacheResourceModificationTimestamp);
+ libraryScanner = new ZipDirectoryEntryScanner();
 
     }
 
@@ -149,7 +152,13 @@
             // try using this class' loader (necessary when running in OSGi)
             basePathURL = this.getClass().getClassLoader().getResource(basePath);
             if (basePathURL == null) {
- return null;
+ // This does not work on GlassFish 3.1 due to GLASSFISH-16229.
+ Set<String> resourcePaths = ctx.getExternalContext().getResourcePaths("/" + libraryName + "/");
+ if (null == resourcePaths || resourcePaths.isEmpty()) {
+ if (!libraryScanner.libraryExists(libraryName)) {
+ return null;
+ }
+ }
             }
         }
 
@@ -157,7 +166,6 @@
         
     }
 
-
     /**
      * @see ResourceHelper#findResource(LibraryInfo, String, String, boolean, javax.faces.context.FacesContext)
      */
Index: jsf-ri/src/main/java/com/sun/faces/config/JavaClassScanningAnnotationScanner.java
===================================================================
--- jsf-ri/src/main/java/com/sun/faces/config/JavaClassScanningAnnotationScanner.java (revision 8930)
+++ jsf-ri/src/main/java/com/sun/faces/config/JavaClassScanningAnnotationScanner.java (working copy)
@@ -76,7 +76,7 @@
  * <li>javax.faces.event.NamedEvent</li>
  * </ul>
  */
-class JavaClassScanningAnnotationScanner extends AnnotationScanner {
+public class JavaClassScanningAnnotationScanner extends AnnotationScanner {
 
     private static final Logger LOGGER = FacesLogger.CONFIG.getLogger();
 
Index: jsf-ri/systest/src/com/sun/faces/systest/composite/JarPackagedCompositeComponentTestCase.java
===================================================================
--- jsf-ri/systest/src/com/sun/faces/systest/composite/JarPackagedCompositeComponentTestCase.java (revision 8930)
+++ jsf-ri/systest/src/com/sun/faces/systest/composite/JarPackagedCompositeComponentTestCase.java (working copy)
@@ -1,67 +0,0 @@
-
-/*
- * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
- *
- * Copyright (c) 1997-2010 Oracle and/or its affiliates. All rights reserved.
- *
- * The contents of this file are subject to the terms of either the GNU
- * General Public License Version 2 only ("GPL") or the Common Development
- * and Distribution License("CDDL") (collectively, the "License"). You
- * may not use this file except in compliance with the License. You can
- * obtain a copy of the License at
- * https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
- * or packager/legal/LICENSE.txt. See the License for the specific
- * language governing permissions and limitations under the License.
- *
- * When distributing the software, include this License Header Notice in each
- * file and include the License file at packager/legal/LICENSE.txt.
- *
- * GPL Classpath Exception:
- * Oracle designates this particular file as subject to the "Classpath"
- * exception as provided by Oracle in the GPL Version 2 section of the License
- * file that accompanied this code.
- *
- * Modifications:
- * If applicable, add the following below the License Header, with the fields
- * enclosed by brackets [] replaced by your own identifying information:
- * "Portions Copyright [year] [name of copyright owner]"
- *
- * Contributor(s):
- * If you wish your version of this file to be governed by only the CDDL or
- * only the GPL Version 2, indicate your decision by adding "[Contributor]
- * elects to include this software in this distribution under the [CDDL or GPL
- * Version 2] license." If you don't indicate a single choice of license, a
- * recipient has the option to distribute your version of this file under
- * either the CDDL, the GPL Version 2 or to extend the choice of license to
- * its licensees as provided above. However, if you add GPL Version 2 code
- * and therefore, elected the GPL Version 2 license, then the option applies
- * only if the new code is made subject to such option by the copyright
- * holder.
- */
-
-package com.sun.faces.systest.composite;
-
-import com.gargoylesoftware.htmlunit.html.HtmlPage;
-import com.sun.faces.htmlunit.HtmlUnitFacesTestCase;
-import junit.framework.Test;
-import junit.framework.TestSuite;
-
-
-
-public class JarPackagedCompositeComponentTestCase extends HtmlUnitFacesTestCase {
-
-
- public JarPackagedCompositeComponentTestCase(String name) {
- super(name);
- }
-
- public static Test suite() {
- return (new TestSuite(JarPackagedCompositeComponentTestCase.class));
- }
-
- public void test01() throws Exception {
-
- HtmlPage page = getPage("/faces/composite/i_jsf_1856-using.xhtml");
- assertTrue(page.asXml().matches("(?s).*<.*input.*value=.attribute\\s*value.*/>.*"));
- }
-}
Index: jsf-ri/systest/web/composite/i_jsf_1856-using.xhtml
===================================================================
--- jsf-ri/systest/web/composite/i_jsf_1856-using.xhtml (revision 8930)
+++ jsf-ri/systest/web/composite/i_jsf_1856-using.xhtml (working copy)
@@ -1,10 +0,0 @@
-<?xml version='1.0' encoding='UTF-8' ?>
-<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
-"http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
-<html xmlns="http://www.w3.org/1999/xhtml"
- xmlns:h="http://java.sun.com/jsf/html"
- xmlns:ez="http://java.sun.com/jsf/composite/i_jsf_1856">
-
- <ez:i_jsf_1856 id="mycc" value="attribute value" />
-
-</html>
Index: jsf-ri/systest/web/WEB-INF/lib/i_jsf_1856.jar
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Index: jsf-test/JAVASERVERFACES-1856/i_jsf_1856/src/main/webapp/WEB-INF/faces-config.xml
===================================================================
Index: jsf-test/JAVASERVERFACES-1856/i_jsf_1856/src/main/webapp/WEB-INF/lib/i_jsf_1856.jar
===================================================================
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Index: jsf-test/JAVASERVERFACES-1856/i_jsf_1856/pom.xml
===================================================================
--- jsf-test/JAVASERVERFACES-1856/i_jsf_1856/pom.xml (revision 0)
+++ jsf-test/JAVASERVERFACES-1856/i_jsf_1856/pom.xml (revision 0)
@@ -0,0 +1,60 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
+ <modelVersion>4.0.0</modelVersion>
+ <groupId>com.sun.faces.test</groupId>
+ <artifactId>i_jsf_1856</artifactId>
+ <packaging>war</packaging>
+ <name>i_jsf_1856</name>
+ <version>0.0.2</version>
+
+ <description></description>
+
+ <properties>
+
+ </properties>
+
+ <dependencies>
+
+ <dependency>
+ <groupId>javax</groupId>
+ <artifactId>javaee-api</artifactId>
+ <version>6.0</version>
+ <scope>provided</scope>
+ </dependency>
+
+ </dependencies>
+
+ <build>
+ <plugins>
+ <plugin>
+ <groupId>org.apache.maven.plugins</groupId>
+ <artifactId>maven-compiler-plugin</artifactId>
+ <version>2.0.2</version>
+ <configuration>
+ <source>1.6</source>
+ <target>1.6</target>
+ </configuration>
+ </plugin>
+ <plugin>
+ <artifactId>maven-war-plugin</artifactId>
+ <groupId>org.apache.maven.plugins</groupId>
+ <version>2.1-alpha-2</version>
+ <configuration>
+ <failOnMissingWebXml>false</failOnMissingWebXml>
+ </configuration>
+ </plugin>
+
+ </plugins>
+ <finalName>i_jsf_1856</finalName>
+ </build>
+
+ <repositories>
+ <repository>
+ <id>java.net</id>
+ <name>java.net</name>
+ <url>http://download.java.net/maven/2</url>
+ <layout>default</layout>
+ </repository>
+ </repositories>
+
+</project>
Index: jsf-test/JAVASERVERFACES-1856/build.xml
===================================================================
--- jsf-test/JAVASERVERFACES-1856/build.xml (revision 0)
+++ jsf-test/JAVASERVERFACES-1856/build.xml (revision 0)
@@ -0,0 +1,90 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<!--
+
+ DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
+
+ Copyright (c) 1997-2010 Oracle and/or its affiliates. All rights reserved.
+
+ The contents of this file are subject to the terms of either the GNU
+ General Public License Version 2 only ("GPL") or the Common Development
+ and Distribution License("CDDL") (collectively, the "License"). You
+ may not use this file except in compliance with the License. You can
+ obtain a copy of the License at
+ https://glassfish.dev.java.net/public/CDDL+GPL_1_1.html
+ or packager/legal/LICENSE.txt. See the License for the specific
+ language governing permissions and limitations under the License.
+
+ When distributing the software, include this License Header Notice in each
+ file and include the License file at packager/legal/LICENSE.txt.
+
+ GPL Classpath Exception:
+ Oracle designates this particular file as subject to the "Classpath"
+ exception as provided by Oracle in the GPL Version 2 section of the License
+ file that accompanied this code.
+
+ Modifications:
+ If applicable, add the following below the License Header, with the fields
+ enclosed by brackets [] replaced by your own identifying information:
+ "Portions Copyright [year] [name of copyright owner]"
+
+ Contributor(s):
+ If you wish your version of this file to be governed by only the CDDL or
+ only the GPL Version 2, indicate your decision by adding "[Contributor]
+ elects to include this software in this distribution under the [CDDL or GPL
+ Version 2] license." If you don't indicate a single choice of license, a
+ recipient has the option to distribute your version of this file under
+ either the CDDL, the GPL Version 2 or to extend the choice of license to
+ its licensees as provided above. However, if you add GPL Version 2 code
+ and therefore, elected the GPL Version 2 license, then the option applies
+ only if the new code is made subject to such option by the copyright
+ holder.
+
+-->
+
+<!-- ************ JSF build file ************************************** -->
+
+<project name="GLASSFISH-11636" default="test" basedir=".">
+
+ <property file="../../build.properties"/>
+
+ <import file="${jsf.build.home}/common/ant/common.xml"/>
+
+ <target name="build">
+
+ <jsf.mvn dir="${basedir}/i_jsf_1856" goals="install" />
+
+ </target>
+
+ <target name="clean">
+
+ <jsf.mvn dir="${basedir}/i_jsf_1856" goals="clean" />
+
+ </target>
+
+ <target name="install">
+ <deploy.artifact
+ artifact="${basedir}/i_jsf_1856/target/i_jsf_1856.war"
+ appName="i_jsf_1856"/>
+
+ </target>
+
+ <target name="remove">
+
+ <undeploy.artifact
+ artifact="${basedir}/i_jsf_1856/target/i_jsf_1856.war"
+ appName="i_jsf_1856"/>
+
+ </target>
+
+ <target name="test" depends="define.scenario.aware.port">
+
+ <jsf.tester request="/faces/i_jsf_1856-using.xhtml"
+ context-path="/i_jsf_1856"
+ classpath-refid="html.classpath"
+ test-results-dir="${regression.test.results.dir}"
+ regexp="(?s).*..*input.*value=.attribute\s*value.*/..*"/>
+ </target>
+
+
+
+</project>
Index: jsf-test/build.xml
===================================================================
--- jsf-test/build.xml (revision 8930)
+++ jsf-test/build.xml (working copy)
@@ -51,15 +51,17 @@
 
     <property name="deploy-exploded-applications" value="" />
 
- <property name="applications-for-V3-only" value="" />
+ <property name="applications-for-V3-only" value="JAVASERVERFACES-1856" />
 
     <property name="applications-for-V3.1-only"
               value="GLASSFISH-11636,
- GLASSFISH-15985" />
+ GLASSFISH-15985,
+ JAVASERVERFACES-1856" />
 
     <property name="applications-for-V3.1_no_cluster-only"
               value="GLASSFISH-11636,
- GLASSFISH-15985" />
+ GLASSFISH-15985,
+ JAVASERVERFACES-1856" />
 
     <property name="container-agnostic-applications" value="" />

-- 
| edward.burns_at_oracle.com | office: +1 407 458 0017
| homepage:               | http://ridingthecrest.com/