Save This Page
Home » Mojarra-2.0.1 » com.sun.faces.application.annotation » [javadoc | source]
    1   /*
    2    * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
    3    *
    4    * Copyright 1997-2009 Sun Microsystems, Inc. All rights reserved.
    5    *
    6    * The contents of this file are subject to the terms of either the GNU
    7    * General Public License Version 2 only ("GPL") or the Common Development
    8    * and Distribution License("CDDL") (collectively, the "License").  You
    9    * may not use this file except in compliance with the License. You can obtain
   10    * a copy of the License at https://glassfish.dev.java.net/public/CDDL+GPL.html
   11    * or glassfish/bootstrap/legal/LICENSE.txt.  See the License for the specific
   12    * language governing permissions and limitations under the License.
   13    *
   14    * When distributing the software, include this License Header Notice in each
   15    * file and include the License file at glassfish/bootstrap/legal/LICENSE.txt.
   16    * Sun designates this particular file as subject to the "Classpath" exception
   17    * as provided by Sun in the GPL Version 2 section of the License file that
   18    * accompanied this code.  If applicable, add the following below the License
   19    * Header, with the fields enclosed by brackets [] replaced by your own
   20    * identifying information: "Portions Copyrighted [year]
   21    * [name of copyright owner]"
   22    *
   23    * Contributor(s):
   24    *
   25    * If you wish your version of this file to be governed by only the CDDL or
   26    * only the GPL Version 2, indicate your decision by adding "[Contributor]
   27    * elects to include this software in this distribution under the [CDDL or GPL
   28    * Version 2] license."  If you don't indicate a single choice of license, a
   29    * recipient has the option to distribute your version of this file under
   30    * either the CDDL, the GPL Version 2 or to extend the choice of license to
   31    * its licensees as provided above.  However, if you add GPL Version 2 code
   32    * and therefore, elected the GPL Version 2 license, then the option applies
   33    * only if the new code is made subject to such option by the copyright
   34    * holder.
   35    */
   36   
   37   package com.sun.faces.application.annotation;
   38   
   39   import java.lang.annotation.Annotation;
   40   import java.util.Collections;
   41   import java.util.HashMap;
   42   import java.util.Map;
   43   import java.util.Collection;
   44   import java.util.Set;
   45   import java.util.concurrent.Callable;
   46   import java.util.concurrent.CancellationException;
   47   import java.util.concurrent.ConcurrentHashMap;
   48   import java.util.concurrent.ConcurrentMap;
   49   import java.util.concurrent.ExecutionException;
   50   import java.util.concurrent.Future;
   51   import java.util.concurrent.FutureTask;
   52   import java.util.logging.Level;
   53   import java.util.logging.Logger;
   54   
   55   import javax.faces.FacesException;
   56   import javax.faces.component.UIComponent;
   57   import javax.faces.component.behavior.Behavior;
   58   import javax.faces.component.behavior.ClientBehaviorBase;
   59   import javax.faces.context.FacesContext;
   60   import javax.faces.convert.Converter;
   61   import javax.faces.render.ClientBehaviorRenderer;
   62   import javax.faces.render.RenderKit;
   63   import javax.faces.render.Renderer;
   64   import javax.faces.validator.Validator;
   65   
   66   import com.sun.faces.util.FacesLogger;
   67   import javax.faces.event.SystemEvent;
   68   
   69   /**
   70    * This class represents the central point for annotation handling within a
   71    * web application.
   72    */
   73   public class AnnotationManager {
   74   
   75       private static final Logger LOGGER = FacesLogger.APPLICATION.getLogger();
   76       private static final Scanner RESOURCE_DEPENDENCY_SCANNER = new ResourceDependencyScanner();
   77       private static final Scanner LISTENER_FOR_SCANNER = new ListenerForScanner();
   78   
   79       /**
   80        * {@link Scanner} instances to be used against {@link Behavior} classes.
   81        */
   82       private static final Scanner[] BEHAVIOR_SCANNERS = {
   83             RESOURCE_DEPENDENCY_SCANNER
   84       };
   85   
   86       /**
   87        * {@link Scanner} instances to be used against {@link ClientBehaviorRenderer} classes.
   88        */
   89       private static final Scanner[] CLIENT_BEHAVIOR_RENDERER_SCANNERS = {
   90             RESOURCE_DEPENDENCY_SCANNER
   91       };
   92   
   93       /**
   94        * {@link Scanner} instances to be used against {@link UIComponent} classes.
   95        */
   96       private static final Scanner[] UICOMPONENT_SCANNERS = {
   97             RESOURCE_DEPENDENCY_SCANNER,
   98             LISTENER_FOR_SCANNER
   99       };
  100   
  101       /**
  102        * {@link Scanner} instances to be used against {@link Validator} classes.
  103        */
  104       private static final Scanner[] VALIDATOR_SCANNERS = {
  105             RESOURCE_DEPENDENCY_SCANNER
  106       };
  107   
  108       /**
  109        * {@link Scanner} instances to be used against {@link Converter} classes.
  110        */
  111       private static final Scanner[] CONVERTER_SCANNERS = {
  112             RESOURCE_DEPENDENCY_SCANNER
  113       };
  114   
  115       /**
  116        * {@link Scanner} instances to be used against {@link Renderer} classes.
  117        */
  118       private static final Scanner[] RENDERER_SCANNERS = {
  119             RESOURCE_DEPENDENCY_SCANNER,
  120             LISTENER_FOR_SCANNER
  121       };
  122   
  123       private static final Scanner[] EVENTS_SCANNERS = {
  124           RESOURCE_DEPENDENCY_SCANNER
  125       };
  126   
  127       /**
  128        * Enum of the different processing targets and their associated
  129        * {@link Scanner}s
  130        */
  131       private enum ProcessingTarget {
  132           Behavior(BEHAVIOR_SCANNERS),
  133           ClientBehaviorRenderer(CLIENT_BEHAVIOR_RENDERER_SCANNERS),
  134           UIComponent(UICOMPONENT_SCANNERS),
  135           Validator(VALIDATOR_SCANNERS),
  136           Converter(CONVERTER_SCANNERS),
  137           Renderer(RENDERER_SCANNERS),
  138           SystemEvent(EVENTS_SCANNERS);
  139   
  140   
  141           @SuppressWarnings({"NonSerializableFieldInSerializableClass"})
  142           private Scanner[] scanners;
  143           ProcessingTarget(Scanner[] scanners) {
  144               this.scanners = scanners;
  145           }
  146   
  147       }
  148   
  149       /**
  150        * The backing cache for all annotation metadata.
  151        */
  152       private ConcurrentMap<Class<?>,Future<Map<Class<? extends Annotation>, RuntimeAnnotationHandler>>> cache;
  153   
  154   
  155       // ------------------------------------------------------------ Constructors
  156   
  157   
  158       /**
  159        * Construct a new AnnotationManager instance.
  160        */
  161       public AnnotationManager() {
  162   
  163           cache = new ConcurrentHashMap<Class<?>,Future<Map<Class<? extends Annotation>, RuntimeAnnotationHandler>>>(40, .75f, 32);
  164   
  165       }
  166   
  167   
  168   
  169       // ---------------------------------------------------------- Public Methods
  170   
  171   
  172       /**
  173        * <p>
  174        * Apply the configuration metadata contained with in the <code>Collection</code>
  175        * of annotated classes.
  176        * </p>
  177        *
  178        * @param ctx FacesContext available during application initialization
  179        * @param annotatedClasses <code>Collection</code> of class names known
  180        *  to contain one or more Faces configuration annotations
  181        */
  182       public void applyConfigAnntations(FacesContext ctx,
  183                                         Class<? extends Annotation> annotationType,
  184                                         Set<? extends Class> annotatedClasses) {
  185   
  186           if (annotatedClasses != null && !annotatedClasses.isEmpty()) {
  187               ConfigAnnotationHandler handler =
  188                     getConfigAnnotationHandlers().get(annotationType);
  189               if (handler == null) {
  190                   throw new IllegalStateException("Internal Error: No ConfigAnnotationHandler for type: " + annotationType);
  191               }
  192               for (Class<?> clazz : annotatedClasses) {
  193                   handler.collect(clazz, clazz.getAnnotation(annotationType));
  194               }
  195               // metadata collected, now push the configuration to the system
  196               handler.push(ctx);
  197           }
  198           
  199       }
  200   
  201       /**
  202        * Apply annotations relevant to {@link javax.faces.component.behavior.Behavior} instances.
  203        * @param ctx the {@link javax.faces.context.FacesContext} for the current request
  204        * @param b the target <code>Behavior</code> to process
  205        */
  206       public void applyBehaviorAnnotations(FacesContext ctx, Behavior b) {
  207   
  208           applyAnnotations(ctx, b.getClass(), ProcessingTarget.Behavior, b);
  209           if (b instanceof ClientBehaviorBase) {
  210               ClientBehaviorBase clientBehavior = (ClientBehaviorBase) b;
  211               String rendererType = clientBehavior.getRendererType();
  212               RenderKit renderKit = ctx.getRenderKit();
  213               if( null != rendererType && null != renderKit){
  214                   ClientBehaviorRenderer behaviorRenderer = renderKit.getClientBehaviorRenderer(rendererType);
  215                   if(null != behaviorRenderer){
  216                       applyClientBehaviorRendererAnnotations(ctx, behaviorRenderer);
  217                   }
  218               }
  219           }
  220   
  221       }
  222   
  223       /**
  224        * Apply annotations relevant to {@link javax.faces.render.ClientBehaviorRenderer} instances.
  225        * @param ctx the {@link javax.faces.context.FacesContext} for the current request
  226        * @param b the target <code>ClientBehaviorRenderer</code> to process
  227        */
  228       public void applyClientBehaviorRendererAnnotations(FacesContext ctx, ClientBehaviorRenderer b) {
  229   
  230           applyAnnotations(ctx, b.getClass(), ProcessingTarget.ClientBehaviorRenderer, b);
  231   
  232       }
  233       
  234       /**
  235        * Apply annotations relevant to {@link javax.faces.component.UIComponent} instances.
  236        * @param ctx the {@link javax.faces.context.FacesContext} for the current request
  237        * @param c the target <code>UIComponent</code> to process
  238        */
  239       public void applyComponentAnnotations(FacesContext ctx, UIComponent c) {
  240   
  241           applyAnnotations(ctx, c.getClass(), ProcessingTarget.UIComponent, c);
  242   
  243       }
  244   
  245   
  246       /**
  247        * Apply annotations relevant to {@link javax.faces.validator.Validator} instances.
  248        * @param ctx the {@link javax.faces.context.FacesContext} for the current request
  249        * @param v the target <code>Validator</code> to process
  250        */
  251       public void applyValidatorAnnotations(FacesContext ctx, Validator v) {
  252   
  253           applyAnnotations(ctx, v.getClass(), ProcessingTarget.Validator, v);
  254   
  255       }
  256   
  257   
  258       /**
  259        * Apply annotations relevant to {@link javax.faces.convert.Converter} instances.
  260        * @param ctx the {@link javax.faces.context.FacesContext} for the current request
  261        * @param c the target <code>Converter</code> to process
  262        */
  263       public void applyConverterAnnotations(FacesContext ctx, Converter c) {
  264   
  265           applyAnnotations(ctx, c.getClass(), ProcessingTarget.Converter, c);
  266   
  267       }
  268   
  269   
  270       /**
  271        * Apply annotations relevent to {@link javax.faces.render.Renderer} instances.
  272        * @param ctx the {@link javax.faces.context.FacesContext} for the current request
  273        * @param r the <code>Renderer</code> to process
  274        * @param c the <code>UIComponent</code> instances that is associated with this
  275        *  <code>Renderer</code>
  276        */
  277       public void applyRendererAnnotations(FacesContext ctx, Renderer r, UIComponent c) {
  278   
  279           applyAnnotations(ctx, r.getClass(), ProcessingTarget.Renderer, r, c);
  280   
  281       }
  282   
  283       public void applySystemEventAnnotations(FacesContext ctx, SystemEvent e) {
  284           applyAnnotations(ctx, e.getClass(), ProcessingTarget.SystemEvent, e);
  285       }
  286   
  287   
  288       // --------------------------------------------------------- Private Methods
  289   
  290   
  291       /**
  292        * @return a new <code>Map</code> which maps the types of annotations to
  293        *  a specific <code>ConfigAnnotationHandler</code>.  Note that each invocation
  294        *  of this method constructs a new <code>Map</code> with new
  295        *  <code>ConfigAnnotationhandler</code> instances as they are not thread
  296        *  safe.
  297        */
  298       private Map<Class<? extends Annotation>,ConfigAnnotationHandler> getConfigAnnotationHandlers() {
  299   
  300           ConfigAnnotationHandler[] handlers = {
  301                 new ComponentConfigHandler(),
  302                 new ConverterConfigHandler(),
  303                 new ValidatorConfigHandler(),
  304                 new BehaviorConfigHandler(),
  305                 new RenderKitConfigHandler(),
  306                 new ManagedBeanConfigHandler(),
  307                 new NamedEventConfigHandler()
  308           };
  309           Map<Class<? extends Annotation>,ConfigAnnotationHandler> handlerMap =
  310                 new HashMap<Class<? extends Annotation>,ConfigAnnotationHandler>();
  311           for (ConfigAnnotationHandler handler : handlers) {
  312               Collection<Class<? extends Annotation>> handledClasses = handler.getHandledAnnotations();
  313               for (Class<? extends Annotation> handled : handledClasses) {
  314                   handlerMap.put(handled, handler);
  315               }
  316           }
  317   
  318           return handlerMap;
  319   
  320       }
  321       
  322   
  323       /**
  324        * Apply all annotations associated with <code>targetClass</code>
  325        *
  326        * @param ctx the {@link javax.faces.context.FacesContext} for the current request
  327        * @param targetClass class of the <code>processingTarget</code>
  328        * @param processingTarget the type of component that is being processed
  329        * @param params one or more parameters to be passed to each {@link RuntimeAnnotationHandler}
  330        */
  331       private void applyAnnotations(FacesContext ctx,
  332                                     Class<?> targetClass,
  333                                     ProcessingTarget processingTarget,
  334                                     Object... params) {
  335   
  336           Map<Class<? extends Annotation>, RuntimeAnnotationHandler> map = getHandlerMap(targetClass, processingTarget);
  337           if (map != null && !map.isEmpty()) {
  338               for (RuntimeAnnotationHandler handler : map.values()) {
  339                   handler.apply(ctx, params);
  340               }
  341           }
  342   
  343       }
  344   
  345   
  346       /**
  347        * Helper method to look up cached annotation metadata.
  348        * @param targetClass class of the <code>processingTarget</code>
  349        * @param processingTarget the type of component being processed
  350        * @return a Map keyed by Annotation class with an AnnotationHandler as the
  351        *  value
  352        */
  353       private Map<Class<? extends Annotation>, RuntimeAnnotationHandler> getHandlerMap(Class<?> targetClass,
  354                                                                                 ProcessingTarget processingTarget) {
  355   
  356           while (true) {
  357               Future<Map<Class<? extends Annotation>, RuntimeAnnotationHandler>> f =
  358                     cache.get(targetClass);
  359               if (f == null) {
  360                   ProcessAnnotationsTask t =
  361                         new ProcessAnnotationsTask(targetClass, processingTarget.scanners);
  362                   FutureTask<Map<Class<? extends Annotation>, RuntimeAnnotationHandler>> ft =
  363                         new FutureTask<Map<Class<? extends Annotation>, RuntimeAnnotationHandler>>(t);
  364                   f = cache.putIfAbsent(targetClass, ft);
  365                   if (f == null) {
  366                       f = ft;
  367                       ft.run();
  368                   }
  369               }
  370               try {
  371                   return f.get();
  372               } catch (CancellationException ce) {
  373                   if (LOGGER.isLoggable(Level.FINEST)) {
  374                       LOGGER.log(Level.FINEST,
  375                                  ce.toString(),
  376                                  ce);
  377                   }
  378                   cache.remove(targetClass);
  379               } catch (InterruptedException ie) {
  380                   if (LOGGER.isLoggable(Level.FINEST)) {
  381                       LOGGER.log(Level.FINEST,
  382                                  ie.toString(),
  383                                  ie);
  384                   }
  385                   cache.remove(targetClass);
  386               } catch (ExecutionException ee) {
  387                   throw new FacesException(ee);
  388               }
  389           }
  390   
  391       }
  392   
  393   
  394       // ----------------------------------------------------------- Inner Classes
  395   
  396   
  397       /**
  398        * This <code>Callable</code> will leverage the provided <code>Scanner</code>s
  399        * to build a mapping between a particular annotation type and an
  400        * <code>AnnotationHandler</code> for that type.
  401        */
  402       private static final class ProcessAnnotationsTask
  403             implements Callable<Map<Class<? extends Annotation>, RuntimeAnnotationHandler>> {
  404   
  405           @SuppressWarnings({"unchecked"})
  406           private static final Map<Class<? extends Annotation>, RuntimeAnnotationHandler> EMPTY =
  407                 Collections.EMPTY_MAP;
  408           private Class<?> clazz;
  409           private Scanner[] scanners;
  410   
  411   
  412           // -------------------------------------------------------- Constructors
  413   
  414   
  415   
  416           public ProcessAnnotationsTask(Class<?> clazz, Scanner[] scanners) {
  417   
  418               this.clazz = clazz;
  419               this.scanners = scanners;
  420   
  421           }
  422   
  423   
  424           // ------------------------------------------------------ Public Methods
  425   
  426   
  427           public Map<Class<? extends Annotation>, RuntimeAnnotationHandler> call() throws Exception {
  428   
  429               Map<Class<? extends Annotation>, RuntimeAnnotationHandler> map = null;
  430               for (Scanner scanner : scanners) {
  431                   RuntimeAnnotationHandler handler = scanner.scan(clazz);
  432                   if (handler != null) {
  433                       if (map == null) {
  434                           map = new HashMap<Class<? extends Annotation>, RuntimeAnnotationHandler>(2, 1.0f);
  435                       }
  436                       map.put(scanner.getAnnotation(), handler);
  437                   }
  438               }
  439   
  440               return ((map != null) ? map : EMPTY);
  441               
  442           }
  443   
  444       } // END ProcessAnnotationsTask
  445   
  446   
  447   
  448   
  449   
  450       
  451   
  452   }

Save This Page
Home » Mojarra-2.0.1 » com.sun.faces.application.annotation » [javadoc | source]