Applying Code Generation Approach in Fabrique
Business Objects Framework Showcase
Here we proceed with a simple showcase to highlight cool features of code generation.
Building the model
With Visual Fabrique we draw a simple diagram:
Here we defined two business objects: Project and Developer, and a relationship between them that says for each project there can be zero or many developers and each developer always participates in one project.
For each business object there is a predefined finder method Find All () (which we call "query") that returns all objects for a given type. In Visual Fabrique we can simply add a new query for Developer that would return all developers who participate in a given project. We code this in FabQL:
Then, we add some business logic to the Developer object by writing a method in FabScript that would say whether a given developer participates in a specified project:
Running the Code Generator
Up to this point we have been modifying Business Object Model. Now it's time to use it. We can now run Fabrique Compiler to generate an actual implementation for the persistence level. But first, we should decide on target platform. There're two options currently available:
- EJB CMP container (WebLogic/JBoss/Orion)
- Hibernate (JBoss/Orion/Tomcat)
In either case, the complier will generate all necessary classes and deployment descriptors and prepare them for deployment. However, regardless of the target platform, there is always part which is the same (what we called "Platform independent code" above). For each business object, two interfaces are generated:
- Business Object interface – with methods that expose the object’s attributes, relationships and business
methods. The name of the interface is the same as the name of the business object. Here is such an interface from
our sample, saved in a file Developer.java:
package model; public interface Developer extends jetbrains.fabrique.bof.rt.BusinessObject { java.lang.Long getPrimaryKey(); java.lang.String getFirstName(); void setFirstName(java.lang.String firstName); java.lang.String getSecondName(); void setSecondName(java.lang.String secondName); model.Project getProject(); void setProject(model.Project project); public boolean isParticipant(java.lang.String projectName); } - Business Object Manager interface– with methods that manage the object's lifecycle and perform fetching
of objects by means of the queries we created. For our sample, here is a corresponding manager for the Developer
object saved in a file DeveloperManager.java:
package model; public interface DeveloperManager extends jetbrains.fabrique.bof.rt.BusinessObjectManager{ public model.Developer create(); public model.Developer create(jetbrains.fabrique.bof.rt.UnitOfWork unitOfWork); public model.Developer find(java.lang.Long primaryKey); public java.util.Collection findAll(); public java.util.Collection findDevelopersByProject(java.lang.String projectName); }
It's safe to depend on these two interfaces from any part of the model. We will consider use cases in the next chapter.
So, what has the compiler done for us? If we run the complier against the EJB/Orion configuration the following things will be generated:
- Implementations of local, remote and home EJB interfaces
- All necessary deployment descriptors
- All necessary code that provides a bridge between Fabrique's Business Object framework and the EJB container
If we run the compiler against the Hibernate/Tomcat configuration it will result in the following output:
- Implementations for Hibernate beans
- Hibernate mapping model
- All necessary code that provides a bridge between Fabrique's Business Object framework and Hibernate