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

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

Go to download

Jakarta Faces defines an MVC framework for building user interfaces for web applications, including UI components, state management, event handing, input validation, page navigation, and support for internationalization and accessibility.

There is a newer version: 4.1.2
Show newest version
/*
 * Copyright (c) 1997, 2020 Oracle and/or its affiliates. All rights reserved.
 *
 * This program and the accompanying materials are made available under the
 * terms of the Eclipse Public License v. 2.0, which is available at
 * http://www.eclipse.org/legal/epl-2.0.
 *
 * This Source Code may also be made available under the following Secondary
 * Licenses when the conditions for such availability set forth in the
 * Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
 * version 2 with the GNU Classpath Exception, which is available at
 * https://www.gnu.org/software/classpath/license.html.
 *
 * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
 */

package com.sun.faces.application.annotation;

import java.lang.annotation.Annotation;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
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 com.sun.faces.util.FacesLogger;

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

/**
 * 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);

        private final Scanner[] scanners;

        ProcessingTarget(Scanner[] scanners) {
            this.scanners = scanners;
        }

    }

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

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

    /**
     * Construct a new AnnotationManager instance.
     */
    public AnnotationManager() {
        cache = new ConcurrentHashMap<>(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 annotationType the involved annotation type * @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 jakarta.faces.component.behavior.Behavior} instances. * * @param ctx the {@link jakarta.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 jakarta.faces.render.ClientBehaviorRenderer} instances. * * @param ctx the {@link jakarta.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 jakarta.faces.component.UIComponent} instances. * * @param ctx the {@link jakarta.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 jakarta.faces.validator.Validator} instances. * * @param ctx the {@link jakarta.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 jakarta.faces.convert.Converter} instances. * * @param ctx the {@link jakarta.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 jakarta.faces.render.Renderer} instances. * * @param ctx the {@link jakarta.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 NamedEventConfigHandler() }; Map, ConfigAnnotationHandler> handlerMap = new HashMap<>(); 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 jakarta.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<>(t); f = cache.putIfAbsent(targetClass, ft); if (f == null) { f = ft; ft.run(); } } try { return f.get(); } catch (CancellationException | InterruptedException ce) { if (LOGGER.isLoggable(Level.FINEST)) { LOGGER.log(Level.FINEST, ce.toString(), ce); } 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 final Class clazz; private final Scanner[] scanners; // -------------------------------------------------------- Constructors public ProcessAnnotationsTask(Class clazz, Scanner[] scanners) { this.clazz = clazz; this.scanners = scanners; } // ------------------------------------------------------ Public Methods @Override 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<>(2, 1.0f); } map.put(scanner.getAnnotation(), handler); } } return map != null ? map : EMPTY; } } // END ProcessAnnotationsTask }




© 2015 - 2025 Weber Informatics LLC | Privacy Policy