pREST

Authors

pREST Tutorial

  1. REST
  2. pREST
  3. pREST application
  4. Creation of pREST application
  5. pREST Controller
  6. Output handling
  7. Input Handling
  8. Annotations
  9. Filters

REST

In today's IT world came a time when trends are changing radically in the Web usage. The Web as the most successful distribution platform of a hypermedia content in the world goes through a season when Rich Internet Applications (RIA, AJAX Web Applications) and REST Web Services get into the foreground. The common attribute of both is the REST.

AJAX Web Applications (RIA) scheme
AJAX Web Applications (RIA) scheme

REST - Representational State Transfer is a software style architecture used for distributed hypermedia systems like the World Wide Web. It was established in Roy Thomas Fielding's thesis "Architectural Styles and the Design of Network-based Software Architectures" . REST is dedicated for defining the way that a good designed Web Application, or Web service should work. From the REST viewpoint the Web Application is a net of Web pages, virtual state machines, through which the user browses thanks to links (state transferees) that always bring the following web page representing the next application state which is transferred to the user.

REST strictly defines collection of principles about net architecture which describes how are the Internet resources defined and addressed. Net architecture also describes Internet resources' URL, their representation and links among them. These principles cover main goals:

REST reached the goals by application of four limitations:

Although REST as a software architecture style is not a standard, it strongly supports a usage of standards as: HTTP, URL, XML/HTML/GIF/JPEG/..., MIME (text/xml, text/html, image/gif, image/jpeg, …). The REST philosophy defends existing principles and Web protocols that they are enough for Rich Web Service production. That means, that developers, who understand HTTP can implement Web Services without the need of using other tools, than they normally use for Web Application development. The key for REST methodology is to write Web Services with the usage of interfaces that are well known and extended. Any client or server application with the support of HTTP can possibly call these services.

IT companies which are involved in the market use REST API for their services for a long period of time. No doupt in fact that REST is a trend on creating Web Services simply and effectively.

Nowadays the majority of Web Services published on the Internet are URI-based.

If the REST did not work then no Web, nor Internet would work.

The architectural style REST introduce unified base for the development of functionally rich AJAX Rich Internet Applications, which hold properties and functionality of traditional desktop applications.

The RIA transfers an adaptation needed for the user interface to a Web client, at the same time when it keeps data which hold an application state on the Application Web Server side. The advantage of the RIA is the ability of desktop application running on a Web browser without the need of installation.

There is an important fact, that the RIA's presentation layer running in a browser can be changed at any time by the interface of standard desktop application, which can use as a data source some REST Web service such as the RIA (in a difference of database connection as it was done long time ago). In addition the RDA (Rich Desktop Application) has the advantage that the application logic is mostly located on the server where it can be better implemented and tested.

pREST

For some years we have felt the need of framework for simple development of Rich Internet and Intranet Applications together with Web Services. For adequate solution we have defined requirements what suitable framework should fulfill:

  1. Modularity – modularity of architectural framework
  2. Extensibility – simple ability of new technology integration
  3. Isolate development of
    • presentation layer
    • server back-end
    • application logic
  4. Horizontal application development – so that common developer does not have to know all technologies used for the development. From this development way we expect a higher code quality
  5. Minimal amount of time for development in the framework – we expect time in hours
  6. The possibility of REST Web Application and Service development - AJAX, RIA
  7. The independence of the higher amount of technologies – simple maintenance and stability through a long period of time
  8. Framework should be platform independent – Java 5 and higher

Unfortunately none of existing Web frameworks which are up to standard of our defined requirements are not based on Java platform. New thoughts and technologies are born on platforms like Python, Ruby, which gave developers more live space for carrying out new ideas but for more code writing price (they are dynamically typed prototype languages). Even though they are far ahead from nowadays Web solution of prominent software companies, they cannot be used in the market (our consumer, our master), or their solution state cannot be marked as productive. Because of these reasons, we have decided to implement our own framework developed under the code name pREST. We have decided to use MVC design pattern, which makes the development of Web Application to be like the development of desktop application.

AJAX Web application (RIA) scheme

pREST Web framework insists on simplicity and development effects. It introduce the development way of:

  1. Traditional Web applications
  2. AJAX Web applications

pREST consists of two components: a server side component and a client side component.

Server side pREST component

The server side pREST component is a controller for the servlet container dedicated for effective development of Web services and Web Applications through the REST architectural style. It implements following attributes:

  1. Controller mapping
  2. Dynamic mapping of URL parameters
  3. Automatic mapping of Web inputs to native data types
  4. Automatic serialization of native data type outputs
  5. Simple interface for own extension implementation
  6. Declarative way in extension usage realized by Java annotations
  7. The set of extensions which modular append the functionality of the controller/filter
  8. The set of validator extensions which validate the syntax and semantics with the support of conversion into a native data type
  9. The isolation of a presentation layer from an application logic with a weak bond hold-back considering the usage of presentation technology
  10. Build-in support of intercepting for aspect-oriented programming
  11. Build-in support for internationalization (i18n) during the process of data validation
  12. Support for linear workflow
  13. The possibility of controller connection and disconnection (also through Web interface)
  14. Role based user access management
  15. The declarative way of documentation inside the code by Java annotations
  16. The Web Interface used for accessing documentation by the Java reflexions
  17. The testing possibility of implemented controllers, Web Services, with the support of build-in Web Interface

Client side pREST component

Client pREST side component is a JavaScript library used for effective implementation of the RIA. The library is independent on pREST component and it is possible to use it with a combination of any server side technology. It implements following attributes:

  1. Signal-Slot design pattern
  2. Object oriented API to visual components (tables, tabs, lists, ...)
  3. Object oriented API of HTML form components and validators
  4. AJAX support
  5. Logging API
  6. Development tools

pREST Project Creation

The pREST application is a Java Web application developed in the pREST Web framework running in a servlet container. For the application deployment we need Java 5 (or higher) and a any servlet container running on Java 5. In this tutorial we use reference implementation of servlet container Apache Tomcat (version 5 and more). For the project composition we use standard tool for Java project building - Ant.

The pREST project structure

The development of the application we start with the creation of the project skeleton. Starting with a creation of tutorial folder we continue with a creation of the following sub content:

tutorial
|-- docs
|-- lib
|-- src
|-- web
|   |-- META-INF
|   |-- WEB-INF
|   |   `-- web.xml
|   `-- index.html
|-- build.properties
`-- build.xml

The meaning of the folders and files in the project:

docs
static documentation files, both API documentation (javadoc), administration documentation, user documentation and any other project documentation.
lib
jar files required for application run. In our case we need just prest.jar
src
Java project source files
web
static web content as HTML, JSP, or other (e.g. pictures). Despite that it has to contain subfolders META-INF and WEB-INF
build.xml
Ant build file
build.properties
build properties used by build.xml
web.xml
deployment descriptor of web application. It is located in web/WEB-INF.
index.html
HTML index page of the application.

For classic web application used to be deployed for web container the files build.xml, build.properties, web.xml and index.html lool like this:

build.xml

		
<project name="tutorial" default="install" basedir=".">
	<property file="build.properties" />
	<property file="${user.home}/build.properties" />
	<property name="app.name" value="tutorial" />
	<property name="app.path" value="/${app.name}" />
	<property name="app.version" value="0.1-dev" />
	<property name="build.home" value="${basedir}/build" />
	<property name="catalina.home" value="../../../.." />
	<property name="dist.home" value="${basedir}/dist" />
	<property name="docs.home" value="${basedir}/docs" />
	<property name="manager.url" value="http://localhost:8080/manager" />
	<property name="src.home" value="${basedir}/src" />
	<property name="web.home" value="${basedir}/web" />
	<property name="lib.home" value="${basedir}/lib" />

	<taskdef name="deploy" classname="org.apache.catalina.ant.DeployTask" />
	<taskdef name="list" classname="org.apache.catalina.ant.ListTask" />
	<taskdef name="reload" classname="org.apache.catalina.ant.ReloadTask" />
	<taskdef name="undeploy" classname="org.apache.catalina.ant.UndeployTask" />

	<property name="compile.debug" value="true" />
	<property name="compile.deprecation" value="false" />
	<property name="compile.optimize" value="true" />

	<path id="compile.classpath">
		<fileset dir="${catalina.home}/lib">
			<include name="*.jar" />
		</fileset>
		<fileset dir="${lib.home}">
			<include name="*.jar" />
		</fileset>
	</path>

	<target name="all" depends="clean,compile" description="Clean build and dist directories, then compile" />

	<target name="clean" description="Delete old build and dist directories">
		<delete dir="${build.home}" />
		<delete dir="${dist.home}" />
	</target>

	<target name="compile" depends="prepare" description="Compile Java sources">
		<mkdir dir="${build.home}/WEB-INF/classes" />
		<javac srcdir="${src.home}" destdir="${build.home}/WEB-INF/classes" debug="${compile.debug}" deprecation="${compile.deprecation}" optimize="${compile.optimize}">
			<classpath refid="compile.classpath" />
		</javac>
		<copy todir="${build.home}/WEB-INF/classes">
			<fileset dir="${src.home}" excludes="**/*.java" />
		</copy>
	</target>


	<target name="dist" depends="compile,javadoc" description="Create binary distribution">
		<mkdir dir="${dist.home}" />
		<copy todir="${build.home}/docs">
			<fileset dir="${docs.home}" />
		</copy>
		<jar jarfile="${dist.home}/${app.name}-${app.version}.war" basedir="${build.home}" />
	</target>

	<target name="install" depends="compile" description="Install application to servlet container">
		<deploy url="${manager.url}" username="${manager.username}" password="${manager.password}" path="${app.path}" localWar="file://${build.home}" />
	</target>
	
	<target name="reinstall" depends="remove,compile" description="Reinstall application to servlet container">
		<deploy url="${manager.url}" username="${manager.username}" password="${manager.password}" path="${app.path}" localWar="file://${build.home}" />
	</target>

	<target name="javadoc" depends="compile" description="Create Javadoc API documentation">
		<mkdir dir="${build.home}/docs/api" />
		<javadoc sourcepath="${src.home}" destdir="${build.home}/docs/api" packagenames="*">
			<classpath refid="compile.classpath" />
		</javadoc>
	</target>

	<target name="list" description="List installed applications on servlet container">
		<list url="${manager.url}" username="${manager.username}" password="${manager.password}" />
	</target>

	<target name="prepare">
		<mkdir dir="${build.home}" />
		<mkdir dir="${build.home}/WEB-INF" />
		<mkdir dir="${build.home}/WEB-INF/classes" />
		<copy todir="${build.home}">
			<fileset dir="${web.home}" />
		</copy>
		<mkdir dir="${build.home}/WEB-INF/lib" />
		<copy todir="${build.home}/WEB-INF/lib">
			<fileset dir="${basedir}/lib" />
		</copy>
	</target>


	<target name="reload" depends="compile" description="Reload application on servlet container">
		<reload url="${manager.url}" username="${manager.username}" password="${manager.password}" path="${app.path}" />
	</target>

	<target name="remove" description="Remove application on servlet container">
		<undeploy url="${manager.url}" username="${manager.username}" password="${manager.password}" path="${app.path}" />
	</target>
</project>

build.xml is a ant build file for building web application. Its purpose is not only to build the project, but also to install/uninstall the application, creating the API documentation, etc. For complete list of targets use Ant with a parameter "-p".

$ ant -p
Buildfile: build.xml

Main targets:

 all        Clean build and dist directories, then compile
 clean      Delete old build and dist directories
 compile    Compile Java sources
 dist       Create binary distribution
 install    Install application to servlet container
 javadoc    Create Javadoc API documentation
 list       List installed applications on servlet container
 reinstall  Reinstall application to servlet container
 reload     Reload application on servlet container
 remove     Remove application on servlet container
Default target: install

build.properties

app.path=/tutorial
app.version=0.1

# Tomcat installation directory
catalina.home=/usr/share/tomcat6

# Manager webapp url, username and password
manager.url=http://localhost:8080/manager
manager.username=user1
manager.password=password1

The meaning of the file build.properties is to provide that properties included in build.xml, which are commonly changed and their change is easier in a small separate file.

web.xml

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE web-app 
	PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" 
	"http://java.sun.com/dtd/web-app_2_3.dtd">

<web-app>	
	<session-config>
		<session-timeout>30</session-timeout><!-- 30 minutes -->
	</session-config>
</web-app>

index.html

<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en" >
	<head>
		<title>pREST Tutorial</title>
		<meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/>
	</head>
	<body>
		<h1>pREST tutoriál</h1>
	</body>
</html>

The index.html is application root index file.

Deployment of the pREST application into the container

This application can be deployed to servlet container in war application package. This method is useful for business production deployment. War package can be deployed into the dist folder by command:

ant dist

During the development, when we have servlet container installed on developing computer, it is better to deploy the application by following command.

ant install

If we need to change the old version for the new one, we can do it by this command.

ant reinstall

The quicker alternative, when no full application replacement will be done, but only its reload.

ant reload

During the process of deployment the web application is created into build sub folder in project folder and it is put into the container directly from this folder.

Finally we can test the functionality at this address

http://localhost:8080/tutorial/

when the page index.html should appear.

The creation of pREST application

To demonstrate the pREST application, we will create an pREST application with the "Tutorial" name with a simple controller. In next steps we are going to describe every part, which are needed for the application creation.

The modification of build.properties file

In the first step we set the application build properties in build.properties file.

Deployment of the framework library "prest.jar"

Since we create pREST application it is required to put the pREST library prest.jar which contains pREST framework into the lib folder.

The actual address structure now looks like this:

tutorial
|-- docs
|-- lib
|   `-- prest.jar
|-- src
|-- web
|   |-- META-INF
|   |-- WEB-INF
|   |   `-- web.xml
|   `-- index.html
|-- build.properties
`-- build.xml

The pREST application deployment

pREST application is represented by a class, which extends the class prest.core.Application. This class is deployed into new servlet container by an adapter which is represented by a servlet filter.

Let's create for tutorial project an application class TutorialApplication.java, which we will put into tutorial package. The class and the package will be created in src folder. The class TutorialApplication.java looks like this:

package tutorial;
		
import prest.core.Application;
import prest.core.ApplicationException;


public class TutorialApplication extends Application {

	@Override
	public void initialize() throws ApplicationException {

	}

}

The actual address structure now looks like this:

tutorial
|-- docs
|-- lib
|   `-- prest.jar
|-- src
|   `-- tutorial
|       `-- TutorialApplication.java
|-- web
|   |-- META-INF
|   |-- WEB-INF
|   |   `-- web.xml
|   `-- index.html
|-- build.properties
`-- build.xml

Now, we deploy the pREST application represented by a class tutorial.TutorialApplication into the Web application of the servlet container using the adapter which is the servlet filter prest.core.ServletFilter. Filter are deployed into the Web application's container by declaring and mapping him in WEB-INF/web.xml file.

<?xml version="1.0" encoding="UTF-8"?>

<!DOCTYPE web-app 
	PUBLIC "-//Sun Microsystems, Inc.//DTD Web Application 2.3//EN" 
	"http://java.sun.com/dtd/web-app_2_3.dtd">

<web-app>	
	<session-config>
		<session-timeout>30</session-timeout><!-- 30 minutes -->
	</session-config>
			
	<filter>
		<filter-name>ServletFilter</filter-name>
		<filter-class >prest.core.ServletFilter</filter-class>
		<init-param>
			<param-name>Application</param-name>
			<param-value>tutorial.TutorialApplication</param-value>
		</init-param>
	</filter>
	<filter-mapping>
		<filter-name>ServletFilter</filter-name>
		<url-pattern>/*</url-pattern>
	</filter-mapping>
</web-app>

The only required parameter of an adapter represented by prest.core.ServletFilter filter is a parameter called Application. The value of the parameter is a cannonical name in the main pREST application class. In our case it is tutorial.TutorialApplication. The deployment itself can be set in the web.xml file.

Controller creation

The next class, which needs to be created is a class HelloController.java, which represents the controller. The controller's class will be placed into the new package tutorial.controllers. The class HelloController.java now looks like this:

package tutorial.controllers;

import prest.core.annotations.Action;
import prest.web.WebController;

public class HelloController extends WebController {

	@Action(name="hello-world")
	public String helloWorld() {
		setContentType(ContentType.TEXT_PLAIN_UTF8);
		return "Hello world!";
	}
}

Action annotation is used for mapping action name (part of URL) and HTTP method into the pREST controller Java method.

The controller is a class which resolves prest.core.Controller or some of its successors (for example prest.web.WebController).

In our case we declare public method helloWorld() which returns string "Hello world".

Mapping controller in one specific URL address

To expose the controller and it's methods on some concrete URL address, it is required to map this controller in the Application class.

The mapping itself is realized by calling the method mount() in the application class. The method mount() has the following syntax:

mount(String location, Controller controller)

How does the controller map into concrete URL address?

The controller maps into concrete part of URL address, which holds the name <controller_path>. Individual methods of the controller are mapped into the concrete part of URL address, called <action>, at their @Action annotation names.

http://<server>/<app_root>/<controller_path>/<action>

In our example we want to map the controller HelloController into the URL address:

http://localhost:8080/tutorial/hello-controller

The method helloWorld() can be then called by a HTTP request at the URL address withs action name hello-world and the output of the method will be shown on the web page.

http://localhost:8080/tutorial/hello-controller/hello-world

The mount method is called in initialize method of the TutorialApplication.java class, which serves as an application initializer.

After adding the mount method, the file TutorialApplication.java now looks like this:

package tutorial;

import prest.core.Application;
import prest.core.ApplicationException;
import tutorial.controllers.HelloController;

public class TutorialApplication extends Application {

	@Override
	public void initialize() throws ApplicationException {
		mount("/hello-controller", new HelloController());
	}
	
}

After adding the HelloController class the actual address structure now looks like this:

tutorial
|-- docs
|-- lib
|   `-- prest.jar
|-- src
|   `-- tutorial
|       |-- TutorialApplication.java
|       `-- controllers
|           `-- HelloController.java
|-- web
|   |-- META-INF
|   |-- WEB-INF
|   |   `-- web.xml
|   `-- index.html
|-- build.properties
`-- build.xml

Ant

Now, the application is ready to be compiled and deployed into servlet container. These actions can be executed by a command ant install from the command prompt.

The application startup

After the successful compilation and installation the application runs and we can test HelloController and his method helloWorld() on URL address:

http://localhost:8080/tutorial/hello-controller/hello-world

pREST controller

In the previous example we have shown, how the simple controller works. In this section we will describe the individual characteristics and the ways of mapping the controller a specific URL address.

Output handling

The HTTP response body can contain either a text, or binary stream. If the controller's method returns one of the following types

or their successors then the object of this type is naturally transformed to the HTTP response body.

In general the method of the controller returns arbitrary Java object, which does not have to represent a text or a binary stream. In that case the string representation of an object is written into HTTP response body. by calling toString() method.

String as a return type

Let's assume that we have the following URL address

http://localhost:8080/tutorial/output/string

We want the action string, which is mapped into the controller method of the same name which itself is mapped into the part of the URL address /output in our application, to return in HTTP request body the string "Hello World".

We will create a new controller OutputHandlingController. We will implement one public method string into the controller. To each HTTP response is required to set ContentType and in case of text response it is also required to set CharacterEncoding into which the output data should be transformed. The controller instance of class OutputHandlingController will be mapped on /output by calling the mount("/output", new OutputHandlingController()) method in the initialize() method body of the TutorialApplication application class.

The class tutorial.controllers.OutputHandlingController now looks like this:

package tutorial.controllers;

import prest.core.annotations.Action;
import prest.web.WebController;

public class OutputHandlingController extends WebController {

	@Action(name="string")
	public String string() {
		setContentType(ContentType.TEXT_PLAIN_UTF8);
		return "Hello world";
	}
}

After the successful calling of the controller the page on which the output of the string method will be shown.

Hello world

Reader as a return type

We will implement the reader() method to the controller class whose body looks like:

@Action(name="reader")
public Reader reader() {
	setContentType(ContentType.TEXT_PLAIN_UTF8);
	Reader reader = new StringReader("Hello. I'm reader.");
	return reader;
}

The reader() method returns an object of Reader type, which is written into HTTP response body.

After the successful calling of this action the page on which the output of the string method will be shown

Hello. I'm reader.

byte[] as a return type

At this example we are going to work with a binary data. In the byteArray() method, which has been implemented into controller and is the return type byte[]. The body of the method looks like this:

@Action(name="byte-array")
public byte[] byteArray() {
	setContentType(ContentType.TEXT_PLAIN_UTF8);
	byte[] bs = "Hello. I'm your pREST :-)".getBytes();
	return bs;
}

In this example we have created a byte[] from the string with using a default encoding. The string of the bytes, which was returned by the method, was naturally transformed into a binary stream and it was written to the HTTP body.

After the successful call of the action, the web page will show on which the following output of the byteArray() method will be shown.

Hello. I'm your pREST :-)

IntputStream as a return type

Like in the previous example, we will create a byte[] which will be naturally transformed into a binary stream.

@Action(name="stream")
public InputStream stream() {
	setContentType(ContentType.TEXT_PLAIN_UTF8);
	byte[] bs = "Hello. I'm your pREST :-)".getBytes();
	InputStream stream = new ByteArrayInputStream(bs);
	
	return stream;
}

After the successful call of the action of the controller, the following web page will show on which the output of the stream() method will be shown.

Hello. I'm your pREST :-)

Using of the toString method

In this example we are going to show the usage of toString() method. We will create OutputObject class, which have two variables of the String type : value1 and value2. As the next thing, we will overload (implement) toString() method, which will return a string representation of this class, which is a string which contains concatenated values of value1 and value2.

The OutputObject class now looks like this:

private class OutputObject {
	private String value1;
	private String value2;
		
	public OutputObject(String value1, String value2) {
		this.value1 = value1;
		this.value2 = value2;
	}
	
	public String toString() {
		return value1 + " " + value2;
	}
}

The defined OutputObject class will be used as a return type of the new controllers method with the Action name object.

@Action(name="object")
public OutputObject object() {
	OutputObject object = new OutputObject("text1", "text2");
		
	return object;
}

After the successful call of the action, the following web page will show on which the output of the object() method will be shown.

text1 text2

Input Handling

pREST resolves these types of input parameters:

The web input can be transferred only in a string representation. The URL and its containing URL and GET parameters are strings as same as transferred POST parameters included in the HTTP body. One of the task which pREST resolves is mapping input parameters either request or URL into native Java types. pREST support following method's parameter types:

Arbitrary types with string constructor and their fields

During the HTTP (URL/GET/POST) parameters mapping into the controller's method input arguments, string HTTP parameters must be converted into the native Java objects. Conversion of string HTTP parameters into Java type is realised by calling public string constructor, whose argument is an appropriate parameter. In case when constructor raises an exception the null value is used instead of the object instance. That means, if for example conversion from a string "a5" into the object type Integer fails, the controller method is called with an appropriate argument, whose value is null.

We resolve two types of mapping, if the mapping is either from URL or from request parameter

  1. The parameters which has a public string constructor (they are not annotated by prest.core.annotations.Key annotation) are initialized from URL parameters in the order as they are listed in method declaration. In case of URL it is in a form:

    http://<server>/<app_root>/<controller_path>/<action>/<p1>/<p2>/.../<pN>

    The parameters p1, p2,...,pN are mapping into appropriate declaration arguments of method in this form:

    public void <actionMethod>(<type1> p1, <type2> p2,..., <typeN> pN) {}

    Let's have the following URL

    http://localhost:8080/tutorial/input-handling/url-parameters1/value

    Let's assume, that we have the InputHandlerController controller in the application. The controller is mapped into the URL part /input-handling. We want this method to be mapped on urlParameters1() method of this controller with a single String parameter.

    To InputHandlerController controller we will implement a public urlParameters1() method to which an action of the same name is automatically mapped. The input parameter from URL is mapped into method's type parameter String. The class tutorial.controllers.InputHandlerController looks like this:

    package tutorial.controllers;
    
    import prest.core.annotations.Action;
    import prest.web.WebController;
    
    public class InputHandlerController extends WebController {
    
    	@Action(name="url-parameters1")
    	public String urlParameters1(String u1) {
    		setContentType(ContentType.TEXT_PLAIN_UTF8);
    		return "" + u1;
    	}
    
    }

    The method urlParameters1() has one (@Key unannotated) string parameter u1, so that during parameter mapping the framework attempts to create an instance of the String type by calling it's string constructor with the parameter value sent as a URL parameter.

    In case that the URL address is in the following style:

    http://localhost:8080/tutorial/input-handling/url-parameters1

    it contains no URL parameter. then the instance of String class is not created (during constructor call, the exception java.lang.NullPointerException was raised) and a method urlParameters1() is called with a parameter u1, whose value is null.

    The method parameter can be not only of a String type, but in arbitrary type which has a public string constructor.

    Let's think about this URL like this:

    http://localhost:8080/tutorial/input-handling/url-parameters2/<p1>/<p2>/<p3>

    We want this action to be mapped on urlParameters2() method, which has 3 parameters: first two are standard Java types Integer and Double, the last is self defined type MyOwnType.

    public class MyOwnType {
    
    	private String s;
    	
    	public MyOwnType(String s) {
    		this.s = s;
    	}
    	
    	public String toString() {
    		return s;
    	}
    }

    While all of the spoken types has a public string constructor, the method urlParameters2() may looks like this:

    @Action(name="url-parameters2")
    public String urlParameters2(Integer i, Double d, MyOwnType myOwn) {
    	setContentType(ContentType.TEXT_PLAIN_UTF8);
    
    	if (i == null || d == null || myOwn == null) {
    		return "Not all parameters was submitted or the conversion " +
    			"to native types has not pass successfully";
    	}
    
    	String result = "";
    	result += "1. URL parameter = " + i + "\n";
    	result += "2. URL parameter = " + d + "\n";
    	result += "3. URL parameter = " + myOwn;
    
    	return result;
    }

    Let's assume a specific URL address:

    http://localhost:8080/tutorial/input-handling/url-parameters2/123/999/abc

    The values 123, 999 and abc are used in stages to build a construct object of types Integer, Double and MyOwnType. After the successful call of a page will show, which contains the following output of urlParameters2() method.

    1. URL parameter = 22
    2. URL parameter = 33.3
    3. URL parameter = abc

    If some of the these parameters missed, the constructor of the specific parameter will be called with a null value. If the constructor call failed (constructor would raise an event) the specific method argument urlParameters2() would have a null value. Mentioned properties are demonstrated in the following examples:

    Missing third URL parameter:

    http://localhost:8080/tutorial/input-handling/url-parameters2/123/999

    The constructor for the third argument of the method will be called with a null value, because among URL parameters the third parameter is missing. Because constructor of the type MyOwnType accepts the value null as a parameter, the instance of this type is correctly created.

    1. URL parameter = 22
    2. URL parameter = 33.3
    3. URL parameter = null

    The wrong value of the parameter:

    http://localhost:8080/tutorial/input-handling/url-parameters2/123/xyz/abc

    The second argument of the method will be null, because the construction of the object type Double from the xyz string will not pass successfully.

    Not all parameters was submitted or the conversion to native types has not pass successfully

    The empty list of URL parameters:

    http://localhost:8080/tutorial/input-handling/url-parameters2

    The all 3 parameters will have a null value.

    Not all parameters was submitted or the conversion to native types has not pass successfully
  2. Parameters, which have a public string constructor and they are annotated by a prest.core.annotations.Key annotation are mapped from request (POST/GET) parameters by a specified key listed as an annotation parameter @Key("name")). In case of submitted form, the key is a request parameter value listed in an attribute name of the form input (input, select, textarea, ...).

    Let's assume HTTP request method GET on an URL in the following form:

    http://<server>/<app_root>/<controller_path>/<action>?<k1>=<value1>&<k2>=<value2>&...&<kN>=<valueN>

    Parameter with the keys <k1>, <k2>,...,<kN> are mapped into the appropriate method declaration arguments in the following form:

    public String <actionMethod>(@Key("<k1>") <type1> v1, @Key("<k2>") <type2> v1,..., @Key("<kN>") <typeN> v3) {}

    Let's assume that we want the action name request-parameters1 corresponding to method requestParameters1() to handle the following form:

    <form method="get" action="request-parameters1">
    	<input type="text" name="name"/>
    	<input type="text" name="age"/>
    	<input type="text" name="kontakt"/>
    	<input type="submit" value="Send"/>
    </form>

    The method requestParameters1(), which handles mentioned form can be defined like this:

    @Action(name="request-parameters1")
    public String requestParameters1(@Key("name") String s,
    		@Key("age") Integer i, @Key("kontakt") MyOwnType myOwn)
    {
    	setContentType(ContentType.TEXT_PLAIN_UTF8);
    
    	if (s == null || i == null || myOwn == null) {
    		return "Not all parameters was submitted or" +
    				"the conversion to native types has not pass successfully";
    	}
    	String result = "";
    	result += "name = " + s + "\n";
    	result += "count = " + i + "\n";
    	result += "kontakt = " + myOwn + "\n";
    	
    	return result;
    }

    Request parameter mapping into method requestParameters1() overshoots by appropriate keys, which are values of the attribute name of the form input. They are listed as annotation parameters: @Key("name"), @Key("age") and @Key("contact").

    As same as in the URL parameter mapping, in this case also the object construction could not pass successfully and the method gets in the appropriate argument a null value.

    In the case, that for the appropriate key there is more then one value (as for example if in the form exists more then one entry with the same name)

    http://<server>/<app_root>/<controller_path>/<action>/<?k1=value1&k1=value2;

    they can be mapped in the way that the method input parameter is an array.

    @Action(name="request-parameters2")
    public String requestParameters2(@Key("name") String[] strings,
    	@Key("age") Integer[] integers,	@Key("kontakt") MyOwnType[] myOwns)
    {
    	setContentType(ContentType.TEXT_PLAIN_UTF8);
    
    	String result = "";
    	for (int i = 0; i < strings.length; i++) {
    		result += "name[" + i + "] = " + strings[i] + "\n";
    	}
    	for (int i = 0; i < integers.length; i++) {
    		result += "count[" + i + "] = " + integers[i] + "\n";
    	}
    	for (int i = 0; i < myOwns.length; i++) {
    		result += "count[" + i + "] = " + myOwns[i] + "\n";
    	}
    	return result;
    }

    This action for the URL address

    http://localhost:8080/tutorial/input/request-parameters2?name=John&name=ABC&age=55

    returns:

    name[0] = John
    name[1] = ABC
    age[0] = 22

Primitive types and its arrays

The primitive types mapping is the same as string constructor type mapping with a difference that in the case of primitive types the object type is transferred into its primitive equivalent type. If the object equivalent instance of primitive Java type could not be created, an error will occur before the method calling.

It is not possible to handle primitive Java type conversion errors inside controller's method body. Use primitive Java types as controller's method arguments carefully.

Build in aggregated types

There are some situations, when the number of the input parameters is variable. In that case we cannot use direct mapping of single characters For this reason we use aggregated types:

  1. prest.core.types.UrlParameters - includes every URL parameters
  2. prest.core.types.RequestParameters - includes every request parameters
  3. prest.core.types.FileRequestParameters - includes every sent files

User defined aggregated types

pREST enables to create user defined types, which instances are automatically created and initialized by appropriate aggregated types in case of using the user defined types as a controller method types. The condition is that the user defined type implements (just) one of the following interfaces:

  1. prest.core.types.UrlParametersType

    Let's assume, that we have an action, which shows a name and an age of some person, while these data are sent as last but one parameter and last parameter. In this case when we do not know the number of every parameter we cannot use the classic URL parameter mapping. One solution for this situation can be a usage of prest.core.types.UrlParameters interface.

    package prest.core.types;
    
    public interface UrlParametersType {
    
    	int getSize();
    
    	void initialize(UrlParameters parameters) throws Exception;
    }

    This interface defines two methods which must be implemented. The method initialize() with an argument of prest.core.types.UrlParameters type. This class includes all necessary methods which are needed for working with URL parameters In our case we need especially the getSize() method, which returns a number of all URL parameters, and also the get(int index) method, which returns the actual URL parameter by providing an index of URL parameter. tutorial.controllers.UrlPerson looks like this:

    import prest.core.types.UrlParameters;
    import prest.core.types.UrlParametersType;
    
    public class UrlPerson implements UrlParametersType{
    
    	private String name;
    	private Integer age;
    	
    	public int getSize() {
    		return 0;
    	}
    
    	public void initialize(UrlParameters urlParameters) throws Exception {
    		int count = urlParameters.getSize();
    		if (count < 2) {
    			return;
    		}
    		try {
    			name = urlParameters.get(count - 2);
    			age = Integer.parseInt(urlParameters.get(count - 1));
    		} catch (NumberFormatException e) {
    			;
    		} 	
    	}
    	
    	public String toString() {
    		return "Name: " + name + "\n" + "Age: " + age;
    	}
    
    }

    This class can be now used as an argument of some controller's method. Let's name it userDefinedParameters1()

    @Action(name="user-defined-parameters1")
    public String userDefinedParameters1(UrlPerson person) {
    	setContentType(ContentType.TEXT_PLAIN_UTF8);
    	return person.toString();
    }

    The output of this action by using this url:

    http://localhost:8080/tutorial/input/user-defined-parameters1/a/b/c/John/22

    is

    Name: John
    Age: 22

    Despite of the number of parameters in the URL address, this action always takes the last two of them.

  2. prest.core.types.RequestsParametersType

    This interface is like the previous one. A class which implements the interface must define initialize() method, which has a parameter of prest.core.types.RequestParameters type and a method getKeys(), which returns a set of all expected or actual keys.

    As same as in the previous example let's assume that an action must work with a name and with an age of the person while these two parameters are not got in the URL parameter form, but in the request parameter form with keys name and age. The class tutorial.controllers.RequestPerson will implement prest.core.types.RequestsParametersType interface and in initialize() method, which needs to be defined, will get and object of prest.core.types.RequestParameters type as a parameter. The object type allows method to get access to all request parameters.

    package tutorial.controllers;
    
    import java.util.Set;
    
    import prest.core.types.RequestParameters;
    import prest.core.types.RequestParametersType;
    
    public class RequestPerson implements RequestParametersType {
    
    	private String name;
    	private Integer age;
    
    	public Set<String> getKeys() {
    		return null;
    	}
    
    	public void initialize(RequestParameters requestParameters) throws Exception {
    		try {
    			name = requestParameters.get("name").get(0);
    			age = Integer.parseInt(requestParameters.get("age").get(0));
    		} catch (Exception e) {
    			;
    		}
    	}
    
    	public String toString() {
    		return "Name: " + name + "\n" + "Age: " + age;
    	}
    	
    }

    A new method with the argument of tutorial.controllers.RequestPerson type will be added into the controller.

    @Action(name="user-defined-parameters2")
    public String userDefinedParameters2(RequestPerson person) {
    	return person.toString();
    }
  3. prest.core.types.FileRequestsParametersType

    Like in the previous examples, this interface declares a initialize() method with a parameter of prest.core.types.FileRequestParameters type.

    The usage of this type we will demonstrate on the next example. We want the action method userDefinedParameters3(), to show the informations about uploaded files.

    @Action(name="user-defined-parameters3")
    public String userDefinedParameters3(FileRequestParameters fileReqParams) {
    	setContentType(ContentType.TEXT_PLAIN_UTF8);
    
    	String result = "";
    	result += "<html>"
    		+ "<head><title></title></head>"
    		+ "<body>";
    
    	result += "<form method=\"post\" action=\"user-defined-parameters3\""
    		+ "enctype=\"multipart/form-data\"><br />"
    	    + "subor1<input type=\"file\" name=\"subor1\" /><br />"
    	    + "subor1<input type=\"file\" name=\"subor1\" /><br />"
    	    + "subor2<input type=\"file\" name=\"subor2\" /><br />"
    	    + "<input type=\"submit\" name=\"submit\" value=\"send file\" /><br />"
    	    + "</form>";
    
    	Set<String> keys = fileReqParams.getKeys();
    	for (String key : keys) {
    		result += "<h2>" + key + "</h2>";
    		java.util.List<FileDetail> fileDetails = fileReqParams.get(key);
    		for (FileDetail fileDetail : fileDetails) {
    			result += "fileName = " + fileDetail.getFileName() + "<br />"
    				+ "contentType = " + fileDetail.getContentType() + "<br />"
    				+ "size = " + fileDetail.getSize() + "<br /><br />;
    		}
    	}
    	result += "</body></html>"
    	return result;
    }
  4. prest.core.types.InputType

    is the most general among all four types. Its method initialize() expects parameters of prest.core.io.Request type, which encapsulates all three previous types.

    Let's assume a situation, that an action should work with some complex number in the way that its real part is got by a first URL parameter and the imagine part is got among request parameters under the "imaginary_part" key. Because we need the access not only to URL parameters but also to request parameters we will create tutorial.controllers.ComplexNumber class, which implements prest.core.types.InputType interface.

    package tutorial.controllers;
    
    import prest.core.types.InputType;
    
    public class ComplexNumber implements InputType {
    
    	Double realPart;
    	Double imaginaryPart;
    
    	public void initialize(prest.core.io.Request request) throws Exception {
    		try {
    			realPart = Double.parseDouble(request.getUrlParameters().get(0));
    			imaginaryPart = Double.parseDouble(request.getRequestParameters()
    					.get("imaginary_part").get(0));
    		} catch (Exception e) {
    			;
    		}
    	}
    
    	public String toString() {
    		return "[" + realPart + "; " + imaginaryPart + "]";
    	}
    
    }

    This type can now be used as argument of userDefinedParameters4 method argument.

    @Action(name="user-defined-parameters4")
    public String userDefinedParameters4(ComplexNumber number) {
    	return number.toString();
    }

    The output for this URL

    http://localhost:8080/tutorial/input/user-defined-parameters4/123?imaginary_part=321

    is

    [123.0; 321.0]

Annotations

pREST introduces couple types of annotations. We can divide them into two parts:

  1. Those which represents meta data for controllers, methods and attributes: Doc, Key a Action.
  2. Those, which serves for filter ordering for method calling.

Action annotation

Action annotation is used for mapping action name (part of URL) and HTTP method into the pREST controller Java method. If the action name is not specified or is empty string, Annotated Java method is mapped directly into the controller path.

@Action(name = "product", httpMethod = "DELETE")
public void deleteProduct(int id) {}

In the shown example, deleteProduct method is mapped into the URL part product, while the method is called, only when the HTTP request is sent by HTTP method DELETE.

Doc annotation

Doc annotation serves for documenting the controller, its methods and parameters. It has two parameters:

  1. value - is a document string used for a class description or a parameter description.
  2. publish - is an optional parameter. It can be used in the case of a class annotation when we want to disable publishing the documentation.

Every pREST controller provides a build-in interface for documentation and also it provides self and parameter test.

pREST _test_ interface
pREST _doc_ interface
pREST _test_ interface
pREST _test_ interface

Let's show how can we by the prest.core.annotations.Doc annotation add a documentation to:

  1. class tutorial.controllers.AnnotationsController
  2. method methodDoc() of the controller tutorial.controllers.AnnotationsController
  3. parameter s1 of the method methodDoc()
package tutorial.controllers;

import prest.core.annotations.Action;
import prest.web.WebController;

@Doc(value="Documentation for class AnnotationsController")
public class AnnotationsController extends WebController{

	@Action
	public String defaultAction() {
		setContentType(ContentType.TEXT_PLAIN_UTF8);
		return "Output from method 'default_action()'";
	}

	@Action(name = "method-doc")
	@Doc("Method with method documentation " +
		"and without method parameter documentation")
	public String methodDoc(String s) {
		setContentType(ContentType.TEXT_PLAIN_UTF8);
		return "with documentation";
	}

	@Action(name = "method-and-param-doc")
	@Doc("Method with method documentation " +
		"and also with method parameter documentation")
	public String methodAndParamDoc(
			@Doc("Documentation for method parameter") String s1,
			String s2)
	{
		setContentType(ContentType.TEXT_PLAIN_UTF8);
		return "with parameter documentation";		 
	}
}

The interface for tutorial.controllers.AnnotationsController class can be found on the following URL address:

http://localhost:8080/tutorial/annotations/_doc_

Also in the addresses

http://localhost:8080/tutorial/annotations/_docs_
http://localhost:8080/tutorial/annotations/_test_/<action>

we have a a graphical interface available for every application controllers and for testing their methods.

Filters

In pREST framework the filters are used for input and output modification. It separates the input and output handling from methods, which executes some jobs and which can return some output. Then filter can modify this output (e.g serialize) and push further. Filter to method assignment is realized by annotations. This approach is characteristic for aspect oriented programming.

Filter rules:

  1. Filters are pushed to filter chain in the order how their annotations are listed.
  2. Annotations listed before the controller class specifies IO filters for any controller's method.
  3. Annotations listed before the controller's method specifies IO filters just for the annotated method.
@Filter1
public class FiltersOrder {

	@Action(name="method1")
	public String method1() {
		setContentType(ContentType.TEXT_PLAIN_UTF8);
		return "abc";
	}

	@Action(name="method2")
	@Filter2
	@Filter3(param = "value1")
	@Filter4
	public String method2() {
		setContentType(ContentType.TEXT_PLAIN_UTF8);
		return "xyz";
	}
}

In this case before method1() is executed the filter Filter1 is applied. Because it is assigned to the class, it is applied before any method of the class.

During handling of the method method2() the other filters are applied in this order: Filter1, Filter2, Filter3 and Filter4.

Method io filter is an implicit pREST filter, dedicated to controller's method excution and method input/output handling.

Practical examples of the filter usage

Example 1 - duration IO filter

Let's assume, that we want to log the method execution duration of the durationTest() method of tutorial.controllers.FilterController controller.

package tutorial.controllers;

public class FilterController extends WebController{

	@Action(name="duration-test")
	public String durationTest() {
		setContentType(ContentType.TEXT_PLAIN_UTF8);
		return "Duration";
	}	

}

which is mounted into URL:

http://localhost:8080/tutorial/filters/

Let us create IO filter for measure action execution time. We have to create:

  1. tutorial.annotations.Duration pREST filter annotation
  2. Annotation handler in the same package as pREST filter annotation with name of annotation with suffix "Filter" tutorial.annotations.DurationFilter

First we create an annotation tutorial.annotations.Duration, through which we asigne filter to the method.

package tutorial.annotations;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(value = {ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface Duration {
	
}

The annotation @Duration itself is annotated by another two annotations:

  1. java.lang.annotation.Target - it is a meta annotation which defines to which elements (clases, methods, parameters ...) can annotation be applied.
  2. java.lang.annotation.Retention - is a meta annotation which defines the amount of validity of the annotation, it has to have a RetentionPolicy.RUNTIME value

Second, we implement pREST annotation IO filter handler in the same package as pREST IO filter annotation @Duration with name of annotation with suffix "Filter" - tutorial.annotations.DurationFilter. This class has to implement prest.core.filters.Filter interface.

package tutorial.annotations;

import java.lang.annotation.Annotation;

import prest.core.Application;
import prest.core.filters.Filter;
import prest.core.filters.FilterChain;
import prest.core.filters.FilterException;
import prest.core.io.Environment;

public class DurationFilter implements Filter {

	public void execute(Environment environment, FilterChain chain)
			throws FilterException
	{
		long start = System.currentTimeMillis();

		// call next IO filter in filter chain
		chain.doFilter(environment);

		long duration = System.currentTimeMillis() - start;

		Application.logger().debug("Duration: %d ms", duration);
	}

	public void setAnnotation(Annotation annotation)
			throws FilterException {
	}

}

The class contains two methods: execute() and setAnnotation(). Their purpose is:

execute(Enviroment enviroment, FilterChain chain)
The method serves as IO filter functionality when it comes into queue in filter chain. It has two parameters:
  • enviroment - is input/output context
  • chain - is an object which represents the filter chain and it contains a doFilter method, which initiates the filter functionality of the next filter in filter chain.
setAnnotation(Annotation annotation)
Its goal is to provide access to IO filter's annotation and annotation parameters for IO filter annotation handler. The method has only one parameter:
  • annotation - is an object which represents an annotation.

In our example we have implemented a method execute() in this way: with method System.currentTimeMillis we have counted the time of executing chain.doFilter and this time was logged in the debug level by a method Application.logger().debug.

The @Duration annotation can be use to assigne to any pREST controller's method now. So we can assigne execution time measiring filter to the duration() method of the FilterController controller.

@Action(name="duration-test")
@Duration
public String durationTest() {
	setContentType(ContentType.TEXT_PLAIN_UTF8);
	return "Duration";
}

The result of the action's calling can be found on the URL address:

http://localhost:8080/tutorial/filters/duration-test

and also in the action's log, where should we found something like this:

Sep 30, 2008 12:02:36 PM org.apache.catalina.core.ApplicationContext log
INFO: DEBUG pREST 32: Duration: 2 ms

Example 2 - uppercase IO filter

In the next example we will create a filter, which test, whether the input data are of the type String and then convert the letters into uppercase or lowercase acording IO filter annotation.

Let's create an annotation class with the name UpperLower:

package tutorial.annotations;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.TYPE, ElementType.METHOD})
public @interface UpperLower  {

	String value() default "lower";

}

Through String value() default="lower" we will define the annotation parameter and its implicit value.

The filter implementation class tutorial.annotations.UpperLowerFilter looks like this:

package tutorial.annotations;

import java.lang.annotation.Annotation;

import prest.core.filters.Filter;
import prest.core.filters.FilterChain;
import prest.core.filters.FilterException;
import prest.core.io.Environment;

public class UpperLowerFilter implements Filter {

	boolean upper = true;

	public void execute(Environment environment, FilterChain chain)
			throws FilterException
	{
		chain.doFilter(environment);

		Object out = environment.getResponse().getOutputData();

		try {
			if (out instanceof String) {
				String s = (String) out;
				if (upper) {
					s = s.toUpperCase();
				} else {
					s = s.toLowerCase();
				}
				environment.getResponse().setOutputData(s);
			}
		} catch (NullPointerException e) {
			Application.logger().debug("UpperLower: Output is null", e);
		} catch (Exception e) {
			Application.logger().debug("UpperLower: ", e);
		}
	}

	public void setAnnotation(Annotation annotation) throws FilterException {
		UpperLower a = (UpperLower) annotation;
		if (a.value().equals("lower")) {
			this.upper = false;
		}
	}

}

In the method setAnnotation we will get access to the annotation parameter and then we can set the value of the private variable according to annotation parameter value. The annotation parameter define whether the text will be transformed into capitals or into lowercase.

The method execute() controls, whether the returned data are String types, or not. If everything is in order, the variable upper is evaluated according to this value is either called the toUpperCase method, or the method toLowerCase of the String class.

We can annotate upperLowerTest() method of the FilterController controller with @UpperLower annotation now. In annotation we can set the parameter value to "upper" or "lower" to choose output string IO filter algorithm. The annotated pREST action method looks like this:

@Action(name="upper-lower-test")
@UpperLower(value="upper")
public String upperLowerTest(String text) {
	setContentType(ContentType.TEXT_PLAIN_UTF8);
	return text;
}

We hope this tutorial will help you to build better, faster and safer Web applications and REST web services.