1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 package org.apache.commons.chain.generic;
17
18
19 import org.apache.commons.chain.Catalog;
20 import org.apache.commons.chain.CatalogFactory;
21 import org.apache.commons.chain.Command;
22 import org.apache.commons.chain.Context;
23 import org.apache.commons.chain.Filter;
24
25
26 /***
27 * <p>Look up a specified {@link Command} (which could also be a
28 * {@link org.apache.commons.chain.Chain})
29 * in a {@link Catalog}, and delegate execution to it. If the delegated-to
30 * {@link Command} is also a {@link Filter}, its <code>postprocess()</code>
31 * method will also be invoked at the appropriate time.</p>
32 *
33 * <p>The name of the {@link Command} can be specified either directly (via
34 * the <code>name</code> property) or indirectly (via the <code>nameKey</code>
35 * property). Exactly one of these must be set.</p>
36 *
37 * <p>If the <code>optional</code> property is set to <code>true</code>,
38 * failure to find the specified command in the specified catalog will be
39 * silently ignored. Otherwise, a lookup failure will trigger an
40 * <code>IllegalArgumentException</code>.</p>
41 *
42 * @author Craig R. McClanahan
43 * @version $Revision: 411876 $ $Date: 2006-06-05 19:02:19 +0100 (Mon, 05 Jun 2006) $
44 */
45
46 public class LookupCommand implements Filter {
47
48
49
50
51 /***
52 * Create an instance, setting its <code>catalogFactory</code> property to the
53 * value of <code>CatalogFactory.getInstance()</code>.
54 *
55 * @since Chain 1.1
56 */
57 public LookupCommand() {
58 this(CatalogFactory.getInstance());
59 }
60
61 /***
62 * Create an instance and initialize the <code>catalogFactory</code> property
63 * to given <code>factory</code>/
64 *
65 * @param factory The Catalog Factory.
66 *
67 * @since Chain 1.1
68 */
69 public LookupCommand(CatalogFactory factory) {
70 this.catalogFactory = factory;
71 }
72
73
74
75
76 private CatalogFactory catalogFactory = null;
77
78 /***
79 * <p>Set the {@link CatalogFactory} from which lookups will be
80 * performed.</p>
81 *
82 * @param catalogFactory The Catalog Factory.
83 *
84 * @since Chain 1.1
85 */
86 public void setCatalogFactory(CatalogFactory catalogFactory) {
87 this.catalogFactory = catalogFactory;
88 }
89
90 /***
91 * Return the {@link CatalogFactory} from which lookups will be performed.
92 * @return The Catalog factory.
93 *
94 * @since Chain 1.1
95 */
96 public CatalogFactory getCatalogFactory() {
97
98 return this.catalogFactory;
99 }
100
101
102 private String catalogName = null;
103
104 /***
105 * <p>Return the name of the {@link Catalog} to be searched, or
106 * <code>null</code> to search the default {@link Catalog}.</p>
107 * @return The Catalog name.
108 */
109 public String getCatalogName() {
110
111 return (this.catalogName);
112
113 }
114
115
116 /***
117 * <p>Set the name of the {@link Catalog} to be searched, or
118 * <code>null</code> to search the default {@link Catalog}.</p>
119 *
120 * @param catalogName The new {@link Catalog} name or <code>null</code>
121 */
122 public void setCatalogName(String catalogName) {
123
124 this.catalogName = catalogName;
125
126 }
127
128
129 private String name = null;
130
131
132 /***
133 * <p>Return the name of the {@link Command} that we will look up and
134 * delegate execution to.</p>
135 * @return The name of the Command.
136 */
137 public String getName() {
138
139 return (this.name);
140
141 }
142
143
144 /***
145 * <p>Set the name of the {@link Command} that we will look up and
146 * delegate execution to.</p>
147 *
148 * @param name The new command name
149 */
150 public void setName(String name) {
151
152 this.name = name;
153
154 }
155
156
157 private String nameKey = null;
158
159
160 /***
161 * <p>Return the context attribute key under which the {@link Command}
162 * name is stored.</p>
163 * @return The context key of the Command.
164 */
165 public String getNameKey() {
166
167 return (this.nameKey);
168
169 }
170
171
172 /***
173 * <p>Set the context attribute key under which the {@link Command}
174 * name is stored.</p>
175 *
176 * @param nameKey The new context attribute key
177 */
178 public void setNameKey(String nameKey) {
179
180 this.nameKey = nameKey;
181
182 }
183
184
185 private boolean optional = false;
186
187
188 /***
189 * <p>Return <code>true</code> if locating the specified command
190 * is optional.</p>
191 * @return <code>true</code> if the Command is optional.
192 */
193 public boolean isOptional() {
194
195 return (this.optional);
196
197 }
198
199
200 /***
201 * <p>Set the optional flag for finding the specified command.</p>
202 *
203 * @param optional The new optional flag
204 */
205 public void setOptional(boolean optional) {
206
207 this.optional = optional;
208
209 }
210
211 private boolean ignoreExecuteResult = false;
212
213 /***
214 * <p>Return <code>true</code> if this command should ignore
215 * the return value from executing the looked-up command.
216 * Defaults to <code>false</code>, which means that the return result
217 * of executing this lookup will be whatever is returned from that
218 * command.</p>
219 * @return <code>true</code> if result of the looked up Command
220 * should be ignored.
221 *
222 * @since Chain 1.1
223 */
224 public boolean isIgnoreExecuteResult() {
225 return ignoreExecuteResult;
226 }
227
228 /***
229 * <p>Set the rules for whether or not this class will ignore or
230 * pass through the value returned from executing the looked up
231 * command.</p>
232 * <p>If you are looking up a chain which may be "aborted" and
233 * you do not want this class to stop chain processing, then this
234 * value should be set to <code>true</code></p>
235 * @param ignoreReturn <code>true</code> if result of the
236 * looked up Command should be ignored.
237 *
238 * @since Chain 1.1
239 */
240 public void setIgnoreExecuteResult(boolean ignoreReturn) {
241 this.ignoreExecuteResult = ignoreReturn;
242 }
243
244 private boolean ignorePostprocessResult = false;
245
246 /***
247 * <p>Return <code>true</code> if this command is a Filter and
248 * should ignore the return value from executing the looked-up Filter's
249 * <code>postprocess()</code> method.
250 * Defaults to <code>false</code>, which means that the return result
251 * of executing this lookup will be whatever is returned from that
252 * Filter.</p>
253 * @return <code>true</code> if result of the looked up Filter's
254 * <code>postprocess()</code> method should be ignored.
255 *
256 * @since Chain 1.1
257 */
258 public boolean isIgnorePostprocessResult() {
259 return ignorePostprocessResult;
260 }
261
262 /***
263 * <p>Set the rules for whether or not this class will ignore or
264 * pass through the value returned from executing the looked up
265 * Filter's <code>postprocess()</code> method.</p>
266 * <p>If you are looking up a Filter which may be "aborted" and
267 * you do not want this class to stop chain processing, then this
268 * value should be set to <code>true</code></p>
269 * @param ignorePostprocessResult <code>true</code> if result of the
270 * looked up Filter's <code>postprocess()</code> method should be ignored.
271 *
272 * @since Chain 1.1
273 */
274 public void setIgnorePostprocessResult(boolean ignorePostprocessResult) {
275 this.ignorePostprocessResult = ignorePostprocessResult;
276 }
277
278
279
280 /***
281 * <p>Look up the specified command, and (if found) execute it.
282 * Unless <code>ignoreExecuteResult</code> is set to <code>true</code>,
283 * return the result of executing the found command. If no command
284 * is found, return <code>false</code>, unless the <code>optional</code>
285 * property is <code>false</code>, in which case an <code>IllegalArgumentException</code>
286 * will be thrown.
287 * </p>
288 *
289 * @param context The context for this request
290 *
291 * @exception IllegalArgumentException if no such {@link Command}
292 * can be found and the <code>optional</code> property is set
293 * to <code>false</code>
294 * @return the result of executing the looked-up command, or
295 * <code>false</code> if no command is found or if the command
296 * is found but the <code>ignoreExecuteResult</code> property of this
297 * instance is <code>true</code>
298 * @throws Exception if and error occurs in the looked-up Command.
299 */
300 public boolean execute(Context context) throws Exception {
301
302 Command command = getCommand(context);
303 if (command != null) {
304 boolean result = (command.execute(context));
305 if (isIgnoreExecuteResult()) {
306 return false;
307 }
308 return result;
309 } else {
310 return (false);
311 }
312
313 }
314
315
316 /***
317 * <p>If the executed command was itself a {@link Filter}, call the
318 * <code>postprocess()</code> method of that {@link Filter} as well.</p>
319 *
320 * @param context The context for this request
321 * @param exception Any <code>Exception</code> thrown by command execution
322 *
323 * @return the result of executing the <code>postprocess</code> method
324 * of the looked-up command, unless <code>ignorePostprocessResult</code> is
325 * <code>true</code>. If no command is found, return <code>false</code>,
326 * unless the <code>optional</code> property is <code>false</code>, in which
327 * case <code>IllegalArgumentException</code> will be thrown.
328 */
329 public boolean postprocess(Context context, Exception exception) {
330
331 Command command = getCommand(context);
332 if (command != null) {
333 if (command instanceof Filter) {
334 boolean result = (((Filter) command).postprocess(context, exception));
335 if (isIgnorePostprocessResult()) {
336 return false;
337 }
338 return result;
339 }
340 }
341 return (false);
342
343 }
344
345
346
347
348
349 /***
350 * <p>Return the {@link Command} instance to be delegated to.</p>
351 *
352 * @param context {@link Context} for this request
353 * @return The looked-up Command.
354 * @exception IllegalArgumentException if no such {@link Command}
355 * can be found and the <code>optional</code> property is set
356 * to <code>false</code>
357 */
358 protected Command getCommand(Context context) {
359 CatalogFactory lookupFactory = this.catalogFactory;
360 if (lookupFactory == null) {
361 lookupFactory = CatalogFactory.getInstance();
362 }
363
364 String catalogName = getCatalogName();
365 Catalog catalog = null;
366 if (catalogName == null) {
367
368 catalog = lookupFactory.getCatalog();
369 } else {
370 catalog = lookupFactory.getCatalog(catalogName);
371 }
372 if (catalog == null) {
373 if (catalogName == null) {
374 throw new IllegalArgumentException
375 ("Cannot find default catalog");
376 } else {
377 throw new IllegalArgumentException
378 ("Cannot find catalog '" + catalogName + "'");
379 }
380 }
381
382 Command command = null;
383 String name = getName();
384 if (name == null) {
385 name = (String) context.get(getNameKey());
386 }
387 if (name != null) {
388 command = catalog.getCommand(name);
389 if ((command == null) && !isOptional()) {
390 if (catalogName == null) {
391 throw new IllegalArgumentException
392 ("Cannot find command '" + name
393 + "' in default catalog");
394 } else {
395 throw new IllegalArgumentException
396 ("Cannot find command '" + name
397 + "' in catalog '" + catalogName + "'");
398 }
399 }
400 return (command);
401 } else {
402 throw new IllegalArgumentException("No command name");
403 }
404
405 }
406
407
408 }