View Javadoc

    1   /*
    2    * $Id: WrappingLookupCommand.java 471754 2006-11-06 14:55:09Z husted $
    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.struts.chain.commands.generic;
    22
    23  import org.apache.commons.beanutils.ConstructorUtils;
    24  import org.apache.commons.chain.Catalog;
    25  import org.apache.commons.chain.CatalogFactory;
    26  import org.apache.commons.chain.Command;
    27  import org.apache.commons.chain.Context;
    28  import org.apache.commons.chain.Filter;
    29  import org.apache.commons.logging.Log;
    30  import org.apache.commons.logging.LogFactory;
    31  import org.apache.struts.chain.commands.util.ClassUtils;
    32
    33  import java.lang.reflect.InvocationTargetException;
    34
    35  /**
    36   * <p>Variant on chain LookupCommand which can optionally wrap the context it
    37   * passes to the looked up command in an alternative class.</p>
    38   */
    39  public class WrappingLookupCommand implements Filter {
    40      /**
    41       * Provide Commons Logging instance for this class.
    42       */
    43      private static final Log LOG =
    44          LogFactory.getLog(WrappingLookupCommand.class);
    45
    46      // ------------------------------------------------------ Instance Variables
    47
    48      /**
    49       * <p>Field for property.</p>
    50       */
    51      private String catalogName = null;
    52
    53      /**
    54       * <p>Field for property.</p>
    55       */
    56      private String name = null;
    57
    58      /**
    59       * <p>Field for property.</p>
    60       */
    61      private String nameKey = null;
    62
    63      /**
    64       * <p>Field for property.</p>
    65       */
    66      private String wrapperClassName = null;
    67
    68      /**
    69       * <p>Field for property.</p>
    70       */
    71      private boolean optional = false;
    72
    73      /**
    74       * <p>Zero-argument constructor.</p>
    75       */
    76      public WrappingLookupCommand() {
    77          catalogName = null;
    78          name = null;
    79          nameKey = null;
    80          optional = false;
    81      }
    82
    83      /**
    84       * <p>Return CatalogName property.  </p>
    85       *
    86       * @return Value of CatalogName property.
    87       */
    88      public String getCatalogName() {
    89          return catalogName;
    90      }
    91
    92      /**
    93       * <p>Set CatalogName property.</p>
    94       *
    95       * @param catalogName New value for CatalogName
    96       */
    97      public void setCatalogName(String catalogName) {
    98          this.catalogName = catalogName;
    99      }
    100
    101     /**
    102      * <p>Retrieve Name property.</p>
    103      *
    104      * @return Value of Name property
    105      */
    106     public String getName() {
    107         return name;
    108     }
    109
    110     /**
    111      * <p>Set Name property.</p>
    112      *
    113      * @param name New value for Name
    114      */
    115     public void setName(String name) {
    116         this.name = name;
    117     }
    118
    119     /**
    120      * <p>Return NameKey property.</p>
    121      *
    122      * @return Value of NameKey property.
    123      */
    124     public String getNameKey() {
    125         return nameKey;
    126     }
    127
    128     /**
    129      * <p>Set NameKey property.</p>
    130      *
    131      * @param nameKey New value for NameKey
    132      */
    133     public void setNameKey(String nameKey) {
    134         this.nameKey = nameKey;
    135     }
    136
    137     /**
    138      * <p>Test Optional property.</p>
    139      *
    140      * @return TRUE if Optional is TRUE.
    141      */
    142     public boolean isOptional() {
    143         return optional;
    144     }
    145
    146     /**
    147      * <p>Set Optional property.</p>
    148      *
    149      * @param optional New value for Optional
    150      */
    151     public void setOptional(boolean optional) {
    152         this.optional = optional;
    153     }
    154
    155     /**
    156      * <p>Return the WrapperClass property.</p>
    157      *
    158      * @return The WrapperClass property
    159      */
    160     public String getWrapperClassName() {
    161         return wrapperClassName;
    162     }
    163
    164     /**
    165      * <p>Set WrappClassName property. </p>
    166      *
    167      * @param wrapperClassName The name of a WrapperClass
    168      */
    169     public void setWrapperClassName(String wrapperClassName) {
    170         this.wrapperClassName = wrapperClassName;
    171     }
    172
    173     /**
    174      * <p>Invoke the Command for a Context, returning TRUE if processing
    175      * should halt.</p>
    176      *
    177      * @param context Our ActionContext
    178      * @return TRUE if processing should halt
    179      * @throws Exception On any error
    180      */
    181     public boolean execute(Context context)
    182         throws Exception {
    183         if (LOG.isTraceEnabled()) {
    184             LOG.trace("execute [" + this + "]");
    185         }
    186
    187         Command command = getCommand(context);
    188
    189         if (command != null) {
    190             return command.execute(getContext(context));
    191         } else {
    192             return false;
    193         }
    194     }
    195
    196     /**
    197      * <p>Process the Exception for any Command that is a filter.</p>
    198      *
    199      * @param context   Our ActionContext
    200      * @param exception The Exception thrown by another Comamnd in a Chain
    201      * @return TRUE if there is a Filter to process
    202      */
    203     public boolean postprocess(Context context, Exception exception) {
    204         Command command = getCommand(context);
    205
    206         if ((command != null) && (command instanceof Filter)) {
    207             try {
    208                 return ((Filter) command).postprocess(getContext(context),
    209                     exception);
    210             } catch (NoSuchMethodException ex) {
    211                 LOG.error("Error wrapping context in postprocess", ex);
    212             } catch (IllegalAccessException ex) {
    213                 LOG.error("Error wrapping context in postprocess", ex);
    214             } catch (InvocationTargetException ex) {
    215                 LOG.error("Error wrapping context in postprocess", ex);
    216             } catch (InstantiationException ex) {
    217                 LOG.error("Error wrapping context in postprocess", ex);
    218             } catch (ClassNotFoundException ex) {
    219                 LOG.error("Error wrapping context in postprocess", ex);
    220             }
    221         }
    222
    223         return false;
    224     }
    225
    226     /**
    227      * <p>Return the Command to process for this Context.</p>
    228      *
    229      * @param context The Context we are processing
    230      * @return The Command to process for this Context
    231      */
    232     protected Command getCommand(Context context) {
    233         CatalogFactory catalogFactory = CatalogFactory.getInstance();
    234         String catalogName = getCatalogName();
    235         Catalog catalog;
    236
    237         if (catalogName == null) {
    238             catalog = catalogFactory.getCatalog();
    239             catalogName = "{default}"; // for debugging purposes
    240         } else {
    241             catalog = catalogFactory.getCatalog(catalogName);
    242         }
    243
    244         if (catalog == null) {
    245             throw new IllegalArgumentException("Cannot find catalog '"
    246                 + catalogName + "'");
    247         }
    248
    249         Command command;
    250         String name = getName();
    251
    252         if (name == null) {
    253             name = (String) context.get(getNameKey());
    254         }
    255
    256         if (name != null) {
    257             if (LOG.isDebugEnabled()) {
    258                 LOG.debug("Lookup command " + name + " in catalog "
    259                     + catalogName);
    260             }
    261
    262             command = catalog.getCommand(name);
    263
    264             if (LOG.isDebugEnabled()) {
    265                 LOG.debug("Found command " + command + ";" + " optional: "
    266                     + isOptional());
    267             }
    268
    269             if ((command == null) && !isOptional()) {
    270                 throw new IllegalArgumentException("Cannot find command " + "'"
    271                     + name + "' in catalog '" + catalogName + "'");
    272             } else {
    273                 return command;
    274             }
    275         } else {
    276             throw new IllegalArgumentException("No command name");
    277         }
    278     }
    279
    280     /**
    281      * <p>If the wrapperClassName property is not null, return a Context of
    282      * the type specified by wrapperClassName, instantiated using a single-arg
    283      * constructor which takes the context passed as an argument to this
    284      * method.</p>
    285      *
    286      * <p>This method throws an exception if the wrapperClass cannot be found,
    287      * or if there are any errors instantiating the wrapping context.</p>
    288      *
    289      * @param context Context we are processing
    290      * @return Context wrapper
    291      * @throws ClassNotFoundException    On failed instantiation
    292      * @throws InstantiationException    On failed instantiation
    293      * @throws InvocationTargetException On failed instantiation
    294      * @throws IllegalAccessException    On failed instantiation
    295      * @throws NoSuchMethodException     On failed instantiation
    296      */
    297     protected Context getContext(Context context)
    298         throws ClassNotFoundException, InstantiationException,
    299             InvocationTargetException, IllegalAccessException,
    300             NoSuchMethodException {
    301         if (wrapperClassName == null) {
    302             if (LOG.isDebugEnabled()) {
    303                 LOG.debug("No defined wrapper class; "
    304                     + "returning original context.");
    305             }
    306
    307             return context;
    308         }
    309
    310         if (LOG.isDebugEnabled()) {
    311             LOG.debug("Looking for wrapper class: " + wrapperClassName);
    312         }
    313
    314         Class wrapperClass = ClassUtils.getApplicationClass(wrapperClassName);
    315
    316         if (LOG.isDebugEnabled()) {
    317             LOG.debug("Instantiating wrapper class");
    318         }
    319
    320         return (Context) ConstructorUtils.invokeConstructor(wrapperClass,
    321             new Object[] { context });
    322     }
    323 }