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.impl;
17  
18  
19  import java.util.Collection;
20  import java.util.Iterator;
21  import org.apache.commons.chain.Chain;
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>Convenience base class for {@link Chain} implementations.</p>
29   *
30   * @author Craig R. McClanahan
31   * @version $Revision: 411876 $ $Date: 2006-06-05 19:02:19 +0100 (Mon, 05 Jun 2006) $
32   */
33  
34  public class ChainBase implements Chain {
35  
36  
37      // ----------------------------------------------------------- Constructors
38  
39  
40      /***
41       * <p>Construct a {@link Chain} with no configured {@link Command}s.</p>
42       */
43      public ChainBase() {
44  
45      }
46  
47  
48      /***
49       * <p>Construct a {@link Chain} configured with the specified
50       * {@link Command}.</p>
51       *
52       * @param command The {@link Command} to be configured
53       *
54       * @exception IllegalArgumentException if <code>command</code>
55       *  is <code>null</code>
56       */
57      public ChainBase(Command command) {
58  
59          addCommand(command);
60  
61      }
62  
63  
64      /***
65       * <p>Construct a {@link Chain} configured with the specified
66       * {@link Command}s.</p>
67       *
68       * @param commands The {@link Command}s to be configured
69       *
70       * @exception IllegalArgumentException if <code>commands</code>,
71       *  or one of the individual {@link Command} elements,
72       *  is <code>null</code>
73       */
74      public ChainBase(Command[] commands) {
75  
76          if (commands == null) {
77              throw new IllegalArgumentException();
78          }
79          for (int i = 0; i < commands.length; i++) {
80              addCommand(commands[i]);
81          }
82  
83      }
84  
85  
86      /***
87       * <p>Construct a {@link Chain} configured with the specified
88       * {@link Command}s.</p>
89       *
90       * @param commands The {@link Command}s to be configured
91       *
92       * @exception IllegalArgumentException if <code>commands</code>,
93       *  or one of the individual {@link Command} elements,
94       *  is <code>null</code>
95       */
96      public ChainBase(Collection commands) {
97  
98          if (commands == null) {
99              throw new IllegalArgumentException();
100         }
101         Iterator elements = commands.iterator();
102         while (elements.hasNext()) {
103             addCommand((Command) elements.next());
104         }
105 
106     }
107 
108 
109     // ----------------------------------------------------- Instance Variables
110 
111 
112     /***
113      * <p>The list of {@link Command}s configured for this {@link Chain}, in
114      * the order in which they may delegate processing to the remainder of
115      * the {@link Chain}.</p>
116      */
117     protected Command[] commands = new Command[0];
118 
119 
120     /***
121      * <p>Flag indicating whether the configuration of our commands list
122      * has been frozen by a call to the <code>execute()</code> method.</p>
123      */
124     protected boolean frozen = false;
125 
126 
127     // ---------------------------------------------------------- Chain Methods
128 
129 
130     /***
131      * See the {@link Chain} JavaDoc.
132      *
133      * @param command The {@link Command} to be added
134      *
135      * @exception IllegalArgumentException if <code>command</code>
136      *  is <code>null</code>
137      * @exception IllegalStateException if no further configuration is allowed
138      */
139     public void addCommand(Command command) {
140 
141         if (command == null) {
142             throw new IllegalArgumentException();
143         }
144         if (frozen) {
145             throw new IllegalStateException();
146         }
147         Command[] results = new Command[commands.length + 1];
148         System.arraycopy(commands, 0, results, 0, commands.length);
149         results[commands.length] = command;
150         commands = results;
151 
152     }
153 
154 
155     /***
156      * See the {@link Chain} JavaDoc.
157      *
158      * @param context The {@link Context} to be processed by this
159      *  {@link Chain}
160      *
161      * @throws Exception if thrown by one of the {@link Command}s
162      *  in this {@link Chain} but not handled by a <code>postprocess()</code>
163      *  method of a {@link Filter}
164      * @throws IllegalArgumentException if <code>context</code>
165      *  is <code>null</code>
166      *
167      * @return <code>true</code> if the processing of this {@link Context}
168      *  has been completed, or <code>false</code> if the processing
169      *  of this {@link Context} should be delegated to a subsequent
170      *  {@link Command} in an enclosing {@link Chain}
171      */
172     public boolean execute(Context context) throws Exception {
173 
174         // Verify our parameters
175         if (context == null) {
176             throw new IllegalArgumentException();
177         }
178 
179         // Freeze the configuration of the command list
180         frozen = true;
181 
182         // Execute the commands in this list until one returns true
183         // or throws an exception
184         boolean saveResult = false;
185         Exception saveException = null;
186         int i = 0;
187         int n = commands.length;
188         for (i = 0; i < n; i++) {
189             try {
190                 saveResult = commands[i].execute(context);
191                 if (saveResult) {
192                     break;
193                 }
194             } catch (Exception e) {
195                 saveException = e;
196                 break;
197             }
198         }
199 
200         // Call postprocess methods on Filters in reverse order
201         if (i >= n) { // Fell off the end of the chain
202             i--;
203         }
204         boolean handled = false;
205         boolean result = false;
206         for (int j = i; j >= 0; j--) {
207             if (commands[j] instanceof Filter) {
208                 try {
209                     result =
210                         ((Filter) commands[j]).postprocess(context,
211                                                            saveException);
212                     if (result) {
213                         handled = true;
214                     }
215                 } catch (Exception e) {
216                       // Silently ignore
217                 }
218             }
219         }
220 
221         // Return the exception or result state from the last execute()
222         if ((saveException != null) && !handled) {
223             throw saveException;
224         } else {
225             return (saveResult);
226         }
227 
228     }
229 
230 
231     // -------------------------------------------------------- Package Methods
232 
233 
234     /***
235      * <p>Return an array of the configured {@link Command}s for this
236      * {@link Chain}.  This method is package private, and is used only
237      * for the unit tests.</p>
238      */
239     Command[] getCommands() {
240 
241         return (commands);
242 
243     }
244 
245 
246 }