View Javadoc

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