/* (non-Javadoc)
* @see org.jasig.portal.rendering.IPortalRenderingPipeline#renderState(javax.servlet.http.HttpServletRequest, javax.servlet.http.HttpServletResponse, org.jasig.portal.IUserInstance)
*/
public void renderState(HttpServletRequest req, HttpServletResponse res, IUserInstance userInstance) throws PortalException {
final IPerson person = userInstance.getPerson();
final LocaleManager localeManager = userInstance.getLocaleManager();
final IUserPreferencesManager uPreferencesManager = userInstance.getPreferencesManager();
final ChannelManager channelManager = userInstance.getChannelManager();
final Object renderingLock = userInstance.getRenderingLock();
UPFileSpec upfs = new UPFileSpec(req);
String rootNodeId = upfs.getMethodNodeId();
if (rootNodeId == null) {
rootNodeId = UPFileSpec.USER_LAYOUT_ROOT_NODE;
}
// see if a new root target has been specified
String newRootNodeId = req.getParameter("uP_detach_target");
// set optimistic uPElement value
UPFileSpec uPElement = new UPFileSpec(UPFileSpec.RENDER_METHOD, rootNodeId, null, null);
if (newRootNodeId != null) {
// set a new root
uPElement.setMethodNodeId(newRootNodeId);
}
channelManager.setUPElement(uPElement);
// proccess possible portlet action
final IPortletWindowId targetedPortletWindowId = this.portletRequestParameterManager.getTargetedPortletWindowId(req);
if (targetedPortletWindowId != null) {
final PortletUrl portletUrl = this.portletRequestParameterManager.getPortletRequestInfo(req, targetedPortletWindowId);
if (RequestType.ACTION.equals(portletUrl.getRequestType())) {
final IPortletEntity targetedPortletEntity = this.portletWindowRegistry.getParentPortletEntity(req, targetedPortletWindowId);
if (targetedPortletEntity != null) {
final String channelSubscribeId = targetedPortletEntity.getChannelSubscribeId();
final boolean actionExecuted = channelManager.doChannelAction(req, res, channelSubscribeId, false);
if (actionExecuted) {
// The action completed, return immediately
return;
}
// The action didn't execute, continue and try to render normally
}
}
}
// process possible worker dispatch
final boolean workerDispatched = this.processWorkerDispatchIfNecessary(req, res, uPreferencesManager, channelManager);
if (workerDispatched) {
//If a worker was dispatched to return immediately
return;
}
//Set a larger buffer to allow for explicit flushing
res.setBufferSize(16 * 1024);
final long startTime = System.currentTimeMillis();
synchronized (renderingLock) {
// This function does ALL the content gathering/presentation work.
// The following filter sequence is processed:
// userLayoutXML (in UserPreferencesManager)
// |
// incorporate StructureAttributes
// |
// Structure transformation
// + (buffering step)
// ChannelRendering Buffer
// |
// ThemeAttributesIncorporation Filter
// |
// Theme Transformatio
// |
// ChannelIncorporation filter
// |
// Serializer (XHTML/WML/HTML/etc.)
// |
// JspWriter
//
try {
// determine uPElement (optimistic prediction) --begin
// We need uPElement for ChannelManager.setReqNRes() call. That call will distribute uPElement
// to Privileged channels. We assume that Privileged channels are smart enough not to delete
// themselves in the detach mode !
// In general transformations will start at the userLayoutRoot node, unless
// we are rendering something in a detach mode.
IUserLayoutNodeDescription rElement = null;
// see if an old detach target exists in the servlet path
// give channels the current locale manager
channelManager.setLocaleManager(localeManager);
IUserLayoutManager ulm = uPreferencesManager.getUserLayoutManager();
// determine uPElement (optimistic prediction) --end
// set up the channel manager
channelManager.startRenderingCycle(req, res, uPElement);
// after this point the layout is determined
UserPreferences userPreferences = uPreferencesManager.getUserPreferences();
StructureStylesheetDescription ssd = uPreferencesManager.getStructureStylesheetDescription();
ThemeStylesheetDescription tsd = uPreferencesManager.getThemeStylesheetDescription();
// verify upElement and determine rendering root --begin
if (newRootNodeId != null && (!newRootNodeId.equals(rootNodeId))) {
// see if the new detach traget is valid
try {
rElement = ulm.getNode(newRootNodeId);
}
catch (PortalException e) {
rElement = null;
}
if (rElement != null) {
// valid new root id was specified. need to redirect
// peterk: should we worry about forwarding
// parameters here ? or those passed with detach
// always get sacked ?
// Andreas: Forwarding parameters with detach
// are not lost anymore with the URLUtil class.
// Skip the uP_detach_target parameter since
// it has already been processed
String[] skipParams = new String[] { "uP_detach_target" };
try {
URLUtil.redirect(req, res, newRootNodeId, true, skipParams, CHARACTER_SET);
}
catch (PortalException pe) {
log.error("PortalException occurred while redirecting",
pe);
}
return;
}
}
// LogService.log(LogService.DEBUG,"uP_detach_target=\""+rootNodeId+"\".");
try {
rElement = ulm.getNode(rootNodeId);
}
catch (PortalException e) {
rElement = null;
}
// if we haven't found root node so far, set it to the userLayoutRoot
if (rElement == null) {
rootNodeId = UPFileSpec.USER_LAYOUT_ROOT_NODE;
}
// update the render target
uPElement.setMethodNodeId(rootNodeId);
// inform channel manager about the new uPElement value
channelManager.setUPElement(uPElement);
// verify upElement and determine rendering root --begin
// Increase output buffer size, buffer will be flushed before and after every <channel>
res.setBufferSize(16 * 1024);
// Disable page caching
res.setHeader("pragma", "no-cache");
res.setHeader("Cache-Control", "no-cache, max-age=0, must-revalidate");
res.setDateHeader("Expires", 0);
// set the response mime type
res.setContentType(tsd.getMimeType() + "; charset=" + CHARACTER_SET);
// obtain the writer - res.getWriter() must occur after res.setContentType()
Writer out = new BufferedWriter(res.getWriter(), 1024);
// get a serializer appropriate for the target media
BaseMarkupSerializer markupSerializer =
MEDIA_MANAGER.getSerializerByName(tsd.getSerializerName(),
new ChannelTitleIncorporationWiterFilter(out, channelManager, ulm));
// set up the serializer
markupSerializer.asContentHandler();
// see if we can use character caching
boolean ccaching = (CHARACTER_CACHE_ENABLED && (markupSerializer instanceof CachingSerializer));
channelManager.setCharacterCaching(ccaching);
// pass along the serializer name
channelManager.setSerializerName(tsd.getSerializerName());
// initialize ChannelIncorporationFilter
CharacterCachingChannelIncorporationFilter cif = new CharacterCachingChannelIncorporationFilter(markupSerializer, channelManager, CACHE_ENABLED && CHARACTER_CACHE_ENABLED, req, res);
String cacheKey = null;
boolean output_produced = false;
if (CACHE_ENABLED) {
boolean ccache_exists = false;
// obtain the cache key
cacheKey = constructCacheKey(uPreferencesManager, rootNodeId);
if (ccaching) {
// obtain character cache
List<CacheEntry> cacheEntries = systemCharacterCache.get(cacheKey);
if(cacheEntries!=null && cacheEntries.size()>0) {
ccache_exists = true;
if (log.isDebugEnabled())
log
.debug("retreived transformation character block cache for a key \""
+ cacheKey + "\"");
// start channel threads
for(int i=0;i<cacheEntries.size();i++) {
CacheEntry ce = cacheEntries.get(i);
if (ce.getCacheType().equals(CacheType.CHANNEL_CONTENT)) {
String channelSubscribeId = ((ChannelContentCacheEntry)ce).getChannelId();
if(channelSubscribeId!=null) {
try {
channelManager.startChannelRendering(req, res, channelSubscribeId);
} catch (PortalException e) {
log.error("UserInstance::renderState() : unable to start rendering channel (subscribeId=\""+channelSubscribeId+"\", user="+person.getID()+" layoutId="+uPreferencesManager.getCurrentProfile().getLayoutId(),e);
}
} else {
log.error("channel entry " + Integer.toString(i)
+ " in character cache is invalid (user=" + person.getID() + ")!");
}
}
}
channelManager.commitToRenderingChannelSet();