You are viewing a plain text version of this content. The canonical link for it is here.
Posted to dev@tapestry.apache.org by hl...@apache.org on 2009/02/27 18:15:06 UTC

svn commit: r748602 - in /tapestry/tapestry5/trunk/tapestry-ioc/src: main/java/org/apache/tapestry5/ main/java/org/apache/tapestry5/ioc/internal/services/ main/java/org/apache/tapestry5/ioc/services/ test/java/org/apache/tapestry5/ioc/internal/services/

Author: hlship
Date: Fri Feb 27 17:15:05 2009
New Revision: 748602

URL: http://svn.apache.org/viewvc?rev=748602&view=rev
Log:
TAP5-542: Add ParallelExecutor service to allow operations to be performed asynchronously in a thread pool

Added:
    tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/IOCSymbols.java
    tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/CachingObjectCreator.java
      - copied, changed from r747598, tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/OneShotObjectCreator.java
    tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/ParallelExecutorImpl.java
    tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/ThunkCreatorImpl.java
    tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/ParallelExecutor.java
    tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/ThunkCreator.java
    tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/services/ParallelExecutorTest.java
Removed:
    tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/OneShotObjectCreator.java
Modified:
    tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/LazyAdvisorImpl.java
    tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/TapestryIOCModule.java

Added: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/IOCSymbols.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/IOCSymbols.java?rev=748602&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/IOCSymbols.java (added)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/IOCSymbols.java Fri Feb 27 17:15:05 2009
@@ -0,0 +1,39 @@
+// Copyright 2009 The Apache Software Foundation
+//
+// Licensed 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.tapestry5;
+
+/**
+ * Configuration symbols used by the IoC container.
+ *
+ * @since 5.1.0.1
+ */
+public class IOCSymbols
+{
+    /**
+     * The minimum size of the thread pool. The default is 3.
+     */
+    public static final String THREAD_POOL_CORE_SIZE = "tapestry.thread-pool.core-pool-size";
+
+    /**
+     * Maximium size of the pool before submitted invocations must wait to execute; the default is 20.
+     */
+    public static final String THREAD_POOL_MAX_SIZE = "tapestry.thread-pool.max-pool-size";
+
+    /**
+     * Time in milliseconds (via {@link org.apache.tapestry5.ioc.util.TimeInterval}) to keep waiting threads alive.
+     * Default is one minute (an epoch in application time).
+     */
+    public static final String THREAD_POOL_KEEP_ALIVE = "tapestry.thread-pool.keep-alive";
+}

Copied: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/CachingObjectCreator.java (from r747598, tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/OneShotObjectCreator.java)
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/CachingObjectCreator.java?p2=tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/CachingObjectCreator.java&p1=tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/OneShotObjectCreator.java&r1=747598&r2=748602&rev=748602&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/OneShotObjectCreator.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/CachingObjectCreator.java Fri Feb 27 17:15:05 2009
@@ -16,26 +16,30 @@
 
 import org.apache.tapestry5.ioc.ObjectCreator;
 
-public class OneShotObjectCreator implements ObjectCreator
+/**
+ * An {@link org.apache.tapestry5.ioc.ObjectCreator} that delegates to another {@link
+ * org.apache.tapestry5.ioc.ObjectCreator} and caches the result.
+ */
+public class CachingObjectCreator implements ObjectCreator
 {
     private boolean cached;
 
     private Object cachedValue;
 
-    private ObjectCreator creator;
+    private ObjectCreator delegate;
 
-    public OneShotObjectCreator(ObjectCreator creator)
+    public CachingObjectCreator(ObjectCreator delegate)
     {
-        this.creator = creator;
+        this.delegate = delegate;
     }
 
     public synchronized Object createObject()
     {
         if (!cached)
         {
-            cachedValue = creator.createObject();
+            cachedValue = delegate.createObject();
             cached = true;
-            creator = null;
+            delegate = null;
         }
 
         return cachedValue;

Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/LazyAdvisorImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/LazyAdvisorImpl.java?rev=748602&r1=748601&r2=748602&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/LazyAdvisorImpl.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/LazyAdvisorImpl.java Fri Feb 27 17:15:05 2009
@@ -19,35 +19,19 @@
 import org.apache.tapestry5.ioc.MethodAdviceReceiver;
 import org.apache.tapestry5.ioc.ObjectCreator;
 import org.apache.tapestry5.ioc.annotations.NotLazy;
-import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
 import org.apache.tapestry5.ioc.internal.util.InternalUtils;
-import org.apache.tapestry5.ioc.services.*;
+import org.apache.tapestry5.ioc.services.LazyAdvisor;
+import org.apache.tapestry5.ioc.services.ThunkCreator;
 
-import java.lang.reflect.InvocationTargetException;
 import java.lang.reflect.Method;
-import java.lang.reflect.Modifier;
-import java.util.Map;
 
 public class LazyAdvisorImpl implements LazyAdvisor
 {
-    /**
-     * Map from an interface type to a corresponding "thunk" class that implements the interface.
-     */
-    private final Map<Class, Class> interfaceToThunkClass = CollectionFactory.newConcurrentMap();
+    private final ThunkCreator thunkCreator;
 
-    private final ClassFactory classFactory;
-
-    private final MethodSignature toStringSignature = new MethodSignature(String.class, "toString", null, null);
-
-    private static final int PRIVATE_FINAL = Modifier.FINAL + Modifier.PRIVATE;
-
-    private static final String DESCRIPTION_FIELD = "_$description";
-    private static final String CREATOR_FIELD = "_$creator";
-    private static final String DELEGATE_METHOD = "_$delegate";
-
-    public LazyAdvisorImpl(@Builtin ClassFactory classFactory)
+    public LazyAdvisorImpl(ThunkCreator thunkCreator)
     {
-        this.classFactory = classFactory;
+        this.thunkCreator = thunkCreator;
     }
 
     public void addLazyMethodInvocationAdvice(MethodAdviceReceiver methodAdviceReceiver)
@@ -61,10 +45,10 @@
 
     private void addAdvice(Method method, MethodAdviceReceiver receiver)
     {
-        final Class thunkClass = getThunkClass(method.getReturnType());
+        final Class thunkType = method.getReturnType();
 
         final String description = String.format("<%s Thunk for %s>",
-                                                 method.getReturnType().getName(),
+                                                 thunkType.getName(),
                                                  InternalUtils.asString(method));
 
         MethodAdvice advice = new MethodAdvice()
@@ -85,9 +69,9 @@
                     }
                 };
 
-                ObjectCreator oneShot = new OneShotObjectCreator(deferred);
+                ObjectCreator oneShot = new CachingObjectCreator(deferred);
 
-                Object thunk = createThunk(thunkClass, description, oneShot);
+                Object thunk = thunkCreator.createThunk(thunkType, oneShot, description);
 
                 invocation.overrideResult(thunk);
             }
@@ -96,73 +80,6 @@
         receiver.adviseMethod(method, advice);
     }
 
-    private Object createThunk(Class thunkClass, String description, ObjectCreator creator)
-    {
-        Throwable failure = null;
-
-        try
-        {
-            return thunkClass.getConstructors()[0].newInstance(description, creator);
-        }
-        catch (InvocationTargetException ex)
-        {
-            failure = ex.getTargetException();
-        }
-        catch (Exception ex)
-        {
-            failure = ex;
-        }
-
-        throw new RuntimeException(String.format("Exception instantiating thunk class %s: %s",
-                                                 thunkClass.getName(),
-                                                 InternalUtils.toMessage(failure)),
-                                   failure);
-    }
-
-    private Class getThunkClass(Class type)
-    {
-        Class result = interfaceToThunkClass.get(type);
-
-        if (result == null)
-        {
-            result = constructThunkClass(type);
-            interfaceToThunkClass.put(type, result);
-        }
-
-        return result;
-    }
-
-    private Class constructThunkClass(Class interfaceType)
-    {
-        ClassFab classFab = classFactory.newClass(interfaceType);
-
-        classFab.addField(DESCRIPTION_FIELD, PRIVATE_FINAL, String.class);
-
-        classFab.addField(CREATOR_FIELD, PRIVATE_FINAL, ObjectCreator.class);
-
-        classFab.addConstructor(new Class[] { String.class, ObjectCreator.class }, null,
-                                String.format("{ %s = $1; %s = $2; }", DESCRIPTION_FIELD, CREATOR_FIELD));
-
-        MethodSignature sig = new MethodSignature(interfaceType, DELEGATE_METHOD, null, null);
-
-        classFab.addMethod(Modifier.PRIVATE, sig, String.format("return ($r) %s.createObject();", CREATOR_FIELD));
-
-        MethodIterator mi = new MethodIterator(interfaceType);
-
-        while (mi.hasNext())
-        {
-            sig = mi.next();
-
-            classFab.addMethod(Modifier.PUBLIC, sig,
-                               String.format("return ($r) %s().%s($$);", DELEGATE_METHOD, sig.getName()));
-        }
-
-        if (!mi.getToString())
-            classFab.addMethod(Modifier.PUBLIC, toStringSignature, String.format("return %s;", DESCRIPTION_FIELD));
-
-        return classFab.createClass();
-    }
-
     private boolean filter(Method method)
     {
         if (method.getAnnotation(NotLazy.class) != null) return false;

Added: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/ParallelExecutorImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/ParallelExecutorImpl.java?rev=748602&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/ParallelExecutorImpl.java (added)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/ParallelExecutorImpl.java Fri Feb 27 17:15:05 2009
@@ -0,0 +1,92 @@
+// Copyright 2009 The Apache Software Foundation
+//
+// Licensed 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.tapestry5.ioc.internal.services;
+
+import org.apache.tapestry5.ioc.Invokable;
+import org.apache.tapestry5.ioc.ObjectCreator;
+import org.apache.tapestry5.ioc.internal.util.Defense;
+import org.apache.tapestry5.ioc.services.ParallelExecutor;
+import org.apache.tapestry5.ioc.services.PerthreadManager;
+import org.apache.tapestry5.ioc.services.ThunkCreator;
+
+import java.util.concurrent.Callable;
+import java.util.concurrent.ExecutorService;
+import java.util.concurrent.Future;
+
+public class ParallelExecutorImpl implements ParallelExecutor
+{
+    private final ThunkCreator thunkCreator;
+
+    private final ExecutorService executorService;
+
+    private final PerthreadManager perthreadManager;
+
+    public ParallelExecutorImpl(ExecutorService executorService, ThunkCreator thunkCreator,
+                                PerthreadManager perthreadManager)
+    {
+        this.executorService = executorService;
+        this.thunkCreator = thunkCreator;
+        this.perthreadManager = perthreadManager;
+    }
+
+    public <T> Future<T> invoke(Invokable<T> invocable)
+    {
+        Defense.notNull(invocable, "invocable");
+
+        return executorService.submit(toCallable(invocable));
+    }
+
+    private <T> Callable<T> toCallable(final Invokable<T> invocable)
+    {
+        return new Callable<T>()
+        {
+            public T call() throws Exception
+            {
+                try
+                {
+                    return invocable.invoke();
+                }
+                finally
+                {
+                    perthreadManager.cleanup();
+                }
+            }
+        };
+    }
+
+    public <T> T invoke(Class<T> proxyType, Invokable<T> invocable)
+    {
+        final Future<T> future = invoke(invocable);
+
+        ObjectCreator creator = new ObjectCreator()
+        {
+            public Object createObject()
+            {
+                try
+                {
+                    return future.get();
+                }
+                catch (Exception ex)
+                {
+                    throw new RuntimeException(ex);
+                }
+            }
+        };
+
+        String description = String.format("FutureThunk[%s]", proxyType.getName());
+
+        return thunkCreator.createThunk(proxyType, new CachingObjectCreator(creator), description);
+    }
+}

Added: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/ThunkCreatorImpl.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/ThunkCreatorImpl.java?rev=748602&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/ThunkCreatorImpl.java (added)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/internal/services/ThunkCreatorImpl.java Fri Feb 27 17:15:05 2009
@@ -0,0 +1,126 @@
+// Copyright 2009 The Apache Software Foundation
+//
+// Licensed 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.tapestry5.ioc.internal.services;
+
+import org.apache.tapestry5.ioc.ObjectCreator;
+import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
+import org.apache.tapestry5.ioc.internal.util.Defense;
+import org.apache.tapestry5.ioc.internal.util.InternalUtils;
+import org.apache.tapestry5.ioc.services.*;
+
+import java.lang.reflect.InvocationTargetException;
+import java.lang.reflect.Modifier;
+import java.util.Map;
+
+public class ThunkCreatorImpl implements ThunkCreator
+{
+    /**
+     * Map from an interface type to a corresponding "thunk" class that implements the interface.
+     */
+    private final Map<Class, Class> interfaceToThunkClass = CollectionFactory.newConcurrentMap();
+
+    private final ClassFactory classFactory;
+
+    private final MethodSignature toStringSignature = new MethodSignature(String.class, "toString", null, null);
+
+    private static final int PRIVATE_FINAL = Modifier.FINAL + Modifier.PRIVATE;
+
+    private static final String DESCRIPTION_FIELD = "_$description";
+    private static final String CREATOR_FIELD = "_$creator";
+    private static final String DELEGATE_METHOD = "_$delegate";
+
+    public ThunkCreatorImpl(@Builtin ClassFactory classFactory)
+    {
+        this.classFactory = classFactory;
+    }
+
+    public <T> T createThunk(Class<T> proxyType, ObjectCreator objectCreator, String description)
+    {
+        Defense.notNull(proxyType, "proxyType");
+        Defense.notNull(objectCreator, "objectCreator");
+        Defense.notBlank(description, "description");
+
+        if (!proxyType.isInterface())
+            throw new IllegalArgumentException(
+                    String.format("Thunks may only be created for interfaces; %s is a class.",
+                                  ClassFabUtils.toJavaClassName(proxyType)));
+
+        final Class thunkClass = getThunkClass(proxyType);
+
+        Throwable failure;
+
+        try
+        {
+            return proxyType.cast(thunkClass.getConstructors()[0].newInstance(description, objectCreator));
+        }
+        catch (InvocationTargetException ex)
+        {
+            failure = ex.getTargetException();
+        }
+        catch (Exception ex)
+        {
+            failure = ex;
+        }
+
+        throw new RuntimeException(String.format("Exception instantiating thunk class %s: %s",
+                                                 thunkClass.getName(),
+                                                 InternalUtils.toMessage(failure)),
+                                   failure);
+    }
+
+    private Class getThunkClass(Class type)
+    {
+        Class result = interfaceToThunkClass.get(type);
+
+        if (result == null)
+        {
+            result = constructThunkClass(type);
+            interfaceToThunkClass.put(type, result);
+        }
+
+        return result;
+    }
+
+    private Class constructThunkClass(Class interfaceType)
+    {
+        ClassFab classFab = classFactory.newClass(interfaceType);
+
+        classFab.addField(DESCRIPTION_FIELD, PRIVATE_FINAL, String.class);
+
+        classFab.addField(CREATOR_FIELD, PRIVATE_FINAL, ObjectCreator.class);
+
+        classFab.addConstructor(new Class[] { String.class, ObjectCreator.class }, null,
+                                String.format("{ %s = $1; %s = $2; }", DESCRIPTION_FIELD, CREATOR_FIELD));
+
+        MethodSignature sig = new MethodSignature(interfaceType, DELEGATE_METHOD, null, null);
+
+        classFab.addMethod(Modifier.PRIVATE, sig, String.format("return ($r) %s.createObject();", CREATOR_FIELD));
+
+        MethodIterator mi = new MethodIterator(interfaceType);
+
+        while (mi.hasNext())
+        {
+            sig = mi.next();
+
+            classFab.addMethod(Modifier.PUBLIC, sig,
+                               String.format("return ($r) %s().%s($$);", DELEGATE_METHOD, sig.getName()));
+        }
+
+        if (!mi.getToString())
+            classFab.addMethod(Modifier.PUBLIC, toStringSignature, String.format("return %s;", DESCRIPTION_FIELD));
+
+        return classFab.createClass();
+    }
+}

Added: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/ParallelExecutor.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/ParallelExecutor.java?rev=748602&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/ParallelExecutor.java (added)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/ParallelExecutor.java Fri Feb 27 17:15:05 2009
@@ -0,0 +1,51 @@
+// Copyright 2009 The Apache Software Foundation
+//
+// Licensed 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.tapestry5.ioc.services;
+
+import org.apache.tapestry5.ioc.Invokable;
+
+import java.util.concurrent.Future;
+
+/**
+ * A service that allows work to occur in parallel using a thread pool. The thread pool is started lazily, and is
+ * shutdown when the Registry is shutdown.
+ *
+ * @since 5.1.0.1
+ */
+public interface ParallelExecutor
+{
+    /**
+     * Submits the invocable object to be executed in a pooled thread. Returns a Future object representing the eventual
+     * result of the invocable's operation.  The actual operation will be wrapped such that {@link
+     * PerthreadManager#cleanup()} is invoked after the operation completes.
+     *
+     * @param invocable to execute in a thread
+     * @param <T>
+     * @return Future result of that invocation
+     */
+    <T> Future<T> invoke(Invokable<T> invocable);
+
+    /**
+     * As with {@link #invoke(org.apache.tapestry5.ioc.Invokable)}, but the result is wrapped inside a {@linkplain
+     * org.apache.tapestry5.ioc.services.ThunkCreator thunk}. Invoking methods on the thunk will block until the value
+     * is available.
+     *
+     * @param proxyType return type, used to create the thunk
+     * @param invocable object that will eventually execute and return a value
+     * @param <T>
+     * @return the thunk
+     */
+    <T> T invoke(Class<T> proxyType, Invokable<T> invocable);
+}

Modified: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/TapestryIOCModule.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/TapestryIOCModule.java?rev=748602&r1=748601&r2=748602&view=diff
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/TapestryIOCModule.java (original)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/TapestryIOCModule.java Fri Feb 27 17:15:05 2009
@@ -14,10 +14,9 @@
 
 package org.apache.tapestry5.ioc.services;
 
+import org.apache.tapestry5.IOCSymbols;
 import org.apache.tapestry5.ioc.*;
-import org.apache.tapestry5.ioc.annotations.Local;
-import org.apache.tapestry5.ioc.annotations.Marker;
-import org.apache.tapestry5.ioc.annotations.PreventServiceDecoration;
+import org.apache.tapestry5.ioc.annotations.*;
 import org.apache.tapestry5.ioc.internal.services.*;
 import org.apache.tapestry5.ioc.util.TimeInterval;
 
@@ -26,6 +25,9 @@
 import java.math.BigDecimal;
 import java.math.BigInteger;
 import java.util.*;
+import java.util.concurrent.LinkedBlockingQueue;
+import java.util.concurrent.ThreadPoolExecutor;
+import java.util.concurrent.TimeUnit;
 
 /**
  * Defines the base set of services for the Tapestry IOC container.
@@ -60,6 +62,7 @@
         binder.bind(ServiceOverride.class, ServiceOverrideImpl.class);
         binder.bind(LoggingAdvisor.class, LoggingAdvisorImpl.class);
         binder.bind(LazyAdvisor.class, LazyAdvisorImpl.class);
+        binder.bind(ThunkCreator.class, ThunkCreatorImpl.class);
     }
 
     /**
@@ -81,7 +84,7 @@
     /**
      * Contributes the "perthread" scope.
      */
-    public void contributeServiceLifecycleSource(MappedConfiguration<String, ServiceLifecycle> configuration)
+    public static void contributeServiceLifecycleSource(MappedConfiguration<String, ServiceLifecycle> configuration)
     {
         configuration.addInstance(ScopeConstants.PERTHREAD, PerThreadServiceLifecycle.class);
     }
@@ -375,4 +378,44 @@
         configuration.add("ApplicationDefaults", applicationDefaults, "after:SystemProperties");
         configuration.add("FactoryDefaults", factoryDefaults, "after:ApplicationDefaults");
     }
+
+    public static ParallelExecutor buildDeferredExecution(
+            @Symbol(IOCSymbols.THREAD_POOL_CORE_SIZE)
+            int coreSize,
+
+            @Symbol(IOCSymbols.THREAD_POOL_MAX_SIZE)
+            int maxSize,
+
+            @Symbol(IOCSymbols.THREAD_POOL_KEEP_ALIVE)
+            @IntermediateType(TimeInterval.class)
+            int keepAliveMillis,
+
+            PerthreadManager perthreadManager,
+
+            RegistryShutdownHub shutdownHub,
+
+            ThunkCreator thunkCreator)
+    {
+
+        final ThreadPoolExecutor executorService = new ThreadPoolExecutor(coreSize, maxSize,
+                                                                          keepAliveMillis, TimeUnit.MILLISECONDS,
+                                                                          new LinkedBlockingQueue(maxSize));
+
+        shutdownHub.addRegistryShutdownListener(new RegistryShutdownListener()
+        {
+            public void registryDidShutdown()
+            {
+                executorService.shutdown();
+            }
+        });
+
+        return new ParallelExecutorImpl(executorService, thunkCreator, perthreadManager);
+    }
+
+    public static void contributeFactoryDefaults(MappedConfiguration<String, String> configuration)
+    {
+        configuration.add(IOCSymbols.THREAD_POOL_CORE_SIZE, "3");
+        configuration.add(IOCSymbols.THREAD_POOL_MAX_SIZE, "20");
+        configuration.add(IOCSymbols.THREAD_POOL_KEEP_ALIVE, "1 m");
+    }
 }

Added: tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/ThunkCreator.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/ThunkCreator.java?rev=748602&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/ThunkCreator.java (added)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/main/java/org/apache/tapestry5/ioc/services/ThunkCreator.java Fri Feb 27 17:15:05 2009
@@ -0,0 +1,39 @@
+// Copyright 2009 The Apache Software Foundation
+//
+// Licensed 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.tapestry5.ioc.services;
+
+import org.apache.tapestry5.ioc.ObjectCreator;
+
+/**
+ * A <a href="http://en.wikipedia.org/wiki/Thunk">thunk</a> is a delayed calculation. In Java and Tapestry terms, a
+ * Thunk is a proxy object of a particular interface that delegates all methods to an object of the same type obtained
+ * from an {@link org.apache.tapestry5.ioc.ObjectProvider}. This is used by {@link
+ * org.apache.tapestry5.ioc.services.LazyAdvisor} to build lazy thunk proxies.
+ *
+ * @since 5.1.0.1
+ */
+public interface ThunkCreator
+{
+    /**
+     * Creates a Thunk of the given proxy type.
+     *
+     * @param proxyType     type of object to create (must be an interface)
+     * @param objectCreator provides an instance of the same type on demand (may be invoked multiple times)
+     * @param description   to be returned from the thunk's toString() method
+     * @param <T>           type of thunk
+     * @return thunk of given type
+     */
+    <T> T createThunk(Class<T> proxyType, ObjectCreator objectCreator, String description);
+}

Added: tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/services/ParallelExecutorTest.java
URL: http://svn.apache.org/viewvc/tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/services/ParallelExecutorTest.java?rev=748602&view=auto
==============================================================================
--- tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/services/ParallelExecutorTest.java (added)
+++ tapestry/tapestry5/trunk/tapestry-ioc/src/test/java/org/apache/tapestry5/ioc/internal/services/ParallelExecutorTest.java Fri Feb 27 17:15:05 2009
@@ -0,0 +1,93 @@
+// Copyright 2009 The Apache Software Foundation
+//
+// Licensed 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.tapestry5.ioc.internal.services;
+
+import org.apache.tapestry5.ioc.Invokable;
+import org.apache.tapestry5.ioc.StringHolder;
+import org.apache.tapestry5.ioc.StringHolderImpl;
+import org.apache.tapestry5.ioc.internal.IOCInternalTestCase;
+import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
+import org.apache.tapestry5.ioc.services.ParallelExecutor;
+import org.testng.annotations.Test;
+
+import java.util.List;
+
+public class ParallelExecutorTest extends IOCInternalTestCase
+{
+    @Test
+    public void thunk_creation()
+    {
+        int count = 100;
+
+        List<StringHolder> thunks = CollectionFactory.newList();
+
+        ParallelExecutor parallelExecutor = getService(ParallelExecutor.class);
+
+        for (int i = 0; i < count; i++)
+        {
+            final String value = String.format("Value[%d]", i);
+
+            Invokable inv = new Invokable()
+            {
+                public Object invoke()
+                {
+                    StringHolder holder = new StringHolderImpl();
+                    holder.setValue(value);
+
+                    return holder;
+                }
+            };
+
+            thunks.add(parallelExecutor.invoke(StringHolder.class, inv));
+        }
+
+        for (int j = 0; j < 2; j++)
+        {
+            for (int i = 0; i < count; i++)
+            {
+                assertEquals(thunks.get(i).getValue(), String.format("Value[%d]", i));
+            }
+        }
+    }
+
+    @Test
+    public void exception_thrown_by_invocation()
+    {
+        ParallelExecutor parallelExecutor = getService(ParallelExecutor.class);
+
+        Invokable inv = new Invokable()
+        {
+            public Object invoke()
+            {
+                throw new RuntimeException("Future failure!");
+            }
+        };
+
+        StringHolder holder = parallelExecutor.invoke(StringHolder.class, inv);
+
+        assertEquals(holder.toString(), "FutureThunk[org.apache.tapestry5.ioc.StringHolder]");
+
+        try
+        {
+            holder.getValue();
+            unreachable();
+        }
+        catch (RuntimeException ex)
+        {
+            assertMessageContains(ex, "Future failure!");
+        }
+    }
+
+}