From 936fd069c78b100ac9666b17b55d0a1469b257ad Mon Sep 17 00:00:00 2001 From: Brent Worden Date: Tue, 24 May 2011 18:28:13 +0000 Subject: [PATCH] COLLECTIONS-313. Added abstract closure that is capable of handling thrown exceptions from closure execution. git-svn-id: https://svn.apache.org/repos/asf/commons/proper/collections/trunk@1127199 13f79535-47bb-0310-9956-ffa450edef68 --- .../functors/CatchAndRethrowClosure.java | 76 +++++++++++++++ .../functors/BasicClosureTestBase.java | 35 +++++++ .../functors/TestCatchAndRethrowClosure.java | 93 +++++++++++++++++++ 3 files changed, 204 insertions(+) create mode 100644 src/java/org/apache/commons/collections/functors/CatchAndRethrowClosure.java create mode 100644 src/test/org/apache/commons/collections/functors/BasicClosureTestBase.java create mode 100644 src/test/org/apache/commons/collections/functors/TestCatchAndRethrowClosure.java diff --git a/src/java/org/apache/commons/collections/functors/CatchAndRethrowClosure.java b/src/java/org/apache/commons/collections/functors/CatchAndRethrowClosure.java new file mode 100644 index 000000000..10c1cebc7 --- /dev/null +++ b/src/java/org/apache/commons/collections/functors/CatchAndRethrowClosure.java @@ -0,0 +1,76 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections.functors; + +import org.apache.commons.collections.Closure; +import org.apache.commons.collections.FunctorException; + +/** + * {@link Closure} that catches any checked exception and re-throws it as a + * {@link FunctorException} runtime exception. Example usage: + * + *
+ * // Create a catch and re-throw closure via anonymous subclass
+ * CatchAndRethrowClosure<String> writer = new ThrowingClosure() {
+ *     private java.io.Writer out = // some writer
+ *     
+ *     protected void executeAndThrow(String input) throws IOException {
+ *         out.write(input); // throwing of IOException allowed
+ *     }
+ * };
+ * 
+ * // use catch and re-throw closure
+ * java.util.List strList = // some list
+ * try {
+ *     CollctionUtils.forAllDo(strList, writer);
+ * } catch (FunctorException ex) {
+ *     Throwable originalError = ex.getCause();
+ *     // handle error
+ * }
+ * 
+ * + * @since Commons Collections 4.0 + * @version $Revision: $ $Date: $ + */ +public abstract class CatchAndRethrowClosure implements Closure { + + /** + * Execute this closure on the specified input object. + * + * @param input the input to execute on + * @throws ClosureException (runtime) if the closure execution resulted in a + * checked exception. + */ + public void execute(E input) { + try { + executeAndThrow(input); + } catch (RuntimeException ex) { + throw ex; + } catch (Throwable t) { + throw new FunctorException(t); + } + } + + /** + * Execute this closure on the specified input object. + * + * @param input the input to execute on + * @throws Throwable if the closure execution resulted in a checked + * exception. + */ + protected abstract void executeAndThrow(E input) throws Throwable; +} diff --git a/src/test/org/apache/commons/collections/functors/BasicClosureTestBase.java b/src/test/org/apache/commons/collections/functors/BasicClosureTestBase.java new file mode 100644 index 000000000..522aa90c3 --- /dev/null +++ b/src/test/org/apache/commons/collections/functors/BasicClosureTestBase.java @@ -0,0 +1,35 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections.functors; + +import org.apache.commons.collections.Closure; +import org.junit.Assert; +import org.junit.Test; + +public abstract class BasicClosureTestBase { + + @Test + public void closureSanityTests() throws Exception { + Closure closure = generateClosure(); + Assert.assertNotNull(closure); + } + + /** + * @return a closure for general sanity tests. + */ + protected abstract Closure generateClosure(); +} diff --git a/src/test/org/apache/commons/collections/functors/TestCatchAndRethrowClosure.java b/src/test/org/apache/commons/collections/functors/TestCatchAndRethrowClosure.java new file mode 100644 index 000000000..b66381f30 --- /dev/null +++ b/src/test/org/apache/commons/collections/functors/TestCatchAndRethrowClosure.java @@ -0,0 +1,93 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.apache.commons.collections.functors; + +import java.io.IOException; + +import org.apache.commons.collections.Closure; +import org.apache.commons.collections.FunctorException; +import org.junit.Assert; +import org.junit.Test; + +public class TestCatchAndRethrowClosure extends BasicClosureTestBase { + + private static Closure generateIOExceptionClosure() { + return new CatchAndRethrowClosure() { + + @Override + protected void executeAndThrow(T input) throws IOException { + throw new IOException(); + } + }; + } + + private static Closure generateNullPointerExceptionClosure() { + return new CatchAndRethrowClosure() { + + @Override + protected void executeAndThrow(T input) { + throw new NullPointerException(); + } + }; + } + + private static Closure generateNoExceptionClosure() { + return new CatchAndRethrowClosure() { + + @Override + protected void executeAndThrow(T input) { + } + }; + } + + @Override + protected Closure generateClosure() { + return generateNoExceptionClosure(); + } + + @Test + public void testThrowingClosure() { + Closure closure = generateNoExceptionClosure(); + try { + closure.execute(Integer.valueOf(0)); + } catch (FunctorException ex) { + Assert.fail(); + } catch (RuntimeException ex) { + Assert.fail(); + } + + closure = generateIOExceptionClosure(); + try { + closure.execute(Integer.valueOf(0)); + Assert.fail(); + } catch (FunctorException ex) { + Assert.assertTrue(ex.getCause() instanceof IOException); + } catch (RuntimeException ex) { + Assert.fail(); + } + + closure = generateNullPointerExceptionClosure(); + try { + closure.execute(Integer.valueOf(0)); + Assert.fail(); + } catch (FunctorException ex) { + Assert.fail(); + } catch (RuntimeException ex) { + Assert.assertTrue(ex instanceof NullPointerException); + } + } +}