Chapter 4. Web applications

4.1. Usage scenarios

TBW

4.2. Servlet-Service framework integration

TBW: Composition, servlet: protocol, inheritance

4.3. Sitemaps in an HTTP environement

TBW: Status codes, Conditional GET requests, Mime-type handling

4.4. System setup

TBW: Logging, JNet, Configuration, Spring integration Deployment: Blocks as deployment units AND Creating a web archive (WAR), Devleopment with Eclispe and Maven

4.5. Connecting pipeline fragments

TBW

4.6. RESTful web services

4.6.1. Sitemap based RESTful web services

4.6.1.1. Introduction

TBW: REST controller, Rendering views using StringTemplate, Request-wide transactions (incl. Subrequests)

4.6.2. JAX-RS based controllers (JSR311)

4.6.2.1. Introduction

JAX-RS (JSR 311) is the Java standard for the development of RESTful web services. It provides a set of annotations that, when being applied, define resources that are exposed by using Uniform Resource Identifiers (URIs).

The wiki of the Jersey project that provides the Reference Implementation of JAX-RS contains a lot of useful information about how to define REST resources.

The main pieces of the JAX-RS/Cocoon-integration are

  • the CocoonJAXRSServlet Servlet-Service, which is responsible for the JAX-RS integration into the Cocoon Servlet-Service framework, and

  • the URLResponseBuilder class, which allows calling resources provided by other Servlet-Services (usually Cocoon pipelines exposed by sitemaps).

4.6.2.2. Cocoon and JAX-RS by example

Adding support for JAX-RS services to your Cocoon application requires following three steps:

  • Add the cocoon-rest module as a dependency.

  • Add the CocoonJAXRSServlet Servlet-Service

  • Add at least one JAX-RS root resource

4.6.2.2.1. Cocoon-Rest dependency

The first step is to add the cocoon-rest module to your Cocoon application:

    <dependency>
      <groupId>org.apache.cocoon.rest</groupId>
      <artifactId>cocoon-rest</artifactId>
    </dependency>
4.6.2.2.2. JAX-RS resource

Then at least one JAX-RS resource is required:

@Path("/sample")                                                                         (1)
public class SampleRestResource {                                                        (2)

    private Settings settings;

    @GET                                                                                 (3)
    @Path("/parameter-passing/{id}")                                                     (4)
    public Response anotherService(
        @PathParam("id") String id,                                                      (5)
        @QueryParam("req-param") String reqParam,                                        (6)
        @Context UriInfo uriInfo,                                                        (7)
        @Context Request request) {                                                      (8)
        
        Map<String, Object> data = new HashMap<String, Object>();                        (9)
        data.put("name", "Donald Duck");
        data.put("id", id);
        data.put("reqparam", reqParam);
        data.put("runningMode", this.settings.getProperty("testProperty"));

        return URLResponseBuilder.newInstance("servlet:sample:/controller/screen", data) (10)
          .build();
    }

    public void setSettings(Settings settings) {
        this.settings = settings;                                                        (11)
    }
}
1

The @javax.ws.rs.Path annotation identifies the URI path that this resource class or class method will serve requests for. The path is relative to the mount point of the servlet-service that references this resource.

2

A JAX-RS root resource.

3

The @javax.ws.rs.GET annotations indicates that this method responds to HTTP GET requests.

4

Again a @Path annotation, but this time at method level. In this example requests for sample/parameter-passing/NNN will be handled by the anotherService() method.

5

The @PathParam annoation binds the URI template value of id to the method parameter id.

6

The @QueryParam annotation binds the request parameter req-param to the method parameter reqParam.

7

By annotating the URIInfo method parameter with the @Context annotations, a current instance of URIInfo is passed to the method.

8

By annotating the Request method parameter with the @Context annotations, a current instance of Request is passed to the method.

9

A map of String/Object is collected.

10

The URLResponseBuilder sends the result of the passed URL as response. It allows passing a map of String/Object which are available in the called resource (usually a pipeline).

In this case the servlet: protocol is used. It allows accessing URLs (that usually expose pipelines) defined by other Servlet-Services.

11

A setter method to allow injecting the Setting bean.

4.6.2.2.3. JAX-RS resource as Spring bean

This resource has to be configured as Spring bean:

<beans xmlns="http://www.springframework.org/schema/beans" 
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans-2.5.xsd">

  <bean id="org.apache.cocoon.sample.rest.resource.one"                                  (1)
    class="org.apache.cocoon.sample.jaxrs.SampleRestResource">
    <property name="settings" 
      ref="org.apache.cocoon.configuration.Settings" />
  </bean>

</beans>
1

The SampleRestResource is a usual Spring bean and in this example it gets the org.apache.cocoon.configuration.Settings bean injected.

4.6.2.2.4. Servlet-Service integration

Finally the Spring bean has to be exposed by the CocoonJAXRSServlet:

<beans xmlns="http://www.springframework.org/schema/beans"
  xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xmlns:servlet="http://cocoon.apache.org/schema/servlet"
  xsi:schemaLocation="http://www.springframework.org/schema/beans 
    http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
  http://cocoon.apache.org/schema/servlet 
    http://cocoon.apache.org/schema/servlet/cocoon-servlet-1.0.xsd>
  
  <!-- A servlet-service that exposes JAX-RS REST endpoints. -->
  <bean id="org.apache.cocoon.sample.rest.servlet"                                       (1)
    class="org.apache.cocoon.rest.jaxrs.container.CocoonJAXRSServlet">
    <servlet:context mount-path="/jax-rs"                                                (2)
      context-path="blockcontext:/cocoon-sample/">
      <servlet:connections>                                                              (3)
        <entry key="sample" value-ref="org.apache.cocoon.sample.servlet" />
      </servlet:connections>      
    </servlet:context>
    
    <property name="restResourcesList">                                                  (4)
      <list>
        <ref bean="org.apache.cocoon.sample.rest.resource.one" />
      </list>
    </property>
  </bean>
</beans>
1

The CocoonJAXRSServlet exposes REST resources.

2

The mount path of this Servlet-Service is /jax-rs.

3

Connections to other Servlet-Services.

4

A list of JAX-RS resources, which also have to be Spring beans, is exposed.

Alternativly a <map> of resources can be injected by the restResourceMap property.

4.7. Caching and conditional GET requests

TBW

4.8. Authentication

TBW

4.9. Testing

TBW: Integeration tests

4.10. Profiling support

A cocoon request goes through many components; while performing a Cocoon request, servlets, sitemaps and pipeline components are being executed. It is also quite common that Cocoon requests are cascaded which makes it sometimes difficult to understand what exactly was happening. Cocoon Profiling enables you to profile any request to your website.

4.10.1. Module configuration

In order to use cocoon-profiling, you simply have to include the cocoon-profiling jar in your classpath. Cocoon-profiling uses Spring AOP, so no further configuration is needed.

4.10.2. Using Cocoon Profiling

Cocoon-profiling provides several generators for xml and graphical output, which is used by the Firebug plugin. However, you can directly access the data using

  • yourdomain.com/controller/profiling/{id} for the xml file (xml schema see profilingSchema.xsd in cocoon-profiling)

  • yourdomain.com/controller/profiling/{id}.png for the graphical representation (example see below)

where {id} is the id of the request. This id (X-Cocoon-Profiling-ID) can be found in the header of the original request.

This is an example for the graphical representation:

4.10.2.1. How can I enable/disable cocoon-profiling on the fly?

Cocoon-profiling is enabled per default. If you just want to use it, you can skip this section.

If you want to start or stop profiling while the server is running, you can use the management bean provided by cocoon-profiling. Cocoon-monitoring automatically exposes this MBean; just make sure that cocoon-monitoring is in your classpath. You can then connect to the server process using jconsole and call the "start" and "stop" method of the org.apache.cocoon.profiling MBean.

Keep in mind that cocoon-profiling uses Spring AOP to intercept method calls, which cannot be enabled or disabled at runtime. Therefore, a disabled cocoon-profiling still affects the performance (at least a little bit). Only removing cocoon-profiling from the classpath and restarting the server guarantees maximum performance.

4.10.2.2. I need cocoon-profiling to profile my custom cocoon component, how can I do that?

Generally, you don't have to change anything. Cocoon-profiling uses Spring AOP to profile all cocoon components and servlets as well as any subclass or cocoon interface implementation.

Advanced users might want to add their own Profiler class to cocoon-profiling if they have a specific component with specific parameters or other bits of data they want cocoon-profiling to collect.

4.10.3. Using Firebug with Cocoon-profiling

Getting the Firebug Plugin able to work is really easy. You'll need to install Firebug 1.4X from http://getfirebug.com/releases/firebug/1.4X and then install the Firebug .xpi from cocoon-profiling-firebug (opening it with Firefox should suffice). The generate the xpi from the sources, simply switch to the cocoon-profiling-firebug folder and type mvn install. This will automatically build a new xpi. After installing the plugins, you should have a little bug on the bottom right corner of your Firefox. Clicking will open it, then you can navigate to the net-panel (you might want to be sure its activated) and there open up a request (you might need to refresh). In the request, there should be a tab called "Cocoon 3 Profiling", if you click it, and the Profiling Service works, you should now see the generated profiling data.

The data itself is presented in two textboxes. The left one is the tree which resembles the .xml that the profiling-component generates, the right one displays the elements, properties, return-values and the profiler of a given (= selected) row in the left tree. You can navigate through the left tree, and based on which row you currently have selected, the right textbox will display the names and values. To add some visual help, pictures are being displayed, based on which kind of element is displayed.

The underline is:

Table 4.1. Icons

Argument
Component
Exception
Invocation
Node
Profiler
Property
Return-value
Servlet
Sitemap
  


You also have two options which can change what you'll be able to see in the Firebug Plugin. These are located on the net Tab Option Panel, which is a little triangle. The options are marked {c3p} and allow you to Show / Hide the Sitemap and to change if the invocations element of the tree is closed or opened. These changes will require a reload, either by reloading your browser, or by clicking the "Reload"-Button in the Profiling Panel.

The other button on the panel will open a new tab in your Firefox in which a graphical outline will be shown which lists your components and the execution time of each of these components. Be aware, though, that the first profiling cycle will present you a kind of wrong picture (it takes a lot longer), because of the java-intern class-loading and other administrative stuff. You'll need to reload the request, not the picture, to change this.

4.10.3.1. Customizing your Firebug Plugin

To customize your Firebug Plugin, go to the plugin folder in your Firefox, select the Profiling plugin, then navigate to chrome\skin\classic\cocoon3profiling.css. In this css, you can change the heigth and width of the trees and of their columns. Simply navigate to the element you want to change, and change the value in there.

4.11. Monitoring support

This module gives you the possibility of monitoring Cocoon 3 applications. It expose a simple API via Spring JMX MBeans and it can be user via jconsole or other JMX console.

4.11.1. Module configuration

All module configurations are defined in META-INF/cocoon/spring/cocoon-monitoring.xml. Each part of module can be enabled or disabled by commenting (or removing) appropriate entry in configuration file, by default all parts are enabled.

4.11.2. Available parts

4.11.2.1. Inspect logging settings and reconfigure them

4.11.2.1.1. Inspect all configured loggers

The operation getLoggers() returns a list of all configured Log4j loggers in the application, it consists of pairs: <class or package name> (category) => <logging level>

4.11.2.1.2. Permanent change of a logging level

For doing permanent changes of logging level for particular class or package use the operation setLoggingLevel(String category, String newLogLevel). Where Category is name of class or package with you want to change logging level and newLogLevel is one of logging level: OFF, INFO, WARN, ERROR, FATAL, TRACE, DEBUG, ALL (this parameter isn't case sensitive, so you can also use lower case names).

4.11.2.1.3. Temporal change of a logging level

For doing temporal changes of logging level for particular class or package use the operation setLoggingTempoporalLevel(String category, String temporalLogLevel, String timeOut). First two parameters are same as in setLoggingLevel(), last one determinate how long this logging level should be used (after that amount of time logging level would be set back to old level). timeOut parameter should match regular expression: ^[0-9.]+[dhm]?$, for example if value of timeOut is set for 1,5h that means that new logging level would be active for one and half hour.

4.11.2.1.4. Load a new configuration file

For loading a completely new configuration file use the operation loadNewConfigurationFile(String path). This method is capable for both XML and properties configuration files. There is only one parameter path that should contain absolute path to new configuration file located locally on the server. Before performning any action that file is validated. First of all the file extension (there are only two appropriate extensions: *.xml and *.properties) is checked. The next validation step is different for both files, for XML files its content is validated against the Log4j DTD or schema then all output log files are checked that they exist and they are writable. Properties configuration files are validated that they contain at least one appender and each output file directory exists and is writable. These validations are done to prevent Log4j to get into an inconsistent state.

4.11.2.2. Inspect available Servlet-Services

Every single Servlet-Service makes his own node in JXM MBean tree. Such node contains below above functions.

4.11.2.2.1. Get path of Servlet-Services

Function getServletServiceMountPaths() returns Servlet-Service mount path.

4.11.2.2.2. Get all connections for Servlet-Service

Function getServletServiceConnections() returns an array of String contains all connections names for given Servlet-Service. Every connection is represented by: <short name> => <full qualified bean name>

4.11.2.2.3. Get informations about Servlet-Service

Function getServletServiceInfo() returns information about Servlet-Service, such as author, version, and copyright.

4.11.2.2.4. List Servlet-Service parameters

Function getServletServiceInitParameters() list all init parameters provided for that Servlet-Service.

4.11.2.3. Overview of cache entries

This module contains three smaller submodules:

CacheMonitor
CacheBurstActions
CacheEntrysMonitor

4.11.2.3.1. CacheMonitor

This submodule exposes all configured caches on with basic operations on every cache.

4.11.2.3.1.1. Clear cache

Operation clear() remove all cache entry's from this particular cache.

4.11.2.3.1.2. List all cache key

Operation listKey() returns list of all CacheKeys that are stored in this particular cache.

4.11.2.3.1.3. Removing cache entry

If you want remove single cache entry you should use operation removeKey(String), where parameter is CacheKey name taken from listKey() result. This operation returns true if it was successes otherwise it return false.

4.11.2.3.1.4. Checking size of cache

It is also possible to check size of particular cache using function size. It will return human readable size of this cache.

4.11.2.3.2. CacheBurstActions

This module add set of operations that can be performed on all caches. You can find and remove all cache entry's which meet certain requirements, specified in operation parameters.

4.11.2.3.2.1. Find all cache entry's that size is greater then specified value

Operation listAllGreatherThen(long) finds all cache entry's in all configured cache's that size (in bytes) is greather then value passed as a parameter.

4.11.2.3.2.2. Find all cache entry's that size is smaller then specified value

Operation listAllSmalledThen(long) finds all cache entry's in all configured cache's that size (in bytes) is smaller then value passed as a parameter.

4.11.2.3.2.3. Find all cache entry's that are older then specified date

Operation listAllOlderThen(String) finds all cache entry's in all configured cache's that are older then value specified in a parameter. Parameter value must match regular expression: ^\d+[smhd]$ where each letter stands for:

s - second
m - minutes
h - hours
d - days

4.11.2.3.2.4. Find all cache entry's that are younger then specified date

Operation listAllYoungerThen(String) finds all cache entry's in all configured cache's that are younger then value specified in a parameter. For parameter description see listAllOlderThen(String).

4.11.2.3.2.5. More flexible cache entry's search

If you want to get more flexibility searching you can use list(long, long, String, String, Sting, Sting). First two long parameters limits cache entry's size, their minimum and maximum size. Second two String parameters limits cache entry minimum and maximum age (syntax is same as in listAllOlderThen(Sting) and listAllYoungerThen(String) functions). Last two String parameters are applicable only to ExpiresCacheKey instances and they limit result entry's on minimum and maximum experience time of entry. Every result entry meets all limitations. For excluding one (or more) limitation you must pas value -1 for long parameters and null or empty String for rest parameters.

4.11.2.3.2.6. Remove all cache entry's that size is greater then specified value

Operation clearAllGreatherThen(long) perform same search action as listAllGratherThen(long) but it removes cache entry's that fulfilled requirements instead of listing them. It will return true if every cache entry was successfully removed, after first failure of removing cache entry this operation will stop and return false.

4.11.2.3.2.7. Remove all cache entry's that size is smaller then specified value.

Operation clearAllSmallerThen(long) perform same search action as listAllSmallerThen(long) but it removes cache entry's that fulfilled requirements instead of listing them. It will return true if every cache entry was successfully removed, after first failure of removing cache entry this operation will stop and return false.

4.11.2.3.2.8. Remove all cache entry's that are older then specified value.

Operation clearAllOlderThen(String) perform same search action as listAllOlderThen(String) but it remove cache etry's that fulfilled requirements instead of listing them, this operation also require same parameter schema as in listAllOlderThen(String). It will return true if every cache entry was successfully removed, after first failure of removing cache entry this operation will stop and return false.

4.11.2.3.2.9. Remove all cache entry's that are younger then specified value.

Operation clearAllYoungerThen(String) perform same search action as listAllYoungerThen(String) but it remove cache etry's that fulfilled requirements instead of listing them, this operation also require same parameter schema as in listAllYoungerThen(String). It will return true if every cache entry was successfully removed, after first failure of removing cache entry this operation will stop and return false.

4.11.2.3.2.10. More flexible cache entry's removing

Operation clear(long, long, String, String, String, String) perform same search action and takes same parameters as described above list(long, long, String, String, String) please see it if you are looking for detailed description.

4.11.2.3.2.11. Extending BurstCacheAction module

You can add your own burst actions. It is very simple, just obtain instance of org.apache.cocoon.monitoring.cache.CacheBurstActions from the container and you can perform any action on cache entry's using performActionOnCaches(long, long, String, String, String, String, CacheAction) method. Meaning of each parameter in this method is same as in list(long, long, String, String, String, String) and clear(long, long, String, String, String, String) methods, but there is one additional parameter, it is implementation of CacheAction interface. This interface has only one method performAction(Cache, CacheKey) and it will be executed on every cache entry that match passed parameters.

4.11.2.3.3. CacheEntrysMonitor

This module enables overview of cache entry's that are connected with specified pipeline. This module will only publish cache entry's for those pipeline's that had jmx-group-id parameter set for unique value/name. This module also require additional refresh action, it can be performed by user or it can be executed in some period of time eg every one minute. Behavior of refresh action can be configured by CacheEntrysMonitorInitializer constructor parameter or on JMX.

4.11.2.3.3.1. Configuring refresh action

AutoRefresh action can be enabled and disabled during runtime. This action will register new MBeans that are connected with new cache entry's and unregister old MBeans that was connected with expired or removed cache entry's.

4.11.2.3.3.1.1. Enable AutoRefresh action

For enable AutoRefresh action call operation enableAutoRefresh(long) where long parameter is period time (in millisecond) between each refresh. This operation will stop previously configured AutoRefresh action and run new with new time period.

4.11.2.3.3.1.2. Disable AutoRefresh action

Operation disableAutoRefresh() will stops actual running AutoRefresh action.

4.11.2.3.3.1.3. Manually perform refresh action

Operation performRefreshAction() will immediately refre's published cache entry's.

4.11.2.3.3.2. Cache entry's operations

On each published cache entry you can perform that set of actions:

4.11.2.3.3.2.1. Obtain CacheKey for that entry

Operation getCacheKey() will return CacheKey connected with that entry.

4.11.2.3.3.2.2. Obtain cache value

Operation getCacheValue() will return value of this cache entry.

4.11.2.3.3.2.3. Set cache value

Operation setCacheValue(String) will set new value of this cache entry.

4.11.2.3.3.2.4. Obtain size of entry

Operation getSize() will return human readable size of current entry.

4.12. Tutorial

TBW