View Javadoc

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