Mar 6, 2016

Introduce to ActFramework - an new MVC/RESTFul service framework in Java

I am happy to share my recent Open Source project ActFramework here.
So some events about ActFramework:
  1. About one year ago I start working on ActFramework.
  2. Three months ago I start using ActFramework to rewrite a commercial project which was written in Jersey originally, and the result is great. We have reduced the lines of code from 8900 to 4500 while keeping the same feature set and functionality.
  3. Last Wednesday I presented ActFramework in the first Sydney JVM meetup at FinTech hub in 2016.
In this blog I will brief major features of ActFramework

Controller

@GetAction("/")  
public void home() {
}    
@PostAction("/customer")   
public String createCustomer(Customer customer) {
      customerDao.save(customer);
      return customer.getId();  
}    
@PutAction("/customer/{id}/email")  
public void updateCustomerEmail(String id, String email) {
      Customer customer = customerDao.findById(id);
      notFoundIfNull(customer);
      customer.setEmail(email);
      customerDao.save(customer);
}
See the documentation for more about controller and action methods

Routing

There are two ways to create routing table:
  1. Through resources/routes file
    GET /customer/{id} any.pkg.CustomerController.get
    POST /customer any.pkg.CustomerController.create  
    ...  
  2. Through action method annoation as shown above
See the documentation for more about routing

Model and DAO

ActFramework support Morphia for MongoDB and Ebean for SQL. You can declare your Model class as a POJO with proper annotation. MorphiaDao and EbeanDao are provided to support find/save/delete entities:
@Entity  
public class Customer {
      @Id
      private ObjectId id;
      private String name;

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

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

      public void setName(String name) {
          this.name = name;
      }  

      public String getName() {
          return this.name;
      }
}
public class CustomerController {
      @Inject MorphiaDao<Customer> dao;

      @GetAction("/customer")
      public Iterable<Customer> list() {
          return dao.findAll();
      } 

      @GetAction("/customer/{id}")
      public Customer get(String id) {
          return dao.findById(new ObjectId(id));
      }  

      @PostAction("/customer")
      public String create(Customer customer) {
          dao.save(customer);
          return customer.getId().toString();
      }
}
See the documentation on more about Model and DAO

Jobs and scheduler

public class MyClass {
      @Every("2s")
      public void jobA() {
          ...
      }  

      @InvokedAfter("MyClass.jobA")
      public void runAfterJobA() {  
        ...
      }   

      @OnAppStart
      public void jobB() {  
        ...
      }

      ...
}
See the documentation for more about jobs and scheduling

Events

public class CustomerController {
      @Inject
      EbeanDao dao;

      @Inject
      EventBus eventBus;

      public void create(Customer customer) {
          dao.save(customer);
          eventBus.trigger("new-customer", customer);
      }

}
@Mailer  
public class PostOffice extends Mailer.Util {

      @On("new-customer")
      @Async
      public void sendWelcomeLetter(Customer customer) {
          to(customer.getEmail());
          from("noreply@mycom.com");
          send(customer);
      }
}
See the documentation for more about events

Interceptors

  public class App {
      @Before(except = "login,logout")
      public void authenticate(ActionContext context) {
          if (!context.session().contains("username")) {
              if (context.isAjax()) {
                  throw new UnAuthorized();
              } else {
                  redirect("/login");
              }
          }
      }

      @Action(value = "/login" methods = {H.Method.GET, H.Method.POST})
      public void login() {
          ...
      }
  }
@With(App.class)  
public class CustomerController() {
      ...
}
See the documentation for more about interceptors

More features

  1. Sending Email
  2. Creating CLI commands

Comparing to PlayFramework v1.x

Project layout

Controller and action methods

  • Play controller must extends play.mvc.Controller. Action method must be void and static
  • Act controller does not need to extend any class. However extending act.controller.Controller.Util makes it easy to use renderXxx methods. Act action method does not need to be static. Act action method can return object

Routing

Templates

  • Play use groovy as default template engine
  • Act use Rythm as default template engine
  • Both framework support plugin different template engine

Models and DAO

  • Play's DAO methods are built into play.db.Model. Sub class get the data access capablitity via byte code enhancement
  • Act framework does not require Model class to extend any class. ActFramework inject default DAO implemenation to host class (e.g. a Controller, or Mailer) to provide DAO capablity

SQL Database access

  • Play use JPA/Hibernate to achieve SQL database access
  • Act use Ebean to achieve SQL database access

MongoDB access

  • Play use PlayMoprhia plugin (created by author of ActFramework) to access mongodb
  • Act use Morphia plugin to access mongodb

Jobs

  • Play job must be put into a class that extends play.jobs.Job. Each class implement one job logic
  • Act job is just a public void method without parameters. The class hosting job method does not require to extend any class

Events

Asynchronous http request handling

i18n

  • Play provides an easy to use i18n support
  • Act support i18n through Rythm's i18n() extension. Act's i18n support needs to be refined and improved

Cache

Sending email

Testing

  • Play provides a very descent testing facilities
  • Act relies on standard junit to implement application testing. Act also provides a specific act-test to support application's Model test. At the moment Morphia support is provided.

Security

  • Play provides limited security support. However there are some third party plugins like Deadbolt and play-aaa (created by author of ActFramework)
  • Act provides authentication/role based authorization/accounting via act-aaa

Modules and depedencies

  • Play applied it's specific way to manage modules and dependencies
  • Act relies on maven to manage dependencies and modules

Database evolutions

  • Play provides database evolution support
  • Act does not provide specific support on database evolution.

logging

  • Play provides a Logger class with static logging method. See document
  • Act does not have any specific class for logging. Developer could use any Logging solution (e.g. Log4J) in their application. However developer are also free to use App.logger to create log items.

Deployment

  • Play can be deployed as a fullstack application or as a war file in JEE application servers
  • Act support only fullstack application deployment at the moment (0.1.1-SNAPSHOT)

Resources