View Javadoc

1   /*
2    * Copyright 2004-2008 the Seasar Foundation and the Others.
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 
13   * either express or implied. See the License for the specific language
14   * governing permissions and limitations under the License.
15   */
16  package org.seasar.uruma.desc.impl;
17  
18  import java.lang.reflect.Field;
19  import java.lang.reflect.Method;
20  import java.util.ArrayList;
21  import java.util.Collections;
22  import java.util.HashMap;
23  import java.util.List;
24  import java.util.Map;
25  import java.util.Map.Entry;
26  
27  import org.seasar.framework.beans.BeanDesc;
28  import org.seasar.framework.beans.PropertyDesc;
29  import org.seasar.framework.beans.factory.BeanDescFactory;
30  import org.seasar.framework.exception.EmptyRuntimeException;
31  import org.seasar.framework.util.StringUtil;
32  import org.seasar.uruma.annotation.ApplicationContext;
33  import org.seasar.uruma.annotation.AsyncMethod;
34  import org.seasar.uruma.annotation.EventListener;
35  import org.seasar.uruma.annotation.InitializeMethod;
36  import org.seasar.uruma.annotation.PostOpenMethod;
37  import org.seasar.uruma.binding.context.ApplicationContextDef;
38  import org.seasar.uruma.binding.method.EventListenerDef;
39  import org.seasar.uruma.core.UrumaMessageCodes;
40  import org.seasar.uruma.desc.PartActionDesc;
41  import org.seasar.uruma.exception.IllegalMethodException;
42  import org.seasar.uruma.exception.InitializeMethodException;
43  import org.seasar.uruma.exception.MethodInvocationException;
44  import org.seasar.uruma.jobs.ProgressMonitor;
45  import org.seasar.uruma.util.AssertionUtil;
46  
47  /**
48   * {@link PartActionDesc} の実装クラスです。<br />
49   * 
50   * @author y-komori
51   */
52  public class PartActionDescImpl implements PartActionDesc, UrumaMessageCodes {
53  
54      private Class<?> partActionClass;
55  
56      private BeanDesc beanDesc;
57  
58      private Method initializeMethod;
59  
60      private Method postOpenMethod;
61  
62      private Map<String, List<Method>> methodsCache = new HashMap<String, List<Method>>();
63  
64      private Map<String, Field> fieldsCache = new HashMap<String, Field>();
65  
66      private List<EventListenerDef> eventListenerDefs = new ArrayList<EventListenerDef>();
67  
68      private List<ApplicationContextDef> appContextDefs = new ArrayList<ApplicationContextDef>();
69  
70      private boolean isAsyncAction;
71  
72      private PropertyDesc progressMonitorProperty;
73  
74      /**
75       * {@link PartActionDescImpl} を構築します。<br />
76       * 
77       * @param partActionClass
78       *            対応するクラスオブジェクト
79       */
80      public PartActionDescImpl(final Class<?> partActionClass) {
81          if (partActionClass == null) {
82              throw new EmptyRuntimeException("partActionClass");
83          }
84  
85          this.partActionClass = partActionClass;
86          this.beanDesc = BeanDescFactory.getBeanDesc(partActionClass);
87  
88          setupIsAsyncMethod();
89          setupMethods();
90          setupFields();
91          setupProgressMonitorProperty();
92      }
93  
94      /*
95       * @see org.seasar.uruma.desc.PartActionDesc#getInitializeMethod()
96       */
97      public Method getInitializeMethod() {
98          return this.initializeMethod;
99      }
100 
101     /*
102      * @see org.seasar.uruma.desc.PartActionDesc#invokeInitializeMethod(java.lang.Object)
103      */
104     public void invokeInitializeMethod(final Object target) {
105         if (initializeMethod != null) {
106             AssertionUtil.assertNotNull("target", target);
107             try {
108                 initializeMethod.invoke(target, (Object[]) null);
109             } catch (Throwable ex) {
110                 throw new InitializeMethodException(ex.getCause(),
111                         partActionClass, initializeMethod, target);
112             }
113         }
114     }
115 
116     /*
117      * @see org.seasar.uruma.desc.PartActionDesc#getPostOpenMethod()
118      */
119     public Method getPostOpenMethod() {
120         return this.postOpenMethod;
121     }
122 
123     /*
124      * @see org.seasar.uruma.desc.PartActionDesc#invokePostOpenMethod(java.lang.Object)
125      */
126     public void invokePostOpenMethod(final Object target) {
127         if (postOpenMethod != null) {
128             AssertionUtil.assertNotNull("target", target);
129             try {
130                 postOpenMethod.invoke(target, (Object[]) null);
131             } catch (Throwable ex) {
132                 throw new MethodInvocationException(ex);
133             }
134         }
135     }
136 
137     /*
138      * @see org.seasar.uruma.desc.PartActionDesc#getEventListenerDefList()
139      */
140     public List<EventListenerDef> getEventListenerDefList() {
141         return Collections.unmodifiableList(eventListenerDefs);
142     }
143 
144     /*
145      * @see org.seasar.uruma.desc.PartActionDesc#getApplicationContextDefList()
146      */
147     public List<ApplicationContextDef> getApplicationContextDefList() {
148         return Collections.unmodifiableList(appContextDefs);
149     }
150 
151     /*
152      * @see org.seasar.uruma.desc.PartActionDesc#getBeanDesc()
153      */
154     public BeanDesc getBeanDesc() {
155         return this.beanDesc;
156     }
157 
158     /*
159      * @see org.seasar.uruma.desc.PartActionDesc#getPartActionClass()
160      */
161     public Class<?> getPartActionClass() {
162         return this.partActionClass;
163     }
164 
165     /*
166      * @see org.seasar.uruma.desc.PartActionDesc#injectProgressMonitor(java.lang.Object,
167      *      org.seasar.uruma.jobs.ProgressMonitor)
168      */
169     public void injectProgressMonitor(final Object target,
170             final ProgressMonitor monitor) {
171         if (progressMonitorProperty != null) {
172             progressMonitorProperty.setValue(target, monitor);
173         }
174     }
175 
176     protected void setupMethods() {
177         Map<String, List<Method>> methodListMap = new HashMap<String, List<Method>>();
178         Method[] methods = partActionClass.getMethods();
179         for (int i = 0; i < methods.length; i++) {
180             List<Method> methodList = methodListMap.get(methods[i].getName());
181             if (methodList == null) {
182                 methodList = new ArrayList<Method>();
183                 methodListMap.put(methods[i].getName(), methodList);
184             }
185             methodList.add(methods[i]);
186 
187             setupInitializeMethod(methods[i]);
188             setupPostOpenMethod(methods[i]);
189             setupEventListenerMethod(methods[i]);
190         }
191 
192         for (Entry<String, List<Method>> entry : methodListMap.entrySet()) {
193             String methodName = entry.getKey();
194             List<Method> methodList = entry.getValue();
195             methodsCache.put(methodName, methodList);
196         }
197     }
198 
199     protected void setupInitializeMethod(final Method method) {
200         if (method.isAnnotationPresent(InitializeMethod.class)) {
201             if ((method.getReturnType() == Void.TYPE)
202                     && (method.getParameterTypes().length == 0)) {
203                 if (initializeMethod == null) {
204                     initializeMethod = method;
205                 } else {
206                     throw new IllegalMethodException(
207                             DUPLICATE_ANNOTATED_METHOD, partActionClass, method);
208                 }
209             } else {
210                 throw new IllegalMethodException(ILLEGAL_METHOD_SIGNATURE,
211                         partActionClass, method);
212             }
213         }
214     }
215 
216     protected void setupPostOpenMethod(final Method method) {
217         if (method.isAnnotationPresent(PostOpenMethod.class)) {
218             if ((method.getReturnType() == Void.TYPE)
219                     && (method.getParameterTypes().length == 0)) {
220                 if (postOpenMethod == null) {
221                     postOpenMethod = method;
222                 } else {
223                     throw new InitializeMethodException(
224                             DUPLICATE_ANNOTATED_METHOD, partActionClass, method);
225                 }
226             } else {
227                 throw new InitializeMethodException(ILLEGAL_METHOD_SIGNATURE,
228                         partActionClass, method);
229             }
230         }
231     }
232 
233     protected void setupEventListenerMethod(final Method method) {
234         EventListener anno = method.getAnnotation(EventListener.class);
235         if (anno != null) {
236             AsyncMethod asyncMethod = method.getAnnotation(AsyncMethod.class);
237             EventListenerDef def = new EventListenerDef(method, anno,
238                     asyncMethod);
239             eventListenerDefs.add(def);
240         }
241     }
242 
243     protected void setupApplicationContext(final Field field) {
244         ApplicationContext anno = field.getAnnotation(ApplicationContext.class);
245         if (anno != null) {
246             String name = anno.name();
247             if (StringUtil.isEmpty(name)) {
248                 name = field.getName();
249             }
250 
251             PropertyDesc pd = beanDesc.getPropertyDesc(field.getName());
252             ApplicationContextDef def = new ApplicationContextDef(pd, name);
253             appContextDefs.add(def);
254         }
255     }
256 
257     protected void setupFields() {
258         setupFieldsByClass(partActionClass);
259         Class<?> superClass = partActionClass.getSuperclass();
260         while (superClass != Object.class && superClass != null) {
261             setupFieldsByClass(superClass);
262             superClass = superClass.getSuperclass();
263         }
264     }
265 
266     protected void setupFieldsByClass(final Class<?> targetClass) {
267         Field[] fields = targetClass.getDeclaredFields();
268         for (int i = 0; i < fields.length; i++) {
269             Field field = fields[i];
270             String fieldName = field.getName();
271             if (!fieldsCache.containsKey(fieldName)) {
272                 field.setAccessible(true);
273                 fieldsCache.put(fieldName, field);
274 
275                 setupApplicationContext(field);
276             }
277         }
278     }
279 
280     protected void setupIsAsyncMethod() {
281         if (partActionClass.isAnnotationPresent(AsyncMethod.class)) {
282             this.isAsyncAction = true;
283         } else {
284             this.isAsyncAction = false;
285         }
286     }
287 
288     protected void setupProgressMonitorProperty() {
289         BeanDesc desc = BeanDescFactory.getBeanDesc(partActionClass);
290         int size = desc.getPropertyDescSize();
291         for (int i = 0; i < size; i++) {
292             PropertyDesc pd = desc.getPropertyDesc(i);
293             Class<?> type = pd.getPropertyType();
294             if (type.isAssignableFrom(ProgressMonitor.class) && pd.isWritable()) {
295                 this.progressMonitorProperty = pd;
296                 break;
297             }
298         }
299     }
300 }