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.collections.functors; 18 19 import java.io.IOException; 20 import java.io.ObjectInputStream; 21 import java.io.ObjectOutputStream; 22 import java.io.Serializable; 23 24 import org.apache.commons.collections.Closure; 25 import org.apache.commons.collections.Predicate; 26 27 /** 28 * Closure implementation that executes a closure repeatedly until a condition is met, 29 * like a do-while or while loop. 30 * <p> 31 * <b>WARNING:</b> from v3.2.2 onwards this class will throw an 32 * {@link UnsupportedOperationException} when trying to serialize or 33 * de-serialize an instance to prevent potential remote code execution exploits. 34 * <p> 35 * In order to re-enable serialization support for {@code WhileClosure} 36 * the following system property can be used (via -Dproperty=true): 37 * <pre> 38 * org.apache.commons.collections.enableUnsafeSerialization 39 * </pre> 40 * 41 * @since Commons Collections 3.0 42 * @version $Revision: 1713845 $ $Date: 2015-11-11 15:02:16 +0100 (Wed, 11 Nov 2015) $ 43 * 44 * @author Stephen Colebourne 45 */ 46 public class WhileClosure implements Closure, Serializable { 47 48 /** Serial version UID */ 49 private static final long serialVersionUID = -3110538116913760108L; 50 51 /** The test condition */ 52 private final Predicate iPredicate; 53 /** The closure to call */ 54 private final Closure iClosure; 55 /** The flag, true is a do loop, false is a while */ 56 private final boolean iDoLoop; 57 58 /** 59 * Factory method that performs validation. 60 * 61 * @param predicate the predicate used to evaluate when the loop terminates, not null 62 * @param closure the closure the execute, not null 63 * @param doLoop true to act as a do-while loop, always executing the closure once 64 * @return the <code>while</code> closure 65 * @throws IllegalArgumentException if the predicate or closure is null 66 */ getInstance(Predicate predicate, Closure closure, boolean doLoop)67 public static Closure getInstance(Predicate predicate, Closure closure, boolean doLoop) { 68 if (predicate == null) { 69 throw new IllegalArgumentException("Predicate must not be null"); 70 } 71 if (closure == null) { 72 throw new IllegalArgumentException("Closure must not be null"); 73 } 74 return new WhileClosure(predicate, closure, doLoop); 75 } 76 77 /** 78 * Constructor that performs no validation. 79 * Use <code>getInstance</code> if you want that. 80 * 81 * @param predicate the predicate used to evaluate when the loop terminates, not null 82 * @param closure the closure the execute, not null 83 * @param doLoop true to act as a do-while loop, always executing the closure once 84 */ WhileClosure(Predicate predicate, Closure closure, boolean doLoop)85 public WhileClosure(Predicate predicate, Closure closure, boolean doLoop) { 86 super(); 87 iPredicate = predicate; 88 iClosure = closure; 89 iDoLoop = doLoop; 90 } 91 92 /** 93 * Executes the closure until the predicate is false. 94 * 95 * @param input the input object 96 */ execute(Object input)97 public void execute(Object input) { 98 if (iDoLoop) { 99 iClosure.execute(input); 100 } 101 while (iPredicate.evaluate(input)) { 102 iClosure.execute(input); 103 } 104 } 105 106 /** 107 * Gets the predicate in use. 108 * 109 * @return the predicate 110 * @since Commons Collections 3.1 111 */ getPredicate()112 public Predicate getPredicate() { 113 return iPredicate; 114 } 115 116 /** 117 * Gets the closure. 118 * 119 * @return the closure 120 * @since Commons Collections 3.1 121 */ getClosure()122 public Closure getClosure() { 123 return iClosure; 124 } 125 126 /** 127 * Is the loop a do-while loop. 128 * 129 * @return true is do-while, false if while 130 * @since Commons Collections 3.1 131 */ isDoLoop()132 public boolean isDoLoop() { 133 return iDoLoop; 134 } 135 136 /** 137 * Overrides the default writeObject implementation to prevent 138 * serialization (see COLLECTIONS-580). 139 */ writeObject(ObjectOutputStream os)140 private void writeObject(ObjectOutputStream os) throws IOException { 141 FunctorUtils.checkUnsafeSerialization(WhileClosure.class); 142 os.defaultWriteObject(); 143 } 144 145 /** 146 * Overrides the default readObject implementation to prevent 147 * de-serialization (see COLLECTIONS-580). 148 */ readObject(ObjectInputStream is)149 private void readObject(ObjectInputStream is) throws ClassNotFoundException, IOException { 150 FunctorUtils.checkUnsafeSerialization(WhileClosure.class); 151 is.defaultReadObject(); 152 } 153 154 } 155