dev@javaserverfaces.java.net

Seeking Review: JAVASERVERFACES-1835: Leverage GlassFish annotation scanning

From: <edward.burns_at_oracle.com>
Date: Fri, 10 Dec 2010 07:08:24 +0000 (GMT)

Leverage GlassFish 3.1 Annotation Scanning, if available
http://java.net/jira/browse/JAVASERVERFACES-1835


SECTION: Modified Files
----------------------------
M
jsf-ri/src/main/java/com/sun/faces/spi/InjectionProviderFactory.java
M
jsf-ri/src/main/java/com/sun/faces/vendor/WebContainerInjectionProvider
.java

- make NoOpInjectionProvider and WebContainerInjectionProvider
implement
  AnnotationScanner

M
jsf-ri/src/main/java/com/sun/faces/spi/AnnotationProviderFactory.java

- change default annotation scanner to be
  DelegateToGlassFishAnnotationScanner. If not found, use
  JavaClassScanningAnnotationScanner

M jsf-ri/src/main/java/com/sun/faces/spi/InjectionProvider.java

- remove newly added methods getAnnotatedClassesInCurrentModule().
  Moved to new interfaces AnnotationScanner.

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

- This one is a biggie.

- Make it so the InjectionProvider instance is available in the
  init-time FacesContext attributes scope.

- Make it so the InjectionProvider is instantiated before annotation
  scanning needs to happen.

- Modify the AnnotationScanTask to be able to leverage the
  InjectionProvider as an AnnotationScanner.

M
jsf-ri/src/main/java/com/sun/faces/application/ApplicationAssociate.jav
a

- Used to be this class caused the InjectionProvider to be
instantiated.
  No more. That happens in ConfigManager. This class now uses the
init
  time FacesContext attributes scope to obtain a reference to the
  InjectionProvider.

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

- This is now the abstract base class for both of the following two
classes.

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

- Handle the annotation scanning inside Mojarra

A
jsf-ri/src/main/java/com/sun/faces/config/DelegateToGlassFishAnnotation
Scanner.java

- Delegate to GlassFish for annotation scanning

A jsf-ri/src/main/java/com/sun/faces/spi/AnnotationScanner.java

- host to the getAnnotatedClassesInCurrentModule() method.


SECTION: Diffs
----------------------------
Index: jsf-ri/src/main/java/com/sun/faces/spi/AnnotationScanner.java
===================================================================
--- jsf-ri/src/main/java/com/sun/faces/spi/AnnotationScanner.java
(revision 0)
+++ jsf-ri/src/main/java/com/sun/faces/spi/AnnotationScanner.java
(revision 0)
@@ -0,0 +1,65 @@
+/*
+ * 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.spi;
+
+import java.net.URI;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+
+import javax.servlet.ServletContext;
+
+/**
+ *
+ */
+public interface AnnotationScanner {
+
+ public abstract Map<String, List<ScannedAnnotation>>
getAnnotatedClassesInCurrentModule(ServletContext extContext)
+ throws InjectionProviderException;
+
+ public interface ScannedAnnotation {
+
+ public Collection<URI> getDefiningURIs();
+
+ public String getFullyQualifiedClassName();
+
+ }
+}
Index:
jsf-ri/src/main/java/com/sun/faces/spi/InjectionProviderFactory.java
===================================================================
---
jsf-ri/src/main/java/com/sun/faces/spi/InjectionProviderFactory.java   
    (revision 8751)
+++
jsf-ri/src/main/java/com/sun/faces/spi/InjectionProviderFactory.java   
    (working copy)
@@ -44,14 +44,12 @@
 import java.io.InputStream;
 import java.io.InputStreamReader;
 import java.io.IOException;
-import java.lang.annotation.Annotation;
 import java.lang.reflect.Constructor;
 import java.lang.reflect.InvocationTargetException;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Enumeration;
 import java.util.Map;
-import java.util.Set;
 import java.util.logging.Level;
 import java.util.logging.Logger;
 import java.net.URL;
@@ -429,7 +427,7 @@
      * be used when the #INJECTION_PROVIDER_PROPERTY is not specified
or
      * is invalid.</p>
      */
-    private static final class NoopInjectionProvider implements
InjectionProvider {
+    private static final class NoopInjectionProvider implements
InjectionProvider, AnnotationScanner {
 
	 /**
	  * <p>This is a no-op.</p>
@@ -437,7 +435,7 @@
	  */
	 public void inject(Object managedBean) { }
 
-	 public Map<Class<? extends Annotation>, Set<Class<?>>>
getAnnotatedClassesInCurrentModule() throws InjectionProviderException
{
+	 public Map<String, List<AnnotationScanner.ScannedAnnotation>>
getAnnotatedClassesInCurrentModule(ServletContext extContext) throws
InjectionProviderException {
	     return Collections.emptyMap();
	 }
 
Index:
jsf-ri/src/main/java/com/sun/faces/spi/AnnotationProviderFactory.java
===================================================================
---
jsf-ri/src/main/java/com/sun/faces/spi/AnnotationProviderFactory.java  
    (revision 8751)
+++
jsf-ri/src/main/java/com/sun/faces/spi/AnnotationProviderFactory.java  
    (working copy)
@@ -40,6 +40,7 @@
 
 package com.sun.faces.spi;
 
+import com.sun.faces.config.DelegateToGlassFishAnnotationScanner;
 import com.sun.faces.config.JavaClassScanningAnnotationScanner;
 
 import javax.servlet.ServletContext;
@@ -53,6 +54,8 @@
 
     private static final Class<? extends AnnotationProvider>
DEFAULT_ANNOTATION_PROVIDER =
	JavaClassScanningAnnotationScanner.class;
+    private static final Class<? extends AnnotationProvider>
GLASSFISH31_ANNOTATION_PROVIDER =
+	DelegateToGlassFishAnnotationScanner.class;
 
     private static final String ANNOTATION_PROVIDER_SERVICE_KEY =
	  "com.sun.faces.spi.annotationprovider";
@@ -89,13 +92,20 @@
 
 
     private static AnnotationProvider
createDefaultProvider(ServletContext sc) {
+	 AnnotationProvider result = null;
+	 Constructor c;
 
	 try {
-	     Constructor c =
DEFAULT_ANNOTATION_PROVIDER.getDeclaredConstructor(new Class<?>[] {
ServletContext.class });
-	     return (AnnotationProvider) c.newInstance(sc);
+	     c =
GLASSFISH31_ANNOTATION_PROVIDER.getDeclaredConstructor(new Class<?>[] {
ServletContext.class });
+	     result = (AnnotationProvider) c.newInstance(sc);
	 } catch (Exception e) {
-	     throw new FacesException(e);
+	     try {
+		 c =
DEFAULT_ANNOTATION_PROVIDER.getDeclaredConstructor(new Class<?>[] {
ServletContext.class });
+		 result = (AnnotationProvider) c.newInstance(sc);
+	     } catch (Exception e2) {
+		 throw new FacesException(e2);
+	     }
	 }
-
+	 return result;
     }
 }
Index: jsf-ri/src/main/java/com/sun/faces/spi/InjectionProvider.java
===================================================================
--- jsf-ri/src/main/java/com/sun/faces/spi/InjectionProvider.java      
(revision 8751)
+++ jsf-ri/src/main/java/com/sun/faces/spi/InjectionProvider.java      
(working copy)
@@ -96,6 +96,4 @@
     public void invokePostConstruct(Object managedBean) 
     throws InjectionProviderException;
     
-    public abstract Map<Class<? extends Annotation>, Set<Class<?>>>
getAnnotatedClassesInCurrentModule()
-    throws InjectionProviderException;
 }
Index:
jsf-ri/src/main/java/com/sun/faces/vendor/WebContainerInjectionProvider
.java
===================================================================
---
jsf-ri/src/main/java/com/sun/faces/vendor/WebContainerInjectionProvider
.java	     (revision 8751)
+++
jsf-ri/src/main/java/com/sun/faces/vendor/WebContainerInjectionProvider
.java	     (working copy)
@@ -40,11 +40,11 @@
 
 package com.sun.faces.vendor;
 
+import com.sun.faces.spi.AnnotationScanner;
 import com.sun.faces.spi.InjectionProvider;
 import com.sun.faces.spi.InjectionProviderException;
 import com.sun.faces.util.FacesLogger;
 import java.util.Map;
-import java.util.Set;
 
 import javax.annotation.PreDestroy;
 import javax.annotation.PostConstruct;
@@ -52,8 +52,10 @@
 import java.lang.reflect.Modifier;
 import java.lang.annotation.Annotation;
 import java.util.Collections;
+import java.util.List;
 import java.util.logging.Logger;
 import java.util.logging.Level;
+import javax.servlet.ServletContext;
 
 /**
  * <p>This <code>InjectionProvider</code> will be used if the
@@ -63,7 +65,7 @@
  *
  * <p>It's important to note that this will not provide resource
injection.</p>
  */
-public class WebContainerInjectionProvider implements
InjectionProvider {
+public class WebContainerInjectionProvider implements
InjectionProvider, AnnotationScanner {
 
 
     private static final Logger LOGGER =
FacesLogger.APPLICATION.getLogger();
@@ -78,7 +80,7 @@
 
     }
 
-    public Map<Class<? extends Annotation>, Set<Class<?>>>
getAnnotatedClassesInCurrentModule() throws InjectionProviderException
{
+    public Map<String, List<AnnotationScanner.ScannedAnnotation>>
getAnnotatedClassesInCurrentModule(ServletContext sc) throws
InjectionProviderException {
	 return Collections.emptyMap();
     }
 
Index:
jsf-ri/src/main/java/com/sun/faces/application/ApplicationAssociate.jav
a
===================================================================
---
jsf-ri/src/main/java/com/sun/faces/application/ApplicationAssociate.jav
a    (revision 8751)
+++
jsf-ri/src/main/java/com/sun/faces/application/ApplicationAssociate.jav
a    (working copy)
@@ -41,11 +41,11 @@
 package com.sun.faces.application;
 
 import com.sun.faces.RIConstants;
-import com.sun.faces.application.ApplicationStateInfo;
 import com.sun.faces.scripting.groovy.GroovyHelper;
 import com.sun.faces.application.resource.ResourceCache;
 import com.sun.faces.application.resource.ResourceManager;
 import com.sun.faces.application.annotation.AnnotationManager;
+import com.sun.faces.config.ConfigManager;
 import com.sun.faces.config.WebConfiguration;
 import com.sun.faces.facelets.compiler.Compiler;
 import com.sun.faces.facelets.compiler.SAXCompiler;
@@ -62,12 +62,10 @@
 import com.sun.faces.facelets.util.DevTools;
 import javax.faces.view.facelets.ResourceResolver;
 import javax.faces.view.facelets.FaceletCache;
-import javax.faces.view.facelets.FaceletCacheFactory;
 import com.sun.faces.facelets.impl.DefaultResourceResolver;
 import com.sun.faces.facelets.impl.DefaultFaceletFactory;
 import com.sun.faces.mgbean.BeanManager;
 import com.sun.faces.spi.InjectionProvider;
-import com.sun.faces.spi.InjectionProviderFactory;
 import com.sun.faces.util.MessageUtils;
 import com.sun.faces.util.Util;
 import com.sun.faces.util.FacesLogger;
@@ -210,7 +208,7 @@
	 externalContext.getApplicationMap().put(ASSOCIATE_KEY, this);
	 //noinspection CollectionWithoutInitialCapacity
	 navigationMap = new ConcurrentHashMap<String,
Set<NavigationCase>>();
-	 injectionProvider =
InjectionProviderFactory.createInstance(externalContext);
+	 injectionProvider = (InjectionProvider)
ctx.getAttributes().get(ConfigManager.INJECTION_PROVIDER_KEY);
	 WebConfiguration webConfig =
WebConfiguration.getInstance(externalContext);
	 beanManager = new BeanManager(injectionProvider,
				       webConfig.isOptionEnabled(
Index: jsf-ri/src/main/java/com/sun/faces/config/ConfigManager.java
===================================================================
--- jsf-ri/src/main/java/com/sun/faces/config/ConfigManager.java       
(revision 8751)
+++ jsf-ri/src/main/java/com/sun/faces/config/ConfigManager.java       
(working copy)
@@ -67,6 +67,8 @@
 import com.sun.faces.config.processor.ValidatorConfigProcessor;
 import com.sun.faces.config.processor.FaceletTaglibConfigProcessor;
 import com.sun.faces.config.processor.FacesConfigExtensionProcessor;
+import com.sun.faces.spi.InjectionProvider;
+import com.sun.faces.spi.InjectionProviderFactory;
 import com.sun.faces.util.FacesLogger;
 import com.sun.faces.util.Timer;
 import org.xml.sax.InputSource;
@@ -174,6 +176,14 @@
 
 
     /**
+     * The initialization time FacesContext scoped key under which the
+     * InjectionProvider is stored.
+     */
+    public static final String INJECTION_PROVIDER_KEY =
+	   ConfigManager.class.getName() + "_INJECTION_PROVIDER_TASK";
+
+
+    /**
      * Name of the attribute added by {_at_link ParseTask} to indiciate a
      * {_at_link Document} instance as a representation of
      * <code>/WEB-INF/faces-config.xml</code>.
@@ -318,19 +328,24 @@
		       new
FacesConfigInfo(facesDocuments[facesDocuments.length - 1]);
 
		 facesDocuments = sortDocuments(facesDocuments,
webInfFacesConfigInfo);
+		 FacesContext context =
FacesContext.getCurrentInstance();
 
+		 InjectionProvider containerConnector =
+			
InjectionProviderFactory.createInstance(context.getExternalContext());
+		 context.getAttributes().put(INJECTION_PROVIDER_KEY,
containerConnector);
+
		 boolean isFaceletsDisabled =
		       isFaceletsDisabled(webConfig,
webInfFacesConfigInfo);
		 if (!webInfFacesConfigInfo.isWebInfFacesConfig() ||
!webInfFacesConfigInfo.isMetadataComplete()) {
		     // execute the Task responsible for finding
annotation classes
-		     FacesConfigDocumentUrlGetter urlGetter = new
FacesConfigDocumentUrlGetter(facesDocuments);
+		     ProvideMetadataToAnnotationScanTask taskMetadata =
new ProvideMetadataToAnnotationScanTask(facesDocuments,
containerConnector);
		     Future<Map<Class<? extends
Annotation>,Set<Class<?>>>> annotationScan;
		     if (executor != null) {
-			 annotationScan = executor.submit(new
AnnotationScanTask(sc, urlGetter));
+			 annotationScan = executor.submit(new
AnnotationScanTask(sc, taskMetadata));
			 pushTaskToContext(sc, annotationScan);
		     } else {
			 annotationScan =
-			       new FutureTask<Map<Class<? extends
Annotation>,Set<Class<?>>>>(new AnnotationScanTask(sc, urlGetter));
+			       new FutureTask<Map<Class<? extends
Annotation>,Set<Class<?>>>>(new AnnotationScanTask(sc, taskMetadata));
			 ((FutureTask) annotationScan).run();
		     }
		     pushTaskToContext(sc, annotationScan);
@@ -713,32 +728,61 @@
 
     // -----------------------------------------------------------
Inner Classes
 
-    private static final class FacesConfigDocumentUrlGetter {
+    private static final class ProvideMetadataToAnnotationScanTask {
	 DocumentInfo [] documentInfos;
-	 public FacesConfigDocumentUrlGetter(DocumentInfo []
documentInfos) {
+	 InjectionProvider containerConnector;
+	 Set<URI> uris = null;
+	 Set<String> jarNames = null;
+
+	 private ProvideMetadataToAnnotationScanTask(DocumentInfo []
documentInfos,
+		 InjectionProvider containerConnector) {
	     this.documentInfos = documentInfos;
+	     this.containerConnector = containerConnector;
	 }
 
-	 private Set<URI> getAnnotationScanURLs() {
-	     Set<URI> urls = new HashSet<URI>(documentInfos.length);
-	     Set<String> jarNames = new
HashSet<String>(documentInfos.length);
+	 private void initializeIvars() {
+	     if (null != uris || null != jarNames) {
+		 assert(null != uris && null != jarNames);
+		 return;
+	     }
+	     uris = new HashSet<URI>(documentInfos.length);
+	     jarNames = new HashSet<String>(documentInfos.length);
	     for (DocumentInfo docInfo : documentInfos) {
-		 Matcher m =
JAR_PATTERN.matcher(docInfo.getSourceURI().toString());
+		 URI sourceURI = docInfo.getSourceURI();
+		 Matcher m = JAR_PATTERN.matcher(sourceURI.toString());
		 if (m.matches()) {
		     String jarName = m.group(2);
		     if (!jarNames.contains(jarName)) {
			 FacesConfigInfo configInfo = new
FacesConfigInfo(docInfo);
			 if (!configInfo.isMetadataComplete()) {
-			     urls.add(docInfo.getSourceURI());
+			     uris.add(sourceURI);
			     jarNames.add(jarName);
			 }
		     }
		 }
-	      }
+	     }
+	 }
 
-	     return urls;
+	 private Set<URI> getAnnotationScanURIs() {
+	     initializeIvars();
 
+	     return uris;
+
	 }
+
+	 private Set<String> getJarNames() {
+	     initializeIvars();
+
+	     return jarNames;
+	 }
+
+	 private com.sun.faces.spi.AnnotationScanner
getAnnotationScanner() {
+	     com.sun.faces.spi.AnnotationScanner result = null;
+	     if (this.containerConnector instanceof
com.sun.faces.spi.AnnotationScanner) {
+		 result = (com.sun.faces.spi.AnnotationScanner)
this.containerConnector;
+	     }
+	     return result;
+	 }
     }
 
 
@@ -750,16 +794,16 @@
 
	 private ServletContext sc;
	 AnnotationProvider provider;
-	 FacesConfigDocumentUrlGetter urlGetter;
+	 ProvideMetadataToAnnotationScanTask metadataGetter;
 
	 // --------------------------------------------------------
Constructors
 
 
-	 public AnnotationScanTask(ServletContext sc,
FacesConfigDocumentUrlGetter urlGetter) {
+	 public AnnotationScanTask(ServletContext sc,
ProvideMetadataToAnnotationScanTask metadataGetter) {
 
	     this.sc = sc;
	     this.provider =
AnnotationProviderFactory.createAnnotationProvider(sc);
-	     this.urlGetter = urlGetter;
+	     this.metadataGetter = metadataGetter;
 
	 }
 
@@ -773,8 +817,19 @@
	     if (t != null) {
		 t.startTiming();
	     }
-	     Set<URI> scanUris = urlGetter.getAnnotationScanURLs();
 
+	     Set<URI> scanUris = null;
+	     com.sun.faces.spi.AnnotationScanner annotationScanner =
+		     metadataGetter.getAnnotationScanner();
+
+	     if (provider instanceof
DelegateToGlassFishAnnotationScanner &&
+		 null != annotationScanner) {
+		
((DelegateToGlassFishAnnotationScanner)provider).setAnnotationScanner(a
nnotationScanner,
+			 metadataGetter.getJarNames());
+		 scanUris = Collections.emptySet();
+	     } else {
+		 scanUris = metadataGetter.getAnnotationScanURIs();
+	     }
	     //AnnotationScanner scanner = new AnnotationScanner(sc);
	     Map<Class<? extends Annotation>,Set<Class<?>>>
annotatedClasses =
		   provider.getAnnotatedClasses(scanUris);
Index: jsf-ri/src/main/java/com/sun/faces/config/AnnotationScanner.java
===================================================================
--- jsf-ri/src/main/java/com/sun/faces/config/AnnotationScanner.java   
(revision 8751)
+++ jsf-ri/src/main/java/com/sun/faces/config/AnnotationScanner.java   
(working copy)
@@ -40,6 +40,13 @@
 
 package com.sun.faces.config;
 
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
 import com.sun.faces.scripting.ScriptManager;
 import com.sun.faces.scripting.groovy.GroovyHelper;
 import com.sun.faces.scripting.groovy.GroovyScriptManager;
@@ -58,10 +65,9 @@
 import javax.faces.validator.FacesValidator;
 import javax.servlet.ServletContext;
 import java.lang.annotation.Annotation;
-import java.net.URI;
-import java.util.*;
 import java.util.logging.Level;
 import java.util.logging.Logger;
+import static
com.sun.faces.config.WebConfiguration.WebContextInitParameter.Annotatio
nScanPackages;
 
 
 /**
@@ -79,16 +85,29 @@
  *  <li>javax.faces.event.NamedEvent</li>
  * </ul>
  */
-public class AnnotationScanner extends AnnotationProvider {
+public abstract class AnnotationScanner extends AnnotationProvider {
 
+
+    // <editor-fold defaultstate="collapsed" desc="data">
+
+    // <editor-fold defaultstate="collapsed" desc="private class
vars">
+
     private static final Logger LOGGER =
FacesLogger.CONFIG.getLogger();
+    private static final String WILDCARD = "*";
+    
+    // </editor-fold>
 
+    // <editor-fold defaultstate="collapsed" desc="protected class
vars">
 
     protected static final Set<String> FACES_ANNOTATIONS;
     protected static final Set<Class<? extends Annotation>>
FACES_ANNOTATION_TYPE;
 
+    // </editor-fold>
+
     static {
	 HashSet<String> annotations = new HashSet<String>(8, 1.0f);
+	 // JAVASERVERFACES-1835 this collection has the same
information twice.
+	 // Once in javap -s format, and once as fully qualified Java
class names.
	 Collections.addAll(annotations,
			    "Ljavax/faces/component/FacesComponent;",
			    "Ljavax/faces/convert/FacesConverter;",
@@ -97,7 +116,15 @@
			    "Ljavax/faces/bean/ManagedBean;",
			    "Ljavax/faces/event/NamedEvent;",
			   
"Ljavax/faces/component/behavior/FacesBehavior;",
-			   
"Ljavax/faces/render/FacesBehaviorRenderer;");
+			   
"Ljavax/faces/render/FacesBehaviorRenderer;",
+			    "javax.faces.component.FacesComponent",
+			    "javax.faces.convert.FacesConverter",
+			    "javax.faces.validator.FacesValidator",
+			    "javax.faces.render.FacesRenderer",
+			    "javax.faces.bean.ManagedBean",
+			    "javax.faces.event.NamedEvent",
+			   
"javax.faces.component.behavior.FacesBehavior",
+			   
"javax.faces.render.FacesBehaviorRenderer");
	 FACES_ANNOTATIONS = Collections.unmodifiableSet(annotations);
	 HashSet<Class<? extends Annotation>> annotationInstances =
	       new HashSet<Class<? extends Annotation>>(8, 1.0f);
@@ -114,10 +141,15 @@
     }
 
     private List<ScriptManager> scriptManagers = new
ArrayList<ScriptManager>();
+    private boolean isAnnotationScanPackagesSet = false;
+    private String[] webInfClassesPackages;
+    private Map<String,String[]> classpathPackages;
 
-    // ------------------------------------------------------------
Constructors
 
+    // </editor-fold>
 
+    // <editor-fold defaultstate="collapsed" desc="constructors">
+
     /**
      * Creates a new <code>AnnotationScanner</code> instance.
      *
@@ -132,32 +164,138 @@
	 }
 
	 WebConfiguration webConfig = WebConfiguration.getInstance(sc);
+	initializeAnnotationScanPackages(webConfig);
 
     }
 
+    // </editor-fold>
 
-    // ----------------------------------------------------------
Public Methods
+    // <editor-fold defaultstate="collapsed" desc="implementation
details">
 
+    private void initializeAnnotationScanPackages(WebConfiguration
webConfig) {
+	 if (!webConfig.isSet(AnnotationScanPackages)) {
+	     return;
+	 }
+	 isAnnotationScanPackagesSet = true;
+	 classpathPackages = new HashMap<String,String[]>(4);
+	 webInfClassesPackages = new String[0];
+	 String[] options =
webConfig.getOptionValue(AnnotationScanPackages, "\\s+");
+	 List<String> packages = new ArrayList<String>(4);
+	 for (String option : options) {
+	     if (option.length() == 0) {
+		 continue;
+	     }
+	     if (option.startsWith("jar:")) {
+		 String[] parts = Util.split(option, ":");
+		 if (parts.length != 3) {
+		     if (LOGGER.isLoggable(Level.WARNING)) {
+			 LOGGER.log(Level.WARNING,
+				   
"jsf.annotation.scanner.configuration.invalid",
+				    new String[] {
AnnotationScanPackages.getQualifiedName(), option });
+		     }
+		 } else {
+		     if (WILDCARD.equals(parts[1]) &&
!classpathPackages.containsKey(WILDCARD)) {
+			 classpathPackages.clear();
+			 classpathPackages.put(WILDCARD,
normalizeJarPackages(Util.split(parts[2], ",")));
+		     } else if (WILDCARD.equals(parts[1]) &&
classpathPackages.containsKey(WILDCARD)) {
+			 if (LOGGER.isLoggable(Level.WARNING)) {
+			     LOGGER.log(Level.WARNING,
+				       
"jsf.annotation.scanner.configuration.duplicate.wildcard",
+					new String[] {
AnnotationScanPackages.getQualifiedName(), option });
+			 }
+		     } else {
+			 if (!classpathPackages.containsKey(WILDCARD))
{
+			     classpathPackages.put(parts[1],
normalizeJarPackages(Util.split(parts[2], ",")));
+			 }
+		     }
+		 }
+	     } else {
+		 if (WILDCARD.equals(option) &&
!packages.contains(WILDCARD)) {
+		     packages.clear();
+		     packages.add(WILDCARD);
+		 } else {
+		     if (!packages.contains(WILDCARD)) {
+			 packages.add(option);
+		     }
+		 }
+	     }
+	 }
+	 webInfClassesPackages = packages.toArray(new
String[packages.size()]);
+   }
 
+    private String[] normalizeJarPackages(String[] packages) {
+
+	 if (packages.length == 0) {
+	     return packages;
+	 }
+	 List<String> normalizedPackages = new
ArrayList<String>(packages.length);
+	 for (String pkg : packages) {
+	     if (WILDCARD.equals(pkg)) {
+		 normalizedPackages.clear();
+		 normalizedPackages.add(WILDCARD);
+		 break;
+	     } else {
+		 normalizedPackages.add(pkg);
+	     }
+	 }
+	 return normalizedPackages.toArray(new
String[normalizedPackages.size()]);
+
+    }
+
+    // </editor-fold>
+
+
+    // ---------------------------------------------------------
Protected Methods
+
+    protected boolean processJar(String entry) {
+
+	// <editor-fold defaultstate="collapsed">
+
+	 return (classpathPackages == null
+		   || (classpathPackages.containsKey(entry)
+			  || classpathPackages.containsKey(WILDCARD)));
+
+	// </editor-fold>
+
+    }
+
     /**
-     * @return a <code>Map</code> of classes mapped to a specific
annotation type.
-     *  If no annotations are present, or the application is
considered
-     * <code>metadata-complete</code> <code>null</code> will be
returned.
+     * @param candidate the class that should be processed
+     * @return <code>true</code> if the class should be processed
further,
+     *  otherwise, <code>false</code>
      */
-    public Map<Class<? extends Annotation>,Set<Class<?>>>
getAnnotatedClasses(Set<URI> uris) {
+    protected boolean processClass(String candidate) {
 
-	 Set<String> classList = new HashSet<String>();
+	// <editor-fold defaultstate="collapsed">
 
-	 processScripts(classList);
+	 return processClass(candidate, webInfClassesPackages);
 
-	 return processClassList(classList);
+	// </editor-fold>
+    }
 
+    protected boolean processClass(String candidate, String []
packages) {
+
+	// <editor-fold defaultstate="collapsed">
+
+	 if (packages == null) {
+	     return true;
+	 }
+
+	 for (String packageName : packages) {
+	     if (candidate.startsWith(packageName) ||
WILDCARD.equals(packageName)) {
+		 return true;
+	     }
+	 }
+	 return false;
+
+	// </editor-fold>
     }
 
 
-    // ---------------------------------------------------------
Protected Methods
+    protected Map<Class<? extends Annotation>,Set<Class<?>>>
processClassList(Set<String> classList) {
 
-    protected Map<Class<? extends Annotation>,Set<Class<?>>>
processClassList(Set<String> classList) {
+	// <editor-fold defaultstate="collapsed">
+
	 Map<Class<? extends Annotation>,Set<Class<?>>>
annotatedClasses = null;
	 if (classList.size() > 0) {
	     annotatedClasses = new HashMap<Class<? extends
Annotation>,Set<Class<?>>>(6, 1.0f);
@@ -199,12 +337,33 @@
	 return ((annotatedClasses != null)
		 ? annotatedClasses
		 : Collections.<Class<? extends Annotation>,
Set<Class<?>>>emptyMap());
+
+	// </editor-fold>
+
     }
 
     protected void processScripts(Set<String> classList) {
+
+	// <editor-fold defaultstate="collapsed">
+
	 for (ScriptManager sm : scriptManagers) {
	     classList.addAll(sm.getScripts());
	 }
+
+	// </editor-fold>
+
     }
 
+    protected boolean isAnnotationScanPackagesSet() {
+	 return isAnnotationScanPackagesSet;
+    }
+
+    protected Map<String,String[]> getClasspathPackages() {
+	 return classpathPackages;
+    }
+
+    protected String [] getWebInfClassesPackages() {
+	 return webInfClassesPackages;
+    }
+
 }
Index:
jsf-ri/src/main/java/com/sun/faces/config/DelegateToGlassFishAnnotation
Scanner.java
===================================================================
---
jsf-ri/src/main/java/com/sun/faces/config/DelegateToGlassFishAnnotation
Scanner.java (revision 0)
+++
jsf-ri/src/main/java/com/sun/faces/config/DelegateToGlassFishAnnotation
Scanner.java (revision 0)
@@ -0,0 +1,166 @@
+
+/*
+ * 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.config;
+
+import com.sun.faces.spi.InjectionProviderException;
+import com.sun.faces.util.FacesLogger;
+import static com.sun.faces.spi.AnnotationScanner.ScannedAnnotation;
+import java.lang.annotation.Annotation;
+import java.net.URI;
+import java.util.Collection;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import javax.servlet.ServletContext;
+
+
+
+public class DelegateToGlassFishAnnotationScanner extends
AnnotationScanner {
+
+    private static final Logger LOGGER =
FacesLogger.CONFIG.getLogger();
+
+
+    private com.sun.faces.spi.AnnotationScanner annotationScanner =
null;
+    Set<String> jarNamesWithoutMetadataComplete = null;
+
+    public DelegateToGlassFishAnnotationScanner(ServletContext sc) {
+	 super(sc);
+    }
+
+    public void
setAnnotationScanner(com.sun.faces.spi.AnnotationScanner
containerConnector, Set<String> jarNamesWithoutMetadataComplete) {
+	 this.annotationScanner = containerConnector;
+	 this.jarNamesWithoutMetadataComplete =
jarNamesWithoutMetadataComplete;
+    }
+
+    @Override
+    public Map<Class<? extends Annotation>,Set<Class<?>>>
getAnnotatedClasses(Set<URI> uris) {
+
+	 Set<String> classList = new HashSet<String>();
+
+	 processAnnotations(classList);
+	 processScripts(classList);
+
+	 return processClassList(classList);
+    }
+
+    private void processAnnotations(Set<String> classList) {
+	 try {
+	     Map<String, List<ScannedAnnotation>> classesByAnnotation =
annotationScanner.getAnnotatedClassesInCurrentModule(this.sc);
+
+	     for (String curAnnotationName :
classesByAnnotation.keySet()) {
+		 if (FACES_ANNOTATIONS.contains(curAnnotationName)) {
+		     for (ScannedAnnotation curAnnotation :
classesByAnnotation.get(curAnnotationName)) {
+			 Collection<URI> definingUris =
curAnnotation.getDefiningURIs();
+			 Iterator<URI> iter = definingUris.iterator();
+			 URI uri, jarUri = null;
+			 String uriString, nameOfJarInJarUri = null;
+			 boolean doAdd = false;
+			 while (!doAdd && iter.hasNext()) {
+			     uri = iter.next();
+			     uriString = uri.toASCIIString();
+
+			     if (uriString.endsWith("WEB-INF/classes")
|| uriString.endsWith("WEB-INF/classes/")) {
+				 doAdd = true;
+			     } else for (String jarName :
jarNamesWithoutMetadataComplete) {
+				 if (uriString.contains(jarName)) {
+				     doAdd = true;
+				     jarUri = uri;
+				     nameOfJarInJarUri = jarName;
+				     break;
+				 }
+			     }
+			 }
+			 if (doAdd) {
+			     // If the annotationScanPackages context
param is set, we
+			     // may yet have to exclude the class
+			     String fqcn =
curAnnotation.getFullyQualifiedClassName();
+			     if (isAnnotationScanPackagesSet()) {
+				 // If the class with the annotation
was found 
+				 // in a jar file
+				 if (null != jarUri) {
+				     // see if the jar file is in the
list of jars to include
+				     String [] allowedPackages =
+					     (getClasspathPackages() !=
null &&
+					     
getClasspathPackages().get(nameOfJarInJarUri) != null)
+					?
getClasspathPackages().get(nameOfJarInJarUri)
+					: new String [0];
+				     if (0 == allowedPackages.length) {
+					 doAdd = false;
+				     }
+				     for (String curPackage :
allowedPackages) {
+					 doAdd =
fqcn.contains(curPackage);
+					 if (doAdd) {
+					     break;
+					 }
+				     }
+				 } else {
+				     doAdd = processClass(fqcn);
+				 }
+
+			     }
+
+			     if (doAdd) {
+				 classList.add(fqcn);
+			     }
+			 }
+		     }
+		 }
+
+	     }
+	     
+	 } catch (InjectionProviderException ex) {
+	     if (LOGGER.isLoggable(Level.SEVERE)) {
+		 LOGGER.log(Level.SEVERE, "Unable to use GlassFish to
perform "
+			 + "annotation scanning.  Annotated artifacts
will not "
+			 + "be declared to runtime.", ex);
+	     }
+
+	 }
+	 
+    }
+    
+
+}
Index:
jsf-ri/src/main/java/com/sun/faces/config/JavaClassScanningAnnotationSc
anner.java
===================================================================
---
jsf-ri/src/main/java/com/sun/faces/config/JavaClassScanningAnnotationSc
anner.java   (revision 8751)
+++
jsf-ri/src/main/java/com/sun/faces/config/JavaClassScanningAnnotationSc
anner.java   (working copy)
@@ -42,7 +42,6 @@
 
 import java.net.URI;
 import com.sun.faces.util.FacesLogger;
-import com.sun.faces.util.Util;
 
 import javax.servlet.ServletContext;
 import java.io.IOException;
@@ -61,7 +60,6 @@
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 
-import static
com.sun.faces.config.WebConfiguration.WebContextInitParameter.Annotatio
nScanPackages;
 
 /**
  * This class is responsible for scanning the class file bytes of
@@ -87,11 +85,8 @@
     private static final Pattern JAR_PATTERN =
Pattern.compile("(.*/(\\S*\\.jar)).*");
 
     private static final String WEB_INF_CLASSES = "/WEB-INF/classes/";
-    private static final String WILDCARD = "*";
 
     private ClassFile classFileScanner;
-    private String[] webInfClassesPackages;
-    private Map<String,String[]> classpathPackages;
 
     // ------------------------------------------------------------
Constructors
 
@@ -107,53 +102,6 @@
 
	 classFileScanner = new ClassFile();
	 
-	 WebConfiguration webConfig = WebConfiguration.getInstance(sc);
-	 if (webConfig.isSet(AnnotationScanPackages)) {
-	     classpathPackages = new HashMap<String,String[]>(4);
-	     webInfClassesPackages = new String[0];
-	     String[] options =
webConfig.getOptionValue(AnnotationScanPackages, "\\s+");
-	     List<String> packages = new ArrayList<String>(4);
-	     for (String option : options) {
-		 if (option.length() == 0) {
-		     continue;
-		 }
-		 if (option.startsWith("jar:")) {
-		     String[] parts = Util.split(option, ":");
-		     if (parts.length != 3) {
-			 if (LOGGER.isLoggable(Level.WARNING)) {
-			     LOGGER.log(Level.WARNING,
-				       
"jsf.annotation.scanner.configuration.invalid",
-					new String[] {
AnnotationScanPackages.getQualifiedName(), option });
-			 }
-		     } else {
-			 if (WILDCARD.equals(parts[1]) &&
!classpathPackages.containsKey(WILDCARD)) {
-			     classpathPackages.clear();
-			     classpathPackages.put(WILDCARD,
normalizeJarPackages(Util.split(parts[2], ",")));
-			 } else if (WILDCARD.equals(parts[1]) &&
classpathPackages.containsKey(WILDCARD)) {
-			     if (LOGGER.isLoggable(Level.WARNING)) {
-				 LOGGER.log(Level.WARNING,
-					   
"jsf.annotation.scanner.configuration.duplicate.wildcard",
-					    new String[] {
AnnotationScanPackages.getQualifiedName(), option });
-			     }
-			 } else {
-			     if
(!classpathPackages.containsKey(WILDCARD)) {
-				 classpathPackages.put(parts[1],
normalizeJarPackages(Util.split(parts[2], ",")));
-			     }
-			 }
-		     }
-		 } else {
-		     if (WILDCARD.equals(option) &&
!packages.contains(WILDCARD)) {
-			 packages.clear();
-			 packages.add(WILDCARD);
-		     } else {
-			 if (!packages.contains(WILDCARD)) {
-			     packages.add(option);
-			 }
-		     }
-		 }
-	     }
-	     webInfClassesPackages = packages.toArray(new
String[packages.size()]);
-	 }
 
 
     }
@@ -217,8 +165,8 @@
		     JarFile jarFile =
			   ((JarURLConnection)
u.openConnection()).getJarFile();
		     processJarEntries(jarFile,
-				       ((classpathPackages != null)
-					?
classpathPackages.get(jarName)
+				       ((getClasspathPackages() !=
null)
+					?
getClasspathPackages().get(jarName)
					: null),
				       classList);
		 } else {
@@ -388,7 +336,7 @@
		     if (pathElement.endsWith(".class")) {
			 String cname =
convertToClassName(WEB_INF_CLASSES,
							      
pathElement);
-			 if (!processClass(cname,
webInfClassesPackages)) {
+			 if (!processClass(cname)) {
			     continue;
			 }
			 if (containsAnnotation(sc, pathElement)) {
@@ -407,26 +355,6 @@
     }
 
 
-    private String[] normalizeJarPackages(String[] packages) {
-
-	 if (packages.length == 0) {
-	     return packages;
-	 }
-	 List<String> normalizedPackages = new
ArrayList<String>(packages.length);
-	 for (String pkg : packages) {
-	     if (WILDCARD.equals(pkg)) {
-		 normalizedPackages.clear();
-		 normalizedPackages.add(WILDCARD);
-		 break;
-	     } else {
-		 normalizedPackages.add(pkg);
-	     }
-	 }
-	 return normalizedPackages.toArray(new
String[normalizedPackages.size()]);
-
-    }
-
-
     /**
      * @param sc the <code>ServletContext</code> for the application
being
      *  scanned
@@ -510,37 +438,8 @@
     }
 
 
-    private boolean processJar(String entry) {
 
-	 return (classpathPackages == null
-		   || (classpathPackages.containsKey(entry)
-			  || classpathPackages.containsKey(WILDCARD)));
 
-    }
-
-
-    /**
-     * @param candidate the class that should be processed
-     * @param packages the packages of classes that are allowed to be
processed
-     * @return <code>true</code> if the class should be processed
further,
-     *  otherwise, <code>false</code>
-     */
-    private boolean processClass(String candidate, String[] packages)
{
-
-	 if (packages == null) {
-	     return true;
-	 }
-
-	 for (String packageName : packages) {
-	     if (candidate.startsWith(packageName) ||
WILDCARD.equals(packageName)) {
-		 return true;
-	     }
-	 }
-	 return false;
-	 
-    }
-
-
     // -----------------------------------------------------------
Inner Classes
 
 
SECTION: New Files
----------------------------
SEE ATTACHMENTS