001/*-------------------------------------------------------------------------+
002|                                                                          |
003| Copyright 2005-2011 the ConQAT Project                                   |
004|                                                                          |
005| Licensed under the Apache License, Version 2.0 (the "License");          |
006| you may not use this file except in compliance with the License.         |
007| You may obtain a copy of the License at                                  |
008|                                                                          |
009|    http://www.apache.org/licenses/LICENSE-2.0                            |
010|                                                                          |
011| Unless required by applicable law or agreed to in writing, software      |
012| distributed under the License is distributed on an "AS IS" BASIS,        |
013| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
014| See the License for the specific language governing permissions and      |
015| limitations under the License.                                           |
016+-------------------------------------------------------------------------*/
017package org.conqat.lib.commons.concurrent;
018
019import org.conqat.lib.commons.assertion.CCSMAssert;
020
021/**
022 * A {@link Runnable} that provides a result that can be read asynchronously and
023 * may also throw an exception.
024 * 
025 * @param <T>
026 *            the return type.
027 * @param <X>
028 *            the exception type.
029 */
030public abstract class RunnableWithAsyncResultBase<T, X extends Throwable> implements Runnable {
031
032        /** The result. */
033        private T result;
034
035        /** The caught exception. */
036        private Throwable caughtException = null;
037
038        /**
039         * Flag storing whether execution has finished (and the result is ready).
040         */
041        private boolean finished = false;
042
043        /** {@inheritDoc} */
044        @Override
045        public final void run() {
046                try {
047                        result = runWithResult();
048                } catch (Throwable e) {
049                        caughtException = e;
050                }
051                finished = true;
052        }
053
054        /** Template method for calculating the result. */
055        public abstract T runWithResult() throws X;
056
057        /** Returns whether the calculation has been finished. */
058        public boolean isFinished() {
059                return finished;
060        }
061
062        /**
063         * Returns the result. If the execution threw an exception, this thrown
064         * here. This applies to checked exceptions of type X as well as to runtime
065         * exceptions and errors. If the {@link #run()} method did not terminate
066         * yet, an {@link AssertionError} is thrown.
067         */
068        @SuppressWarnings("unchecked")
069        public T getResult() throws X {
070                CCSMAssert.isTrue(finished, "Can not query result before run() is finished!");
071
072                if (caughtException instanceof RuntimeException) {
073                        throw (RuntimeException) caughtException;
074                } else if (caughtException instanceof Error) {
075                        throw (Error) caughtException;
076                } else if (caughtException != null) {
077                        // must be an X in this case
078                        throw (X) caughtException;
079                }
080
081                return result;
082        }
083}