Brutos Framework

The Brutos Framework (Brutos Application Framework) is MVC controller developed in Java. Designed to reduce the complexity of web development, with configurable mapping, view resolution as well as support for Uploading and downloading files. Can be configured using XML, annotations and CoC.

The framework follows the below principles:

  • Flexibility;
  • low coupling;
  • Productivity.

Examples

Quick Start

pom.xml

...
<dependencies>
  <dependency>
      <groupId>org.brandao</groupId>
      <artifactId>brutos-core</artifactId>
      <version>2.0-b5</version>
  </dependency>
  <dependency>
     <groupId>org.brandao</groupId>
     <artifactId>brutos-web</artifactId>
     <version>2.0-b5</version>
  </dependency>
  <dependency>
     <groupId>org.brandao</groupId>
     <artifactId>brutos-annotation</artifactId>
     <version>2.0-b5</version>
  </dependency>
</dependencies>
...

web.xml

...
<listener>
    <listener-class>org.brandao.brutos.web.ContextLoaderListener</listener-class>
</listener>

<filter>
    <filter-name>Brutos Framework Filter</filter-name>
    <filter-class>org.brandao.brutos.web.http.BrutosRequestFilter</filter-class>
</filter>
<filter-mapping>
    <filter-name>Brutos Framework Filter</filter-name>
    <url-pattern>*</url-pattern>
    <dispatcher>REQUEST</dispatcher>
    <dispatcher>FORWARD</dispatcher>
    <dispatcher>INCLUDE</dispatcher>
    <dispatcher>ERROR</dispatcher>
</filter-mapping>
...

brutos-config.xml

<?xml version="1.0" encoding="UTF-8"?>
<controllers  xmlns:xsi='http://www.w3.org/2001/XMLSchema-instance'
              xmlns='http://www.brutosframework.com.br/schema/controllers'
              xmlns:context='http://www.brutosframework.com.br/schema/context'
              xsi:schemaLocation='
   http://www.brutosframework.com.br/schema/controllers 
http://www.brutosframework.com.br/schema/controllers/brutos-controllers-1.1.xsd
   http://www.brutosframework.com.br/schema/context 
http://www.brutosframework.com.br/schema/context/brutos-context-1.1.xsd'>

</controllers>

Creating a simple controller

URI mapping:

Controller/Action

URI

View

| IndexController

/Index

/WEB-INF/index/index.jsp

| IndexController.defaultAction()

/Index/default

/WEB-INF/index/defaultaction/index.jsp

Controller

public class IndexController{
  
   public void defaultAction(){
       ...
   }

}

Defining the path of controller

URI mapping:

Controller/Action

URI

View

| IndexController

/mycontroller

/WEB-INF/index/index.jsp

| IndexController.defaultAction()

/mycontroller/default

/WEB-INF/index/defaultaction/index.jsp

Controller

@Controller("/mycontroller")
public class IndexController{
  
   public void defaultAction(){
       ...
   }

}

Defining the path of action

URI mapping:

Controller/Action

URI

View

| IndexController

/mycontroller

/WEB-INF/index/index.jsp

| IndexController.defaultAction()

/mycontroller/myaction

/WEB-INF/index/defaultaction/index.jsp

Controller

@Controller("/mycontroller")
public class IndexController{
  
   @Action("/myaction")
   public void defaultAction(){
       ...
   }

}

Defining the action strategy

URI mapping:

Controller/Action

URI

View

| IndexController

/Index

/WEB-INF/index/index.jsp

| IndexController.defaultAction()

/Index/default

/WEB-INF/index/defaultaction/index.jsp

Controller

@ActionStrategy(ActionStrategyType.Hierarchy)
public class IndexController{
  
   public void defaultAction(){
   }

}

The action strategy Detached

URI mapping:

Controller/Action

URI

View

| IndexController

| -

| -

| IndexController.defaultAction()

/default

/WEB-INF/index/defaultaction/index.jsp

Controller

@ActionStrategy(ActionStrategyType.Detached)
public class IndexController{
  
   @Action("/default")
   public void defaultAction(){
       ...
   }

}

The action strategy Hierarchy

URI mapping:

Controller/Action

URI

View

| IndexController

/Index

/WEB-INF/index/index.jsp

| IndexController.defaultAction()

/Index/default

/WEB-INF/index/defaultaction/index.jsp

Controller

@ActionStrategy(ActionStrategyType.Hierarchy)
public class IndexController{
  
   public void defaultAction(){
       ...
   }

}

The action strategy Parameter

URI mapping:

Controller/Action

URI

View

| IndexController

/Index

/WEB-INF/index/index.jsp

| IndexController.defaultAction()

/Index?invoke=default

/WEB-INF/index/defaultaction/index.jsp

Controller

@ActionStrategy(ActionStrategyType.Parameter)
public class IndexController{
  
   public void defaultAction(){
      ...
   }

}

Defining the default action

URI mapping:

Controller/Action

URI

View

| IndexController.defaultAction()

/Index

/WEB-INF/index/index.jsp

| IndexController.defaultAction()

/Index/default

/WEB-INF/index/defaultaction/index.jsp

Controller

@Controller(defaultActionName="/default")
public class IndexController{
  
   public void defaultAction(){
       ...
   }

}

Defining the abstract action

URI mapping:

Controller/Action

URI

View

| IndexController

/Index

/WEB-INF/index/index.jsp

| IndexController

/Index/abstractAction

/WEB-INF/index/view.jsp

| IndexController.defaultAction()

/Index/default

/WEB-INF/index/defaultaction/index.jsp

Controller

@Action(value="/abstractAction", view=@View("view"))
public class IndexController{
  
   public void defaultAction(){
   }

}

Using URI template

URI mapping:

Controller/Action

URI

View

| IndexController

/mycontroller/{user}

/WEB-INF/index/index.jsp

| IndexController.defaultAction()

/mycontroller/{user}/default

/WEB-INF/index/defaultaction/index.jsp

Controller

@Controller("/mycontroller/{user}")
public class IndexController{
  
   private String user;

   public void defaultAction(){
       ...
   }

}

File upload

Form

<form method="POST" enctype="multipart/form-data" action="/Index/default">
  <input type="file" name="image"/>
</form>

Controller

public class IndexController{
  
   public void defaultAction(@Identify(bean="image") File image){
       //the parameter image is a temporary file
       ...
   }

}

File download

Controller

public class IndexController{
  
   public File downloadAction(){
       return new File("/path/file.ext");
   }

}

Mounting the result action

Controller

public class IndexController{
  
   public ResultAction action1Action(ResultAction result){
      result.addInfo("Content-Type", "text/html; charset=utf-8")
            .setContentType(String.class)
            .setContent("<html><body>test</body></html>");
      return result;
   }

    public ResultAction action2Action (ResultAction result){
        result.addInfo("Content-Type", "text/html; charset=utf-8")
            .setView("myView")
            .add("value1", BigDecimal.ONE);
        return result;
    }

}

Creating a simple interceptor

Interceptor

public class MyInterceptorController implements InterceptorController{
  
    private Map props;

    public void setProperties( Map props ){
       this.props = props;
    }

    public boolean isConfigured(){
        return this.props != null;
    }

    public void intercepted( InterceptorStack stack, InterceptorHandler handler ) throws          
           InterceptedException{
        //code before action
        stack.next(handler);
        //code after action
    }
    
    public boolean accept(InterceptorHandler handler){
        return true;
    }

}

Controller

@InterceptedBy(@Intercept(interceptor=MyInterceptorController.class))
public class IndexController{
  
    ...

}

Creating a simple interceptor stack

Interceptor A

@InterceptsStack(name="stackA")
public class MyInterceptorAInterceptorController implements InterceptorController{
    ...
}

Interceptor B

@InterceptsStack(name="stackA", executeAfter=MyInterceptorAInterceptorController.class)
public class MyInterceptorBInterceptorController implements InterceptorController{
    ...
}

Controller

@InterceptedBy(@Intercept(name="stackA"))
public class IndexController{
    ...
}

Handling exceptions

URI mapping

Controller/Action

URI

View

| IndexController

/Index

/WEB-INF/index/index.jsp

| IndexController.defaultAction()

/Index/default

/WEB-INF/index/defaultaction/index.jsp

| throw NullPointerException

/Index/default

/WEB-INF/index/defaultaction/nullpointerexception.jsp

Controller

public class IndexController{
  
   public void defaultAction() throw NullPointerException{
       ...
   }

}

Specifying handling exception

Controller

URI mapping

Controller/Action

URI

View

| IndexController

/Index

/WEB-INF/index/index.jsp

| IndexController.defaultAction()

/Index/default

/WEB-INF/index/defaultaction/index.jsp

| throw NullPointerException

/Index/default

/WEB-INF/index/defaultaction/npe.jsp

Controller

@ThrowSafe(target=NullPointerException.class, view="npe")
public class IndexController{
  
   public void defaultAction() throw NullPointerException{
       ...
   }

}
Action

URI mapping

Controller/Action

URI

View

| IndexController

/Index

/WEB-INF/index/index.jsp

| IndexController.defaultAction()

/Index/default

/WEB-INF/index/defaultaction/index.jsp

| throw NullPointerException

/Index/default

/WEB-INF/index/defaultaction/npe.jsp

Controller

public class IndexController{
  
   @ThrowSafe(target=NullPointerException.class, view="npe")
   public void defaultAction() throw NullPointerException{
       ...
   }

}

Mapping simple bean

Form

<form method="POST" action="/Index">
  <input type="hidden" name="invoke" value="default">
  <input type="text" name="myBean.id">
</form>

Bean

@Bean
public class MyBean{
  
    private Integer id;

    public void setId(Integer id){
        this.id = id;
    }

    public Integer getId(){
        return this.id;
    }

}

Controller

public class IndexController{
  
   public void defaultAction(@Identify(bean="myBean") MyBean bean) {
       ...
   }

}

Defining scope of property

Bean

@Bean
public class MyBean{
  
    private Integer id;

    @Identify(scope=ScopeType.SESSION)
    private User user;
    
    ...
}

Defining the name of property

Form

<form method="post" ... > 
    <input type="text" name="paramName.my_id"> 
</form>

Bean

@Bean
public class MyBean{
  
    @Identify(bean="my_id")
    private Integer id;
    
    ...
}

Defining the constructor of bean

Bean

@Bean
public class MyBean{

    public MyBean(){...}

    @Constructor
    public MyBean(Integer id){...}

}

Defining the target class of mapping

Controller

public class MyController{

    @Target(LinkedHashMap.class)
    private Map property;
    ...
}

Collection mapping

Form

<form method="post" action="...">
    <input type="text" name="person.name">
    <input type="text" name="person.address.element[0].type">
    <input type="text" name="person.address.element[0].street">
    <input type="text" name="person.address.element[0].city">
    <input type="text" name="person.address.element[0].state">
</form>

Bean

@Bean
public class Person {
    private String name;

    private List<Address> address;

    ...
}

Bean

@Bean
public class Address {

    private String type;
    private String street;
    private String city;
    private String state;
    ...
}

Collection mapping

Form

<form method="post" action="/person/save"> 
    <input type="text" name="person.name"> 
    <input type="file" name="person.address.key[0]"> 
    <input type="file" name="person.address.element[0].type"> 
    <input type="file" name="person.address.element[0].street"> 
    <input type="file" name="person.address.element[0].city"> 
    <input type="file" name="person.address.element[0].state"> 
</form>

Bean

@Bean
public class Person {
    private String name;

    private Map<String, Address> address;

    ...
}

Defining view of action

URI mapping

Controller/Action

URI

View

| IndexController

/Index

/WEB-INF/index/controllerView.jsp

| IndexController.defaultAction()

/Index/default

/jsp/index.jsp

Controller

@View("controllerView")
public class IndexController{
  
   @View(value="/jsp/index.jsp", resolved=true)
   public void defaultAction(){
   }

}

Using Bean Validator

Action

public class IndexController{
  
   public void defaultAction(@NotNull Integer arg1){
       ...
   }

}

Action

public class IndexController{
   
   @NotNull
   public Integer defaultAction(){
       ...
       return result;
   }

}

Controller

public class IndexController{
  
   @NotNull
   private Integer value;

   public void defaultAction(){
       ...
   }

}

Controller

public class IndexController{
  
   private Integer value;

   public void setValue(@NotNull Integer value){
       this.value = value;
   }
   ...
}

Bean

@Bean
public class MyBean{
  
   @NotNull
   private Integer value;

   ...

}

Bean

@Bean
public class MyBean{
  
   private Integer value;

   public void setValue(@NotNull Integer value){
       this.value = value;
   }

   ...

}

Bean

@Bean
public class MyBean{
  
   
   private Integer value;

   public voud setValue(@NotNull Integer value){
       this.value = value;
   }

   ...

}

Complex form and mixing form and session.

Form

<form method="post" action="/Person/save"> 
    Person: <br>
    <input type="hidden" name="person.id"> 
    <input type="text" name="person.firstName"> 
    <input type="text" name="person.lastName">
    <input type="text" name="person.dateOfBirth">
    <input type="radio" name="person.gender" value="MALE"> Male
    <input type="radio" name="person.gender" value="FEMALE"> Female

    Childs <br>
    <!-- Child 1 -->
    <input type="text" name="person.childs.element[0].firstName"> 
    <input type="text" name="person.childs.element[0].lastName">
    <input type="text" name="person.childs.element[0].dateOfBirth">
    <input type="radio" name="person.childs.element[0].gender" value="MALE"> Male
    <input type="radio" name="person.childs.element[0].gender" value="FEMALE"> Female
    <!-- Child 2 -->
    <input type="text" name="person.childs.element[1].firstName"> 
    <input type="text" name="person.childs.element[1].lastName">
    <input type="text" name="person.childs.element[1].dateOfBirth">
    <input type="radio" name="person.childs.element[1].gender" value="MALE"> Male
    <input type="radio" name="person.childs.element[1].gender" value="FEMALE"> Female
    <!-- Child 3 -->
    <input type="text" name="person.childs.element[2].firstName"> 
    <input type="text" name="person.childs.element[2].lastName">
    <input type="text" name="person.childs.element[2].dateOfBirth">
    <input type="radio" name="person.childs.element[2].gender" value="MALE"> Male
    <input type="radio" name="person.childs.element[2].gender" value="FEMALE"> Female
</form>

Bean

public enunm Gender{

   MALE,

   FEMALE;

}

Bean

@Bean
public class Person{

   private Integer id;

   private String firstName;

   private String lastName;

   private Date dateOfBirth;

   //@Enumerated(EnumerationType.STRING)
   private Gender gender;

   private List<Person> childs;

   ...

}

Controller

public class PersonController{

   //or inject logged user here
   //@Idendify(scope="session") 
   //private User loggerdUser;

    public void saveAction(@Idendify(scope="session") User loggerdUser, 
            @Idendify(bean="person") Person person){
        ...
    }
}

See also

  • Model–view–controller
  • Inversion of control
  • Web application framework
  • Comparison of web application frameworks