blob: 737d3740764c5b43a223976fcb95b3c1e4d7614f [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.jsf.annotation;
import org.apache.myfaces.config.RuntimeConfig;
import org.apache.myfaces.config.element.ManagedBean;
import org.apache.myfaces.config.element.NavigationRule;
import org.apache.myfaces.extensions.scripting.core.api.AnnotationScanListener;
import org.apache.myfaces.extensions.scripting.core.common.util.ReflectUtil;
import org.apache.myfaces.extensions.scripting.core.common.util.StringUtils;
import javax.faces.bean.ApplicationScoped;
import javax.faces.bean.CustomScoped;
import javax.faces.bean.ManagedProperty;
import javax.faces.bean.NoneScoped;
import javax.faces.bean.RequestScoped;
import javax.faces.bean.SessionScoped;
import javax.faces.bean.ViewScoped;
import javax.faces.context.FacesContext;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.logging.Level;
/**
* bean implementation listener which registers new java sources
* into the runtime config, note this class is not thread safe
* it is only allowed to be called from a single thread
*
* @author Werner Punz (latest modification by $Author$)
* @version $Revision$ $Date$
*/
public class MyFacesBeanImplementationListener extends BaseAnnotationScanListener implements AnnotationScanListener
{
public boolean supportsAnnotation(String annotation) {
return annotation.equals(javax.faces.bean.ManagedBean.class.getName());
}
public boolean supportsAnnotation(Class annotation) {
return annotation.equals(javax.faces.bean.ManagedBean.class);
}
public void register(Class clazz, java.lang.annotation.Annotation ann) {
javax.faces.bean.ManagedBean annCasted = (javax.faces.bean.ManagedBean) ann;
String beanName = annCasted.name();
if (StringUtils.isBlank(beanName)) {
beanName = normalizeName(clazz.getName());
}
beanName = beanName.replaceAll("\"", "");
//we need to reregister for every bean due to possible managed prop
//and scope changes
registerManagedBean(clazz, beanName);
}
/**
* registers a new managed bean into runtime config
* @param clazz
* @param beanName
*/
protected void registerManagedBean(Class clazz, String beanName)
{
RuntimeConfig config = getRuntimeConfig();
ManagedBean mbean;
if (!hasToReregister(beanName, clazz)) {
mbean = (ManagedBean) _alreadyRegistered.get(beanName);
//return;
} else {
mbean = ManagedBeanHandler.newInstance();
}
ManagedBeanHandler.setBeanClass(mbean, clazz.getName());
//mbean.setBeanClass(clazz.getName());
ReflectUtil.setField(mbean, "beanClass", null, true);
ManagedBeanHandler.setName(mbean, beanName);
// mbean.setName(beanName);
handleManagedpropertiesCompiled(mbean, fields(clazz));
resolveScope(clazz, mbean);
_alreadyRegistered.put(beanName, mbean);
config.addManagedBean(beanName, mbean);
}
private void resolveScope(Class clazz, ManagedBean mbean) {
//now lets resolve the scope
String scope = "none";
if (clazz.isAnnotationPresent(RequestScoped.class)) {
scope = "request";
} else if (clazz.isAnnotationPresent(SessionScoped.class)) {
scope = "session";
} else if (clazz.isAnnotationPresent(ApplicationScoped.class)) {
scope = "application";
} else if (clazz.isAnnotationPresent(ViewScoped.class)) {
scope = "view";
} else if (clazz.isAnnotationPresent(NoneScoped.class)) {
scope = "none";
} else if (clazz.isAnnotationPresent(CustomScoped.class)) {
CustomScoped customScoped = (CustomScoped) clazz.getAnnotation(CustomScoped.class);
scope = (customScoped != null) ? customScoped.value() : "custom";
}
//mbean.setScope(scope);
ManagedBeanHandler.setScope(mbean, scope);
}
protected void handleManagedpropertiesCompiled(ManagedBean mbean, Field[] fields) {
/*since we reprocess the managed properties we can handle them here by clearing them first*/
mbean.getManagedProperties().clear();
for (Field field : fields) {
if (_log.isLoggable(Level.FINEST)) {
_log.log(Level.FINEST, " Scanning field '" + field.getName() + "'");
}
ManagedProperty property = field
.getAnnotation(ManagedProperty.class);
if (property != null) {
if (_log.isLoggable(Level.FINE)) {
_log.log(Level.FINE, " Field '" + field.getName()
+ "' has a @ManagedProperty annotation");
}
org.apache.myfaces.config.element.ManagedProperty mpc = ManagedPropertyHandler.newInstance();
String name = property.name();
if ((name == null) || "".equals(name)) {
name = field.getName();
}
ManagedPropertyHandler.setPropertyName(mpc, name);
//mpc.setPropertyName(name);
ManagedPropertyHandler.setPropertyClass(mpc, field.getType().getName());
//mpc.setPropertyClass(field.getType().getName()); // FIXME - primitives, arrays, etc.
ManagedPropertyHandler.setValue(mpc, property.value());// FIXME - primitives, arrays, etc.
//mpc.setValue(property.value());
ReflectUtil.executeMethod(mbean, "addProperty", mpc);
}
}
}
/**
* <p>Return an array of all <code>Field</code>s reflecting declared
* fields in this class, or in any superclass other than
* <code>java.lang.Object</code>.</p>
*
* @param clazz Class to be analyzed
* @return the array of fields
*/
private Field[] fields(Class clazz) {
Map<String, Field> fields = new HashMap<String, Field>();
do {
for (Field field : clazz.getDeclaredFields()) {
if (!fields.containsKey(field.getName())) {
fields.put(field.getName(), field);
}
}
} while ((clazz = clazz.getSuperclass()) != Object.class);
return fields.values().toArray(new Field[fields.size()]);
}
protected boolean hasToReregister(String name, Class clazz) {
ManagedBean mbean = (ManagedBean) _alreadyRegistered.get(name);
return mbean == null || !mbean.getManagedBeanClassName().equals(clazz.getName());
}
/**
* name normalizer for automated name mapping
* (aka if no name attribute is given in the annotation)
*
* @param className the classname to be mapped (can be with package=
* @return the normalized jsf bean name
*/
private String normalizeName(String className) {
String name = className.substring(className.lastIndexOf(".") + 1);
return name.substring(0, 1).toLowerCase() + name.substring(1);
}
@SuppressWarnings("unchecked")
public void purge(String className) {
RuntimeConfig config = getRuntimeConfig();
//We have to purge and readd our managed beans, unfortunatly the myfaces impl enforces
//us to do the same for the nav rules after purge
//we cannot purge the managed beans and nav rules separately
Collection<NavigationRule> navigationRules = new ArrayList<NavigationRule>();
Map managedBeans = new HashMap<String, org.apache.myfaces.config.element.ManagedBean>();
navigationRules.addAll(config.getNavigationRules());
managedBeans.putAll(config.getManagedBeans());
config.purge();
for (NavigationRule navRule : navigationRules) {
config.addNavigationRule(navRule);
}
//We refresh the managed beans, dead references still can cause
//runtime errors but in this case we cannot do anything
org.apache.myfaces.config.element.ManagedBean mbeanFound = null;
List<String> mbeanKey = new LinkedList<String>();
for (Object entry : managedBeans.entrySet()) {
Map.Entry mbean = (Map.Entry) entry;
Object bean = mbean.getValue();
if (!((Class)ReflectUtil.executeMethod( bean, "getManagedBeanClass")).getName().equals(className)) {
config.addManagedBean((String) mbean.getKey(), (org.apache.myfaces.config.element.ManagedBean) mbean.getValue());
} else {
Object mbeanf = mbean.getValue();
mbeanKey.add((String)ReflectUtil.executeMethod(mbeanf, "getManagedBeanName"));
}
}
if (mbeanFound != null) {
for (String toRemove : mbeanKey) {
_alreadyRegistered.remove(toRemove);
}
}
}
protected RuntimeConfig getRuntimeConfig() {
final FacesContext facesContext = FacesContext.getCurrentInstance();
//runtime config not started
if (facesContext == null) {
return null;
}
return RuntimeConfig.getCurrentInstance(facesContext.getExternalContext());
}
}