// 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
UPFileSpec upfs=new UPFileSpec(req);
String rootNodeId = upfs.getMethodNodeId();
if(rootNodeId==null) {
rootNodeId=USER_LAYOUT_ROOT_NODE;
}
// give channels the current locale manager
channelManager.setLocaleManager(localeManager);
// see if a new root target has been specified
String newRootNodeId = req.getParameter("uP_detach_target");
// set optimistic uPElement value
UPFileSpec uPElement=new UPFileSpec(PortalSessionManager.INTERNAL_TAG_VALUE,UPFileSpec.RENDER_METHOD,rootNodeId,null,null);
if(newRootNodeId!=null) {
// set a new root
uPElement.setMethodNodeId(newRootNodeId);
}
IUserLayoutManager ulm=uPreferencesManager.getUserLayoutManager();
// process events that have to be handed directly to the userPreferencesManager.
// (examples of such events are "remove channel", "minimize channel", etc.
// basically things that directly affect the userLayout structure)
try {
processUserLayoutParameters(req,channelManager);
} catch (PortalException pe) {
log.error("UserInstance.renderState(): processUserLayoutParameters() threw an exception - ", pe);
}
// 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("UserInstance::renderState() : PortalException occurred while redirecting", pe);
}
return;
}
}
// else ignore new id, proceed with the old root target (or the lack of such)
if (rootNodeId != null) {
// LogService.log(LogService.DEBUG,"UserInstance::renderState() : 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=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
// 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()
PrintWriter out = res.getWriter();
// get a serializer appropriate for the target media
BaseMarkupSerializer markupSerializer = MEDIAMANAGER.getSerializerByName(tsd.getSerializerName(), out);
// set up the serializer
markupSerializer.asContentHandler();
// see if we can use character caching
boolean ccaching=(CHARACTER_CACHE_ENABLED && (markupSerializer instanceof CachingSerializer));
channelManager.setCharacterCaching(ccaching);
// initialize ChannelIncorporationFilter
// ChannelIncorporationFilter cif = new ChannelIncorporationFilter(markupSerializer, channelManager); // this should be slightly faster then the ccaching version, may be worth adding support later
CharacterCachingChannelIncorporationFilter cif = new CharacterCachingChannelIncorporationFilter(markupSerializer, channelManager,UserInstance.CACHE_ENABLED && UserInstance.CHARACTER_CACHE_ENABLED);
String cacheKey=null;
boolean output_produced=false;
if(UserInstance.CACHE_ENABLED) {
boolean ccache_exists=false;
// obtain the cache key
cacheKey=constructCacheKey(this.getPerson(),rootNodeId);
if(ccaching) {
// obtain character cache
CharacterCacheEntry cCache=(CharacterCacheEntry) this.systemCharacterCache.get(cacheKey);
if(cCache!=null && cCache.channelIds!=null && cCache.systemBuffers!=null) {
ccache_exists=true;
if (log.isDebugEnabled())
log.debug("UserInstance::renderState() : retreived transformation character block cache for a key \""+cacheKey+"\"");
// start channel threads
for(int i=0;i<cCache.channelIds.size();i++) {
String channelSubscribeId=(String) cCache.channelIds.get(i);
if(channelSubscribeId!=null) {
try {
channelManager.startChannelRendering(channelSubscribeId);
} catch (PortalException e) {
log.error("UserInstance::renderState() : unable to start rendering channel (subscribeId=\""+channelSubscribeId+"\", user="+person.getID()+" layoutId="+uPreferencesManager.getCurrentProfile().getLayoutId()+e.getCause().toString());
}
} else {
log.error("UserInstance::renderState() : channel entry "+Integer.toString(i)+" in character cache is invalid (user="+person.getID()+")!");
}
}
channelManager.commitToRenderingChannelSet();
// go through the output loop
int ccsize=cCache.systemBuffers.size();
if(cCache.channelIds.size()!=ccsize-1) {
log.error("UserInstance::renderState() : channelIds character cache has invalid size ! " +
"UserInstance::renderState() : ccache cotnains "+cCache.systemBuffers.size()+" system buffers and "+cCache.channelIds.size()+" channel entries");
}
CachingSerializer cSerializer=(CachingSerializer) markupSerializer;
cSerializer.setDocumentStarted(true);
for(int sb=0; sb<ccsize-1;sb++) {
cSerializer.printRawCharacters((String)cCache.systemBuffers.get(sb));
if (log.isDebugEnabled()){
log.debug("----------printing frame piece "+Integer.toString(sb));
log.debug((String)cCache.systemBuffers.get(sb));
}
// get channel output
String channelSubscribeId=(String) cCache.channelIds.get(sb);
channelManager.outputChannel(channelSubscribeId,markupSerializer);
}
// print out the last block
cSerializer.printRawCharacters((String)cCache.systemBuffers.get(ccsize-1));
if (log.isDebugEnabled()){
log.debug("----------printing frame piece "+Integer.toString(ccsize-1));
log.debug((String)cCache.systemBuffers.get(ccsize-1));
}
cSerializer.flush();
output_produced=true;
}
}
// if this failed, try XSLT cache
if((!ccaching) || (!ccache_exists)) {
// obtain XSLT cache
SAX2BufferImpl cachedBuffer=(SAX2BufferImpl) this.systemCache.get(cacheKey);
if(cachedBuffer!=null) {
// replay the buffer to channel incorporation filter
if (log.isDebugEnabled())
log.debug("UserInstance::renderState() : retreived XSLT transformation cache for a key \""+cacheKey+"\"");
// attach rendering buffer downstream of the cached buffer
ChannelRenderingBuffer crb = new ChannelRenderingBuffer((XMLReader)cachedBuffer,channelManager,ccaching);
// attach channel incorporation filter downstream of the channel rendering buffer
cif.setParent(crb);
crb.setOutputAtDocumentEnd(true);
cachedBuffer.outputBuffer((ContentHandler)crb);
output_produced=true;
}
}
}
// fallback on the regular rendering procedure
if(!output_produced) {
// obtain transformer handlers for both structure and theme stylesheets
TransformerHandler ssth = XSLT.getTransformerHandler(ResourceLoader.getResourceAsURL(UserInstance.class, ssd.getStylesheetURI()).toString());
TransformerHandler tsth = XSLT.getTransformerHandler(tsd.getStylesheetURI(), localeManager.getLocales(), this);
// obtain transformer references from the handlers
Transformer sst=ssth.getTransformer();
Transformer tst=tsth.getTransformer();
// initialize ChannelRenderingBuffer and attach it downstream of the structure transformer
ChannelRenderingBuffer crb = new ChannelRenderingBuffer(channelManager,ccaching);
ssth.setResult(new SAXResult(crb));
// determine and set the stylesheet params
// prepare .uP element and detach flag to be passed to the stylesheets
// Including the context path in front of uPElement is necessary for phone.com browsers to work
sst.setParameter("baseActionURL", uPElement.getUPFile());
// construct idempotent version of the uPElement
UPFileSpec uPIdempotentElement=new UPFileSpec(uPElement);
uPIdempotentElement.setTagId(PortalSessionManager.IDEMPOTENT_URL_TAG);
sst.setParameter("baseIdempotentActionURL",uPElement.getUPFile());
Hashtable supTable = userPreferences.getStructureStylesheetUserPreferences().getParameterValues();
for (Enumeration e = supTable.keys(); e.hasMoreElements();) {
String pName = (String)e.nextElement();
String pValue = (String)supTable.get(pName);
if (log.isDebugEnabled())
log.debug("UserInstance::renderState() : setting sparam \"" + pName + "\"=\"" + pValue + "\".");
sst.setParameter(pName, pValue);
}
// all the parameters are set up, fire up structure transformation
// filter to fill in channel/folder attributes for the "structure" transformation.
StructureAttributesIncorporationFilter saif = new StructureAttributesIncorporationFilter(ssth, userPreferences.getStructureStylesheetUserPreferences());
// This is a debug statement that will print out XML incoming to the
// structure transformation to a log file serializer to a printstream
StringWriter dbwr1 = null;
OutputFormat outputFormat = null;
if (logXMLBeforeStructureTransformation) {
dbwr1 = new StringWriter();
outputFormat = new OutputFormat();
outputFormat.setIndenting(true);
XMLSerializer dbser1 = new XMLSerializer(dbwr1, outputFormat);
SAX2DuplicatingFilterImpl dupl1 = new SAX2DuplicatingFilterImpl(ssth, dbser1);
dupl1.setParent(saif);
}
// if operating in the detach mode, need wrap everything
// in a document node and a <layout_fragment> node
boolean detachMode=!rootNodeId.equals(USER_LAYOUT_ROOT_NODE);
if (detachMode) {
saif.startDocument();
saif.startElement("","layout_fragment","layout_fragment", new org.xml.sax.helpers.AttributesImpl());
// emptyt.transform(new DOMSource(rElement),new SAXResult(new ChannelSAXStreamFilter((ContentHandler)saif)));
if(rElement==null) {
ulm.getUserLayout(new ChannelSAXStreamFilter((ContentHandler)saif));
} else {
ulm.getUserLayout(rElement.getId(),new ChannelSAXStreamFilter((ContentHandler)saif));
}
saif.endElement("","layout_fragment","layout_fragment");
saif.endDocument();
} else {
if(rElement==null) {
ulm.getUserLayout((ContentHandler)saif);
} else {
ulm.getUserLayout(rElement.getId(),(ContentHandler)saif);
}
// emptyt.transform(new DOMSource(rElement),new SAXResult((ContentHandler)saif));
}
// all channels should be rendering now