1 /*
2 * Licensed to the Apache Software Foundation (ASF) under one
3 * or more contributor license agreements. See the NOTICE file
4 * distributed with this work for additional information
5 * regarding copyright ownership. The ASF licenses this file
6 * to you under the Apache License, Version 2.0 (the
7 * "License"); you may not use this file except in compliance
8 * with the License. You may obtain a copy of the License at
9 *
10 * http://www.apache.org/licenses/LICENSE-2.0
11 *
12 * Unless required by applicable law or agreed to in writing,
13 * software distributed under the License is distributed on an
14 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15 * KIND, either express or implied. See the License for the
16 * specific language governing permissions and limitations
17 * under the License.
18 */
19 package org.apache.myfaces.orchestra.annotation.spring;
20
21 import org.apache.commons.logging.Log;
22 import org.apache.commons.logging.LogFactory;
23 import org.apache.myfaces.orchestra.annotation.AnnotationInfo;
24 import org.apache.myfaces.orchestra.annotation.AnnotationInfoManager;
25 import org.apache.myfaces.orchestra.conversation.annotations.ConversationName;
26 import org.apache.myfaces.orchestra.conversation.spring.BeanDefinitionConversationNameAttrDecorator;
27 import org.apache.myfaces.orchestra.conversation.spring._SpringUtils;
28 import org.apache.myfaces.shared_orchestra.util.ClassUtils;
29 import org.springframework.beans.BeansException;
30 import org.springframework.beans.factory.config.BeanDefinition;
31 import org.springframework.beans.factory.config.BeanFactoryPostProcessor;
32 import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
33 import org.springframework.core.Ordered;
34
35 /**
36 * Parse all configured spring beans and extract Orchestra annotations out of
37 * them.
38 * <p>
39 * Just declaring an instance of this type as a Spring Singleton will cause the
40 * postProcessBeanFactory to be called passing in info about all the bean
41 * declarations in the spring context, allowing Orchestra annotations on any
42 * directly declared class to be discovered and processed.
43 * <p>
44 * Every class referenced from a bean declaration is then passed to the
45 * AnnotationInfoManager instance that has been injected into this object.
46 */
47 public class AnnotationsInfoInitializer implements BeanFactoryPostProcessor, Ordered
48 {
49 private Log log = LogFactory.getLog(AnnotationsInfoInitializer.class);
50
51 private int order = Ordered.LOWEST_PRECEDENCE; // default: same as non-Ordered
52
53 private AnnotationInfoManager annotationInfoManager;
54
55 /**
56 * Implement the Spring Ordered interface.
57 */
58 public int getOrder()
59 {
60 return order;
61 }
62
63 public void setOrder(int order)
64 {
65 this.order = order;
66 }
67
68 /**
69 * Inject the object that actually inspects each Class for Orchestra annotations.
70 */
71 public void setAnnotationInfoManager(AnnotationInfoManager annotationInfoManager)
72 {
73 this.annotationInfoManager = annotationInfoManager;
74 }
75
76 /**
77 * For each bean in the beanFactory, load the appropriate Class object and
78 * pass it to the annotationInfoManager object for inspection.
79 */
80 public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory)
81 throws BeansException
82 {
83 String[] beanNames = beanFactory.getBeanDefinitionNames();
84 for (String beanName : beanNames)
85 {
86 BeanDefinition beanDefinition = beanFactory.getBeanDefinition(beanName);
87 String className = beanDefinition.getBeanClassName();
88 if (className != null)
89 {
90 Class<?> beanClass = null;
91 try
92 {
93 beanClass = ClassUtils.classForName(className);
94 }
95 catch (ClassNotFoundException e)
96 {
97
98 if (log.isDebugEnabled())
99 {
100 log.debug(e.getLocalizedMessage(), e);
101 }
102 }
103
104 if (beanClass != null)
105 {
106 // XXX: Hack to deal with aop:scope-proxy (scopedTarget.) beans
107 if (!_SpringUtils.isAlternateBeanName(beanName))
108 {
109 // we are not on a scopedTarget ... check if there is one
110 String alternateBeanName = _SpringUtils.getAlternateBeanName(beanName);
111 if (beanFactory.containsBeanDefinition(alternateBeanName))
112 {
113 // ... yes, we are just interested in the alternate one.
114 continue;
115 }
116 }
117 String realBeanName = _SpringUtils.getRealBeanName(beanName);
118
119 // check whether the bean is an orchestra-annotated bean,
120 // and if so cache its annotation info for later use.
121 annotationInfoManager.processBeanAnnotations(realBeanName, beanClass);
122
123 // Now deal with any annotation data that must be processed at startup.
124 AnnotationInfo info = annotationInfoManager
125 .getAnnotationInfoByBeanName(realBeanName);
126 if (info != null)
127 {
128 processStartupAnnotations(beanDefinition, info);
129 }
130 }
131 }
132 }
133 }
134
135 /**
136 * Handle any annotations on a bean which should be processed on startup.
137 * <p>
138 * One such annotation is the
139 *
140 * @ConversationName annotation, which should modify the beanDefinition
141 * object, as it is equivalent to putting an
142 * orchestra:conversationName attribute in the spring bean
143 * declaration.
144 */
145 private void processStartupAnnotations(BeanDefinition beanDefinition, AnnotationInfo info)
146 {
147 ConversationName conversationName = info.getConversationName();
148 if (conversationName != null)
149 {
150 String convNameFromAnno = conversationName.value();
151 if (convNameFromAnno != null && convNameFromAnno.length() > 0)
152 {
153 String convNameFromDef = getConversationName(beanDefinition);
154 if (convNameFromDef == null)
155 {
156 setConversationName(beanDefinition, convNameFromAnno);
157 }
158 }
159 }
160 }
161
162 /**
163 * Get the orchestra conversationName attribute (if any) from the spring
164 * bean definition.
165 */
166 // TODO: Move this method into orchestra-core, then call it from here, from
167 // AbstractSpringOrchestraScope and BeanDefinition*Decorator. This of course
168 // creates a dependency from this code onto that modified orchestra-core
169 // version.
170 private static String getConversationName(BeanDefinition def)
171 {
172 return (String) def
173 .getAttribute(BeanDefinitionConversationNameAttrDecorator.CONVERSATION_NAME_ATTRIBUTE);
174 }
175
176 // See getConversationName
177 private static void setConversationName(BeanDefinition def, String convName)
178 {
179 def.setAttribute(BeanDefinitionConversationNameAttrDecorator.CONVERSATION_NAME_ATTRIBUTE,
180 convName);
181 }
182 }