Rendering
Purpose
The rendering package (org.jasig.portal.rendering) contains interfaces and implementation that are used to compile uPortal presentation. Rendering subsystem aims to provide an extensible set of abstractions that can be configured to generate diverse context presentations.
Renderers
A top-level object responsible for generating context presentation is defined by the simple IPortalRenderer interface. Although the interface is general enough to allow for a wide variety of implementations, the uPortal3 takes an approach where the presentation is compiled by a set of connected rendering components. Components pass presentation from one to another, adding/transforming or filtering presentation content, until the final component sends presentation to the response object. The logic of the presentation is modified by adding, removing, connecting and configuring individual components. Main rendering components are illustrated in a partial ULM inheritance/association diagram below (UPC:pdf version)
Tree Renderer
TreeRenderer is the main renderer implementation. It assumes that rendering components are organized as a tree, with a single top-level entry component (root) at which the rendering is initiated. The root component itself must also implement IPortalRenderer interface.
TreeRenderer is responsible for establishing the rendering cycle and firing RenderingPipelineEvent (those are used to inform components of the rendering cycle events).
Component Managers
TreeRenderer does not deal with components themselves, instead it delegates component management responsibilities to the IRenderingComponentManager. The component manager implementation defines the topology in which the rendering components are connected. Knowing the topology one can enumerate components of the rendering path, and decide on an optimal cache entry point.
PipelineComponentManager is an implementation that assumes a linear rendering pipeline (such as the one present in uPortal2).
SAX rendering pipelines
org.jasig.portal.rendering.sax package contains renering components that operate with SAX content streams. SaxPipelineComponentManager allows to build pipelines composed exclusively of SAX rendering components (such as SAX filters, transformers, etc.)
String rendering pipelines
Similarly to SAX streams, content can be handed over from one component to another in a form of a simple string. org.jasig.portal.renering.string package contains String rendering components, that can be composed into all-string rendering pipelines using StringPipelineComponent.
Hybrid rendering pipelines
Hybrid rendering pipelines allow to compose pipelines that contain different types of components. CompositePipelineComponentManager is provided with with a List of disparate rendering components, and a set of IComponentConntector instances that can be used to wire together rendering components. A SaxComponentConnector will, for example, connect neighboring components by setting appropriate ContentHandlers.
Adding new component type
To add a new type of rendering components (beside SAX and String) and use it in hybrid rendering pipelines, one would create an appropriate connector implementation and, hopefully, a cache manager with corresponding cache entry point implementation (see below).
Content Caching
Content caching he package also includes some abstractions for caching implementation. Given a network of rendering components, there are might be multiple points at which the content is cached. Each such point is described by an ICacheEntryPoint interface (which allows to reply the cache).
The rendering component manager is tasked with determining an optimal (and valid) cache entry point for each rendering cycle. PipelineComponentManager delegates this responsibility to a IPipelineCacheManager instance (see diagram below, or UPC:pdf version). SaxPipelineCacheManager and StringPipelineCacheManager provide specific implementation for processing cache entry points of SAX and String rendering components.
Caching itself is performed by special components, implementing ICacheFilter interface (or, normally, an extension of it). Filters are provided cache key. SAX and Sting component-specific extensions of ICacheFilter (ISaxCacheFilter and IStringCacheFilter) provides methods for requesting a set of upstream component validity objects for a current cache key, and replaying the cache. These are used by cache manager implementation to construct a set of all potential cache entry points along the pipeline, check their validity and find an optimal (i.e. latest) valid cache entry point that should be replayed.
Example: uPortal2 rendering pipeline
The following Spring configuration creates a pipeline that mimic uPortal2 operation. It is a hybrid pipeline, with a first part consisting of SAX components, transitioning into String pipeline at the end. Two parts of the pipeline are connected through SaxToStringCacheFilter, which serializes SAX streams into String representation, and caches content.
<!-- a hybrid pipeline configuration with a "sax to string" caching filter --> <bean id="hybridPipeline" class="org.jasig.portal.rendering.TreeRenderer"> <property name="componentManager"> <bean id="compositeComponentManager" class="org.jasig.portal.rendering.hybrid.CompositePipelineComponentManager"> <!-- set up composite cache manager --> <property name="cacheManager"> <bean id="cacheManager" class="org.jasig.portal.rendering.hybrid.CompositePipelineCacheManager"> <property name="cacheManagers"> <list> <bean id="stringCacheManager" class="org.jasig.portal.rendering.string.StringPipelineCacheManager"/> <!-- note: sax cache manager is not really necessary, since pipeline described below does not contain any SAX cache filters --> <bean id="saxCacheManager" class="org.jasig.portal.rendering.sax.SaxPipelineCacheManager"/> </list> </property> </bean> </property> <!-- set up component connectors --> <property name="componentConnectors"> <list> <bean id="stringComponentConnector" class="org.jasig.portal.rendering.hybrid.StringComponentConnector"/> <bean id="saxComponentConnector" class="org.jasig.portal.rendering.hybrid.SaxComponentConnector"/> </list> </property> <!-- set up pipeline elements --> <property name="pipelineElements"> <list> <!-- layout source bean --> <ref bean="simpleUserLayoutManagerSource"/> <!-- transformation filters --> <ref bean="structureTransformationFilter"/> <ref bean="themeTransformationFilter"/> <!-- sax to string caching filter --> <bean id="sax2stringFilter" class="org.jasig.portal.rendering.hybrid.SaxToStringCacheFilter"> <property name="outputFormat"> <bean id="xmlFormat" class="org.apache.xml.serialize.OutputFormat"> <constructor-arg index="0"> <value>XHTML</value> </constructor-arg> <constructor-arg index="1"> <value>UTF-8</value> </constructor-arg> <constructor-arg index="2"> <value>true</value> </constructor-arg> <property name="indenting"> <value>true</value> </property> <property name="omitXMLDeclaration"> <value>true</value> </property> </bean> </property> <property name="cache"> <ref bean="saxCache"/> </property> </bean> <!-- portlet rendering initiation filter --> <bean id="renderingInitiationFilter" class="org.jasig.portal.rendering.string.PortletRenderingInitiationFilter"> <property name="portletWindowManager"> <ref bean="portletWindowManager"/> </property> </bean> <!-- portlet content incorporation filter --> <bean id="portletContentIncorporationFilter" class="org.jasig.portal.rendering.string.PortletContentIncorporationFilter"> <property name="portletWindowManager"> <ref bean="portletWindowManager"/> </property> </bean> <!-- recorder component --> <bean id="writer" class="org.jasig.portal.rendering.string.StringResponseWriter"/> </list> </property> </bean> </property> </bean>