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