001: /*
002: * Copyright 1999-2004 The Apache Software Foundation
003: *
004: * Licensed under the Apache License, Version 2.0 (the "License");
005: * you may not use this file except in compliance with the License.
006: * You may obtain a copy of the License at
007: *
008: * http://www.apache.org/licenses/LICENSE-2.0
009: *
010: * Unless required by applicable law or agreed to in writing, software
011: * distributed under the License is distributed on an "AS IS" BASIS,
012: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013: * See the License for the specific language governing permissions and
014: * limitations under the License.
015: */
016: package org.apache.commons.chain.impl;
017:
018: import java.util.Collection;
019: import java.util.Iterator;
020: import org.apache.commons.chain.Chain;
021: import org.apache.commons.chain.Command;
022: import org.apache.commons.chain.Context;
023: import org.apache.commons.chain.Filter;
024:
025: /**
026: * <p>Convenience base class for {@link Chain} implementations.</p>
027: *
028: * @author Craig R. McClanahan
029: * @version $Revision: 411876 $ $Date: 2006-06-05 19:02:19 +0100 (Mon, 05 Jun 2006) $
030: */
031:
032: public class ChainBase implements Chain {
033:
034: // ----------------------------------------------------------- Constructors
035:
036: /**
037: * <p>Construct a {@link Chain} with no configured {@link Command}s.</p>
038: */
039: public ChainBase() {
040:
041: }
042:
043: /**
044: * <p>Construct a {@link Chain} configured with the specified
045: * {@link Command}.</p>
046: *
047: * @param command The {@link Command} to be configured
048: *
049: * @exception IllegalArgumentException if <code>command</code>
050: * is <code>null</code>
051: */
052: public ChainBase(Command command) {
053:
054: addCommand(command);
055:
056: }
057:
058: /**
059: * <p>Construct a {@link Chain} configured with the specified
060: * {@link Command}s.</p>
061: *
062: * @param commands The {@link Command}s to be configured
063: *
064: * @exception IllegalArgumentException if <code>commands</code>,
065: * or one of the individual {@link Command} elements,
066: * is <code>null</code>
067: */
068: public ChainBase(Command[] commands) {
069:
070: if (commands == null) {
071: throw new IllegalArgumentException();
072: }
073: for (int i = 0; i < commands.length; i++) {
074: addCommand(commands[i]);
075: }
076:
077: }
078:
079: /**
080: * <p>Construct a {@link Chain} configured with the specified
081: * {@link Command}s.</p>
082: *
083: * @param commands The {@link Command}s to be configured
084: *
085: * @exception IllegalArgumentException if <code>commands</code>,
086: * or one of the individual {@link Command} elements,
087: * is <code>null</code>
088: */
089: public ChainBase(Collection commands) {
090:
091: if (commands == null) {
092: throw new IllegalArgumentException();
093: }
094: Iterator elements = commands.iterator();
095: while (elements.hasNext()) {
096: addCommand((Command) elements.next());
097: }
098:
099: }
100:
101: // ----------------------------------------------------- Instance Variables
102:
103: /**
104: * <p>The list of {@link Command}s configured for this {@link Chain}, in
105: * the order in which they may delegate processing to the remainder of
106: * the {@link Chain}.</p>
107: */
108: protected Command[] commands = new Command[0];
109:
110: /**
111: * <p>Flag indicating whether the configuration of our commands list
112: * has been frozen by a call to the <code>execute()</code> method.</p>
113: */
114: protected boolean frozen = false;
115:
116: // ---------------------------------------------------------- Chain Methods
117:
118: /**
119: * See the {@link Chain} JavaDoc.
120: *
121: * @param command The {@link Command} to be added
122: *
123: * @exception IllegalArgumentException if <code>command</code>
124: * is <code>null</code>
125: * @exception IllegalStateException if no further configuration is allowed
126: */
127: public void addCommand(Command command) {
128:
129: if (command == null) {
130: throw new IllegalArgumentException();
131: }
132: if (frozen) {
133: throw new IllegalStateException();
134: }
135: Command[] results = new Command[commands.length + 1];
136: System.arraycopy(commands, 0, results, 0, commands.length);
137: results[commands.length] = command;
138: commands = results;
139:
140: }
141:
142: /**
143: * See the {@link Chain} JavaDoc.
144: *
145: * @param context The {@link Context} to be processed by this
146: * {@link Chain}
147: *
148: * @throws Exception if thrown by one of the {@link Command}s
149: * in this {@link Chain} but not handled by a <code>postprocess()</code>
150: * method of a {@link Filter}
151: * @throws IllegalArgumentException if <code>context</code>
152: * is <code>null</code>
153: *
154: * @return <code>true</code> if the processing of this {@link Context}
155: * has been completed, or <code>false</code> if the processing
156: * of this {@link Context} should be delegated to a subsequent
157: * {@link Command} in an enclosing {@link Chain}
158: */
159: public boolean execute(Context context) throws Exception {
160:
161: // Verify our parameters
162: if (context == null) {
163: throw new IllegalArgumentException();
164: }
165:
166: // Freeze the configuration of the command list
167: frozen = true;
168:
169: // Execute the commands in this list until one returns true
170: // or throws an exception
171: boolean saveResult = false;
172: Exception saveException = null;
173: int i = 0;
174: int n = commands.length;
175: for (i = 0; i < n; i++) {
176: try {
177: saveResult = commands[i].execute(context);
178: if (saveResult) {
179: break;
180: }
181: } catch (Exception e) {
182: saveException = e;
183: break;
184: }
185: }
186:
187: // Call postprocess methods on Filters in reverse order
188: if (i >= n) { // Fell off the end of the chain
189: i--;
190: }
191: boolean handled = false;
192: boolean result = false;
193: for (int j = i; j >= 0; j--) {
194: if (commands[j] instanceof Filter) {
195: try {
196: result = ((Filter) commands[j]).postprocess(
197: context, saveException);
198: if (result) {
199: handled = true;
200: }
201: } catch (Exception e) {
202: // Silently ignore
203: }
204: }
205: }
206:
207: // Return the exception or result state from the last execute()
208: if ((saveException != null) && !handled) {
209: throw saveException;
210: } else {
211: return (saveResult);
212: }
213:
214: }
215:
216: // -------------------------------------------------------- Package Methods
217:
218: /**
219: * <p>Return an array of the configured {@link Command}s for this
220: * {@link Chain}. This method is package private, and is used only
221: * for the unit tests.</p>
222: */
223: Command[] getCommands() {
224:
225: return (commands);
226:
227: }
228:
229: }
|