View Javadoc

1   /*
2    * Copyright 1999-2004 The Apache Software Foundation
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
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      // -------------------------------------------------------------- Constructors
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      // -------------------------------------------------------------- Properties
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     // ---------------------------------------------------------- Filter Methods
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     // --------------------------------------------------------- Private Methods
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             // use default catalog
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 }