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 }