View Javadoc

1   /*
2    * $Id: PlexusObjectFactory.java 439747 2006-09-03 09:22:46Z mrdon $
3    *
4    * Copyright 2006 The Apache Software Foundation.
5    *
6    * Licensed under the Apache License, Version 2.0 (the "License");
7    * you may not use this file except in compliance with the License.
8    * 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, software
13   * distributed under the License is distributed on an "AS IS" BASIS,
14   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15   * See the License for the specific language governing permissions and
16   * limitations under the License.
17   */
18  package org.apache.struts2.plexus;
19  
20  import java.util.HashMap;
21  import java.util.Map;
22  
23  import javax.servlet.ServletContext;
24  
25  import org.apache.commons.logging.Log;
26  import org.apache.commons.logging.LogFactory;
27  import org.apache.struts2.util.ObjectFactoryInitializable;
28  import org.codehaus.plexus.PlexusContainer;
29  
30  import com.opensymphony.xwork2.Action;
31  import com.opensymphony.xwork2.ObjectFactory;
32  import com.opensymphony.xwork2.Result;
33  import com.opensymphony.xwork2.config.ConfigurationException;
34  import com.opensymphony.xwork2.config.entities.ActionConfig;
35  import com.opensymphony.xwork2.config.entities.InterceptorConfig;
36  import com.opensymphony.xwork2.config.entities.ResultConfig;
37  import com.opensymphony.xwork2.interceptor.Interceptor;
38  import com.opensymphony.xwork2.util.OgnlUtil;
39  import com.opensymphony.xwork2.validator.Validator;
40  
41  /***
42   * Plexus integartion. You need three optional files: plexus-request.xml, plexus-session.xml, and
43   * plexus-application.xml.
44   * <p/>
45   * The syntax of these files is:
46   * <p/>
47   * <pre>
48   * &lt;plexus&gt;
49   * &lt;components&gt;
50   *  &lt;component&gt;
51   *      &lt;role&gt;com.acme.MyBean&lt;/role&gt;
52   *      &lt;implementation&gt;com.acme.MyBean|com.acme.MyBeanImpl&lt;/implementation&gt;
53   *      &lt;componentComposer&gt;field|setter|?&lt;/componentComposer&gt;
54   *      &lt;requirements&gt;
55   *          &lt;requirement&gt;
56   *              &lt;role&gt;com.acme.MyOtherBean&lt;/role&gt;
57   *          &lt;/requirement&gt;
58   *      &lt;/requirements&gt;
59   *      &lt;configuration&gt;
60   *          &lt;foo&gt;123&lt;/foo&gt;
61   *          &lt;bar&gt;hello, world&lt;/bar&gt;
62   *      &lt;/configuration&gt;
63   *      &lt;/component&gt;
64   *  &lt;/components&gt;
65   * &lt;/plexus&gt;
66   * </pre>
67   *
68   * @author <a href="mailto:evenisse@apache.org">Emmanuel Venisse</a>
69   */
70  public class PlexusObjectFactory extends ObjectFactory implements ObjectFactoryInitializable {
71      private static final Log log = LogFactory.getLog(PlexusObjectFactory.class);
72  
73      private static final String PLEXUS_COMPONENT_TYPE = "plexus.component.type";
74  
75      private PlexusContainer base;
76  
77      /* (non-Javadoc)
78       * @see org.apache.struts2.util.ObjectFactoryInitializable#init(javax.servlet.ServletContext)
79       */
80      public void init(ServletContext servletContext) {
81          if (!PlexusLifecycleListener.isLoaded() || !PlexusFilter.isLoaded()) {
82              // uh oh! looks like the lifecycle listener wasn't installed. Let's inform the user
83              String message = "********** FATAL ERROR STARTING UP PLEXUS-STRUTS INTEGRATION **********\n" +
84                      "Looks like the Plexus listener was not configured for your web app! \n" +
85                      "You need to add the following to web.xml: \n" +
86                      "\n" +
87                      "    <!-- this should be before the Struts filter -->\n" +
88                      "    <filter>\n" +
89                      "        <filter-name>plexus</filter-name>\n" +
90                      "        <filter-class>org.apache.struts2.plexus.PlexusFilter</filter-class>\n" +
91                      "    </filter>\n" +
92                      "\n" +
93                      "...\n" +
94                      "\n" +
95                      "    <!-- this should be before the Struts filter -->\n" +
96                      "    <filter-mapping>\n" +
97                      "        <filter-name>plexus</filter-name>\n" +
98                      "        <url-pattern>/*</url-pattern>\n" +
99                      "    </filter-mapping>\n" +
100                     "\n" +
101                     "...\n" +
102                     "\n" +
103                     "    <listener>\n" +
104                     "        <listener-class>org.apache.struts2.plexus.PlexusLifecycleListener</listener-class>\n" +
105                     "    </listener>";
106             log.fatal(message);
107             return;
108         }
109 
110         base = (PlexusContainer) servletContext.getAttribute(PlexusLifecycleListener.KEY);
111     }
112 
113     /* (non-Javadoc)
114      * @see com.opensymphony.xwork2.ObjectFactory#buildAction(java.lang.String, java.lang.String, com.opensymphony.xwork2.config.entities.ActionConfig, java.util.Map)
115      */
116     public Object buildAction(String actionName, String namespace, ActionConfig config, Map extraContext)
117             throws Exception {
118         if (extraContext == null) {
119             extraContext = new HashMap();
120         }
121 
122         extraContext.put(PLEXUS_COMPONENT_TYPE, Action.class.getName());
123 
124         return super.buildAction(actionName, namespace, config, extraContext);
125     }
126 
127     /* (non-Javadoc)
128      * @see com.opensymphony.xwork2.ObjectFactory#buildInterceptor(com.opensymphony.xwork2.config.entities.InterceptorConfig, java.util.Map)
129      */
130     public Interceptor buildInterceptor(InterceptorConfig interceptorConfig, Map interceptorRefParams)
131             throws ConfigurationException {
132         String interceptorClassName = interceptorConfig.getClassName();
133         Map thisInterceptorClassParams = interceptorConfig.getParams();
134         Map params = (thisInterceptorClassParams == null) ? new HashMap() : new HashMap(thisInterceptorClassParams);
135         params.putAll(interceptorRefParams);
136 
137         String message;
138         Throwable cause;
139 
140         try {
141             Map extraContext = new HashMap();
142             extraContext.put(PLEXUS_COMPONENT_TYPE, Interceptor.class.getName());
143             Interceptor interceptor = (Interceptor) buildBean(interceptorClassName, extraContext);
144             OgnlUtil.setProperties(params, interceptor);
145             interceptor.init();
146 
147             return interceptor;
148         }
149         catch (InstantiationException e) {
150             cause = e;
151             message = "Unable to instantiate an instance of Interceptor class [" + interceptorClassName + "].";
152         }
153         catch (IllegalAccessException e) {
154             cause = e;
155             message = "IllegalAccessException while attempting to instantiate an instance of Interceptor class [" + interceptorClassName + "].";
156         }
157         catch (ClassCastException e) {
158             cause = e;
159             message = "Class [" + interceptorClassName + "] does not implement com.opensymphony.xwork2.interceptor.Interceptor";
160         }
161         catch (Exception e) {
162             cause = e;
163             message = "Caught Exception while registering Interceptor class " + interceptorClassName;
164         }
165         catch (NoClassDefFoundError e) {
166             cause = e;
167             message = "Could not load class " + interceptorClassName + ". Perhaps it exists but certain dependencies are not available?";
168         }
169 
170         throw new ConfigurationException(message, cause);
171     }
172 
173     /* (non-Javadoc)
174      * @see com.opensymphony.xwork2.ObjectFactory#buildResult(com.opensymphony.xwork2.config.entities.ResultConfig, java.util.Map)
175      */
176     public Result buildResult(ResultConfig resultConfig, Map extraContext)
177             throws Exception {
178         if (extraContext == null) {
179             extraContext = new HashMap();
180         }
181 
182         extraContext.put(PLEXUS_COMPONENT_TYPE, Result.class.getName());
183 
184         return super.buildResult(resultConfig, extraContext);
185     }
186 
187     /* (non-Javadoc)
188      * @see com.opensymphony.xwork2.ObjectFactory#buildValidator(java.lang.String, java.util.Map, java.util.Map)
189      */
190     public Validator buildValidator(String className, Map params, Map extraContext)
191             throws Exception {
192         Map context = new HashMap();
193         context.put(PLEXUS_COMPONENT_TYPE, Validator.class.getName());
194         Validator validator = (Validator) buildBean(className, context);
195         OgnlUtil.setProperties(params, validator);
196 
197         return validator;
198     }
199 
200     /* (non-Javadoc)
201      * @see com.opensymphony.xwork2.ObjectFactory#buildBean(java.lang.Class, java.util.Map)
202      */
203     public Object buildBean(Class clazz, Map extraContext)
204             throws Exception {
205         try {
206             return lookup(clazz.getName(), extraContext);
207         }
208         catch (Exception e) {
209             if (extraContext != null) {
210                 String type = (String) extraContext.get(PLEXUS_COMPONENT_TYPE);
211 
212                 if (type != null) {
213                     return lookup(type, clazz.getName(), extraContext);
214                 }
215             }
216 
217             throw e;
218         }
219     }
220 
221     /* (non-Javadoc)
222      * @see com.opensymphony.xwork2.ObjectFactory#getClassInstance(java.lang.String)
223      */
224     public Class getClassInstance(String className)
225             throws ClassNotFoundException {
226         PlexusContainer pc = PlexusThreadLocal.getPlexusContainer();
227 
228         if (pc == null) {
229             pc = base;
230         }
231 
232         try {
233             return pc.lookup(className).getClass();
234         }
235         catch (Exception e1) {
236             try {
237                 return pc.lookup(Action.class.getName(), className).getClass();
238             }
239             catch (Exception e2) {
240                 try {
241                     return pc.lookup(Interceptor.class.getName(), className).getClass();
242                 }
243                 catch (Exception e3) {
244                     try {
245                         return pc.lookup(Validator.class.getName(), className).getClass();
246                     }
247                     catch (Exception e4) {
248                         try {
249                             return pc.lookup(Result.class.getName(), className).getClass();
250                         }
251                         catch (Exception e5) {
252                             return super.getClassInstance(className);
253                         }
254                     }
255                 }
256             }
257         }
258     }
259 
260     /***
261      * Looks up an object
262      * 
263      * @param role The role name
264      * @param extraContext The extra context
265      * @return The object
266      * @throws Exception If the lookup fails
267      */
268     private Object lookup(String role, Map extraContext)
269             throws Exception {
270         return lookup(role, null, extraContext);
271     }
272 
273     /***
274      * Looks up an object
275      * 
276      * @param role The role name
277      * @param roleHint The role hint
278      * @param extraContext The extra context
279      * @return The object
280      * @throws Exception If the lookup fails
281      */
282     private Object lookup(String role, String roleHint, Map extraContext)
283             throws Exception {
284         PlexusContainer pc = PlexusThreadLocal.getPlexusContainer();
285 
286         if (pc == null) {
287             pc = base;
288         }
289 
290         try {
291             return pc.lookup(role, roleHint);
292         }
293         catch (Exception e) {
294             log.debug("Can't load component (" + role + "/" + roleHint + ") with plexus, try now with struts.", e);
295             Object o = super.buildBean(super.getClassInstance(role), extraContext);
296             pc.autowire(o);
297             return o;
298         }
299     }
300 }