/* * JBoss, Home of Professional Open Source * Copyright 2011, Red Hat, Inc., and individual contributors * by the @authors tag. See the copyright.txt in the distribution for a * full listing of individual contributors. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * http://www.apache.org/licenses/LICENSE-2.0 * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package org.jboss.seam.faces.projectstage; import org.jboss.solder.logging.Logger; import org.jboss.solder.util.Sortable; import org.jboss.solder.util.service.ServiceLoader; import javax.enterprise.event.Observes; import javax.enterprise.inject.spi.AnnotatedType; import javax.enterprise.inject.spi.Extension; import javax.enterprise.inject.spi.ProcessAnnotatedType; import javax.faces.application.ProjectStage; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.Iterator; import java.util.List; import java.util.Set; /** * Extension that supports to veto beans that should only be active in certain * JSF project stages. * * @author Christian Kaltepoth <christian@kaltepoth.de> * */ public class ProjectStageExtension implements Extension { private transient final Logger log = Logger.getLogger(ProjectStageExtension.class); /** * The default project stage */ private final static ProjectStage DEFAULT_PROJECT_STAGE = ProjectStage.Production; /** * Field to store the detected project stage. The field is lazily initialized in * {@link #processAnnotatedType(ProcessAnnotatedType)} */ private ProjectStage stage; /** * Observes {@link ProcessAnnotatedType} events and sends a veto if the type should be * ignored due to the current project stage. */ public <T> void processAnnotatedType(@Observes ProcessAnnotatedType<T> pat) { // lazily obtain the project stage if (stage == null) { stage = detectProjectStage(); } // the project stages explicitly specified on the type Set<ProjectStage> validProjectStages = getProjectStagesForType(pat.getAnnotatedType()); // veto the type if the current project stage doesn't match if (validProjectStages.size() > 0 && !validProjectStages.contains(stage)) { if (log.isDebugEnabled()) { log.debug("Preventing class " + pat.getAnnotatedType().getJavaClass().getName() + " from being installed due to the current project stage"); } // veto this type pat.veto(); } } /** * Returns a set of {@link ProjectStage}s for which the supplied {@link AnnotatedType} has been enabled using one or more of * the annotations {@link Development}, {@link Production}, {@link SystemTest} and {@link UnitTest}. The method will return * an empty set if the type isn't annotated with any of the annotations. * * @param type The {@link AnnotatedType} to process * @return The list of project stages */ private <T> Set<ProjectStage> getProjectStagesForType(AnnotatedType<T> type) { Set<ProjectStage> stages = new HashSet<ProjectStage>(); if (type.getAnnotation(Development.class) != null) { stages.add(ProjectStage.Development); } if (type.getAnnotation(Production.class) != null) { stages.add(ProjectStage.Production); } if (type.getAnnotation(SystemTest.class) != null) { stages.add(ProjectStage.SystemTest); } if (type.getAnnotation(UnitTest.class) != null) { stages.add(ProjectStage.UnitTest); } return stages; } /** * Method to detect the current project stage. The method will use the {@link ProjectStageDetector} SPI to obtain the * project stage. The fall back value is {@link ProjectStage#Development}. */ private ProjectStage detectProjectStage() { // build sorted list of detector implementations List<ProjectStageDetector> detectors = new ArrayList<ProjectStageDetector>(); for (Iterator<ProjectStageDetector> iter = ServiceLoader.load(ProjectStageDetector.class).iterator(); iter.hasNext();) { detectors.add(iter.next()); } Collections.sort(detectors, new Sortable.Comparator()); // try all detectors for(ProjectStageDetector detector : detectors) { // lets the detector do its job ProjectStage stage = detector.getProjectStage(); if (log.isTraceEnabled()) { log.trace("Detector " + detector.getClass().getName() + " returned: " + stage); } if (stage != null) { log.info("Detected project stage: " + stage); return stage; } } if (log.isDebugEnabled()) { log.debug("No result from detectors! Using default project stage: " + DEFAULT_PROJECT_STAGE); } return DEFAULT_PROJECT_STAGE; } }