Skip to content

Instantly share code, notes, and snippets.

@uklance
Last active August 29, 2015 14:08
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save uklance/88c9a5400872273d9b14 to your computer and use it in GitHub Desktop.
Save uklance/88c9a5400872273d9b14 to your computer and use it in GitHub Desktop.
Tapestry - Render body in parallel
<t:parallel>
<t:someComponent />
</t:parallel>
package com.foo.bar.components;
public class Parallel {
@Inject ComponentResources componentResources;
@Inject TypeCoercer typeCoercer;
@Inject PerThreadManager perThreadManager;
@Inject ParallelManager parallelManager;
@Inject Logger logger;
public boolean setupRender(MarkupWriter markupWriter) {
Block bodyBlock = componentResources.getBody();
final RenderCommand bodyCommand = typeCoercer.coerce(bodyBlock, RenderCommand.class);
final Element newDiv = markupWriter.element("div");
markupWriter.end();
final Thread parentThread = Thread.currentThread();
Runnable task = new Runnable {
public void run() {
try {
parallelManager.setParentThread(parentThread);
MarkupWriterImpl parallelWriter = new MarkupWriterImpl();
RenderQueueImpl parallelQueue = new RenderQueueImpl(logger);
bodyCommand.render(parallelWriter, parallelQueue);
Element rootElement = parallelWriter.getDocument().getRootElement();
for (Node node : rootElement.getChildren()) {
// hopefully this doesn't cause a concurrent modification exception
node.moveToBottom(newDiv);
}
} finally {
parallelManager.taskFinished(task);
perThreadManager.cleanupThread();
}
}
};
parallelManager.submitTask(task);
// return false to exit the normal render flow
return false;
}
}
/**
* The implementation of this class will be @Scope(ScopeConstants.PER_THREAD)
*/
public interface ParallelManager {
// Submit a task to the thread pool and maintain a mechanism to wait for in waitForTasks()
Future<?> submitTask(Runnable task);
// this will allow waitForTasks() to finish when all tasks (for the current request) complete
void taskFinished(Runnable task);
// Since this service is PER_THREAD scoped, set a member variable
void setParentThread(Thread parentThread);
// A custom PerThreadManager could check this boolean
boolean isChildThread();
// A custom PerThreadManager could delegate to the parent Thread's PerThreadValues somehow
Thread getParentThread();
// The request thread will need to wait for all child tasks to complete before writing to the response
void waitForTasks();
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment