Author: taylor
Date: Mon Jan 15 14:01:14 2007
New Revision: 496514
URL: http://svn.apache.org/viewvc?view=rev&rev=496514
Log:
contribution from Woonsan Ko:
Added 'deployment hints' and 'timeout option' features as attached.
In my modification, I expected the deployment hint put like the following:
<portlet>
<portlet-name>PickANumberPortlet</portlet-name>
<js:metadata name="timeout">4000</js:metadata> <!-- ms -->
</portlet>
I used the metadata tag for simplicity.
Currently, I think that a positive number for timeout means requiring a thread
automatically.
Because our unit test is incomplete, I tested this on a production server.
My tests were as follows:
- First, in the /WEB-INF/assembly/pipelines.xml, I replaced
'org.apache.jetspeed.aggregator.PageAggregator' with
'org.apache.jetspeed.aggregator.AsyncPageAggregator' for the 'aggregatorValve'
bean constructor
argument.
- Second, to test an asynchronous portlet rendering, I added the timeout hints
for the
PickANumber portlet in the /demo/WEB-INF/jetspeed-portlet.xml, as mentioned
above.
In this case, only the PickANumber portlet is asynchronously rendered, and
the others are
synchronously rendered.
Also, to test the PickANumber portlet to be interrupted, I added a line like
'Thread.sleep(5000);' in the /demo/WEB-INF/demo/simple/PickANumber.jsp'.
- Third, to test all portlets asynchronous-rendering, I modified the default
portlet timeout
constructor argument to 4000 for the
'org.apache.jetspeed.aggregator.PortletRenderer' bean in the
/WEB-INF/assembly/aggregation.xml.
In this case, all portlets are asynchronously rendered.
On my implementations:
- I added some methods and properties to the RenderingJob for timeout.
- The WorkerMonitorImpl has a RenderingJobTimeoutMonitor thread, which will
check timeouts
periodically.
If an asynchronous portlet exceeds the time limit, the
RenderingJobTimeoutMonitor just
interrupt the worker thread for the job. So, a worker thread is killed, and a
new fresh worker may
be created by getWorker() method of WorkerMonitorImpl if necessary.
Modified:
portals/jetspeed-2/trunk/components/portal/src/java/org/apache/jetspeed/aggregator/impl/AsyncPageAggregatorImpl.java
portals/jetspeed-2/trunk/components/portal/src/java/org/apache/jetspeed/aggregator/impl/PortletRendererImpl.java
portals/jetspeed-2/trunk/components/portal/src/java/org/apache/jetspeed/aggregator/impl/RenderingJobImpl.java
portals/jetspeed-2/trunk/components/portal/src/java/org/apache/jetspeed/aggregator/impl/WorkerMonitorImpl.java
portals/jetspeed-2/trunk/jetspeed-api/src/java/org/apache/jetspeed/aggregator/RenderingJob.java
portals/jetspeed-2/trunk/src/webapp/WEB-INF/assembly/aggregation.xml
Modified:
portals/jetspeed-2/trunk/components/portal/src/java/org/apache/jetspeed/aggregator/impl/AsyncPageAggregatorImpl.java
URL:
http://svn.apache.org/viewvc/portals/jetspeed-2/trunk/components/portal/src/java/org/apache/jetspeed/aggregator/impl/AsyncPageAggregatorImpl.java?view=diff&rev=496514&r1=496513&r2=496514
==============================================================================
---
portals/jetspeed-2/trunk/components/portal/src/java/org/apache/jetspeed/aggregator/impl/AsyncPageAggregatorImpl.java
(original)
+++
portals/jetspeed-2/trunk/components/portal/src/java/org/apache/jetspeed/aggregator/impl/AsyncPageAggregatorImpl.java
Mon Jan 15 14:01:14 2007
@@ -188,8 +188,12 @@
{
// kick off render thread
// and store the portlet rendering job into the
portlet jobs list.
- RenderingJob job = renderer.render(child, context);
- portletJobs.add(job);
+ RenderingJob job = renderer.render(child, context);
+
+ if (job.getTimeout() > 0)
+ {
+ portletJobs.add(job);
+ }
}
else
{
Modified:
portals/jetspeed-2/trunk/components/portal/src/java/org/apache/jetspeed/aggregator/impl/PortletRendererImpl.java
URL:
http://svn.apache.org/viewvc/portals/jetspeed-2/trunk/components/portal/src/java/org/apache/jetspeed/aggregator/impl/PortletRendererImpl.java?view=diff&rev=496514&r1=496513&r2=496514
==============================================================================
---
portals/jetspeed-2/trunk/components/portal/src/java/org/apache/jetspeed/aggregator/impl/PortletRendererImpl.java
(original)
+++
portals/jetspeed-2/trunk/components/portal/src/java/org/apache/jetspeed/aggregator/impl/PortletRendererImpl.java
Mon Jan 15 14:01:14 2007
@@ -17,6 +17,8 @@
import java.util.HashMap;
import java.util.Map;
+import java.util.Collection;
+import java.util.Iterator;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
@@ -37,6 +39,9 @@
import org.apache.jetspeed.container.window.FailedToRetrievePortletWindow;
import org.apache.jetspeed.container.window.PortletWindowAccessor;
import org.apache.jetspeed.om.common.portlet.MutablePortletEntity;
+import org.apache.jetspeed.om.common.portlet.PortletDefinitionComposite;
+import org.apache.jetspeed.om.common.GenericMetadata;
+import org.apache.jetspeed.om.common.LocalizedField;
import org.apache.jetspeed.om.page.ContentFragment;
import org.apache.jetspeed.request.RequestContext;
import org.apache.jetspeed.services.title.DynamicTitleService;
@@ -65,18 +70,30 @@
protected PortletWindowAccessor windowAccessor;
protected PortalStatistics statistics;
protected DynamicTitleService addTitleService;
+ protected long defaultPortletTimeout;
public PortletRendererImpl(PortletContainer container,
PortletWindowAccessor windowAccessor,
WorkerMonitor workMonitor,
PortalStatistics statistics,
- DynamicTitleService addTitleService)
+ DynamicTitleService addTitleService,
+ long defaultPortletTimeout)
{
this.container = container;
this.windowAccessor = windowAccessor;
this.workMonitor = workMonitor;
this.statistics = statistics;
this.addTitleService = addTitleService;
+ this.defaultPortletTimeout = defaultPortletTimeout;
+ }
+
+ public PortletRendererImpl(PortletContainer container,
+ PortletWindowAccessor windowAccessor,
+ WorkerMonitor workMonitor,
+ PortalStatistics statistics,
+ DynamicTitleService addTitleService)
+ {
+ this( container, windowAccessor, workMonitor, statistics, null, 0 );
}
public PortletRendererImpl(PortletContainer container,
@@ -197,8 +214,17 @@
portletWindow = getPortletWindow(fragment);
servletRequest = requestContext.getRequestForWindow(portletWindow);
servletResponse =
dispatcherCtrl.getResponseForWindow(portletWindow, requestContext);
- rJob = buildRenderingJob(fragment, servletRequest,
servletResponse, requestContext, true);
- workMonitor.process(rJob);
+ rJob = buildRenderingJob(fragment, servletRequest,
servletResponse, requestContext, true);
+
+ if (rJob.getTimeout() > 0)
+ {
+ workMonitor.process(rJob);
+ }
+ else
+ {
+ rJob.execute();
+ }
+
addTitleToHeader( portletWindow, fragment, servletRequest,
servletResponse );
}
catch (Exception e1)
@@ -250,13 +276,15 @@
}
protected RenderingJob buildRenderingJob( ContentFragment fragment,
HttpServletRequest request,
- HttpServletResponse response, RequestContext requestContext, boolean
isParallel )
- throws FailedToRetrievePortletWindow, FailedToRenderFragmentException,
PortletEntityNotStoredException
+ HttpServletResponse response,
RequestContext requestContext, boolean isParallel )
+ throws FailedToRetrievePortletWindow, FailedToRenderFragmentException,
PortletEntityNotStoredException
{
RenderingJob rJob = null;
ContentDispatcher dispatcher = null;
PortletWindow portletWindow = getPortletWindow(fragment);
+ PortletDefinitionComposite portletDefinition =
+ (PortletDefinitionComposite)
portletWindow.getPortletEntity().getPortletDefinition();
ContentDispatcherCtrl dispatcherCtrl =
getDispatcherCtrl(requestContext, true);
dispatcher = getDispatcher(requestContext, true);
request = requestContext.getRequestForWindow(portletWindow);
@@ -271,7 +299,7 @@
request.setAttribute(PortalReservedParameters.PORTLET_WINDOW_ATTRIBUTE,
portletWindow);
PortletContent portletContent = dispatcher.getPortletContent(fragment);
fragment.setPortletContent(portletContent);
-
+
// In case of parallel mode, store attributes in a map to be refered
by worker.
if (isParallel)
{
@@ -285,8 +313,7 @@
// the portlet invoker is not thread safe; it stores current
portlet definition as a member variable.
// so, store portlet definition as an attribute of worker
-
workerAttrs.put(PortalReservedParameters.PORTLET_DEFINITION_ATTRIBUTE,
-
portletWindow.getPortletEntity().getPortletDefinition());
+
workerAttrs.put(PortalReservedParameters.PORTLET_DEFINITION_ATTRIBUTE,
portletDefinition);
rJob = new RenderingJobImpl(container, portletContent, fragment,
request, response, requestContext, portletWindow, statistics, workerAttrs);
}
@@ -295,6 +322,37 @@
rJob = new RenderingJobImpl(container, portletContent, fragment,
request, response, requestContext, portletWindow, statistics);
}
+ long timeoutMetadata = 0;
+
+ Collection timeoutFields =
portletDefinition.getMetadata().getFields("timeout");
+
+ if (timeoutFields != null)
+ {
+ Iterator it = timeoutFields.iterator();
+
+ if (it.hasNext())
+ {
+ LocalizedField timeoutField = (LocalizedField)
timeoutFields.iterator().next();
+
+ try
+ {
+ timeoutMetadata = Long.parseLong(timeoutField.getValue());
+ }
+ catch (NumberFormatException nfe)
+ {
+ log.warn("Invalid timeout metadata: " + nfe.getMessage());
+ }
+ }
+ }
+
+ if (timeoutMetadata > 0)
+ {
+ rJob.setTimeout(timeoutMetadata);
+ }
+ else if (this.defaultPortletTimeout > 0)
+ {
+ rJob.setTimeout(this.defaultPortletTimeout);
+ }
return rJob;
Modified:
portals/jetspeed-2/trunk/components/portal/src/java/org/apache/jetspeed/aggregator/impl/RenderingJobImpl.java
URL:
http://svn.apache.org/viewvc/portals/jetspeed-2/trunk/components/portal/src/java/org/apache/jetspeed/aggregator/impl/RenderingJobImpl.java?view=diff&rev=496514&r1=496513&r2=496514
==============================================================================
---
portals/jetspeed-2/trunk/components/portal/src/java/org/apache/jetspeed/aggregator/impl/RenderingJobImpl.java
(original)
+++
portals/jetspeed-2/trunk/components/portal/src/java/org/apache/jetspeed/aggregator/impl/RenderingJobImpl.java
Mon Jan 15 14:01:14 2007
@@ -65,6 +65,9 @@
protected PortalStatistics statistics;
protected Map workerAttributes;
+
+ protected long startTimeMillis = 0;
+ protected long timeout;
public RenderingJobImpl(PortletContainer container,
PortletContent portletContent,
@@ -102,6 +105,31 @@
}
/**
+ * Sets portlet timout in milliseconds.
+ */
+ public void setTimeout(long timeout) {
+ this.timeout = timeout;
+ }
+
+ /**
+ * Gets portlet timout in milliseconds.
+ */
+ public long getTimeout() {
+ return this.timeout;
+ }
+
+ /**
+ * Checks if the portlet rendering is timeout
+ */
+ public boolean isTimeout() {
+ if ((this.timeout > 0) && (this.startTimeMillis > 0)) {
+ return (System.currentTimeMillis() - this.startTimeMillis >
this.timeout);
+ }
+
+ return false;
+ }
+
+ /**
* Checks if queue is empty, if not try to empty it by calling
* the WorkerMonitor. When done, pause until next scheduled scan.
*/
@@ -109,6 +137,10 @@
{
try
{
+ if (this.timeout > 0) {
+ this.startTimeMillis = System.currentTimeMillis();
+ }
+
// A little baby hack to make sure the worker thread has
PortletContent to write too.
fragment.setPortletContent(portletContent);
execute();
@@ -183,11 +215,10 @@
}
catch (Throwable t)
{
- // this will happen is request is prematurely aborted
- if ( t instanceof UnavailableException)
+ if (t instanceof UnavailableException)
{
// no need to dump a full stack trace to the log
- log.error("Error rendering portlet OID
"+this.window.getId()+": "+t.toString());
+ log.error("Error rendering portlet OID " + this.window.getId()
+ ": " + t.toString());
}
else
{
Modified:
portals/jetspeed-2/trunk/components/portal/src/java/org/apache/jetspeed/aggregator/impl/WorkerMonitorImpl.java
URL:
http://svn.apache.org/viewvc/portals/jetspeed-2/trunk/components/portal/src/java/org/apache/jetspeed/aggregator/impl/WorkerMonitorImpl.java?view=diff&rev=496514&r1=496513&r2=496514
==============================================================================
---
portals/jetspeed-2/trunk/components/portal/src/java/org/apache/jetspeed/aggregator/impl/WorkerMonitorImpl.java
(original)
+++
portals/jetspeed-2/trunk/components/portal/src/java/org/apache/jetspeed/aggregator/impl/WorkerMonitorImpl.java
Mon Jan 15 14:01:14 2007
@@ -21,15 +21,21 @@
import java.util.ArrayList;
import java.util.List;
import java.util.Stack;
+import java.util.LinkedList;
+import java.util.Collections;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.jetspeed.aggregator.RenderingJob;
import org.apache.jetspeed.aggregator.Worker;
import org.apache.jetspeed.aggregator.WorkerMonitor;
+import org.apache.jetspeed.aggregator.PortletContent;
import org.apache.jetspeed.util.Queue;
import org.apache.jetspeed.util.FIFOQueue;
+import org.apache.pluto.om.window.PortletWindow;
+import org.apache.pluto.om.common.ObjectID;
+
/**
* The WorkerMonitor is responsible for dispatching jobs to workers
* It uses an Apache HTTPd configuration style of min/max/spare workers
@@ -81,10 +87,19 @@
/** Job queue */
protected Queue queue;
+ /** Workers to be monitored for timeout checking */
+ protected List workersMonitored = Collections.synchronizedList(new
LinkedList());
+
+ /** Renering Job Timeout monitor */
+ protected RenderingJobTimeoutMonitor jobMonitor;
+
public void start()
{
addWorkers(this.minWorkers);
setQueue(new FIFOQueue());
+
+ jobMonitor = new RenderingJobTimeoutMonitor(1000);
+ jobMonitor.start();
}
public void stop()
@@ -170,6 +185,11 @@
synchronized (worker)
{
worker.setJob(job, context);
+
+ if (job.getTimeout() > 0) {
+ workersMonitored.add(worker);
+ }
+
worker.notify();
runningJobs++;
}
@@ -191,6 +211,8 @@
// backlog job to this worker, else reset job count and put
// it on the idle queue.
+ long jobTimeout = ((RenderingJob) worker.getJob()).getTimeout();
+
synchronized (worker)
{
if ((worker.getJobCount()<this.maxJobsPerWorker)&&(queue.size()>0))
@@ -209,6 +231,10 @@
}
}
+ if (jobTimeout > 0) {
+ workersMonitored.remove(worker);
+ }
+
synchronized (this.workers)
{
this.workers.push(worker);
@@ -234,4 +260,78 @@
return this.tg.activeCount();
}
+ class RenderingJobTimeoutMonitor extends Thread {
+
+ long interval = 1000;
+
+ RenderingJobTimeoutMonitor(long interval) {
+ super("RenderingJobTimeoutMonitor");
+
+ if (interval > 0) {
+ this.interval = interval;
+ }
+ }
+
+ public void run() {
+ while (true) {
+ try {
+ int size = workersMonitored.size();
+
+ for (int i = 0; i < size; i++) {
+ WorkerImpl worker = (WorkerImpl)
workersMonitored.get(i);
+
+ if (null == worker) {
+ break;
+ }
+
+ RenderingJob job = (RenderingJob) worker.getJob();
+
+ if (null != job) {
+ if (job.isTimeout()) {
+ killJob(worker, job);
+ }
+ }
+ }
+ } catch (Exception e) {
+ log.error("Exception during job monitoring.", e);
+ }
+
+ try {
+ synchronized (this) {
+ wait(this.interval);
+ }
+ } catch (InterruptedException e) {
+ ;
+ }
+ }
+ }
+
+ public void killJob(WorkerImpl worker, RenderingJob job) {
+ try {
+ if (log.isWarnEnabled()) {
+ PortletWindow window = job.getWindow();
+ ObjectID windowId = (null != window ? window.getId() :
null);
+ log.warn("Portlet Rendering job to be interrupted by
timeout (" + job.getTimeout() + "ms): " + windowId);
+ }
+
+ int waitCount = 0;
+ PortletContent content = job.getPortletContent();
+
+ while (!content.isComplete()) {
+ if (++waitCount > 10) {
+ break;
+ }
+
+ worker.interrupt();
+
+ synchronized (content) {
+ content.wait();
+ }
+ }
+ } catch (Exception e) {
+ log.error("Exceptiong during job killing.", e);
+ }
+ }
+
+ }
}
Modified:
portals/jetspeed-2/trunk/jetspeed-api/src/java/org/apache/jetspeed/aggregator/RenderingJob.java
URL:
http://svn.apache.org/viewvc/portals/jetspeed-2/trunk/jetspeed-api/src/java/org/apache/jetspeed/aggregator/RenderingJob.java?view=diff&rev=496514&r1=496513&r2=496514
==============================================================================
---
portals/jetspeed-2/trunk/jetspeed-api/src/java/org/apache/jetspeed/aggregator/RenderingJob.java
(original)
+++
portals/jetspeed-2/trunk/jetspeed-api/src/java/org/apache/jetspeed/aggregator/RenderingJob.java
Mon Jan 15 14:01:14 2007
@@ -33,6 +33,11 @@
PortletWindow getWindow();
PortletContent getPortletContent();
-
+
+ void setTimeout(long portletTimeout);
+
+ long getTimeout();
+
+ boolean isTimeout();
}
Modified: portals/jetspeed-2/trunk/src/webapp/WEB-INF/assembly/aggregation.xml
URL:
http://svn.apache.org/viewvc/portals/jetspeed-2/trunk/src/webapp/WEB-INF/assembly/aggregation.xml?view=diff&rev=496514&r1=496513&r2=496514
==============================================================================
--- portals/jetspeed-2/trunk/src/webapp/WEB-INF/assembly/aggregation.xml
(original)
+++ portals/jetspeed-2/trunk/src/webapp/WEB-INF/assembly/aggregation.xml Mon
Jan 15 14:01:14 2007
@@ -45,6 +45,15 @@
<constructor-arg>
<ref bean="PortalStatistics" />
</constructor-arg>
+ <constructor-arg>
+ <null/>
+ </constructor-arg>
+ <!-- Default portlet timeout in milliseconds:
+ Zero means no portlet timeout option by default.
+ -->
+ <constructor-arg>
+ <value>0</value>
+ </constructor-arg>
</bean>
<!-- Portlet Renderer w/title in http response header -->
---------------------------------------------------------------------
To unsubscribe, e-mail: [EMAIL PROTECTED]
For additional commands, e-mail: [EMAIL PROTECTED]