Brutos Framework
Developer(s) | Brandao |
---|---|
Initial release | May 17, 2009 |
Stable release |
2.0RC1
/ 30 June 2015 |
Development status | Active |
Written in | Java |
Operating system | Cross-platform |
Platform | Java Virtual Machine |
Type | Application framework |
License | Apache License 2.0 |
Website |
www |
The Brutos Application Framework is MVC controller written 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;
- loose coupling and
- productivity.
Release Bundle Downloads
The Brutos team provides release bundles hosted on the SourceForge File Release System, in ZIP.
Each release bundle contains JARs, documentation, source code, and other information.
You can download releases of Brutos, from the list at sourceforge
Maven Repository Artifacts
They are produced a number of artifacts. All under the org.brandao groupId.
- brutos-core: The main artifact, it is needed to build applications using the Brutos native APIs.
- brutos-annotation: Optional artifact that allows building applications using annotations. This artifact depends on the brutos-core.
- brutos-web: Optional artifact that allows building web applications. This artifact depends on the brutos-core.
The official repository is www
How to configure?
Register the listener in web.xml
<listener>
<listener-class>org.brandao.brutos.web.ContextLoaderListener</listener-class>
</listener>
Register the filter in web.xml
<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>
</filter>
Attention: If you are using a container that supports the Servlet 3.0 specification, the registration of ContextLoadListener and DispatcherServlet or BrutosRequestFilter are not necessary. They will be automatically registered.
Register the artifacts in pom.xml
...
<dependencies>
<dependency>
<groupId>org.brandao</groupId>
<artifactId>brutos-core</artifactId>
<version>2.0-rc1</version>
</dependency>
<dependency>
<groupId>org.brandao</groupId>
<artifactId>brutos-web</artifactId>
<version>2.0-rc1</version>
</dependency>
<dependency>
<groupId>org.brandao</groupId>
<artifactId>brutos-annotation</artifactId>
<version>2.0-rc1</version>
</dependency>
</dependencies>
...
Create the file brutos-config.xml in /WEB-INF.
<?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>
Examples
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 controller path
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 action path
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 Detached action strategy
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 Hierarchy 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 Parameter action strategy
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{
//@Identify version before 2.0 rc1
public void defaultAction(@Basic(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
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{
...
}
}
Simple bean mapping
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{
//@Identify version before 2.0 rc1
public void defaultAction(@Basic(bean="myBean") MyBean bean) {
...
}
}
Defining the property scope
Bean
@Bean
public class MyBean{
private Integer id;
//@Identify version before 2.0 rc1
@Basic(scope=ScopeType.SESSION)
private User user;
...
}
Defining the property name
Form
<form method="post" ... >
<input type="text" name="paramName.my_id">
</form>
Bean
@Bean
public class MyBean{
//@Identify version before 2.0 rc1
@Basic(bean="my_id")
private Integer id;
...
}
Defining the bean constructor
Bean
@Bean
public class MyBean{
public MyBean(){...}
@Constructor
public MyBean(Integer id){...}
}
Defining the target class
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;
...
}
Map
Form
<form method="post" action="/person/save">
<input type="text" name="person.name">
<input type="text" name="person.address.key[0]">
<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 Map<String, Address> address;
...
}
Defining tha action view
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.birthday">
<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].birthday">
<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].birthday">
<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].birthday">
<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 enum Gender{
MALE,
FEMALE;
}
Bean
@Bean
public class Person{
private Integer id;
private String firstName;
private String lastName;
private Date birthday;
//@Enumerated(EnumerationType.STRING)
private Gender gender;
private List<Person> childs;
...
}
Controller
public class PersonController{
//or inject logged user here
//@Identify(scope="session")
//private User loggerdUser;
public void saveAction(@Basic(scope="session") User loggerdUser,
@Basic(bean="person") Person person){
...
}
}
Polymorphic Mapping
Mapping a polymorphic action parameter
@Controller("/property")
public class PropertyController{
@Action("/save")
public void saveProperty(
@Basic(bean="property")
@Any(
metaBean=@Basic(bean="property_type")
metaValues={
@MetaValue(name="Decimal", target=DecimalProperty.class),
@MetaValue(name="Set", target=SetProperty.class)
}
)
Property property){
...
}
}
Mapping a polymorphic collection
@Controller("/property")
public class PropertyController{
@Action("/save")
public void saveProperty(
@Basic(bean="properties")
@ElementCollection(
any=
@Any(
metaBean=@Basic(bean="property_type")
metaValues={
@MetaValue(name="Decimal", target=DecimalProperty.class),
@MetaValue(name="Set", target=SetProperty.class)
}
)
)
List<Property> properties){
...
}
}
Mapping a polymorphic map
@Controller("/property")
public class PropertyController{
@Action("/save")
public void saveProperty(
@Basic(bean="properties")
@KeyCollection(
any=
@Any(
metaBean=@Basic(bean="property_type")
metaValues={
@MetaValue(name="Decimal", target=DecimalProperty.class),
@MetaValue(name="Set", target=SetProperty.class)
}
)
)
Map<Property,String> properties){
...
}
}
Mapping a polymorphic property
@Controller("/property")
public class PropertyController{
@Basic(bean="property")
@Any(
metaBean=@Basic(bean="property_type")
metaValues={
@MetaValue(name="Decimal", target=DecimalProperty.class),
@MetaValue(name="Set", target=SetProperty.class)
}
)
private Property property;
@Action("/save")
public void saveProperty(){
...
}
}