Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

UP-4964: Fix configuration of BranchingRenderingPipeline on uP5 #1050

Merged
merged 8 commits into from
Nov 22, 2017
14 changes: 7 additions & 7 deletions docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -168,13 +168,13 @@ below.

## Sections

* [Building / Deploying uPortal](building-and-deploying-uportal.md)
* [Implementing uPortal](implement/README.md)
* [uPortal System Administration](sysadmin/README.md)
* [Developer's Guide](developer/README.md)
* [Supported web browsers](SUPPORTED_BROWSERS.md)
* [Accessibility](ACCESSIBILITY.md)
* [Project Committers](COMMITTERS.md)
1. [Building / Deploying uPortal](building-and-deploying-uportal.md)
2. [Implementing uPortal](implement/README.md)
3. [uPortal System Administration](sysadmin/README.md)
4. [Developer's Guide](developer/README.md)
5. [Supported web browsers](SUPPORTED_BROWSERS.md)
6. [Accessibility](ACCESSIBILITY.md)
7. [Project Committers](COMMITTERS.md)

## External Links

Expand Down
15 changes: 8 additions & 7 deletions docs/implement/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@
This section covers topics related to implementing the portal: adding your
users, groups, layouts, *etc.*

1. [Authentication](authentication/README.md)
2. [User Attributes](user-attributes/README.md)
3. Groups and Permissions (TBD)
4. Layout Management (TBD)
5. Content (TBD)
6. [Frontend](frontend/README.md)
7. [Security](security.md)
1. uPortal Core Subsystems
1. [Authentication](authentication/README.md)
2. [User Attributes](user-attributes/README.md)
3. Groups and Permissions (TBD)
4. Layout Management (TBD)
5. Content (TBD)
2. [Frontend](frontend/README.md)
3. [Security](security.md)
3 changes: 3 additions & 0 deletions docs/implement/frontend/README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,8 @@
# Frontend Implementation / Customization
uPortal offers a flexible ability to customize the look and feel of the user experience.

## Topics

* [Skinning uPortal](SKINNING_UPORTAL.md)
* [Configuring the uPortal Rendering Pipeline](RENDERING_PIPELINE.md)
* [Using Angular](USING_ANGULAR.md)
190 changes: 190 additions & 0 deletions docs/implement/frontend/RENDERING_PIPELINE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,190 @@
# Configuring the uPortal Rendering Pipeline

uPortal implements rendering of complete pages using a _pipeline_: a nested structure of discrete,
pluggable elements that each implement the same Java interface. The word "pipeline" is suitable
because it invokes the concepts of _movement_ and _throughput_, but in software this design is also
known as the [Decorator Pattern][].

The Java interface at the center of the uPortal Rendering Pipeline is `IPortalRenderingPipeline`.
Instances of `IPortalRenderingPipeline` are Spring-managed beans. The primary rendering pipline
bean is assigned an id (in Spring) of `portalRenderingPipeline`. Components in other parts of the
portal (outside the Rendering Pipeline) use this bean (exclusively) to interact with rendering in
the portal.

The `IPortalRenderingPipeline` interface defines only one method:

``` java
public void renderState(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException;
```

## uPortal Standard Pipeline

The "standard" rendering pipeline is the one that comes with uPortal out-of-the-box: by default,
uPortal 5 uses the same rendering pipeline configuration as uPortal 4.3 -- based on an instance of
`DynamicRenderingPipeline` that contains a number of _components_.

The components within `DynamicRenderingPipeline` also each implement a single interface:
`CharacterPipelineComponent`, which itself extends
`PipelineComponent<CharacterEventReader, CharacterEvent>`. (The standard rendering pipeline is
hard-wired for XML/XSLT.) Each component implements a discrete step in the rendering of a page
request.

The standard pipeline includes (as of this writing) the following components (steps):

1. `analyticsIncorporationComponent`
2. `portletRenderingIncorporationComponent`
3. `portletRenderingInitiationCharacterComponent`
4. `themeCachingComponent`
5. `postSerializerLogger`
6. `staxSerializingComponent`
7. `postThemeTransformLogger`
8. `themeTransformComponent`
9. `preThemeTransformLogger`
10. `themeAttributeIncorporationComponent`
11. `portletRenderingInitiationComponent`
12. `structureCachingComponent`
13. `postStructureTransformLogger`
14. `structureTransformComponent`
15. `preStructureTransformLogger`
16. `structureAttributeIncorporationComponent`
17. `portletWindowAttributeIncorporationComponent`
18. `dashboardWindowStateSettingsStAXComponent`
19. `postUserLayoutStoreLogger`
20. `userLayoutStoreComponent`

The order of processing for these pipeline components is essentially _backwards_: bottom to top.

## Using `RenderingPipelineBranchPoint` Beans

uPortal adopters may configure the Rendering Pipeline to suit their needs. Most common use cases
can be satisfied using `RenderingPipelineBranchPoint` beans. Rendering branch points are Java
objects (Spring-managed beans) that tell some (or all) HTTP requests to follow a different path.
Rendering branch points follow the standard uPortal 5 configuration strategy for Spring-managed
beans: if you supply a properly-configured bean of the correct type (_viz._
`RenderingPipelineBranchPoint`) to the Spring Application Context, uPortal will _discover_ it and
_do the right thing_. (uPortal will provide it as a dependency to the components that know what
to do with it.)

uPortal evaluates `RenderingPipelineBranchPoint` beans, if present, in the specified order. If a
branch indicates that it _should_ be followed, it _will_ be followed, and no further branches will
be tested. If no branch is followed, the standard rendering pipeline will be used.

`RenderingPipelineBranchPoint` beans accept the following configuration settings:

| Property | Type | Required? | Notes |
| -------- | ---- |:---------:| ----- |
| `order` | `int` | N* | Defines the sequence of branch points when more than one are present (in which case `order` is required). Branches with lower `order` values come before higher values. |
| `predicate` | `java.util.function.Predicate<HttpServletRequest>` | Y | If the `predicate` returns `true`, the branch will be followed; otherwise the next branch will be tested. |
| `alternatePipe` | `IPortalRenderingPipeline` | Y | The rendering path that will be followed if the `predicate` returns `true`. |

### Examples

The following examples illustrate some typical uses for `RenderingPipelineBranchPoint` beans. Each
of these examples can be configured in
`uPortal-start/overlays/uPortal/src/main/resources/properties/contextOverrides/overridesContext.xml`.

#### Example 1: Redirect Unauthenticated Users to CAS/Shibboleth

This example illustrates a commonly-requested feature: disallow unauthenticated access to the
portal.

``` xml
<bean id="guestUserBranchPoint" class="org.apereo.portal.rendering.RenderingPipelineBranchPoint">
<property name="predicate">
<bean class="org.apereo.portal.rendering.predicates.GuestUserPredicate" />
</property>
<property name="alternatePipe">
<bean class="org.apereo.portal.rendering.RedirectRenderingPipelineTerminator">
<property name="redirectTo" value="${org.apereo.portal.channels.CLogin.CasLoginUrl}" />
</bean>
</property>
</bean>
```

#### Example 2: Integrate uPortal-home

This example illustrates required uPortal Rendering Pipeline configuration for integration with
[uPortal-home][].

``` xml
<bean id="redirectToWebMaybe" class="org.jasig.portal.rendering.RenderingPipelineBranchPoint">
<property name="order" value="1" />
<property name="predicate">
<bean class="org.jasig.portal.rendering.predicates.GuestUserPredicate" />
</property>
<property name="alternatePipe" ref="redirectToWeb" />
</bean>

<bean id="maybeRedirectToExclusive" class="org.jasig.portal.rendering.RenderingPipelineBranchPoint">
<property name="order" value="2" />
<property name="predicate">
<bean class="java.util.function.Predicate" factory-method="and" factory-bean="focusedOnOnePortletPredicate">
<constructor-arg>
<bean class="java.util.function.Predicate" factory-method="and" factory-bean="urlNotInExclusiveStatePredicate">
<constructor-arg>
<bean class="org.jasig.portal.rendering.predicates.RenderOnWebFlagSetPredicate" />
</constructor-arg>
</bean>
</constructor-arg>
</bean>
</property>
<property name="alternatePipe" ref="redirectToWebExclusive" />
</bean>

<!-- if the request is for a simple content portlet, redirect to
uPortal-home to render that portlet statically. -->
<bean id="maybeRedirectToWebStatic" class="org.jasig.portal.rendering.RenderingPipelineBranchPoint">
<property name="order" value="3" />
<property name="predicate">
<bean class="java.util.function.Predicate" factory-method="and" factory-bean="focusedOnOnePortletPredicate">
<constructor-arg>
<bean class="java.util.function.Predicate" factory-method="and" factory-bean="urlInMaximizedStatePredicate">
<constructor-arg>
<ref bean="webAppNameContainsSimpleContentPortletPredicate" />
</constructor-arg>
</bean>
</constructor-arg>
</bean>
</property>
<property name="alternatePipe" ref="redirectToWebStatic" />
</bean>

<!-- Common Predicates -->

<bean id="focusedOnOnePortletPredicate" class="org.jasig.portal.rendering.predicates.FocusedOnOnePortletPredicate" />

<bean id="urlNotInExclusiveStatePredicate" class="org.jasig.portal.rendering.predicates.URLInSpecificStatePredicate">
<property name="state" value="EXCLUSIVE" />
<property name="negated" value="true" />
</bean>

<bean id="urlInMaximizedStatePredicate" class="org.jasig.portal.rendering.predicates.URLInSpecificStatePredicate">
<property name="state" value="MAX" />
</bean>

<bean id="webAppNameContainsSimpleContentPortletPredicate" class="org.jasig.portal.rendering.predicates.WebAppNameContainsStringPredicate">
<property name="webAppNameToMatch" value="SimpleContentPortlet" />
</bean>

<!-- Pipeline Terminators -->

<bean id="redirectToWeb" class="org.jasig.portal.rendering.RedirectRenderingPipelineTerminator">
<property name="redirectTo" value="${angular.landing.page}" />
</bean>

<bean id="redirectToWebExclusive" class="org.jasig.portal.rendering.RedirectRenderingPipelineTerminator">
<property name="redirectTo" value="${angular.landing.page}exclusive/" />
<property name="appender" value="fname" />
</bean>

<!-- Redirect to uPortal-home,
instructing uPortal-home to render a particular portlet statically. -->
<bean id="redirectToWebStatic" class="org.jasig.portal.rendering.RedirectRenderingPipelineTerminator">
<property name="redirectTo" value="${angular.landing.page}static/" />
<property name="appender" value="fname" />
</bean>
```

[Decorator Pattern]: https://en.wikipedia.org/wiki/Decorator_pattern
[uPortal-home]: https://github.com/uPortal-Project/uportal-home
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@
*/
package org.apereo.portal.rendering;

import com.google.common.base.Predicate;
import java.io.IOException;
import java.util.function.Predicate;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
Expand All @@ -30,7 +30,10 @@
* proceed down the false branch.
*
* @since 4.2
* @deprecated In favor of {@link RenderingPipelineBranchPoint}, which supports configuration of the
* same components/features in the uP5 style.
*/
@Deprecated
public class BranchingRenderingPipeline implements IPortalRenderingPipeline {

protected final Logger logger = LoggerFactory.getLogger(getClass());
Expand All @@ -51,7 +54,7 @@ public void renderState(final HttpServletRequest request, final HttpServletRespo
// render either the true or false pipe, depending on the trueness or falseness of the
// predicate

if (predicate.apply(request)) {
if (predicate.test(request)) {
logger.trace("Branching to the true pipe [{}].", truePipe);
truePipe.renderState(request, response);
} else {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

/** Describes the entry point into the uPortal rendering pipeline. */
public interface IPortalRenderingPipeline {

/**
* <code>renderState</code> method orchestrates the rendering pipeline which includes worker
* dispatching, and the rendering process from layout access, to channel rendering, to writing
Expand All @@ -31,6 +32,6 @@ public interface IPortalRenderingPipeline {
* @param res the <code>HttpServletResponse</code>
* @exception PortalException if an error occurs
*/
public void renderState(HttpServletRequest req, HttpServletResponse res)
void renderState(HttpServletRequest req, HttpServletResponse res)
throws ServletException, IOException;
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,9 @@
public interface PipelineComponent<R, E> {

/** Get the cache key for the request */
public CacheKey getCacheKey(HttpServletRequest request, HttpServletResponse response);
CacheKey getCacheKey(HttpServletRequest request, HttpServletResponse response);

/** Get the event reader and corresponding cache key for the request */
public PipelineEventReader<R, E> getEventReader(
PipelineEventReader<R, E> getEventReader(
HttpServletRequest request, HttpServletResponse response);
}
Loading