@@ -0,0 +1,2788 @@
+// Copyright 2013 The Apache Software Foundation%0A//%0A// Licensed under the Apache License, Version 2.0 (the %22License%22);%0A// you may not use this file except in compliance with the License.%0A// You may obtain a copy of the License at%0A//%0A//     http:#www.apache.org/licenses/LICENSE-2.0%0A//%0A// Unless required by applicable law or agreed to in writing, software%0A// distributed under the License is distributed on an %22AS IS%22 BASIS,%0A// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.%0A// See the License for the specific language governing permissions and%0A// limitations under the License.%0A%0Apackage org.apache.tapestry5.internal.util;%0A%0Aimport org.apache.tapestry5.ioc.Invokable;%0Aimport org.apache.tapestry5.services.InvalidationEventHub;%0A%0A/**%0A * A utility class for managing a cacheable result that can be recomputed when needed.%0A */%0Apublic class RecomputableSupport%0A%7B%0A    private volatile int masterVersion = 1;%0A%0A    /**%0A     * Invalidates any existing %7B@link #create(org.apache.tapestry5.ioc.Invokable)%7D wrappers%7D such that they will%0A     * re-perform the computation when next invoked.%0A     */%0A    public void invalidate()%0A    %7B%0A        masterVersion++;%0A    %7D%0A%0A    /**%0A     * Forces %7B@link #invalidate()%7D to be invoked when the hub emits an %7B@linkplain InvalidationEventHub#addInvalidationCallback(Runnable) invalidation callback%7D.%0A     *%0A     * @param hub%0A     */%0A    public void initialize(InvalidationEventHub hub)%0A    %7B%0A        hub.addInvalidationCallback(new Runnable()%0A        %7B%0A            @Override%0A            public void run()%0A            %7B%0A                invalidate();%0A            %7D%0A        %7D);%0A    %7D%0A%0A    /**%0A     * Wraps a computation with caching logic; once computed, the Invokable will return the same value, until%0A     * %7B@link #invalidate()%7D is invoked.%0A     *%0A     * @param invokable%0A     *         a computation to perform, whose results are cacheable until invalidated%0A     * @param %3CT%3E%0A     *         type of result%0A     * @return caching-enabled wrapper around invokable%0A     */%0A    public %3CT%3E Invokable%3CT%3E create(final Invokable%3CT%3E invokable)%0A    %7B%0A        return new Invokable%3CT%3E()%0A        %7B%0A            private volatile int localVersion = masterVersion;%0A%0A            private volatile T cachedResult;%0A%0A            @Override%0A            public T invoke()%0A            %7B%0A                // Has the master version changed since the computation was last executed?%0A                if (localVersion != masterVersion)%0A                %7B%0A                    cachedResult = null;%0A                    localVersion = masterVersion;%0A                %7D%0A%0A                if (cachedResult == null)%0A                %7B%0A                    cachedResult = invokable.invoke();%0A                %7D%0A%0A%0A                return cachedResult;%0A            %7D%0A        %7D;%0A    %7D%0A%7D%0A

Add a utility for caching/recomputing computations