001: /*
002: * $Id: WrappingLookupCommand.java 471754 2006-11-06 14:55:09Z husted $
003: *
004: * Licensed to the Apache Software Foundation (ASF) under one
005: * or more contributor license agreements. See the NOTICE file
006: * distributed with this work for additional information
007: * regarding copyright ownership. The ASF licenses this file
008: * to you under the Apache License, Version 2.0 (the
009: * "License"); you may not use this file except in compliance
010: * with the License. You may obtain a copy of the License at
011: *
012: * http://www.apache.org/licenses/LICENSE-2.0
013: *
014: * Unless required by applicable law or agreed to in writing,
015: * software distributed under the License is distributed on an
016: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
017: * KIND, either express or implied. See the License for the
018: * specific language governing permissions and limitations
019: * under the License.
020: */
021: package org.apache.struts.chain.commands.generic;
022:
023: import org.apache.commons.beanutils.ConstructorUtils;
024: import org.apache.commons.chain.Catalog;
025: import org.apache.commons.chain.CatalogFactory;
026: import org.apache.commons.chain.Command;
027: import org.apache.commons.chain.Context;
028: import org.apache.commons.chain.Filter;
029: import org.apache.commons.logging.Log;
030: import org.apache.commons.logging.LogFactory;
031: import org.apache.struts.chain.commands.util.ClassUtils;
032:
033: import java.lang.reflect.InvocationTargetException;
034:
035: /**
036: * <p>Variant on chain LookupCommand which can optionally wrap the context it
037: * passes to the looked up command in an alternative class.</p>
038: */
039: public class WrappingLookupCommand implements Filter {
040: /**
041: * Provide Commons Logging instance for this class.
042: */
043: private static final Log LOG = LogFactory
044: .getLog(WrappingLookupCommand.class);
045:
046: // ------------------------------------------------------ Instance Variables
047:
048: /**
049: * <p>Field for property.</p>
050: */
051: private String catalogName = null;
052:
053: /**
054: * <p>Field for property.</p>
055: */
056: private String name = null;
057:
058: /**
059: * <p>Field for property.</p>
060: */
061: private String nameKey = null;
062:
063: /**
064: * <p>Field for property.</p>
065: */
066: private String wrapperClassName = null;
067:
068: /**
069: * <p>Field for property.</p>
070: */
071: private boolean optional = false;
072:
073: /**
074: * <p>Zero-argument constructor.</p>
075: */
076: public WrappingLookupCommand() {
077: catalogName = null;
078: name = null;
079: nameKey = null;
080: optional = false;
081: }
082:
083: /**
084: * <p>Return CatalogName property. </p>
085: *
086: * @return Value of CatalogName property.
087: */
088: public String getCatalogName() {
089: return catalogName;
090: }
091:
092: /**
093: * <p>Set CatalogName property.</p>
094: *
095: * @param catalogName New value for CatalogName
096: */
097: public void setCatalogName(String catalogName) {
098: this .catalogName = catalogName;
099: }
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) throws Exception {
182: if (LOG.isTraceEnabled()) {
183: LOG.trace("execute [" + this + "]");
184: }
185:
186: Command command = getCommand(context);
187:
188: if (command != null) {
189: return command.execute(getContext(context));
190: } else {
191: return false;
192: }
193: }
194:
195: /**
196: * <p>Process the Exception for any Command that is a filter.</p>
197: *
198: * @param context Our ActionContext
199: * @param exception The Exception thrown by another Comamnd in a Chain
200: * @return TRUE if there is a Filter to process
201: */
202: public boolean postprocess(Context context, Exception exception) {
203: Command command = getCommand(context);
204:
205: if ((command != null) && (command instanceof Filter)) {
206: try {
207: return ((Filter) command).postprocess(
208: getContext(context), exception);
209: } catch (NoSuchMethodException ex) {
210: LOG.error("Error wrapping context in postprocess", ex);
211: } catch (IllegalAccessException ex) {
212: LOG.error("Error wrapping context in postprocess", ex);
213: } catch (InvocationTargetException ex) {
214: LOG.error("Error wrapping context in postprocess", ex);
215: } catch (InstantiationException ex) {
216: LOG.error("Error wrapping context in postprocess", ex);
217: } catch (ClassNotFoundException ex) {
218: LOG.error("Error wrapping context in postprocess", ex);
219: }
220: }
221:
222: return false;
223: }
224:
225: /**
226: * <p>Return the Command to process for this Context.</p>
227: *
228: * @param context The Context we are processing
229: * @return The Command to process for this Context
230: */
231: protected Command getCommand(Context context) {
232: CatalogFactory catalogFactory = CatalogFactory.getInstance();
233: String catalogName = getCatalogName();
234: Catalog catalog;
235:
236: if (catalogName == null) {
237: catalog = catalogFactory.getCatalog();
238: catalogName = "{default}"; // for debugging purposes
239: } else {
240: catalog = catalogFactory.getCatalog(catalogName);
241: }
242:
243: if (catalog == null) {
244: throw new IllegalArgumentException("Cannot find catalog '"
245: + catalogName + "'");
246: }
247:
248: Command command;
249: String name = getName();
250:
251: if (name == null) {
252: name = (String) context.get(getNameKey());
253: }
254:
255: if (name != null) {
256: if (LOG.isDebugEnabled()) {
257: LOG.debug("Lookup command " + name + " in catalog "
258: + catalogName);
259: }
260:
261: command = catalog.getCommand(name);
262:
263: if (LOG.isDebugEnabled()) {
264: LOG.debug("Found command " + command + ";"
265: + " optional: " + isOptional());
266: }
267:
268: if ((command == null) && !isOptional()) {
269: throw new IllegalArgumentException(
270: "Cannot find command " + "'" + name
271: + "' 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
315: .getApplicationClass(wrapperClassName);
316:
317: if (LOG.isDebugEnabled()) {
318: LOG.debug("Instantiating wrapper class");
319: }
320:
321: return (Context) ConstructorUtils.invokeConstructor(
322: wrapperClass, new Object[] { context });
323: }
324: }
|