CAS3 Design and Development

"If you don't know where you are going, you might wind up someplace else." - Yogi Berra

Overview

This document describes the Goals, Stategies and Code Conventions for CAS3 Design and Development. Design Goals are where we think we are going...without these nothing else would make much sense. Strategies provide guidelines and practical knowledge for achieving our goals. Code Conventions are simple but important code formatting rules that ensure our code base is consistent and readable. It is assumed that every CAS3 contributer is familiar with this document.

Design Goals

  1. First and foremost CAS3 will be Supple, Extensible and Elegant. It will be a joy to install, configure and run.
  2. CAS3 will maintain backward compatibility with the CAS 2.0 and CAS 1.0 protocols while providing extension points for well-known modifications and new features such as support for Web Services, SAML and Shibboleth.
  3. CAS Clients written for older versions of CAS will work with CAS3 without modification. Of course older clients may not be able to take advantage of new features unless they are updated.

Design Strategy

something about DDD, UL, Spring, etc.

Naming Strategy

Interface Names

Interface names should correspond to the natural name of the concept being modeled. For instance, the proper name for an interface that represents a ticket is Ticket. The name should be chosen carefully so that it evokes the responsibilities inherent in our common understanding of the domain. In otherwords, a "Rose is a rose is a rose is a rose." This approach is important. It ensures the code easy to read, understand and discuss. It reinforces the best practice of programming to interfaces and our use of Ubiquitous Language to craft a proper Domain Model.

Implementation Names

Whereas interface names should evoke the specific concept being modeled, implementation names decorate the natural name with clues about the intended use or characteristic of the implementation.

Consider an interface named Foobar. The various implementation names could be:

  • AbstractFoobar - skeletal implementation typically using the Template Method Pattern (requires subclassing)
  • SimpleFoobar - a simple version with more impls likely
  • DefaultFoobar - the default impl with more impls possible
  • FoobarImpl - the only possible impl (most likely final - prohibits subclassing)
  • FoobarSupport - a convenient concrete impl with Hook Methods (does not require sublassing, but possible)

This approach provides the reader a map of the design contours and extention points for adaptation and integration.

Abstract Implementation

AbstractFoobar is an skeletal implementation that provides a base level of functionality. They typically use the Template Method Pattern and always require subclassing. Abstract implementations can be used to support all the other implementation types including Simple, Default, Internal and Support. AbstractTicket is a good example of organizing common Ticket behavior with this approach.

Simple Implementation

SimpleFoobar is simply the simplest impl possible. More sophisticated alternatives are likely to be provided by CAS3 and by users. An example would be SimpleTestUsernamePasswordAuthenticationHandler , a simple test implemenation of the AuthenticationHandler interface. CAS3 provides a number of more sophisticated alternatives in the org.jasig.cas.authentication.handler.support package that can be configured at runtime.

Default Implementation

DefaultFoobar on the otherhand is the production quality default or common impl. Alternatives are possible and may be supplied by CAS3 or by users. DefaultTicketFactory is an example which provide the out-of-the-box default or common implementation of the TicketFactory interface. While alternatives are possible, the product will function properly in production using this implementation without any configuration done by the user.

Internal Implemenation

FooBarImpl is an internal product component. It is not designed for customization and does not make up part of the public API. Typically only one implementation exists and it should be made as inaccessible as possible to the outside world by making it final, package visible, or even private static nested. [Bloch, 2001] (The private solution, however, makes is less convenient to unit test. Restricting to package scope is a good mix of encapsulation and exposure that still enables JUnit testing with the corresponding test being in the same package as the class to be tested.) TicketManagerImpl is a good example of an internal product component implementation.

Support Implementation

FoobarSupport is a convenient concrete impl that provides full functionality. Subclassing is not required, but made possible by design. Extensibility is typically supported with one or more Hook Methods.

Package Organization

Packages define logical subsystems
loose coupling between them
names part of Ubiquitous Language

If there is one implementation for any given interface, it belongs in the same package as the interface. However, when there are multiple implementations for an interface they go into a support sub-package. For example the TicketCreator interface resides in org.jasig.cas.ticket.factory package while multiple implementations namely ProxyGrantingTicketCreator, ProxyTicketCreator, ServiceTicketCreator, and TicketGrantingTicketCreator reside in org.jasig.cas.ticket.factory.support package.

Code conventions

See our Code Conventions guide.