Attila The Framework

Table of contents

  1. Controllers
  2. Views
  3. Authentication
  4. Attila The REST'ish
  5. Forms
  6. Rules about Rules
  7. Helpers
  8. JSP tags & functions

Introduction

Attila The Framework is a simple Controller-View -framework that is built on top of the Servlet specification.

It is designed to be lightweight and easy to use.

Controllers

  1. Create controller class
      public class FooController extends AttilaTheController{
        public void index(HttpServletRequest request, HttpServletResponse response){
        }
      }
    
  2. Configure web.xml
    <servlet>
      <servlet-name>FooController</servlet>
      <servlet-class>com.example.FooController</servlet-class>
    </servlet>
    <servlet-mapping>
      <servlet-name>FooController</servlet-name>
      <url-pattern>/foo/*</url-pattern>
    </servlet-mapping>
    
  3. Create a view and render it
      SampleView view = new SampleView()
      view.render(request, response);
    

Views

Views come in two flavors: ad-hoc views and concrete views. If you have a simple view that doesn't need a complex setup or is only used in one place you should use ad-hoc views for rendering your pages. If your view is complex to setup, contains lot of data and you feel a need to encapsulate it to a neat class then you should use concrete views.

Ad-hoc views

When you create an ad-hoc view, you just create an instance of one of Attila's generic views, set the Tiles2 layout or a jsp-page, set the data (optional) and render the view.

@HTTPMethod
public void create(HttpServletRequest request, HttpServletResponse response){
	GenericJSPCompositeViewable view = new GenericJSPCompositeViewable("user.create");
	view.render(request, response);
}

Concrete views

  1. Choose the type of your view and create a class
    • JSPViewable (single JSP)
    • JSPCompositeViewable (composite of multiple JSP fragments)
      public class SampleView extends JSPViewable{
        public SampleView(){
          setJspPage("/view/index.jsp");
        }
      }
    
  2. Add setters and getters for data
      public void setUsername(String username){
        this.username = username;
      }
      public String getUsername(){
        return username;
      }
    
  3. Render the data in you JSP template
    /variants/${variant}/public/view/index.jps
      <p>Hello ${username}!</p>
    

NOTE! Paths to your public JSPs go as follows:
Path in your project: ${project}/variants/${variant}/public/view/index.jsp
Path in a deployed app: /view/index.jsp

Authentication

Use @Authentication-annotation to make controllers or actions authenticable by Attila.

HINT! You can exclude actions from authentication process by marking an action with @Authentication(checkAuthentication=false)-annotation

Before you can use the authentication mechanism, you have to:

  1. Implement AttilaTheUser-interface in you User-model (or similar)
  2. Implement a controller for logging in / authentication
  3. Configure Attila to redirect to your login-controller in web.xml

Examples:

Check user's authentication before executing on every action of the controller

@Authentication
public class StoryController extends AttilaTheController {

	@Override
	public void index(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {}

	@HTTPMethod(method=HttpMethodEnum.POST)
	public void createnew(int themeId, HttpServletRequest request, HttpServletResponse response) throws IOException{
	}
	
}

Check authentication on every action except one

Attila will check user's authentication status on index() but not on createnew().

@Authentication
public class StoryController extends AttilaTheController {

	@Override
	public void index(HttpServletRequest request, HttpServletResponse response)	throws ServletException, IOException {}

	@Authentication(checkAuthentication=false)
	@HTTPMethod(method=HttpMethodEnum.POST)
	public void createnew(int themeId, HttpServletRequest request, HttpServletResponse response) throws IOException{
	}
	
}

Restricting user access with @AuthLevel-annotation

There are situations when some users should be allowed to access an action and some users should not. The usual way is to get the user model instance of the signed in user and then check if she has the correct usage rights. This usually ends up causing multiple nested if's and duplication of the same code everywhere. Attila's solution for simplifying and encapsulating this process is @AuthLevel-annotation and AuthenticationLevel-interface.

To use this feature you need to implement AuthenticationLevel and assign it to an action or a controller with @AuthLevel.

Below is a simplistic example of an AuthenticationLevel-implementation:

import attila.core.auth.*;

public class AdminLevel implements AuthenticationLevel {

	@Override
	public boolean checkUserAuthenticationLevel(AttilaTheUser attilaUser) {
		User user = (User) attilaUser;
		if(user.getId() == 1){
			return true;
		}else{
			return false;			
		}
	}

}

Example of using the above implementation to restrict access to an action only for one user:

@AuthLevel(level=AdminLevel.class,errorController=DashboardController.class)
@HTTPMethod(method=HttpMethodEnum.POST)
public void createnew(HttpServletRequest request, HttpServletResponse response) throws IOException{
}

NOTE! Using @AuthLevel alone does not enable authentication process. @AuthLevel is only an instruction for the framework to be used in the authentication process. You must always use @Authentication in addition to @AuthLevel if you want to enable finer grained access control.

Attila The REST'ish and actions

The biggest advantage of Attila over the usual servlet programming is Attila's ability to map URLs to methods radically increasing readability and maintainability of the application. Attila also supports passing parameters to methods provided they're simple types. Currently Attila supports the following types in actions:

Syntax of Attila's urls:

http://example.com/[controller]/[action]/[param1]/[param2]/[nth-param]

Automagical parameter mapping:

http://example.com/foo/bar/24 maps to:

public void bar(int b, HttpServletRequest request, HttpServletResponse response){}

Overloaded actions

Since r180 Attila supports overloaded actions with certain limitations. The biggest limitation is that Attila differs between two different actions by the amount of parameters they take in. So you are not able to use two actions that take same amount of parameters but of different types (resolving the requested action would require guesswork that would make the framework unpredictable).

Below is an example of valid overloading:

@HTTPMethod
public void createnew(HttpServletRequest request, HttpServletResponse response) throws IOException{
}

@HTTPMethod
public void createnew(String username, HttpServletRequest request, HttpServletResponse response) throws IOException{
}

Forms

  1. Extend attila.form.SimpleForm or implement(not recommended) attila.form.Form.
      public class FooForm extends SimpleForm{}
    
  2. Add Fields to your form
      private Field username;
      public FooForm(){
        username = new SimpleField("username", new StringRule(), "username fail");
        addField(username);
      }
    
  3. Validate the form on submit in your controller
      public void add(HttpServletRequest request, HttpServletResponse response){
        Form fooForm = new FooForm();
        if(fooForm.validate(request)){
          //do something
        }
      }
    

Rules about Rules

  1. Rules implement attila.form.validators.Rule
  2. Rules validate full Strings and return true or false depending on the success of validation
  3. Rules can be chained by using using RuleSequence or by implementing a composite Rule as an anonymous inner class.

Helpers

Read parameters safely from requests by using attila.helper.RequestHelper and its static methods. For reading from Cookies, use attila.helper.CookieHelper

JSP tags & functions

Import taglib to each of your JSPs where you intend to use them:

  <%@ taglib uri="/WEB-INF/taglib.tld" prefix="atf" %>