blob: 766a726cea91385417ccd6ce6fba9fe49df3b100 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you 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.apache.myfaces.extensions.scripting.jsf2.annotation;
import org.apache.myfaces.extensions.scripting.api.*;
import org.apache.myfaces.extensions.scripting.core.util.WeavingContext;
import org.apache.myfaces.extensions.scripting.loaders.java.ScannerClassloader;
import org.apache.myfaces.extensions.scripting.monitor.ClassResource;
import org.apache.myfaces.extensions.scripting.monitor.RefreshAttribute;
import javax.faces.context.FacesContext;
import java.util.*;
import java.util.logging.Level;
import java.util.logging.Logger;
/**
* @author Werner Punz (latest modification by $Author$)
* @version $Revision$ $Date$
* <p/>
* Source path annotation scanner for java it scans all sources in the specified source paths
* recursively for additional information
* and then adds the id/name -> class binding information to the correct factory locations,
* wherever possible
*/
@SuppressWarnings("unused")
public class GenericAnnotationScanner extends BaseAnnotationScanListener implements ClassScanner {
List<ClassScanListener> _listeners = new LinkedList<ClassScanListener>();
Map<String, String> _registeredAnnotations = new HashMap<String, String>();
LinkedList<String> _sourcePaths = new LinkedList<String>();
ScriptingWeaver _weaver = null;
public GenericAnnotationScanner() {
initDefaultListeners();
}
public GenericAnnotationScanner(ScriptingWeaver weaver) {
_weaver = weaver;
initDefaultListeners();
}
public void addScanPath(String sourcePath) {
_sourcePaths.addFirst(sourcePath);
}
Collection<java.lang.annotation.Annotation> filterAnnotations(java.lang.annotation.Annotation[] annotations) {
List<java.lang.annotation.Annotation> retVal = new ArrayList<java.lang.annotation.Annotation>(annotations.length);
for (java.lang.annotation.Annotation annotation : annotations) {
if (annotation.annotationType().getName().startsWith(ScriptingConst.JAVAX_FACES)) {
retVal.add(annotation);
}
}
return retVal;
}
public void scanClass(Class clazz) {
java.lang.annotation.Annotation[] annotations = clazz.getAnnotations();
Collection<java.lang.annotation.Annotation> annCol = filterAnnotations(annotations);
if (!annCol.isEmpty()) {
addOrMoveAnnotations(clazz);
} else {
removeAnnotations(clazz);
}
}
private void initDefaultListeners() {
_listeners.add(new BeanImplementationListener());
_listeners.add(new BehaviorImplementationListener());
_listeners.add(new ComponentImplementationListener());
_listeners.add(new ConverterImplementationListener());
_listeners.add(new RendererImplementationListener());
_listeners.add(new ValidatorImplementationListener());
}
/**
* builds up the parsing chain and then notifies its observers
* on the found data
*/
public void scanPaths() {
//https://issues.apache.org/jira/browse/EXTSCRIPT-33
//check if the faces config is already available otherwise we cannot scan yet
final FacesContext facesContext = FacesContext.getCurrentInstance();
//runtime config not started
//for now we only can reach the runtime config in the referenced BaseAnnotatonScanListener
//if we have a facesContext reachable.
if (facesContext == null) {
//TODO (1.1) decouple the scan in the BaseAnnotationScanListener from the facesConfig
//to get the runtime config
return;
}
for (String className : _weaver.loadPossibleDynamicClasses()) {
try {
ScannerClassloader loader = new ScannerClassloader(Thread.currentThread().getContextClassLoader(), -1, null, WeavingContext.getConfiguration().getCompileTarget());
Class clazz;
//in case the class does not exist we have to load it from our weavingcontext
//otherwise we do just a scan on the class to avoid side behavior
if (WeavingContext.getFileChangedDaemon().getClassMap().get(className) == null) {
clazz = _weaver.loadScriptingClassFromName(className);
} else {
clazz = loader.loadClass(className);
}
if (clazz != null) {
java.lang.annotation.Annotation[] anns = clazz.getAnnotations();
if (anns != null && anns.length > 0) {
addOrMoveAnnotations(clazz);
} else {
removeAnnotations(clazz);
}
}
} catch (ClassNotFoundException e) {
Logger _logger = Logger.getLogger(this.getClass().getName());
_logger.log(Level.WARNING, "", e);
}
}
}
/**
* add or moves a class level annotation
* to a new place
*
* @param clazz the class to have the annotation moved or added
*/
private void addOrMoveAnnotations(Class clazz) {
java.lang.annotation.Annotation[] anns = clazz.getAnnotations();
for (java.lang.annotation.Annotation ann : anns) {
for (ClassScanListener cListener : _listeners) {
AnnotationScanListener listener = (AnnotationScanListener) cListener;
if (listener.supportsAnnotation(ann.annotationType())) {
listener.register(clazz, ann);
_registeredAnnotations.put(clazz.getName(), ann.annotationType().getName());
//TODO check if we still need this
ClassResource metaData = WeavingContext.getFileChangedDaemon().getClassMap().get(clazz.getName());
}
}
}
}
/**
* use case annotation removed
* we have to entirely remove the annotation
* from our internal registry and the myfaces registry
*
* @param clazz the class to have the annotation removed
*/
private void removeAnnotations(Class clazz) {
String registeredAnnotation = _registeredAnnotations.get(clazz.getName());
if (registeredAnnotation != null) {
for (ClassScanListener cListener : _listeners) {
AnnotationScanListener listener = (AnnotationScanListener) cListener;
if (listener.supportsAnnotation(registeredAnnotation)) {
listener.purge(clazz.getName());
_registeredAnnotations.remove(clazz.getName());
WeavingContext.getFileChangedDaemon().getClassMap().remove(clazz.getName());
}
}
}
}
public void clearListeners() {
_listeners.clear();
}
public void addListener(ClassScanListener listener) {
_listeners.add(listener);
}
@Override
public void scanAndMarkChange() {
//do nothing here
}
}