/* (non-Javadoc) * @see org.apereo.portal.portlet.rendering.IPortletExecutionManager#serveResource(org.apereo.portal.portlet.om.IPortletWindowId, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) */ @Override public void doPortletServeResource( IPortletWindowId portletWindowId, HttpServletRequest request, HttpServletResponse response) { final long timeout = getPortletResourceTimeout(portletWindowId, request); final IPortletExecutionWorker<Long> resourceWorker = this.portletWorkerFactory.createResourceWorker(request, response, portletWindowId); resourceWorker.submit(); try { resourceWorker.get(timeout); } catch (Exception e) { // Log the exception but not this thread's stacktrace. The portlet worker has already logged // its stack trace this.logger.error( "resource worker {} failed with exception {}", resourceWorker, e.toString()); // render generic serveResource error try { if (!response.isCommitted()) { response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE, "resource unavailable"); } } catch (IOException e1) { logger.error( "caught IOException trying to send error response for failed resource worker", e); } } // If the worker is still running add it to the hung-workers queue if (!resourceWorker.isComplete()) { cancelWorker(request, resourceWorker); } }
protected void waitForEventWorker( HttpServletRequest request, PortletEventQueue eventQueue, IPortletExecutionWorker<Long> eventWorker, IPortletWindowId portletWindowId) { final long timeout = getPortletEventTimeout(portletWindowId, request); try { eventWorker.get(timeout); } catch (Exception e) { // put the exception into the error map for the session // TODO event error handling? final IPortletWindow portletWindow = this.portletWindowRegistry.getPortletWindow(request, portletWindowId); logger.warn( portletWindow + " threw an execption while executing an event. This chain of event handling will terminate.", e); } // If the worker is still running add it to the hung-workers queue if (!eventWorker.isComplete()) { cancelWorker(request, eventWorker); } }
/** Cancel the worker and add it to the hung workers queue */ protected void cancelWorker( HttpServletRequest request, IPortletExecutionWorker<?> portletExecutionWorker) { final IPortletWindowId portletWindowId = portletExecutionWorker.getPortletWindowId(); final IPortletWindow portletWindow = this.portletWindowRegistry.getPortletWindow(request, portletWindowId); this.logger.warn( "{} has not completed, adding to hung-worker cleanup queue: {}", portletExecutionWorker, portletWindow); portletExecutionWorker.cancel(); this.portletExecutionEventFactory.publishPortletHungEvent( request, this, portletExecutionWorker); hungWorkers.offer(portletExecutionWorker); }
/* (non-Javadoc) * @see org.apereo.portal.portlet.rendering.IPortletExecutionManager#doPortletAction(org.apereo.portal.portlet.om.IPortletWindowId, javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse) */ @Override public void doPortletAction( IPortletWindowId portletWindowId, HttpServletRequest request, HttpServletResponse response) { final long timeout = getPortletActionTimeout(portletWindowId, request); final IPortletExecutionWorker<Long> portletActionExecutionWorker = this.portletWorkerFactory.createActionWorker(request, response, portletWindowId); portletActionExecutionWorker.submit(); try { portletActionExecutionWorker.get(timeout); } catch (Exception e) { // put the exception into the error map for the session final Map<IPortletWindowId, Exception> portletFailureMap = getPortletErrorMap(request); portletFailureMap.put(portletWindowId, e); } // If the worker is still running add it to the hung-workers queue if (!portletActionExecutionWorker.isComplete()) { cancelWorker(request, portletActionExecutionWorker); } // Is this portlet permitted to emit events? (Or is it disablePortletEvents=true?) final IPortletWindow portletWindow = portletWindowRegistry.getPortletWindow(request, portletWindowId); IPortletDefinition portletDefinition = portletWindow.getPortletEntity().getPortletDefinition(); IPortletDefinitionParameter disablePortletEvents = portletDefinition.getParameter(DISABLE_PORTLET_EVENTS_PARAMETER); if (disablePortletEvents != null && Boolean.parseBoolean(disablePortletEvents.getValue())) { logger.info( "Ignoring portlet events for portlet '{}' because they have been disabled.", portletDefinition.getFName()); } else { // Proceed with events... final PortletEventQueue portletEventQueue = this.eventCoordinationService.getPortletEventQueue(request); this.doPortletEvents(portletEventQueue, request, response); } }
@Scheduled(fixedRate = 1000) public void cleanupHungWorkers() { if (this.hungWorkers.isEmpty()) { return; } for (final Iterator<IPortletExecutionWorker<?>> workerItr = this.hungWorkers.iterator(); workerItr.hasNext(); ) { final IPortletExecutionWorker<?> worker = workerItr.next(); // If the worker completed remove it from queue if (worker.isComplete()) { workerItr.remove(); this.logger.debug( "{} has completed and is removed from the hung worker queue after {} cancels", worker, worker.getCancelCount()); this.portletExecutionEventFactory.publishPortletHungCompleteEvent(this, worker); } // If the worker is still running cancel it else { // Log a warning about the worker once every 30 seconds or so final int cancelCount = worker.getCancelCount(); if (cancelCount % 150 == 0) { this.logger.warn( "{} is still hung, cancel has been called {} times", worker, cancelCount); } else { this.logger.debug( "{} is still hung, cancel has been called {} times", worker, cancelCount); } worker.cancel(); } } }
public void doPortletEvents( PortletEventQueue eventQueue, HttpServletRequest request, HttpServletResponse response) { if (eventQueue.getUnresolvedEvents().isEmpty()) { return; } final Map<IPortletWindowId, IPortletExecutionWorker<Long>> eventWorkers = new LinkedHashMap<IPortletWindowId, IPortletExecutionWorker<Long>>(); // TODO what to do if we hit the max iterations? int iteration = 0; for (; iteration < this.maxEventIterations; iteration++) { // Make sure all queued events have been resolved this.eventCoordinationService.resolvePortletEvents(request, eventQueue); // Create and submit an event worker for each window with a queued event for (final IPortletWindowId eventWindowId : eventQueue) { if (eventWorkers.containsKey(eventWindowId)) { /* * PLT.15.2.5 says that event processing per window must be serialized, if there * is already a working in the map for the window ID skip it for now. we'll get back to it eventually */ continue; } final QueuedEvent queuedEvent = eventQueue.pollEvent(eventWindowId); if (queuedEvent != null) { final Event event = queuedEvent.getEvent(); final IPortletExecutionWorker<Long> portletEventExecutionWorker = this.portletWorkerFactory.createEventWorker(request, response, eventWindowId, event); eventWorkers.put(eventWindowId, portletEventExecutionWorker); portletEventExecutionWorker.submit(); } } // If no event workers exist we're done with event processing! if (eventWorkers.isEmpty()) { return; } // See if any of the events have completed int completedEventWorkers = 0; final Set<Entry<IPortletWindowId, IPortletExecutionWorker<Long>>> entrySet = eventWorkers.entrySet(); for (final Iterator<Entry<IPortletWindowId, IPortletExecutionWorker<Long>>> eventWorkerEntryItr = entrySet.iterator(); eventWorkerEntryItr.hasNext(); ) { final Entry<IPortletWindowId, IPortletExecutionWorker<Long>> eventWorkerEntry = eventWorkerEntryItr.next(); final IPortletExecutionWorker<Long> eventWorker = eventWorkerEntry.getValue(); if (eventWorker.isComplete()) { final IPortletWindowId portletWindowId = eventWorkerEntry.getKey(); // TODO return number of new queued events, use to break the loop earlier waitForEventWorker(request, eventQueue, eventWorker, portletWindowId); eventWorkerEntryItr.remove(); completedEventWorkers++; } } /* * If no event workers have completed without waiting wait for the first one and then loop again * Not waiting for all events since each event may spawn more events and we want to start them * processing as soon as possible */ if (completedEventWorkers == 0) { final Iterator<Entry<IPortletWindowId, IPortletExecutionWorker<Long>>> eventWorkerEntryItr = entrySet.iterator(); final Entry<IPortletWindowId, IPortletExecutionWorker<Long>> eventWorkerEntry = eventWorkerEntryItr.next(); eventWorkerEntryItr.remove(); final IPortletWindowId portletWindowId = eventWorkerEntry.getKey(); final IPortletExecutionWorker<Long> eventWorker = eventWorkerEntry.getValue(); waitForEventWorker(request, eventQueue, eventWorker, portletWindowId); } } if (iteration == this.maxEventIterations) { this.logger.error( "The Event dispatching iteration maximum of " + this.maxEventIterations + " was hit, consider either raising this limit or reviewing the portlets that use events to reduce the number of events spawned"); } }