The Basics
How Solstice Interacts with the Web and You

Solstice lives on top of Apache and provides a structure for applications built upon it. It creates a request lifecycle, based upon discreet tasks needed to run a Web application, that dictates the work an application does. It also provides a rich set of APIs and services that an application writer can utilize to remove almost all of the tediousness of creating a web application.
Solstice also provides several mechanisms for applications to communicate with one another. Through the use of services, applications can embed parts of other Solstice applications. Applications can also listen for events broadcasted by other applications, or broadcast events themselves. For instance, every time group membership is changed, applications can be notified to update any related data (such as an .htaccess file on a separate system).
MVC Framework
Solstice is based heavily on a design pattern called Model View Controller, or MVC. This separates the work in an application into discrete objects, each with separate tasks. Controllers are responsible for business logic, Views for producing an output for users, and Models are for managing data. More information on MVC is widely available. See, for example: http://en.wikipedia.org/wiki/Model-view-controller.

Managing State
One of the primary benefits of the Solstice framework is removing the necessity of tracking user state in an application. In this context, state refers to knowing what a user is doing, and what the user can be doing next. We define the user’s current context within the application as Session.
An Intro to State
In every application, there are a number of tasks a user can perform as well as a set order in which they can perform them. With a message board, for example, a user can compose a new posting for a message board or delete a thread, but you certainly do not want a thread deleted after a new message is posted. In a Solstice application, each of these tasks in bundled into a state, and each state exists in a vacuum. The post a new message state does not need to know (and should not know) what state the user is coming from nor should it worry too much about what the user will do next.
The relationships between these different states are specified in an XML file, one per application. Changing application flow just requires modifying the XML. After parsing, the data in the XML file becomes a state map, which maps all of the user interactions in the application. Represented graphically, it will probably look very similar to a screen flow diagram.
Example State Map

The following graphic is the state map for the Catalyst Account Screen application. This application is meant to be a smart dashboard for all of the tools that a user owns. The home screen displays ‘items’, or specific tool implementations, that the user has flagged. The user can go to a separate screen to flag more ‘items’, and they can modify their profile.
The state map has two primary components. There are the states themselves, represented by the circles, and there are the transitions, which are represented by the dashed arrows. Every transition has a set of attributes that are set on it in the XML file. First, every transition has a label associated with it so that views can create proper transitions away from themselves and so that the central Solstice State Machine knows how to direct the application. Transitions also have a collection of potential actions: update, validate, commit, revert, and freshen. These actions constitute the majority of the vocabulary that a Solstice Controller must understand. Various combinations of these actions are what make the two transitions from profile to tagged distinct in the example state map. The save_profile transition will run update, validate and commit, whereas the cancel_edit transition will run revert.
Here is the suggested role of each of the transition actions:
- Validate – this should validate user input from CGI values.
- Update – this should take values from CGI, and update the Model with them.
- Commit – this should save the model to a permanent data store.
- Revert – this should replace a model with one pulled from a permanent data store.
- Freshen – this is the same as revert, but it is called earlier in the process.
How Solstice Manages a Lifecycle
A lifecycle in solstice encompasses everything that happens from when a user submits a page until a new page is rendered. The entire process is dictated by the state machine and what it determines should happen on the given transition. In the lifecycle process, there are two controllers to contended with, a ‘Post-click’ and a ‘Pre-click’ controller. This is because the state for each page is entirely self-contained. A new instance of the same controller that created the page handles the processing of data for that page.

The View

The view’s role in the controller lifecycle is very simple. It knows about a template, and then it populates that template with data from the model it was given by the Controller. The work of populating the template is handled in a central Solstice View superclass, so all the View has to do is return a reference to a hash of values in a method called _getTemplateParams.
The ‘Pre-click’ Controller

The pre-click controller is the beginning of a new page. It has two jobs that will always be called, validPreConditions and getView. ValidPreConditions is a check to ensure that the controller has all of the data it needs to proceed. If it returns a non-true value, an error page will be displayed. GetView’s job is returning a View object that represents the new page.
Since the error screen cannot be customized at this point, validPreConditions is underutilized, and in danger of deprecation.
The ‘Post-click’ Controller

The post-click controller is responsible for handling 4 of the 5 actions that can happen on a transition. This controller contains the code for reverting its model, updating its model, validating user input, and saving the model.
The Solstice Layer

The pre and post click are both driven by the Solstice layer. This is where the magic happens that determines the state you are in and you will go to next. This layer is driven by a Controller called Solstice::Controller::Application::Main, or SCAM. This controller loads the state machine, figures out what button you have clicked, and then loads the post and pre click controllers. During the post-click phase of the lifecycle, SCAM queries the state machine to decide what methods should be called on the post-click controller. After it has called all of the appropriate methods on the post-click controller, SCAM queries the state machine to find the pre-click controller that should be loaded.
There are two things that can interrupt this flow. The first is a failure to validate user input. If the validate method fails, there are several consequences. First, commit not run, regardless of what the state map thinks should happen. Second, the transition to the next state will not happen. Instead, the pre-click controller that is loaded will be a new instantiation of the post-click controller. This results in the user seeing the same view they just left, with the data they submitted in place and with an instructional set of messages explaining why their input was not accepted. The second interruption occurs during the pre-click phase. If validPreConditions fails, all processing is halted, and the user is shown an error screen.
From the State’s Perspective

Another way of visualizing this process is from the state’s perspective. This better captures the user’s flow through a page. A caution, though: the process handling the ‘before the user sees it’ and the process handling the ‘after the user sees it’ sections may be entirely different. They may even be on separate servers.