001 /* 002 * Copyright 1999-2001,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 017 package org.apache.commons.workflow.core; 018 019 020 import java.util.EmptyStackException; 021 import org.apache.commons.workflow.Block; 022 import org.apache.commons.workflow.BlockState; 023 import org.apache.commons.workflow.Context; 024 import org.apache.commons.workflow.Descriptor; 025 import org.apache.commons.workflow.Iterator; 026 import org.apache.commons.workflow.Step; 027 import org.apache.commons.workflow.StepException; 028 import org.apache.commons.workflow.base.BaseBlock; 029 030 031 /** 032 * <p>Repeatedly evaluate the properties specified by the associated 033 * Descriptors, and execute the nested Steps if and only if 034 * <strong>ALL</strong> of them evaluate to a positive result. 035 * To avoid non-deterministic evaluation 036 * stack behavior, all of the specified Descriptors are always 037 * evaluated exactly once.</p> 038 * 039 * @version $Revision: 155475 $ $Date: 2005-02-26 13:31:11 +0000 (Sat, 26 Feb 2005) $ 040 * @author Craig R. McClanahan 041 */ 042 043 public class WhileStep extends BaseBlock implements Iterator { 044 045 046 // ----------------------------------------------------------= Constructors 047 048 049 /** 050 * Construct a default instance of this Step. 051 */ 052 public WhileStep() { 053 054 super(); 055 056 } 057 058 059 /** 060 * Construct an instance of this Step with the specified identifier. 061 * 062 * @param id Step identifier 063 */ 064 public WhileStep(String id) { 065 066 this(id, null); 067 068 } 069 070 071 /** 072 * Construct a fully configured instance of this Step. 073 * 074 * @param id Step identifier of this step 075 * @param descriptor Initial descriptor to be added 076 */ 077 public WhileStep(String id, Descriptor descriptor) { 078 079 super(); 080 setId(id); 081 if (descriptor != null) 082 addDescriptor(descriptor); 083 084 } 085 086 087 // --------------------------------------------------------- Public Methods 088 089 090 /** 091 * Render a string representation of this Step. 092 */ 093 public String toString() { 094 095 StringBuffer sb = new StringBuffer("<core:while"); 096 if (getId() != null) { 097 sb.append(" id=\""); 098 sb.append(getId()); 099 sb.append("\""); 100 } 101 sb.append(">"); 102 Descriptor descriptors[] = findDescriptors(); 103 for (int i = 0; i < descriptors.length; i++) 104 sb.append(descriptors[i]); 105 Step steps[] = getSteps(); 106 for (int i = 0; i < steps.length; i++) 107 sb.append(steps[i]); 108 sb.append("</core:while>"); 109 return (sb.toString()); 110 111 } 112 113 114 // ------------------------------------------------------ Protected Methods 115 116 117 /** 118 * Evaluate the condition specified by the Descriptors associated with 119 * this Block, and return the resulting boolean value. 120 * 121 * @param context Context within which to evaluate the descriptors 122 */ 123 protected boolean evaluate(Context context) { 124 125 boolean condition = true; 126 Descriptor descriptors[] = findDescriptors(); 127 for (int i = 0; i < descriptors.length; i++) { 128 if (descriptors[i] == null) 129 continue; 130 if (!descriptors[i].positive(context)) 131 condition = false; 132 } 133 return (condition); 134 135 } 136 137 138 /** 139 * Process the initial entry into this Block. 140 * 141 * @param context Context within which to evaluate the condition 142 */ 143 protected void initial(Context context) { 144 145 if (evaluate(context)) { 146 BlockState state = new BlockState(this, true); 147 context.pushBlockState(state); 148 context.setNextStep(getFirstStep()); 149 } else { 150 context.setNextStep(getNextStep()); 151 } 152 153 } 154 155 156 /** 157 * Process the return from nested execution of the Steps assocaited 158 * with this Block. 159 * 160 * @param context Context within which to evaluate the condition 161 * @param state BlockState for our block 162 */ 163 protected void subsequent(Context context, BlockState state) { 164 165 166 // Was a "break" Step executed within this Block? 167 if (!state.getNest()) { 168 context.popBlockState(); 169 context.setNextStep(getNextStep()); 170 return; 171 } 172 173 // Re-evaluate the loop conditions 174 if (evaluate(context)) { 175 context.setNextStep(getFirstStep()); 176 } else { 177 context.popBlockState(); 178 context.setNextStep(getNextStep()); 179 } 180 181 182 } 183 184 185 }