Skip to main content

Customizing uPortal (Part 2)

Decorator Pattern

In our previous post, we covered the motivation for using design patterns to limit custom code changes in uPortal 5 and discussed two of the most useful patterns, Decorator and Strategy. In this post, we provide a real example of applying Decorator to uPortal5.  In our next post, we will provide a real example of Strategy.

This post assumes you are comfortable with Spring Framework and XML contexts for configuration. The key point is that Spring instantiates beans based on the XML contexts and wires them up together when one bean references another. For example:

```
    <bean id="portalPreAuthenticationFilter"
        class="org.apereo.portal.spring.security.preauth.PortalPreAuthenticatedProcessingFilter">
        <property name="authenticationManager" ref="authenticationManager" />
    </bean>
```

This stanza denotes a bean, an object of class PortalPreAuthenticatedProcessingFilter, that will be created by Spring, and that a setter or property will be given another bean named authenticationManager. There are several ways to wire up beans, including annotations, that provide a rich (and sometimes confusing) environment to inject beans and values into other beans.

On to our patterns ...

Decorator

By nature, Decorators are often quite simple. Too much additional code is usually a sign that more than a decorator class is needed. So, our example is the need for a straightforward feature -- the ability to turn on/off CAS authenticationFilter for uPortal.

The goal for this change is to allow setting a simple configuration value in a property file to enable the use of the Central Authentication Service (CAS) authentication filter, which is only needed when ‘Guest Redirect to CAS’ is desired. For a majority of portal deployments, this is not used. If we did not have the requirement that this feature needs to be driven by a property value, we might have simply documented how to add the bean and update other beans. However, the decorator approach provides a simple solution to address this requirement.

Let’s start with the class. It was easy to come up with a name, OptionalFilterDecorator, that describes this feature. If you would like to look at the live code, feel free to search for it, but we will take a look at the significant parts here.

The class implements javax.servlet.Filter  interface.

```
public class OptionalFilterDecorator implements Filter {
```

It only has two properties: the flag and the filter it wraps, with setters.

```
    private boolean enable = false;
    private Filter wrappedFilter;

    public void setEnable(boolean enable) {
        this.enable = enable;
    }

    public void setWrappedFilter(Filter wrappedFilter) {
        this.wrappedFilter = wrappedFilter;
    }
```

The remainder of the class implements the Filter interface and checks the enable property to determine if the wrapped filter should be called.

```

    @Override
    public void init(FilterConfig filterConfig) throws ServletException {
        if (wrappedFilter == null) {
            throw new ServletException("No wrappedFilter configured");
        }

        if (this.enable) {
            this.wrappedFilter.init(filterConfig);
        }
    }

    @Override
    public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain)
            throws IOException, ServletException {
        if (wrappedFilter == null) {
            throw new ServletException("No wrappedFilter configured");
        }

        if (this.enable) {
            this.wrappedFilter.doFilter(request, response, chain);
        } else {
            chain.doFilter(request, response);
        }
    }

    @Override
    public void destroy() {
        if (this.enable && this.wrappedFilter != null) {
            this.wrappedFilter.destroy();
        }
    }
}
```

This is so generic, it could decorate any derived Filter object that needs this functionality. Nothing in this class cares that it is currently meant for a CAS filter. This generality is not always possible, but it is nice when we can attain it.

On to the Spring context XML. The live version is in the securityContext.xml file in uPortal. These are the last two bean definitions in that file. Here, we get to leverage what Spring offers: injection of control! Typically, the CAS authentication filter is named casAuthenticationFilter. No surprises there. In our case, we are going to name the actual filter casInnerAuthenticationFilter and name the decorator casAuthenticationFilter.

The last bit of the puzzle is how to set enable to TRUE or FALSE from a properties file. Here, uPortal shines. It already supports loading a predefined set of properties files and importing them into the Spring context. Setting a default is also supported. In our real-world example, the property value is casAuthenticationFilter, which is set in uPortal.properties.

Pulled all together, here is what the Spring bean definition looks like:

```

    <!--
     | Spring-managed instance of CAS AuthenticationFilter. As above, this allows us to configure
     | CAS authentication in the preferred approach. This is only needed for 'Guest Redirect to CAS'.
     +-->
    <bean name="casAuthenticationFilter" class="org.apereo.portal.spring.web.OptionalFilterDecorator">
        <property name="wrappedFilter" ref="casInnerAuthenticationFilter" />
        <property name="enable" value="${cas.enable.redirect.guest.to.login:false}" />
    </bean>

    <bean name="casInnerAuthenticationFilter" class="org.jasig.cas.client.authentication.AuthenticationFilter">
        <property name="casServerLoginUrl" value="${cas.authenticationFilter.cas.login.url}" />
        <property name="service" value="${cas.authenticationFilter.service}" />
        <property name="gateway" value="false" />
        <property name="encodeServiceUrl" value="true" />
    </bean>
</beans>

```

In the decorator bean definition, we define the class to the decorator. We also tell Spring to use the bean named casInnerAuthenticationFilter as the wrapped filter value. We also pull the properties value as the value of enable, including a default of FALSE.

So, that is a real example of using the Decorator pattern in uPortal. While this is not used a whole lot, when applicable, it sure is nice to implement, test, and review.

In our next post, we will look at using the Strategy pattern to customize a class by modifying its behavior versus what the Community usually needs.

Stay tuned, and contact us with any questions!

Useful Reading:

Benito Gonzalez

Benito Gonzalez

Senior Software Developer
Benito Gonzalez is a Software Architect at Unicon, Inc., a leading provider of education technology consulting and digital services. Benito joined Unicon in 2015 and has over 25 years of professional IT experience. He holds a Bachelor of Science degree in Computer Science. Benito has been active in web development since 1999. Benito spent six years prior to joining Unicon as the Enterprise Web Applications Manager at University of California, Merced, where he managed several campus-wide services, such as CAS, uPortal and Sakai CLE.