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 }