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!");
+ }
+ }
+
+}