dev@javaserverfaces.java.net

Seeking Review: long standing bug in resource loading

From: Ed Burns <Ed.Burns_at_Sun.COM>
Date: Wed, 05 Nov 2008 15:18:24 -0500

Issue: 841 @ResourceDependency, library=="this", script backed annotations

This used to work but has been broken for a long time. I found some
time to investigate it today. The problem is that the logic that
converts a library name of "this" into the library name of the current
composite component was somehow lost in the case of a script backed
component.

This changebundle hacks this through by pushing the top level component
down to ResourceDependencyHandler where that map is created which is
later used to create the resource.

SECTION: changes

M jsf-ri/src/com/sun/faces/application/annotation/Scanner.java
M jsf-ri/src/com/sun/faces/application/annotation/ListenerForScanner.java

- Add params to scan() method.

M jsf-ri/src/com/sun/faces/application/annotation/ResourceDependencyScanner.java

- Add params to scan() method.

- pass params to ResourceDependencyHandler ctor

M jsf-ri/src/com/sun/faces/application/annotation/ResourceDependencyHandler.java

- take params in ctor, store as ivar

- in map building code, leverage params to get the component that is the
  top level component in the composite component. As in other cases
  where "this" is turned into the current library name, this information
  comes from the Resource entry in the top level components attr map.

M jsf-ri/src/com/sun/faces/application/annotation/AnnotationManager.java

- pass through params

M jsf-ri/src/com/sun/faces/application/ApplicationImpl.java

- IMPORTANT, this must be in the spec as well.

  Make sure that the thing that starts the annotation processing on the
  script based component has access to the resource from which the top
  level component was created.

SECTION: diffs

Index: jsf-ri/src/com/sun/faces/application/annotation/ResourceDependencyScanner.java
===================================================================
--- jsf-ri/src/com/sun/faces/application/annotation/ResourceDependencyScanner.java (revision 5688)
+++ jsf-ri/src/com/sun/faces/application/annotation/ResourceDependencyScanner.java (working copy)
@@ -23,7 +23,7 @@
     }
 
 
- public RuntimeAnnotationHandler scan(Class<?> clazz) {
+ public RuntimeAnnotationHandler scan(Class<?> clazz, Object... params) {
 
         Util.notNull("clazz", clazz);
 
@@ -34,7 +34,7 @@
         } else {
             ResourceDependencies deps = clazz.getAnnotation(ResourceDependencies.class);
             if (deps != null) {
- handler = new ResourceDependencyHandler(deps.value());
+ handler = new ResourceDependencyHandler(deps.value(), params);
             }
         }
 
Index: jsf-ri/src/com/sun/faces/application/annotation/ResourceDependencyHandler.java
===================================================================
--- jsf-ri/src/com/sun/faces/application/annotation/ResourceDependencyHandler.java (revision 5688)
+++ jsf-ri/src/com/sun/faces/application/annotation/ResourceDependencyHandler.java (working copy)
@@ -10,6 +10,7 @@
 import javax.faces.context.FacesContext;
 
 import com.sun.faces.el.ELUtils;
+import javax.faces.application.Resource;
 
 /**
  * {_at_link RuntimeAnnotationHandler} responsible for processing {_at_link ResourceDependency} annotations.
@@ -18,12 +19,14 @@
 
     private ResourceDependency[] dependencies;
     private Map<ResourceDependency,Expressions> expressionsMap;
+ private Object[] params;
 
 
     // ------------------------------------------------------------ Constructors
 
 
- public ResourceDependencyHandler(ResourceDependency[] dependencies) {
+ public ResourceDependencyHandler(ResourceDependency[] dependencies, Object... params) {
+ this.params = params;
 
         this.dependencies = dependencies;
         expressionsMap = new HashMap<ResourceDependency,Expressions>(dependencies.length, 1.0f);
@@ -32,6 +35,19 @@
             exprs.name = dep.name();
             String lib = dep.library();
             if (lib.length() > 0) {
+ // Take special action to resolve the "this" library name
+ if ("this".equals(lib)) {
+ UIComponent currentComponent = (UIComponent) params[0];
+ Resource componentResource = (Resource)
+ currentComponent.getAttributes().get(Resource.COMPONENT_RESOURCE_KEY);
+ if (null != componentResource) {
+ String libName = null;
+ if (null != (libName = componentResource.getLibraryName())) {
+ lib = libName;
+ }
+ }
+ }
+
                 exprs.library = lib;
             }
             String tgt = dep.target();
Index: jsf-ri/src/com/sun/faces/application/annotation/AnnotationManager.java
===================================================================
--- jsf-ri/src/com/sun/faces/application/annotation/AnnotationManager.java (revision 5688)
+++ jsf-ri/src/com/sun/faces/application/annotation/AnnotationManager.java (working copy)
@@ -243,7 +243,8 @@
                                   ProcessingTarget processingTarget,
                                   Object... params) {
 
- Map<Class<? extends Annotation>, RuntimeAnnotationHandler> map = getHandlerMap(targetClass, processingTarget);
+ Map<Class<? extends Annotation>, RuntimeAnnotationHandler> map =
+ getHandlerMap(targetClass, processingTarget, params);
         if (map != null && !map.isEmpty()) {
             for (RuntimeAnnotationHandler handler : map.values()) {
                 handler.apply(ctx, params);
@@ -261,14 +262,15 @@
      * value
      */
     private Map<Class<? extends Annotation>, RuntimeAnnotationHandler> getHandlerMap(Class<?> targetClass,
- ProcessingTarget processingTarget) {
+ ProcessingTarget processingTarget,
+ Object... params) {
 
         while (true) {
             Future<Map<Class<? extends Annotation>, RuntimeAnnotationHandler>> f =
                   cache.get(targetClass);
             if (f == null) {
                 ProcessAnnotationsTask t =
- new ProcessAnnotationsTask(targetClass, processingTarget.scanners);
+ new ProcessAnnotationsTask(targetClass, processingTarget.scanners, params);
                 FutureTask<Map<Class<? extends Annotation>, RuntimeAnnotationHandler>> ft =
                       new FutureTask<Map<Class<? extends Annotation>, RuntimeAnnotationHandler>>(t);
                 f = cache.putIfAbsent(targetClass, ft);
@@ -317,16 +319,18 @@
               Collections.EMPTY_MAP;
         private Class<?> clazz;
         private Scanner[] scanners;
+ private Object[] params;
 
 
         // -------------------------------------------------------- Constructors
 
 
 
- public ProcessAnnotationsTask(Class<?> clazz, Scanner[] scanners) {
+ public ProcessAnnotationsTask(Class<?> clazz, Scanner[] scanners, Object... params) {
 
             this.clazz = clazz;
             this.scanners = scanners;
+ this.params = params;
 
         }
 
@@ -338,7 +342,7 @@
 
             Map<Class<? extends Annotation>, RuntimeAnnotationHandler> map = null;
             for (Scanner scanner : scanners) {
- RuntimeAnnotationHandler handler = scanner.scan(clazz);
+ RuntimeAnnotationHandler handler = scanner.scan(clazz, params);
                 if (handler != null) {
                     if (map == null) {
                         map = new HashMap<Class<? extends Annotation>, RuntimeAnnotationHandler>(2, 1.0f);
Index: jsf-ri/src/com/sun/faces/application/annotation/ListenerForScanner.java
===================================================================
--- jsf-ri/src/com/sun/faces/application/annotation/ListenerForScanner.java (revision 5688)
+++ jsf-ri/src/com/sun/faces/application/annotation/ListenerForScanner.java (working copy)
@@ -23,7 +23,7 @@
     }
 
 
- public RuntimeAnnotationHandler scan(Class<?> clazz) {
+ public RuntimeAnnotationHandler scan(Class<?> clazz, Object... params) {
 
         Util.notNull("clazz", clazz);
 
Index: jsf-ri/src/com/sun/faces/application/annotation/Scanner.java
===================================================================
--- jsf-ri/src/com/sun/faces/application/annotation/Scanner.java (revision 5688)
+++ jsf-ri/src/com/sun/faces/application/annotation/Scanner.java (working copy)
@@ -23,10 +23,11 @@
     /**
      * Scan the target class for the {_at_link java.lang.annotation.Annotation}s this scanner handles.
      * @param clazz the target class
+ * @param params one or more parameters, from {_at_link AnnotationManager#applyAnnotations}
      * @return a new {_at_link RuntimeAnnotationHandler} instance capable of processing the
      * annotations defined on this class. If no relevant {_at_link java.lang.annotation.Annotation}s
      * are found, return <code>null</code>.
      */
- public RuntimeAnnotationHandler scan(Class<?> clazz);
+ public RuntimeAnnotationHandler scan(Class<?> clazz, Object... params);
     
 }

Index: jsf-ri/src/com/sun/faces/application/ApplicationImpl.java
===================================================================
--- jsf-ri/src/com/sun/faces/application/ApplicationImpl.java (revision 5688)
+++ jsf-ri/src/com/sun/faces/application/ApplicationImpl.java (working copy)
@@ -902,14 +902,14 @@
 
 
         // Step 2. If that didn't work, if a script based resource can be
- // found for the componentResource,
+ // found for the scriptComponentResource,
         // see if a component can be generated from it
         if (null == result) {
             Resource scriptComponentResource = pdl.getScriptComponentResource(context, componentResource);
 
             if (null != scriptComponentResource) {
                 result = createComponentFromScriptResource(context,
- scriptComponentResource);
+ scriptComponentResource, componentResource);
             }
         }
 
@@ -1597,11 +1597,12 @@
 
 
     private UIComponent createComponentFromScriptResource(FacesContext context,
+ Resource scriptComponentResource,
                                                           Resource componentResource) {
 
         UIComponent result = null;
 
- String className = componentResource.getResourceName();
+ String className = scriptComponentResource.getResourceName();
         int lastDot = className.lastIndexOf('.');
         className = className.substring(0, lastDot);
 
@@ -1624,6 +1625,8 @@
         }
 
         if (result != null) {
+ result.getAttributes().put(Resource.COMPONENT_RESOURCE_KEY,
+ componentResource);
             associate.getAnnotationManager()
                   .applyComponentAnnotations(context, result);
         }

--