ActiveRecord is to Ruby on Rails as Active Objects is to Java. Ideally it would be called AwesomeObjects. At last, persisting data for your Java web application is not all xml, POJOS, EJBs and did I mention xml? I don’t hate xml but I find configuring your application extremely inefficient after working with other frameworks that utilize convention over configuration.
Why do I have to specifiy a log4j properties file, hibernate persistance.xml configuration. And there’s soooo many options of how to develop: JPA, Wicket, OJB, Spring, Struts, Torque, Cayenne, Jaxor, TJDO, JDBM, pBeans, JPOX, Simple ORM, Ibatis, XORM, Speedo, Smyle, PAT, LiDO, JDO, IntelliBO, KodoJDO, Hamlets, Faces, RIFE, Shale, Sling, Stripes, Vaadin, Poopdeck (okay, I just made that one up). Point is that It can be a real headache to develop a Java web app.
Furthermore, why do I have to create my POJOs and SQL for my database? Why can’t a framework just create my data objects, along with nice RESTful CRUD operations for each. Why, crow, why?! So at least for the moment, finding ActiveObjects is lemonade to quench my thirst for answers.
The documentation is lacking for ActiveObject but I was able to get it working quite easily. As soon as I saw the interface annotations for this library, I knew it would be a blast working with - assuming the pesticides had been spread around the source code e.g. no bugs. The website can be found here: http://java.net/projects/activeobjects/pages/Home
Below I have an example on how to use Active Objects. Let us assume our web application has the concept of “templates” which we want to persist in the database. Templates can have questions, instances and permissions (those are all just interfaces too). As you can see below we just define java interfaces with get and set methods. You don’t implement the methods, just define them for reflection by AO. Also every interface will have a getID()
method inherited from the parent Entity class. You can also add any annotations to describe any more specific mappings between your Java interface, other interfaces and also types for the database table. For example, below I use @OneToMany
and @SQLType(Types.CLOB)
.
import java.sql.Timestamp;
import java.sql.Types;
import net.java.ao.Entity;
import net.java.ao.OneToMany;
import net.java.ao.schema.SQLType;
public interface Template extends Entity {
public String getName();
public void setName(String name);
@SQLType(Types.CLOB)
public String getDescription();
@SQLType(Types.CLOB)
public void setDescription(String description);
public String getIncludePattern();
public void setIncludePattern(String includePattern);
public String getExcludePattern();
public void setExcludePattern(String excludePattern);
public String getCreateDate();
public void setCreateDate(String createDate);
public Timestamp getLastUpdated();
public void setLastUpdated(Timestamp lastUpdated);
public Integer getCurrentInstance();
public void setCurrentInstance(Integer currentInstance);
@OneToMany
public Permission[] getPermissions();
@OneToMany
public Instance[] getInstances();
@OneToMany
public Question[] getQuestions();
}
I had attempted to use Active Objects with a Blackboard Building Block (also called a B2), but the Blackboard API didn’t seem to want to give me a proper information on how to connect to the database (Bb v 9.1.7). Therefore I never actually got around to using this code, but I’ll share it with you since you’re already here. And I wanna give a big shout out to Peter Fokkinga’s since I’m using his DbUtils class which can be found on edugarage.
// a class that I would use to get the Active Objects Database connection
// however didn't use due to the inconsistent behavior of data returned from
// Blackboard's VirtualInstallation (found case in 9.1.7 where bad database host was given
public class Database extends net.java.ao.DatabaseProvider {
static Database _instance;
static EntityManager _manager;
@Override
public Class<? extends Driver> getDriverClass() throws ClassNotFoundException {
VirtualInstallation vi = Database.information();
if(vi.getDbType().equals("mssql")) return (Class<? extends Driver>) Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver");
else if(vi.getDbType().equals("oracle")) return (Class<? extends Driver>) Class.forName("oracle.jdbc.driver.OracleDriver");
return null;
}
@Override
protected String renderAutoIncrement() {
VirtualInstallation vi = Database.information();
if(vi.getDbType().equals("mssql")) return "IDENTITY(1,1)";
return "IDENTITY";
}
public static Database instance()
{
if(_instance == null) {
VirtualInstallation vi = Database.information();
String dbInstance = (vi.getDbInstance() != null ? vi.getDbInstance() : "") + "/" + vi.getDbUser();
DbUtils.SupportedDatabase dbType = DbUtils.SupportedDatabase.fromDriver(vi.getDbType());
String jdbc = dbType.getConnectString(vi.getDbHost(), vi.getDbPort(), dbInstance);
_instance = new Database(jdbc, vi.getDbUser(), vi.getDbPass());
}
return _instance;
}
public static EntityManager manager() throws PlugInException
{
if(_manager == null) {
_manager = new EntityManager(instance());
}
return _manager;
}
}
So how would we use this Database class? Assuming the virtual installation worked consistently, below is an example using Spring with controller request mappings of how to do an edit and update.
Assuming you had the Database class from above then you could do something like this in your controller, below I really only use the find() but you can use all the goodies from Active Objects (see here: http://activeobjects.java.net/0.8.2/api) like create, count, find, get, delete, and even migrate (creates your table for you just based on the interface definitions). Yes, you don’t use a POJO class, you use an POJO interface - which is really just genius.
@RequestMapping(value="/templates/{id}", method = RequestMethod.GET)
public String get(@PathVariable("id") Integer id, Model model) {
Template[] templates = Database.manager().find(Template.class, "id = ?", id);
// We didn't find a template with this id so just show the index page
if(templates.length == 0) return "redirect:/templates/";
// found a template with this id, so let's edit that template
model.addAttribute("template", templates[0]);
model.addAttribute("helper", new ViewHelper());
return "templates/edit";
}
@RequestMapping(value="/templates/{id}", method = RequestMethod.POST)
public String update(HttpServletRequest request, @PathVariable("id") Integer id,
Model model) {
// Get the requests for this template
String name = request.getParameter("template_name");
String description = request.getParameter("template_description_text");
String includePattern = request.getParameter("include_pattern_text");
String excludePattern = request.getParameter("exclude_pattern_text");
// Find the template and save the new values
Template[] templates = Database.manager().find(Template.class, "id = ?", id);
if(templates.length != 0) {
templates[0].setName(name);
templates[0].setDescription(description);
templates[0].setIncludePattern(includePattern);
templates[0].setExcludePattern(excludePattern);
templates[0].save();
}
return "redirect:/templates/";
}
f I come onto any projects that need a standalone website I would like to combine the Grails or Play! framework and use ActiveObjects for the Model part of the MVC framework - resulting in sheer Java bad-ass-ery. I know Java is a huge language and web frameworks only covers a small part of it’s ability; however, I really like the idea of Java becoming a competitor for simple turnkey web apps, the same ones that can be made in a short time using the conventions of CakePHP, Zend, Django and Rails. Developing in Play! and ActiveObjects is just plain easier. I don’t imagine that JEE, ContextFactories and extensive xml configurations are just going to magically disappear (you know job security and all that), but this is the age of designing RESTful web services and shunning away the complexities of CORBA and even SOAP.
I’m sure in ten years, something new will be along to lay rest to REST (sorry I couldn’t resist) but for now, the general consensus seems to be that web applications should be very simple to develop and maintain, i.e. wham, bam, thank you mam.