Surf Platform - Developers Guide

From alfrescowiki

Jump to: navigation, search

NOTE: This page describes the Alfresco Surf Platform which is included in Alfresco 3.0, 3.1 and 3.2.

If you are looking for information about Alfresco 3.3, please visit Spring Surf.


Back to the Alfresco Surf Platform.

Web Application Basics

Surf is a lightweight, scriptable Java-based web framework. As such, it runs inside of a web application. A Surf application is typically packaged as a standalone WAR file which is then deployed to your Java application server.

One such example is the alfwf.war file that builds by default within the Alfresco Web Framework project. You could take this WAR file and drop it into an application server so as to use it. That's all there is to it.

Typically, the WAR file will contain:

  • The Surf Platform runtime
  • Your Surf objects

We'll assume this to be the case as we proceed.

Structure

When the WAR file expands, it has a structure much like the one shown here:

/core
/css
/images
/WEB-INF
/WEB-INF/classes/alfresco
index.jsp

You may have some additional directories, but these are the essential ones. It is a very straightforward web application.

The first file to look at is the web.xml file, located under WEB-INF. The servlet container begins by reading this file. Within web.xml, there are declarations for servlets and Spring objects. It is kept lightweight, but you should note some of the sections.

The following section tells the Spring Framework context how to load. Spring is included with the Surf platform and is responsible for bean management and instantiation. The Spring ContextLoaderListener is configured as a servlet listener and reads the bean configuration files when the Surf application starts.

   <listener>
      <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
   </listener>

The Spring context loader uses the contextConfigLocation context parameter to find what beans to configure. The context-param section bootstraps webscript-framework-application-context.xml (which loads the Web Script Engine configuration). It then bootstraps web-framework-application-context.xml (which loads the Surf platform config).

   <context-param>
      <param-name>contextConfigLocation</param-name>
      <param-value>
         classpath:alfresco/webscript-framework-application-context.xml
         classpath:alfresco/web-framework-application-context.xml
      </param-value>
      <description>Spring config file locations</description>
   </context-param>

Once the web application starts up, several servlets are made available. One such servlet is the DispatcherServlet which is the main handler for requests that enter the Surf platform:

   <servlet>
      <servlet-name>pageRendererServlet</servlet-name>
      <servlet-class>org.alfresco.web.site.servlet.DispatcherServlet</servlet-class>
      <load-on-startup>1</load-on-startup>
   </servlet>  
   <servlet-mapping>
      <servlet-name>pageRendererServlet</servlet-name>
      <url-pattern>/page/*</url-pattern>
   </servlet-mapping>
   <servlet-mapping>
      <servlet-name>pageRendererServlet</servlet-name>
      <url-pattern>/p/*</url-pattern>
   </servlet-mapping>

Requests that arrive to the web application hit index.jsp, which forwards the request to the dispatcher servlet (a forward to /page).

Surf MVC

Once requests are directed to the dispatcher servlet, the Surf Platform begins execution of a Model-View-Controller pattern so as to determine how to render back the entire page. This MVC model is described here.

Controller: Dispatcher Servlet

The Dispatcher Servlet is responsible for rendering back a page to the user. It must consider the incoming request context and figure what and how to render. The dispatcher can receive requests for the following:

A specific page 
A page id may be given to the dispatcher directly.
A type of page 
For instance, the user may be requesting the login page. The application may actually have several login pages (one for customers, one for partners, one for employees, and so on) and it must select one and render it back.
An object 
An object id may be given to the dispatcher. The dispatcher must then figure out which page to use to render this object.

There are other combinations; the permutations are numerous. As such, the Dispatcher Servlet has been implemented in such a way as to allow developers to customize its behavior with a minimal amount of work.

The Advanced section of this documentation covers further concepts such as Page Mappers, Rendering Engines and overrides, and display processors.

Model: Surf Object Model

The Surf Platform provides a default object model that implements that majority of common web site and web application object types that you might expect. These include things like Pages, Templates, Components and Themes.

Furthermore, the Surf Platform enables you to define your own object model or extend the out-of-the-box object model to accommodate your needs.

Surf Platform model objects are managed in memory as standard POJOs (Plain Old Java Objects). When written to disk, they are serialized as XML.

In the case of our standalone WAR file, the XML is stored in subdirectories within the following location:

   /WEB-INF/classes/alfresco/site-data

Within this directory, you see the following subdirectories, one for each type of model object that is managed by the Surf platform:

   /site-data/chrome
   /site-data/component-types
   /site-data/components
   /site-data/configurations
   /site-data/content-associations
   /site-data/page-associations
   /site-data/page-types
   /site-data/pages
   /site-data/template-instances
   /site-data/template-types
   /site-data/themes

Inside each subdirectory, you may find XML which represents a serialized model object. For instance, within the default alfwf.war file, there is a file called welcome.xml. This is a page with id welcome and it contains the following XML:

   <?xml version='1.0' encoding='UTF-8'?>
   <page>
      <title>The test welcome page</title>
      <template-instance>welcome-main</template-instance>
      <authentication>none</authentication>
   </page>

The exact semantics of each object type is covered later in this document, but this should give you a general feel. From looking at the XML, you can see that this is a page whose title is The test welcome page and which points to a template that has the id welcome-main. No authentication is required to access this page.

As you create new pages, new components, or any model object, you do so by dropping new XML into these directories. This means there is no need to access databases or customize web clients.

Views: Renderers

The Surf Platform controller looks at its model and then asks specific model objects to render. Typically, these are things like components or templates. When the model objects render, they can render using any of Surf's supported rendering engines.

There are several rendering engines supported out-of-the-box. These include:

  • Web Scripts
  • Freemarker
  • JSP
  • HTML

However, you may also wish to implement your own. The Surf Platform has been designed to allow developers to define their own rendering engines and hook them into existing model objects or their own custom types.

Web Script Renderers

The Web Scripts rendering engine is provided by default and is the most advanced engine since it allows you to take advantage of both JavaScript (for pre-render processing) and Freemarker (for presentation processing). If you have built web scripts using Alfresco's web script engine before, then you will already be familiar with this. Otherwise, take a look at the Web Scripts guide.

Within the Surf platform, web scripts are used most commonly to render components. You build your own web scripts and then drop them into the /WEB-INF/classes/alfresco/site-webscripts directory. They will then be picked up by the container and can be used by your model objects.

To tell a component to use a web script, simply set the url property to the URL of the web script.

Freemarker Rendering Engine

The Freemarker rendering engine is provided by default and is used most commonly to render templates. It is also automatically used in conjunction with the web script renderer, but that is only applicable to components. With templates, you can use Freemarker directly.

If you have built Freemarker templates before and used them within Alfresco, then you will already be familiar with what they can do. If you are not familiar with Freemarker templates, see the Alfresco Freemarker Template Guide.

Within the Surf platform, your Freemarker .ftl template files can be placed into the /WEB-INF/classes/alfresco/templates directory. Then they will be picked up by the template processor and will be accessible by your model objects.

To tell a template to use a Freemarker .ftl file, set the template-type parameter to the file's path (relative to /templates).

JSP Renderers

The JSP renderer is used to render either components or templates, and provide you with access to the full Java language and the Surf platform Java API. They require knowledge of Java programming.

To use a JSP renderer, you have to write your .jsp file and place it anywhere within your web application, though we recommend a convention of placing them under the /app/components directory.

Once you have done that, you set the renderer property to the path of the JSP (relative to the web application). This is covered in greater detail later on.

The Object Model

The Web Application Basics section provides a high level overview of the Surf platform data model. This section goes into detail concerning each object type.

Chrome

Chrome describes the border elements around a region or a component. These border elements may include styling elements like shadows, or they may introduce drag and drop capabilities into the page. They may also introduce user-functionality like buttons for popping up component settings (as you frequently see in portals).

By default, chrome is kept to a minimum within the Surf platform. New components that are dropped onto a page will receive the default chrome for the web application (which is empty out-of-the-box).

Storage location 
/WEB-INF/classes/alfresco/site-data/chrome
Properties
  • id => the id of the object (optional)
  • title => the title of the chrome
  • description => the description of the chrome
  • renderer-type => the id of the renderer (as defined in the config)
  • renderer => the path to the file to be executed by the renderer

Sample JSP Chrome

   <chrome>
      <title>Sample Chrome 1</title>
      <renderer>/app/sample-chrome-1.jsp</renderer>
      <renderer-type>jsp</renderer-type>
   </chrome>

Note: renderer is the path to the JSP file (relative to the web application)

Sample Web Script Chrome

   <chrome>
      <title>Sample Chrome 2</title>
      <renderer>/sample/chrome-2</renderer>
      <renderer-type>webscript</renderer-type>
   </chrome>

Note: renderer is the URL to the web script as defined in the web script's XML description document.

Sample Chrome Template for Region

Use @component to include the component in the region.

<div id="${htmlid}">
   <@component/>
</div>

Sample Chrome Template for Component

Use @componentInclude for the place where the component is to be rendered.

<!-- Start Debug Component Chrome -->
<div style="border: 2px black solid">
   <div style="background-color: #aaaaaa; border-bottom: 1px black solid; color: white; padding: 2px"><B>${htmlid}</B></div>
   <div style="background-color: #dddddd; padding: 2px">
     <@componentInclude/>
   </div>
</div>
<!-- End Debug Component Chrome -->

Component Type

A component type is something that the web site builder can grab at and instantiate in many places across their web application. They bind the new instances into pages by snapping them into regions (or slots). In other frameworks it is sometimes called a widget, a gadget, a portlet, or a dashlet.

Storage location 
/WEB-INF/classes/alfresco/site-data/component-types
Properties
  • id => the id of the object (optional)
  • title => the title of the component type
  • description => the description of the component type
  • renderer-type => the id of the renderer (as defined in the config, typically one of: webscript, jsp, java)
  • renderer => the path to the file to be executed by the renderer

Sample Web Script Component Type

   <component-type>
      <title>Alfresco RSS Newsfeed Component</title>
      <description>Displays a configurable number of Alfresco news items</description>
      <renderer-type>webscript</renderer-type>		
      <renderer>/sample/alfresco-newsfeed</renderer>
   </component-type>

Note: renderer is the URL to the web script as defined in the web script's XML descriptor file

Sample JSP Component Type

   <component-type>
      <id>jsp-sample-component-type</id>
      <title>Alfresco RSS Newsfeed Component</title>
      <description>Displays a configurable number of Alfresco news items</description>
      <renderer-type>jsp</renderer-type>		
      <renderer>/app/components/alfresco-newsfeed</renderer>
   </component-type>

Note: renderer is the path to the JSP file (relative to the web application)

Sample Java Bean Component Type

   <component-type>
      <title>Alfresco RSS Newsfeed Component</title>
      <description>Displays a configurable number of Alfresco news items</description>
      <renderer-type>java</renderer-type>		
      <renderer>org.alfresco.web.site.ui.AlfrescoRSSNewsFeed</renderer>
   </component-type>

Note: renderer is the class name of the Java Bean to be instantiated. This Java class must implement the Renderable interface. This is covered in a greater detail in another section.

Component

A component is an instance of a component type that has been "bound" into a region or a slot. It represents a binding along with the instance-specific state for that component instance.

Storage location 
/WEB-INF/classes/alfresco/site-data/components
Properties
  • id => the id of the object (optional)
  • title => the title of the component (optional)
  • description => the description of the component (optional)
  • component-type => the id of the component type (optional) (I think this is supposed to be "component-type-id". --Jeff)
  • scope => the scope of the binding (either global, template or page).
  • region-id => the id of the region (or slot) into which the component is bound
  • source-id => either global or the id of the page or template to which the component is bound.
  • url => the path to the file to be executed by the renderer

Sample Web Script Component

   <component>
      <scope>page</scope>
      <region-id>content</region-id>
      <source-id>welcome</source-id>
      <url>/test/configtest</url>
   </component>

Note: A page-scoped component that is bound to content region of the welcome page. The component type is not specified, so the url property is inspected and determined to be a web script. Therefore, this component will execute the web script at url /test/configtest.

Sample JSP Component

   <component>
      <component-type>jsp-sample-component-type</component-type>
      <scope>template</scope>
      <region-id>news</region-id>
      <source-id>product</source-id>
   </component>

Note: A template-scoped component that is bound to news region of the product template. The component type is jsp-sample-component-type which is from a previous sample. This is a JSP renderer and all of the rendering information is contained on the component type.

Configuration

A Configuration object is a collection of XML, the purpose of which is general in nature. As opposed to Model objects that have structured XML persistence (with known properties and members), a Configuration has only one requirement - an id. This id can either be specified in the XML or determined from the file name.

In general, other for advanced customization, you will not need to deal with Configuration objects. They are mostly used internally by the system.

Storage location 
/WEB-INF/classes/alfresco/site-data/configurations
Properties
  • id => the id of the object (optional)
  • title => the title of the component (optional)
  • description => the description of the component (optional)

Sample Configuration

One place where Configuration objects are used is to store information that pertains to the global site. At present, there does not exist the notion of a "web site" object. Instead, web site configuration stored as a Configuration XML file. An example is shown here (note the root-page element that specifies first page to be invoked):

  <configuration>
    <title>Surf Platform 3.0 Sample Site</title>
    <description>Surf Platform 3.0 Sample Site</description>
    <source-id>site</source-id>
    <properties>
      <root-page>welcome</root-page>
    </properties>
  </configuration>

Note: This XML could have any structure that you wish. In this sense, you can think of a Configuration object as a general purpose Model Object.

Content Association

A Content Association object describes to the Surf platform how it should handle the rendition of a view for a given piece of content.

To put it another way, imagine that an end-user clicks on a link to view details about a given document. Their objective is not to open up the document, but rather to view its metadata and properties.

With the Surf platform, you might define a general purpose page called document-details-viewer. Your intention would be to use this page anytime an end-user wants to view the details about any document in the system.

You can do this by creating a Content Association that associates the document to the Page. It can associate either a specific document (by object id) or all documents of a specific type (by object type id). It can associate to a Page instance or it could also associate to a Page Type.

The Surf platform will realize that the end-user clicked on a document and will then look to the Content Association instance to tell it where to go in order to render this content. The rendering Page and all downstream components will have the Content object available to it so that no reloads are necessary.

Storage location 
/WEB-INF/classes/alfresco/site-data/content-associations
Properties
  • id => the id of the object (optional)
  • title => the title of the Content Association (optional)
  • description => the description of the Content Association(optional)
  • source-id => the content type to be associated
  • dest-id => the page or component that will render the content type
  • assoc-type => the type of association, i.e. page, etc.

Sample Configuration

  <content-association>
    <title>details: cm_content</title>
    <source-id>{http://www.alfresco.org/model/content/1.0}content</source-id>
    <dest-id>page.content.details</dest-id>
    <assoc-type>page</assoc-type>
  </content-association>

Note: Association between content of type {http://www.alfresco.org/model/content/1.0}content and the page with id page.content.details, which will be used to render it. This is an example of how you might use the Surf platform to render Alfresco content into a page.

Page

A page is a navigable page in your web application. It may have associations to other pages and multiple formats keyed from it to templates. A page is a top-level object from which you can traverse either additional navigation or rendering paths.

Storage location 
/WEB-INF/classes/alfresco/site-data/pages
Properties
  • id => the id of the object (optional)
  • title => the title of the component (optional)
  • description => the description of the component (optional)
  • template-instance => the id of the template instance to render this page
  • authentication => authentication required to view this page (either none, user, or admin)

Sample Home Page

   <page>
      <title>My Home Page</title>
      <template-instance>home-main</template-instance>
      <authentication>none</authentication>
   </page>

Note: A simple unauthenticated home page. When rendering, the page will delegate to the home-main template to render the page markup.

Page Association

The Page Association objects allows you to link two pages together. Most commonly, this link is of type child and is meant to depict a fixed structure like a navigation tree. However, other types are possible and there is no requirement to use Page Associations as a means to support only a single fixed tree.

Using associations, multiple trees are possible. The nature of the associations, when expanded beyond child, is very similar to that of classifiers, categories, or tags. In other words, Pages may be associated to other pages, but they may also be laterally associated to other elements. This allows for implementations of faceted navigation and tag clouds.

Storage location 
/WEB-INF/classes/alfresco/site-data/page-associations
Properties
  • id => the id of the object (optional)
  • title => the title of the Page Association(optional)
  • description => the description of the Page Association(optional)
  • source-id => the id of the parent element, often a page id
  • dest-id => the id of the linked element, often a page id
  • assoc-type => the type of the association

Sample Page Association

  <page-association>
    <title>Products</title>
    <source-id>page.home</source-id>
    <dest-id>page.products</dest-id>
    <assoc-type>child</assoc-type>
  </page-association>

Note: Links the Home page to the Products page using a child relationship. At present, child relationships are the only ones understood by the Surf platform.

Template Instance

This sample is from share's site-data\template-instances\search.xml. It points to FreeMarker renderer classes/alfresco/templates/org/alfresco/search.ftl.


<?xml version='1.0' encoding='UTF-8'?>
<template-instance>
   <template-type>org/alfresco/search</template-type>
   <properties>
   </properties>
</template-instance>

The above sample works because if template-type is not known to Surf (i.e. not webscript, freemarker, etc), it assumes freemarker and looks for it at the specified URI. A way to specify this more explicitly is:

<?xml version='1.0' encoding='UTF-8'?>
<template-instance>
	<template-type>freemarker</template-type>
	<url>org/alfresco/search</url>
       <properties>
       </properties>
<template-instance>

Template Type

This example is from the default empty Surf project, and specifies Freemarker as the renderer:

<?xml version="1.0" encoding="UTF-8"?>
<template-type>
    <title>Freemarker Template Type</title>
    <description>A reusable Freemarker Template Type</description>

    <!-- Define the rendering processors for this template type -->	
    <processor mode="view">
       <id>freemarker</id>
    </processor>
    
</template-type>

This next example shows how to use a JSP renderer (taken from Share's main index page):

<?xml version="1.0" encoding="UTF-8"?>
<template-type>
    <title>JSP Template Type</title>
    <description>A JSP Template Type</description>

    <!-- Define the rendering processors for this template type -->	
    <processor mode="view">
       <id>jsp</id>
       <jsp-path>/myjspfile.jsp</jsp-path>
    </processor>
    
</template-type>

The JSP path is relative to the top level application folder (for instance, /webapps/surf/ in Tomcat).

Template Renderer

Example below is from share's search.ftl.

<#import "import/alfresco-template.ftl" as template />
<@template.header>
  <link rel="stylesheet" type="text/css" href="${url.context}/templates/wiki/wiki.css" />
</@>

<@template.body>
   <div id="hd">
      <@region id="header" scope="global" protected=true />
      <@region id="title" scope="template" protected=true />
   </div>
   <div id="bd">
      <div class="yui-t1">
         <div id="yui-main">
            <@region id="search" scope="template" protected=true />
         </div>
      </div>
   </div>
</@>

<@template.footer>
   <div id="ft">
      <@region id="footer" scope="global" protected=true />
   </div>
</@>

Theme

Creating a New Template

Freemarker Example

JSP Example

Creating a New Component

Web Script Example

JSP Example

Java Bean Example

Advanced Surf Platform Configuration

DispatcherServlet can be customized by changing the way it creates pages, users, links, etc. Of course, the Surf platform provides default implementations for all of these. In most cases, you will be able to use the default implementations.

Modifying the mechanisms typically involves extending one or more of the following (look in the source code for examples on how to do so):

Request Context

Request Context Factory 
An implementation of the RequestContextFactory interface - responsible for generating a RequestContext instance. RequestContext instances are created at the top of the request processing chain and are then made available to all rendering items downstream.

Page Mapper

Page Mapper 
An implementation of the PageMapper interface. This is responsible for examining request parameters, headers, and attributes so as to populate the RequestContext instance with page state.

Users

User Factory 
An implementation of the UserFactory interface. This is responsible for examining the request state and ensuring that a valid User object is loaded into the request context. The User object is then available to all rendering items downstream.

Link Builder

Link Builder 
An implementation of the LinkBuilder interface. This is responsible for creating links that the aforementioned pieces are able to properly interpret.

File Systems

Formats

Model Types

Tag Libraries

Renderers

Content Loaders

Error Handlers

System Pages

Dispatcher Defaults

Application Defaults

Debug Settings

Advanced Remote Configuration

Personal tools
© 2014 Alfresco Software, Inc. All Rights Reserved. Legal | Privacy | Accessibility