001: package org.vraptor.webapp;
002:
003: import java.lang.reflect.Method;
004: import java.lang.reflect.Modifier;
005: import java.util.ArrayList;
006: import java.util.HashSet;
007: import java.util.List;
008: import java.util.Map;
009: import java.util.Set;
010: import java.util.concurrent.ConcurrentHashMap;
011: import java.util.concurrent.ConcurrentMap;
012:
013: import org.apache.log4j.Logger;
014: import org.vraptor.annotations.Component;
015: import org.vraptor.annotations.Destroy;
016: import org.vraptor.annotations.In;
017: import org.vraptor.annotations.Parameter;
018: import org.vraptor.annotations.Read;
019: import org.vraptor.component.BeanConstructor;
020: import org.vraptor.component.Clazz;
021: import org.vraptor.component.ComponentManager;
022: import org.vraptor.component.ComponentNotFoundException;
023: import org.vraptor.component.ComponentType;
024: import org.vraptor.component.DefaultComponentType;
025: import org.vraptor.component.DefaultLogicMethod;
026: import org.vraptor.component.FieldAnnotation;
027: import org.vraptor.component.InvalidComponentException;
028: import org.vraptor.component.LogicMethod;
029: import org.vraptor.component.LogicMethodFactory;
030: import org.vraptor.component.LogicNotFoundException;
031: import org.vraptor.interceptor.InterceptorType;
032: import org.vraptor.introspector.FieldParameter;
033: import org.vraptor.introspector.FieldReadParameter;
034: import org.vraptor.introspector.ReadParameter;
035: import org.vraptor.reflection.ReflectionUtil;
036: import org.vraptor.reflection.StringUtil;
037: import org.vraptor.scope.ScopeType;
038:
039: /**
040: * A simple implementation of a component manager.
041: *
042: * @author Guilherme Silveira
043: */
044: public class DefaultComponentManager implements ComponentManager {
045:
046: private static final Logger LOG = Logger
047: .getLogger(DefaultComponentManager.class);
048:
049: public static final String VALIDATE_METHOD_INITIALS = "validate";
050:
051: public static final String[] COMPONENT_TERMINATIONS = {
052: "Controller", "Logic", "Command", "Action", "Component" };
053:
054: private final ConcurrentMap<String, ConcurrentMap<String, ComponentType>> components = new ConcurrentHashMap<String, ConcurrentMap<String, ComponentType>>();
055:
056: private final LogicMethodFactory factory;
057:
058: public DefaultComponentManager(LogicMethodFactory factory) {
059: this .factory = factory;
060: }
061:
062: private List<ReadParameter> findParameters(Class<?> type) {
063: ArrayList<ReadParameter> reads = new ArrayList<ReadParameter>();
064: for (FieldAnnotation<Read> info : ReflectionUtil
065: .readAnnotations(type, Read.class)) {
066: reads.add(new FieldReadParameter(info));
067: }
068: for (FieldAnnotation<Parameter> info : ReflectionUtil
069: .readAnnotations(type, Parameter.class)) {
070: reads.add(new FieldParameter(info));
071: }
072: return reads;
073: }
074:
075: public ComponentType getComponent(String name, String logic)
076: throws ComponentNotFoundException, LogicNotFoundException {
077: if (!this .components.containsKey(name)) {
078: throw new ComponentNotFoundException(String.format(
079: "Component for %s not found", name));
080: }
081: if (!this .components.get(name).containsKey(logic)) {
082: throw new LogicNotFoundException(String.format(
083: "Logic for %s not found in component %s", logic,
084: name));
085: }
086: return this .components.get(name).get(logic);
087: }
088:
089: private String getComponentName(Class<?> type) {
090: String componentName;
091:
092: if (type.isAnnotationPresent(Component.class)) {
093: Component ann = ((Component) type
094: .getAnnotation(Component.class));
095: if (!ann.value().equals("")) {
096: componentName = ann.value();
097: } else {
098: String name = StringUtil.removeEnding(type
099: .getSimpleName(), COMPONENT_TERMINATIONS);
100:
101: if (!name.equals(type.getSimpleName())) {
102: componentName = name.toLowerCase();
103: } else {
104: componentName = type.getSimpleName();
105: }
106: }
107: } else {
108: componentName = type.getSimpleName();
109: }
110:
111: return componentName;
112: }
113:
114: public Set<ComponentType> getComponents() {
115: HashSet<ComponentType> components = new HashSet<ComponentType>();
116: for (Map<String, ComponentType> map : this .components.values()) {
117: components.addAll(map.values());
118: }
119: return components;
120: }
121:
122: public ComponentType getComponentType(Class<?> type)
123: throws InvalidComponentException {
124: String componentName = getComponentName(type);
125:
126: if (!type.isAnnotationPresent(Component.class)) {
127: LOG.warn("Deprecated: registering " + type.getName()
128: + " component without @Component annotation.");
129: }
130:
131: if (LOG.isDebugEnabled()) {
132: LOG.debug("Component found: " + componentName + " from "
133: + type.getName());
134: }
135:
136: ScopeType scope = getScope(type);
137:
138: Clazz clazz = new Clazz(type);
139: BeanConstructor constructor = clazz.findSingleConstructor();
140: LOG.debug("Registered constructor: " + constructor);
141:
142: Map<String, DefaultLogicMethod> actions = factory
143: .loadLogics(type);
144:
145: List<InterceptorType> interceptors = InterceptorType
146: .getInterceptors(type);
147:
148: // read fields
149: List<FieldAnnotation<In>> ins = ReflectionUtil.readAnnotations(
150: type, In.class);
151:
152: // destroy method
153: String destroyLogicName = getDestroyLogicName(type);
154:
155: LOG.debug("Component clazz " + type.getName() + " read");
156:
157: List<ReadParameter> reads = findParameters(type);
158:
159: DefaultComponentType componentType = new DefaultComponentType(
160: type, componentName, scope, constructor, actions, ins,
161: interceptors, destroyLogicName, reads);
162: for (DefaultLogicMethod method : actions.values()) {
163: method.setComponentType(componentType);
164: }
165: return componentType;
166:
167: }
168:
169: private String getDestroyLogicName(Class<?> type) {
170: String destroyLogicName = "destroy";
171: for (Method m : type.getMethods()) {
172: if (m.isAnnotationPresent(Destroy.class)) {
173: destroyLogicName = m.getName();
174: }
175: }
176: return destroyLogicName;
177: }
178:
179: private ScopeType getScope(Class<?> type) {
180: return type.isAnnotationPresent(Component.class) ? type
181: .getAnnotation(Component.class).scope()
182: : ScopeType.REQUEST;
183: }
184:
185: public void register(ComponentType type)
186: throws LogicNotFoundException {
187: LOG.debug(String.format("Registering component %s as %s", type
188: .getComponentClass(), type.getName()));
189: if (!this .components.containsKey(type.getName())) {
190: this .components.put(type.getName(),
191: new ConcurrentHashMap<String, ComponentType>());
192: }
193: for (LogicMethod logic : type.getLogics()) {
194: this .components.get(type.getName()).put(logic.getName(),
195: type);
196: }
197: }
198:
199: public boolean register(String typeClazz)
200: throws InvalidComponentException {
201: try {
202: Class<?> type = Class.forName(typeClazz);
203: if (Modifier.isPublic(type.getModifiers())) {
204: ComponentType component = getComponentType(type);
205: register(component);
206: return true;
207: } else {
208: LOG.warn("Ignoring non public class " + typeClazz);
209: return false;
210: }
211: } catch (LogicNotFoundException e) {
212: throw new InvalidComponentException(
213: "Unable to logic for type " + typeClazz, e);
214: } catch (ClassNotFoundException e) {
215: throw new InvalidComponentException("Unable to find type "
216: + typeClazz, e);
217: }
218: }
219:
220: }
|