All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.sun.faces.application.annotation.AnnotationManager Maven / Gradle / Ivy

/*
 * 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.annotation;

import java.lang.annotation.Annotation;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
import java.util.Collection;
import java.util.Set;
import java.util.concurrent.Callable;
import java.util.concurrent.CancellationException;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;
import java.util.concurrent.FutureTask;
import java.util.logging.Level;
import java.util.logging.Logger;

import javax.faces.FacesException;
import javax.faces.component.UIComponent;
import javax.faces.component.behavior.Behavior;
import javax.faces.component.behavior.ClientBehaviorBase;
import javax.faces.context.FacesContext;
import javax.faces.convert.Converter;
import javax.faces.render.ClientBehaviorRenderer;
import javax.faces.render.RenderKit;
import javax.faces.render.Renderer;
import javax.faces.validator.Validator;

import com.sun.faces.util.FacesLogger;
import javax.faces.event.SystemEvent;

/**
 * This class represents the central point for annotation handling within a
 * web application.
 */
public class AnnotationManager {

    private static final Logger LOGGER = FacesLogger.APPLICATION.getLogger();
    private static final Scanner RESOURCE_DEPENDENCY_SCANNER = new ResourceDependencyScanner();
    private static final Scanner LISTENER_FOR_SCANNER = new ListenerForScanner();

    /**
     * {@link Scanner} instances to be used against {@link Behavior} classes.
     */
    private static final Scanner[] BEHAVIOR_SCANNERS = {
          RESOURCE_DEPENDENCY_SCANNER
    };

    /**
     * {@link Scanner} instances to be used against {@link ClientBehaviorRenderer} classes.
     */
    private static final Scanner[] CLIENT_BEHAVIOR_RENDERER_SCANNERS = {
          RESOURCE_DEPENDENCY_SCANNER
    };

    /**
     * {@link Scanner} instances to be used against {@link UIComponent} classes.
     */
    private static final Scanner[] UICOMPONENT_SCANNERS = {
          RESOURCE_DEPENDENCY_SCANNER,
          LISTENER_FOR_SCANNER
    };

    /**
     * {@link Scanner} instances to be used against {@link Validator} classes.
     */
    private static final Scanner[] VALIDATOR_SCANNERS = {
          RESOURCE_DEPENDENCY_SCANNER
    };

    /**
     * {@link Scanner} instances to be used against {@link Converter} classes.
     */
    private static final Scanner[] CONVERTER_SCANNERS = {
          RESOURCE_DEPENDENCY_SCANNER
    };

    /**
     * {@link Scanner} instances to be used against {@link Renderer} classes.
     */
    private static final Scanner[] RENDERER_SCANNERS = {
          RESOURCE_DEPENDENCY_SCANNER,
          LISTENER_FOR_SCANNER
    };

    private static final Scanner[] EVENTS_SCANNERS = {
        RESOURCE_DEPENDENCY_SCANNER
    };

    /**
     * Enum of the different processing targets and their associated
     * {@link Scanner}s
     */
    private enum ProcessingTarget {
        Behavior(BEHAVIOR_SCANNERS),
        ClientBehaviorRenderer(CLIENT_BEHAVIOR_RENDERER_SCANNERS),
        UIComponent(UICOMPONENT_SCANNERS),
        Validator(VALIDATOR_SCANNERS),
        Converter(CONVERTER_SCANNERS),
        Renderer(RENDERER_SCANNERS),
        SystemEvent(EVENTS_SCANNERS);


        @SuppressWarnings({"NonSerializableFieldInSerializableClass"})
        private Scanner[] scanners;
        ProcessingTarget(Scanner[] scanners) {
            this.scanners = scanners;
        }

    }

    /**
     * The backing cache for all annotation metadata.
     */
    private ConcurrentMap,Future, RuntimeAnnotationHandler>>> cache;


    // ------------------------------------------------------------ Constructors


    /**
     * Construct a new AnnotationManager instance.
     */
    public AnnotationManager() {

        cache = new ConcurrentHashMap,Future, RuntimeAnnotationHandler>>>(40, .75f, 32);

    }



    // ---------------------------------------------------------- Public Methods


    /**
     * 

* Apply the configuration metadata contained with in the Collection * of annotated classes. *

* * @param ctx FacesContext available during application initialization * @param annotatedClasses Collection of class names known * to contain one or more Faces configuration annotations */ public void applyConfigAnnotations(FacesContext ctx, Class annotationType, Set annotatedClasses) { if (annotatedClasses != null && !annotatedClasses.isEmpty()) { ConfigAnnotationHandler handler = getConfigAnnotationHandlers().get(annotationType); if (handler == null) { throw new IllegalStateException("Internal Error: No ConfigAnnotationHandler for type: " + annotationType); } for (Class clazz : annotatedClasses) { handler.collect(clazz, clazz.getAnnotation(annotationType)); } // metadata collected, now push the configuration to the system handler.push(ctx); } } /** * Apply annotations relevant to {@link javax.faces.component.behavior.Behavior} instances. * @param ctx the {@link javax.faces.context.FacesContext} for the current request * @param b the target Behavior to process */ public void applyBehaviorAnnotations(FacesContext ctx, Behavior b) { applyAnnotations(ctx, b.getClass(), ProcessingTarget.Behavior, b); if (b instanceof ClientBehaviorBase) { ClientBehaviorBase clientBehavior = (ClientBehaviorBase) b; String rendererType = clientBehavior.getRendererType(); RenderKit renderKit = ctx.getRenderKit(); if( null != rendererType && null != renderKit){ ClientBehaviorRenderer behaviorRenderer = renderKit.getClientBehaviorRenderer(rendererType); if(null != behaviorRenderer){ applyClientBehaviorRendererAnnotations(ctx, behaviorRenderer); } } } } /** * Apply annotations relevant to {@link javax.faces.render.ClientBehaviorRenderer} instances. * @param ctx the {@link javax.faces.context.FacesContext} for the current request * @param b the target ClientBehaviorRenderer to process */ public void applyClientBehaviorRendererAnnotations(FacesContext ctx, ClientBehaviorRenderer b) { applyAnnotations(ctx, b.getClass(), ProcessingTarget.ClientBehaviorRenderer, b); } /** * Apply annotations relevant to {@link javax.faces.component.UIComponent} instances. * @param ctx the {@link javax.faces.context.FacesContext} for the current request * @param c the target UIComponent to process */ public void applyComponentAnnotations(FacesContext ctx, UIComponent c) { applyAnnotations(ctx, c.getClass(), ProcessingTarget.UIComponent, c); } /** * Apply annotations relevant to {@link javax.faces.validator.Validator} instances. * @param ctx the {@link javax.faces.context.FacesContext} for the current request * @param v the target Validator to process */ public void applyValidatorAnnotations(FacesContext ctx, Validator v) { applyAnnotations(ctx, v.getClass(), ProcessingTarget.Validator, v); } /** * Apply annotations relevant to {@link javax.faces.convert.Converter} instances. * @param ctx the {@link javax.faces.context.FacesContext} for the current request * @param c the target Converter to process */ public void applyConverterAnnotations(FacesContext ctx, Converter c) { applyAnnotations(ctx, c.getClass(), ProcessingTarget.Converter, c); } /** * Apply annotations relevent to {@link javax.faces.render.Renderer} instances. * @param ctx the {@link javax.faces.context.FacesContext} for the current request * @param r the Renderer to process * @param c the UIComponent instances that is associated with this * Renderer */ public void applyRendererAnnotations(FacesContext ctx, Renderer r, UIComponent c) { applyAnnotations(ctx, r.getClass(), ProcessingTarget.Renderer, r, c); } public void applySystemEventAnnotations(FacesContext ctx, SystemEvent e) { applyAnnotations(ctx, e.getClass(), ProcessingTarget.SystemEvent, e); } // --------------------------------------------------------- Private Methods /** * @return a new Map which maps the types of annotations to * a specific ConfigAnnotationHandler. Note that each invocation * of this method constructs a new Map with new * ConfigAnnotationhandler instances as they are not thread * safe. */ private Map,ConfigAnnotationHandler> getConfigAnnotationHandlers() { ConfigAnnotationHandler[] handlers = { new ComponentConfigHandler(), new ConverterConfigHandler(), new ValidatorConfigHandler(), new BehaviorConfigHandler(), new RenderKitConfigHandler(), new ManagedBeanConfigHandler(), new NamedEventConfigHandler() }; Map,ConfigAnnotationHandler> handlerMap = new HashMap,ConfigAnnotationHandler>(); for (ConfigAnnotationHandler handler : handlers) { Collection> handledClasses = handler.getHandledAnnotations(); for (Class handled : handledClasses) { handlerMap.put(handled, handler); } } return handlerMap; } /** * Apply all annotations associated with targetClass * * @param ctx the {@link javax.faces.context.FacesContext} for the current request * @param targetClass class of the processingTarget * @param processingTarget the type of component that is being processed * @param params one or more parameters to be passed to each {@link RuntimeAnnotationHandler} */ private void applyAnnotations(FacesContext ctx, Class targetClass, ProcessingTarget processingTarget, Object... params) { Map, RuntimeAnnotationHandler> map = getHandlerMap(targetClass, processingTarget); if (map != null && !map.isEmpty()) { for (RuntimeAnnotationHandler handler : map.values()) { handler.apply(ctx, params); } } } /** * Helper method to look up cached annotation metadata. * @param targetClass class of the processingTarget * @param processingTarget the type of component being processed * @return a Map keyed by Annotation class with an AnnotationHandler as the * value */ private Map, RuntimeAnnotationHandler> getHandlerMap(Class targetClass, ProcessingTarget processingTarget) { while (true) { Future, RuntimeAnnotationHandler>> f = cache.get(targetClass); if (f == null) { ProcessAnnotationsTask t = new ProcessAnnotationsTask(targetClass, processingTarget.scanners); FutureTask, RuntimeAnnotationHandler>> ft = new FutureTask, RuntimeAnnotationHandler>>(t); f = cache.putIfAbsent(targetClass, ft); if (f == null) { f = ft; ft.run(); } } try { return f.get(); } catch (CancellationException ce) { if (LOGGER.isLoggable(Level.FINEST)) { LOGGER.log(Level.FINEST, ce.toString(), ce); } cache.remove(targetClass); } catch (InterruptedException ie) { if (LOGGER.isLoggable(Level.FINEST)) { LOGGER.log(Level.FINEST, ie.toString(), ie); } cache.remove(targetClass); } catch (ExecutionException ee) { throw new FacesException(ee); } } } // ----------------------------------------------------------- Inner Classes /** * This Callable will leverage the provided Scanners * to build a mapping between a particular annotation type and an * AnnotationHandler for that type. */ private static final class ProcessAnnotationsTask implements Callable, RuntimeAnnotationHandler>> { @SuppressWarnings({"unchecked"}) private static final Map, RuntimeAnnotationHandler> EMPTY = Collections.EMPTY_MAP; private Class clazz; private Scanner[] scanners; // -------------------------------------------------------- Constructors public ProcessAnnotationsTask(Class clazz, Scanner[] scanners) { this.clazz = clazz; this.scanners = scanners; } // ------------------------------------------------------ Public Methods public Map, RuntimeAnnotationHandler> call() throws Exception { Map, RuntimeAnnotationHandler> map = null; for (Scanner scanner : scanners) { RuntimeAnnotationHandler handler = scanner.scan(clazz); if (handler != null) { if (map == null) { map = new HashMap, RuntimeAnnotationHandler>(2, 1.0f); } map.put(scanner.getAnnotation(), handler); } } return ((map != null) ? map : EMPTY); } } // END ProcessAnnotationsTask }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy