Skip to content

Latest commit

 

History

History
128 lines (76 loc) · 12.6 KB

README.md

File metadata and controls

128 lines (76 loc) · 12.6 KB

Adaptive RESTful API

An Adaptive RESTful API is a library for automatic HTTP request handling based on the chain of filters. It's written in Java and is dedicated to use within the Java EE applications.

NOTICE: This project is a result of the author's work on his diploma thesis.

Overview

The basic idea behind the library is to process the HTTP request in the chain of filters represented by the Filter class. It's a responsibility of the concrete filter to decide what to do with the request, if it handles completely (creates a response), or it makes something useful with the content (eq. converts JSON to POJO) of the request and then resigns the processing to the next filter in the chain. You can see an example flow of the request in this picture.

To be able to process the request through the filters in some manner, there are two basic concepts: model and configuration of this model. The model is used to describe your domain classes which you want to reveal in the API. Model consists of entities which contain properties (attributes and relationships).

The configuration allows you to customize a meaning of the each part in the model in a hierarchical way. It makes possible to use some global configuration applicable to the whole model and to refine each individual part of the model as required.

Architecture

The library is divided into seperate modules. On the base level is core module which depends on the meta module. The rest of the modules add support for more concrete types of the filter. The example module shows how to use the library in a "real world" application.

Meta

The meta module is used to build the model of the entities with properties (attributes and relationships) and it's configuration. The inspection process is done by the inspector. The first task is to inspect concrete package for classes in it. Then inspects triplets of the field, it's getter (starts with is or get) and setter (starts with set) methods. The inspector is not responsible for creating instances of the entities, nor propeties, but it delegates this work to a model listener. After the model is built, the configuration is inspected. The inspector goes through the model and asks configuration listener for the list of variables of the property, entity or model. The configuration respects the hierarchy of the model, so if you ask for some value on the attribute, it will flow through the hierarchy of configurations from the most specific to the most general configuration.

Core

This module contains probably the most essesential part of the library, a filter. The filter is used to create the chain which defines the flow of the HTTP request goes through. Each filter accepts the HTTP context, model and configuration via the process method. In this method you decide what to do with the request, there are basically three options:

  1. set the response and stop chaining the process,
  2. do something with the request and resign the process to the next filter,
  3. throw an exception if something goes wrong.

This is an example implementation of the filter:

public class HelloFilter extends Filter {

    @Override
    public final HttpContext process(HttpContext httpContext, Model model, Configuration configuration) throws FilterException {
        String requestContent = httpContext.getRequestContent();
        
        if (requestContent.startsWith("Hello,")) {
            String name = requestContent.substring("Hello,".length());
            
            // set the content for next filter
            httpContext.setContent(new Hello(name));
            
            // resign the process to the next filter
            return this.resign(httpContext, model, configuration);
            
        } else {
            throw new FilterException(HttpStatus.S_400); // bad request
        }
    }

}

There is no responsibility to create an HTTP context, model, nor configuration, it must be done somewhere else.


Caching

Adds default implementation of the filter for the caching and provides abstract methods to handle the request. If the load method hits the cache, the filter returns the context immediately, otherwise it resigns the process and finally tries to save the context.

This module contains simple implementation of the If-Modified-Since caching mechanism.

Data

The purpose of this module is to deal with content of the HTTP context. The dispatcher resolves an HTTP method, and the entity via the router, then it loads data handler from the configuration and delegates the process to him. There are available interfaces for GET, POST, PUT and DELETE methods.

The module also provides basic implementation of the data handlers for JPA's entity manager, see persistence package. It's not the responsibility of this module to create an entity manager.

Security

The security is divided into the two parts:

Both abstract classes provides methods, where the security process should be handled. If the authentication, resp. authorization fails, then the appropriate exception must be thrown.

This module comes with an implementation of the HTTP Basic authentication.

Serialization

The responsibility of this module is to serialize, resp. deserialize the content of the HTTP response, resp. request. The resolver loads the concrete serializer from configuration and delegates the (de)serialization process to him.

The JSON (de)serializer and plain text serializer are provided.

Servlet

The FilteredServlet class implements service(request, response) method to handle all HTTP communication. First off all, it asks for the ApplicationContext singleton, which provides current model and configuration. The second step is to create a HttpContext from the HttpServletRequest object. Then starts the processing through the filter's chain passing the httpContext, model and configuration. Finally, it sets the HttpServletResponse from processed HttpContent or catched FilteredException.

You use FilteredServlet directly by creating an instance or subclassing it and setting the desired filter.


Example

An example is built using a servlet implementation, so the initialization of the ApplicationContext is done within the contextInitialized method of the ServletContextListener. The inspector uses these model and configuration listeners. The model of the application is defined here, it's a simple project/issue management system. The entity manager is created by the PersistentContext, the usage of persistence handlers is shown in the configuration listener. The API is capable to communicate in the JSON format, and in a read-only mode of the plain text. The application is able to handle HTTP Basic authentication, method and serialization authorization (for more details look at the Users class and configuration listener).

So, an example request $ curl -u admin:1234 --header "Accept: application/json;charset=UTF-8" --header "Content-Type: application/json;charset=UTF-8" http://localhost:8080/Project/2 will end up to the response:

{
    "started": false,
    "id": 2,
    "startedAt": null,
    "name": "Project B",
    "bugs": [ 2, 3 ],
    "manager": 4,
    "tasks": [ 3 ]
}

Contact

Author

Jan Bobisud

Supervisor

Karel Čemus

License

Adaptive RESTful API is available under the LGPL license. See the LICENSE file for more info.