Brutos Framework
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.
Developer(s) | UoU Technology |
---|---|
Initial release | May 17, 2009 |
Stable release | 2.0-rc3
/ 14 August 2018 |
Written in | Java |
Operating system | Cross-platform |
Platform | Java Virtual Machine |
Type | Application framework |
License | Apache License 2.0 |
Website | www |
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-rc3</version>
</dependency>
<dependency>
<groupId>org.brandao</groupId>
<artifactId>brutos-web</artifactId>
<version>2.0-rc3</version>
</dependency>
<dependency>
<groupId>org.brandao</groupId>
<artifactId>brutos-annotation</artifactId>
<version>2.0-rc3</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
http://www.brutosframework.com.br/schema/web http://www.brutosframework.com.br/schema/web/brutos-web-1.1.xsd'>
</controllers>
Examples
Web Service
Methods:
URI | HTTP method | Method |
---|---|---|
/users | GET | UserWebService.list() |
/users | POST | UserWebService.add(User) |
/users/{user.id} | PUT | UserWebService.update(User) |
/users/{id} | DELETE | UserWebService.delete(Integer) |
Controller:
@Controller
@AcceptRequestType(MediaTypes.APPLICATION_JSON)
@ResponseType(MediaTypes.APPLICATION_JSON)
@ResponseError(code=HttpStatus.NOT_FOUND, target=NotFoundException.class)
public class UserWebService {
@Inject
private UserService userService;
@Action("/users")
public List<User> list() {
return this.userService.list();
}
@Action("/users")
@RequestMethod(RequestMethodTypes.POST)
@ResponseStatus(HttpStatus.CREATED)
public void add(User user) {
this.userService.save(user);
}
@Action("/users/{user.id}")
@RequestMethod(RequestMethodTypes.PUT)
@ResponseStatus(HttpStatus.NO_CONTENT)
public void update(User user) throws NotFoundException {
if (user == null) {
throw new NotFoundException();
}
this.userService.update(user);
}
@Action("/users/{id}")
@RequestMethod(RequestMethodTypes.DELETE)
@ResponseStatus(HttpStatus.NO_CONTENT)
public void delete(Integer id) throws NotFoundException {
User e = this.userService.remove(id);
if (e == null) {
throw new NotFoundException();
}
}
}
Exception Handler
Controller Level
@ResponseError(value=HttpStatus.CONFLICT,
reason="Data integrity violation", target=DataIntegrityViolationException.class)
public class ExampleController {
@Action("/action")
public void action() throws DataIntegrityViolationException{
...
}
}
Action Level
public class ExampleController{
@Action("/action")
@ResponseError(value=HttpStatus.CONFLICT,
reason="Data integrity violation", target=DataIntegrityViolationException.class)
public void action() throws DataIntegrityViolationException{
...
}
}
Method
public class ExampleController{
@Action("/action")
public void action() throws MyBadDataException {
...
}
@ResponseError(MyBadDataException.class)
public WebActionResult myBadDataException(Throwable exception, WebActionResult result) {
result
.setResponseStatus(HttpStatus.BAD_REQUEST)
.setView("errorView")
.add("exception", exception);
return result;
}
}
Build Action Result
Controller
public class IndexController {
public WebResultAction action1Action(WebResultAction result) {
result.addHeader("Content-Type", "text/html; charset=utf-8")
.setContentType(String.class)
.setContent("<html><body>test</body></html>");
return result;
}
public WebResultAction action2Action (WebResultAction result) {
result.addHeader("Content-Type", "text/html; charset=utf-8")
.setView("myView")
.add("value1", BigDecimal.ONE);
return result;
}
}
Polymorphic Mapping
Methods:
URI | Http Method | method |
---|---|---|
/add | POST | ExampleController.add(Fruit) |
Controller
public class ExampleController{
@Action("/add")
@RequestMethod(RequestMethodTypes.POST)
public void add(
@Any(
metaBean=@Basic(bean="type")
metaValues={
@MetaValue(name="apple", target=Apple.class),
@MetaValue(name="orange", target=Orange.class)
}
)
Fruit fruit) {
...
}
}
Beans
public abstract class Fruit {
...
}
public class Apple extends Fruit {
...
}
public class Orange extends Fruit {
...
}
Abstract action
URI mapping:
Controller/Action | URI | View |
---|---|---|
ExampleController | /path | /WEB-INF/views/view.jsp |
ExampleController | /path/ | /WEB-INF/views/view.jsp |
Controller
@Controller("/path", defaultAction="/")
@Action(value="/", view=@View("view"))
public class ExampleController{
}
Using URI template
URI mapping:
Controller/Action | URI | View |
---|---|---|
ExampleController | /path/{user} | /WEB-INF/views/index/index.jsp |
ExampleController.getUser(String) | /path/{userId}/showUser | /WEB-INF/views/index/getuser/index.jsp |
Controller
@Controller("/path/{userId}")
public class ExampleController{
@Action("/showUser")
public User getUser(String userId) {
...
}
}
File upload and download
@Controller("/files")
public class ExampleController {
@Action("/")
@RequestMethod(RequestMethodTypes.POST)
public void uploadAction(File file) {
//the parameter file is a temporary file
...
}
@Action("/{fileName:.*}")
@RequestMethod(RequestMethodTypes.GET)
public File downloadAction(String fileName) {
File file = ...;
return file;
}
}
Form and Session
public class PersonController{
@Action("/save")
public void saveAction(
@Basic(scope="session") User loggerdUser, @Basic(bean="person") Person person) {
...
}
}