001: /*
002: * Copyright 1999-2004 The Apache Software Foundation
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: package org.apache.commons.chain.generic;
017:
018: import org.apache.commons.chain.Catalog;
019: import org.apache.commons.chain.CatalogFactory;
020: import org.apache.commons.chain.Command;
021: import org.apache.commons.chain.Context;
022: import org.apache.commons.chain.Filter;
023:
024: /**
025: * <p>Look up a specified {@link Command} (which could also be a
026: * {@link org.apache.commons.chain.Chain})
027: * in a {@link Catalog}, and delegate execution to it. If the delegated-to
028: * {@link Command} is also a {@link Filter}, its <code>postprocess()</code>
029: * method will also be invoked at the appropriate time.</p>
030: *
031: * <p>The name of the {@link Command} can be specified either directly (via
032: * the <code>name</code> property) or indirectly (via the <code>nameKey</code>
033: * property). Exactly one of these must be set.</p>
034: *
035: * <p>If the <code>optional</code> property is set to <code>true</code>,
036: * failure to find the specified command in the specified catalog will be
037: * silently ignored. Otherwise, a lookup failure will trigger an
038: * <code>IllegalArgumentException</code>.</p>
039: *
040: * @author Craig R. McClanahan
041: * @version $Revision: 411876 $ $Date: 2006-06-05 19:02:19 +0100 (Mon, 05 Jun 2006) $
042: */
043:
044: public class LookupCommand implements Filter {
045:
046: // -------------------------------------------------------------- Constructors
047:
048: /**
049: * Create an instance, setting its <code>catalogFactory</code> property to the
050: * value of <code>CatalogFactory.getInstance()</code>.
051: *
052: * @since Chain 1.1
053: */
054: public LookupCommand() {
055: this (CatalogFactory.getInstance());
056: }
057:
058: /**
059: * Create an instance and initialize the <code>catalogFactory</code> property
060: * to given <code>factory</code>/
061: *
062: * @param factory The Catalog Factory.
063: *
064: * @since Chain 1.1
065: */
066: public LookupCommand(CatalogFactory factory) {
067: this .catalogFactory = factory;
068: }
069:
070: // -------------------------------------------------------------- Properties
071:
072: private CatalogFactory catalogFactory = null;
073:
074: /**
075: * <p>Set the {@link CatalogFactory} from which lookups will be
076: * performed.</p>
077: *
078: * @param catalogFactory The Catalog Factory.
079: *
080: * @since Chain 1.1
081: */
082: public void setCatalogFactory(CatalogFactory catalogFactory) {
083: this .catalogFactory = catalogFactory;
084: }
085:
086: /**
087: * Return the {@link CatalogFactory} from which lookups will be performed.
088: * @return The Catalog factory.
089: *
090: * @since Chain 1.1
091: */
092: public CatalogFactory getCatalogFactory() {
093:
094: return this .catalogFactory;
095: }
096:
097: private String catalogName = null;
098:
099: /**
100: * <p>Return the name of the {@link Catalog} to be searched, or
101: * <code>null</code> to search the default {@link Catalog}.</p>
102: * @return The Catalog name.
103: */
104: public String getCatalogName() {
105:
106: return (this .catalogName);
107:
108: }
109:
110: /**
111: * <p>Set the name of the {@link Catalog} to be searched, or
112: * <code>null</code> to search the default {@link Catalog}.</p>
113: *
114: * @param catalogName The new {@link Catalog} name or <code>null</code>
115: */
116: public void setCatalogName(String catalogName) {
117:
118: this .catalogName = catalogName;
119:
120: }
121:
122: private String name = null;
123:
124: /**
125: * <p>Return the name of the {@link Command} that we will look up and
126: * delegate execution to.</p>
127: * @return The name of the Command.
128: */
129: public String getName() {
130:
131: return (this .name);
132:
133: }
134:
135: /**
136: * <p>Set the name of the {@link Command} that we will look up and
137: * delegate execution to.</p>
138: *
139: * @param name The new command name
140: */
141: public void setName(String name) {
142:
143: this .name = name;
144:
145: }
146:
147: private String nameKey = null;
148:
149: /**
150: * <p>Return the context attribute key under which the {@link Command}
151: * name is stored.</p>
152: * @return The context key of the Command.
153: */
154: public String getNameKey() {
155:
156: return (this .nameKey);
157:
158: }
159:
160: /**
161: * <p>Set the context attribute key under which the {@link Command}
162: * name is stored.</p>
163: *
164: * @param nameKey The new context attribute key
165: */
166: public void setNameKey(String nameKey) {
167:
168: this .nameKey = nameKey;
169:
170: }
171:
172: private boolean optional = false;
173:
174: /**
175: * <p>Return <code>true</code> if locating the specified command
176: * is optional.</p>
177: * @return <code>true</code> if the Command is optional.
178: */
179: public boolean isOptional() {
180:
181: return (this .optional);
182:
183: }
184:
185: /**
186: * <p>Set the optional flag for finding the specified command.</p>
187: *
188: * @param optional The new optional flag
189: */
190: public void setOptional(boolean optional) {
191:
192: this .optional = optional;
193:
194: }
195:
196: private boolean ignoreExecuteResult = false;
197:
198: /**
199: * <p>Return <code>true</code> if this command should ignore
200: * the return value from executing the looked-up command.
201: * Defaults to <code>false</code>, which means that the return result
202: * of executing this lookup will be whatever is returned from that
203: * command.</p>
204: * @return <code>true</code> if result of the looked up Command
205: * should be ignored.
206: *
207: * @since Chain 1.1
208: */
209: public boolean isIgnoreExecuteResult() {
210: return ignoreExecuteResult;
211: }
212:
213: /**
214: * <p>Set the rules for whether or not this class will ignore or
215: * pass through the value returned from executing the looked up
216: * command.</p>
217: * <p>If you are looking up a chain which may be "aborted" and
218: * you do not want this class to stop chain processing, then this
219: * value should be set to <code>true</code></p>
220: * @param ignoreReturn <code>true</code> if result of the
221: * looked up Command should be ignored.
222: *
223: * @since Chain 1.1
224: */
225: public void setIgnoreExecuteResult(boolean ignoreReturn) {
226: this .ignoreExecuteResult = ignoreReturn;
227: }
228:
229: private boolean ignorePostprocessResult = false;
230:
231: /**
232: * <p>Return <code>true</code> if this command is a Filter and
233: * should ignore the return value from executing the looked-up Filter's
234: * <code>postprocess()</code> method.
235: * Defaults to <code>false</code>, which means that the return result
236: * of executing this lookup will be whatever is returned from that
237: * Filter.</p>
238: * @return <code>true</code> if result of the looked up Filter's
239: * <code>postprocess()</code> method should be ignored.
240: *
241: * @since Chain 1.1
242: */
243: public boolean isIgnorePostprocessResult() {
244: return ignorePostprocessResult;
245: }
246:
247: /**
248: * <p>Set the rules for whether or not this class will ignore or
249: * pass through the value returned from executing the looked up
250: * Filter's <code>postprocess()</code> method.</p>
251: * <p>If you are looking up a Filter which may be "aborted" and
252: * you do not want this class to stop chain processing, then this
253: * value should be set to <code>true</code></p>
254: * @param ignorePostprocessResult <code>true</code> if result of the
255: * looked up Filter's <code>postprocess()</code> method should be ignored.
256: *
257: * @since Chain 1.1
258: */
259: public void setIgnorePostprocessResult(
260: boolean ignorePostprocessResult) {
261: this .ignorePostprocessResult = ignorePostprocessResult;
262: }
263:
264: // ---------------------------------------------------------- Filter Methods
265:
266: /**
267: * <p>Look up the specified command, and (if found) execute it.
268: * Unless <code>ignoreExecuteResult</code> is set to <code>true</code>,
269: * return the result of executing the found command. If no command
270: * is found, return <code>false</code>, unless the <code>optional</code>
271: * property is <code>false</code>, in which case an <code>IllegalArgumentException</code>
272: * will be thrown.
273: * </p>
274: *
275: * @param context The context for this request
276: *
277: * @exception IllegalArgumentException if no such {@link Command}
278: * can be found and the <code>optional</code> property is set
279: * to <code>false</code>
280: * @return the result of executing the looked-up command, or
281: * <code>false</code> if no command is found or if the command
282: * is found but the <code>ignoreExecuteResult</code> property of this
283: * instance is <code>true</code>
284: * @throws Exception if and error occurs in the looked-up Command.
285: */
286: public boolean execute(Context context) throws Exception {
287:
288: Command command = getCommand(context);
289: if (command != null) {
290: boolean result = (command.execute(context));
291: if (isIgnoreExecuteResult()) {
292: return false;
293: }
294: return result;
295: } else {
296: return (false);
297: }
298:
299: }
300:
301: /**
302: * <p>If the executed command was itself a {@link Filter}, call the
303: * <code>postprocess()</code> method of that {@link Filter} as well.</p>
304: *
305: * @param context The context for this request
306: * @param exception Any <code>Exception</code> thrown by command execution
307: *
308: * @return the result of executing the <code>postprocess</code> method
309: * of the looked-up command, unless <code>ignorePostprocessResult</code> is
310: * <code>true</code>. If no command is found, return <code>false</code>,
311: * unless the <code>optional</code> property is <code>false</code>, in which
312: * case <code>IllegalArgumentException</code> will be thrown.
313: */
314: public boolean postprocess(Context context, Exception exception) {
315:
316: Command command = getCommand(context);
317: if (command != null) {
318: if (command instanceof Filter) {
319: boolean result = (((Filter) command).postprocess(
320: context, exception));
321: if (isIgnorePostprocessResult()) {
322: return false;
323: }
324: return result;
325: }
326: }
327: return (false);
328:
329: }
330:
331: // --------------------------------------------------------- Private Methods
332:
333: /**
334: * <p>Return the {@link Command} instance to be delegated to.</p>
335: *
336: * @param context {@link Context} for this request
337: * @return The looked-up Command.
338: * @exception IllegalArgumentException if no such {@link Command}
339: * can be found and the <code>optional</code> property is set
340: * to <code>false</code>
341: */
342: protected Command getCommand(Context context) {
343: CatalogFactory lookupFactory = this .catalogFactory;
344: if (lookupFactory == null) {
345: lookupFactory = CatalogFactory.getInstance();
346: }
347:
348: String catalogName = getCatalogName();
349: Catalog catalog = null;
350: if (catalogName == null) {
351: // use default catalog
352: catalog = lookupFactory.getCatalog();
353: } else {
354: catalog = lookupFactory.getCatalog(catalogName);
355: }
356: if (catalog == null) {
357: if (catalogName == null) {
358: throw new IllegalArgumentException(
359: "Cannot find default catalog");
360: } else {
361: throw new IllegalArgumentException(
362: "Cannot find catalog '" + catalogName + "'");
363: }
364: }
365:
366: Command command = null;
367: String name = getName();
368: if (name == null) {
369: name = (String) context.get(getNameKey());
370: }
371: if (name != null) {
372: command = catalog.getCommand(name);
373: if ((command == null) && !isOptional()) {
374: if (catalogName == null) {
375: throw new IllegalArgumentException(
376: "Cannot find command '" + name
377: + "' in default catalog");
378: } else {
379: throw new IllegalArgumentException(
380: "Cannot find command '" + name
381: + "' in catalog '" + catalogName
382: + "'");
383: }
384: }
385: return (command);
386: } else {
387: throw new IllegalArgumentException("No command name");
388: }
389:
390: }
391:
392: }
|