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 }