-
Notifications
You must be signed in to change notification settings - Fork 1
Model
The foundation of data driven web applications obviously is the data model. To avoid re-inventing the wheel, we rely on proven ORM solutions for the Java environment but have to add a little more specific details.
The available ORMs / storage backends are:
- Java Data Objects (JDO)
- CoreMedia Adaptor (CoMA)
- MongoDB Morphia
- Objectify
- Java Persistence API (JPA)
- EBean
The first implementation of a storage layer for Tangram was the Java Data Objects
(JDO) implementation DataNucleus Access Plattform. There is no
second implementation of JDO available. The separate Package org.tangram.nucleus
as the specialized variant of org.tangram.jdo
stems from the formlerly
available org.tangram.gae
which also used this API.
To be able to use DataNucleus, that compiled classes need to be "enhanced" (byte code transformed to include database acccess methods). The gradle-tangram plugin does this automatically for you. If you don't want to use that plugin refer to the DataNucleus documentation.
With the JDO solution it is also possible to place model classes as code resources in the JDO based storage backend.
These classes are created as instances of org.tangram.nucleus.Code
with a
mime type of application/x-groovy
. The code needs too be a full persistence
capable class implementation for JDO/DataNucleus and can be a subclass of the
Java based static classes. The annotation is not important in this case. It is
recommended to place the name of the superclass of the implemented class here,
to receive help items in the Tangram editor left of the code text.
After the start of the application these models are added to the list of available model classes and can be used like standard Java based model classes (persistence capable in JDO lingo). The byte-code transformation called "enhancing" (s.a.) is handled by an internal Tangram component internally on startup or any change of the classes in the code parts of the content repository.
Through the CoreMedia Adaptor CoMA it is possible to use the Database of a CoreMedia (versions 5.2/2008 and up) Content Server - Content Management Server, Master Live Server, Replication Live Server - as the read only data source for a tangram instance.
The mapping of content to Java instances is quite limited at the moment since though.
Tangram contains a module JPA to use Java Persistence API based model implementations as the storage backend.
All of the supported JPA implementations need or support byte code transformations after the compilation of the model describing classes. This byte code transformation is called "enhancing" with DataNucleus, Hibernate, and OpenJPA while EclipseLink calles it "weaving".
This being said it is obvious that special variants of the module need to be available containing byte code transformed class files for the JPA implementation in use.
Except DataNucleus all of the JPA implementations also support model classes without byte code transformation and Tangram contains a "clean" version of the JPA module for that purpose.
The Tangram gradle plugin again supports automatic byte code transformation for the JPA implementation in use which is automatically discovered from the compile time class path.
EBean is a lean ORM implementation similar to JPA in its syntax for the model classes. Like with other ORM solutions the code of the model classes must be byte code transformed to be used.
Again the Tangram gradle plugin automatically discoveres the use of EBean and transforms the compiled model classes.
When you decide to limit yourself to the use of MongoDB as your database of choice - which is very well supported with JDO/DataNucleus and supported with some JPA implementations - you can consider using the Morphia Java API for MongoDB.
With the Morphia solution it is also possible to place model classes as code resources in the - in turn - Morphia based storage backend.
These classes are created as instances of org.tangram.morpcia.Code
with a
mime type of application/x-groovy
. The code needs too be a full entity class
implementation for Morhpia and can be a subclass of the Java based static classes.
The annotation is not important in this case. It is recommended to place the name
of the superclass of the implemented class here, to receive help items in the
Tangram editor left of the code text.
After the start of the application these models are added to the list of available model classes and can be used like standard Java based Morphia model classes (Entities in Morphia lingo). Update of the additional classes for models is handled by a Tangram component internally on startup or any change of the classes in the code parts of the content repository.
Another data model layer option which is also related to a given backend is Objectify. It can be used in conjunction with the data store of the Google App Engine. It forms the foundation of a new Google App Engine support for Tangram.
In addition to the ORM solutions usable with Tangram there are some extensions and constraints built on top of the plain ORM layer.
The main contraint vor model classes to be usable within Tangram is, that they
must implement the org.tangram.content.Content
interface.
Any of the content base classes provided by the ORM specific modules of Tangram implements this interface and provides all the necessary details. If you use derived classes you are safe.
package org.tangram.example;
import javax.persistence.MappedSuperclass;
import org.tangram.content.Content;
import org.tangram.ebean.EContent;
@MappedSuperclass
public abstract class Linkable extends EContent {
private String title;
private String shortTitle;
private String keywords;
} // Linkable
EBean example
Tangram supports structured text in a property of a class. This structured text can be either HTML fragments (divs and ps) or markdown.
If the getters and setters of the property use char[]
as the property type,
this property is handled as a HTML fragment holder and editing takes place through
the CKEditor in the Tangram editor module.
If you prefer to edit structured text as markdown, you have to wrap your internal
data as org.tangram.content.Markdown
.
package org.tangram.example;
import javax.jdo.annotations.PersistenceCapable;
import lombok.Getter;
import lombok.Setter;
import org.tangram.content.Markdown;
@PersistenceCapable
public class Article extends Linkable {
@Getter
@Setter
private char[] text;
private char[] markdown;
public Markdown getMarkdown() {
return new Markdown(markdown);
}
public void setMarkdown(Markdown markdown) {
this.markdown = markdown.getContent();
}
} // Article
JDO Example using DataNucleus Access Plattform
Besides the getter and setter constraints you are free to store the data internally
as String
, char[]
, or blob whichevery fits your storage needs better.
If you need to track the modification time of an object through the Tangram editor
module, you simply have to implement the org.tangram.mutable.HasModificationTime
interface and store a long
value together with the needed getters and setters.
All code implementations of Tangram implement this interface, so you will be able to check when you last modified the codes stored in the Tangram repository like you can do this on you local disk storage with file containing code.
Also the ftp module has been extended to make use of the modification time field.
In some situation you might only want to avoid that classes are instanciated
through Tangram and not in general. (Sometimes there might be limitations with
the model implementation leading to pseudo-abstract classes.) In such situations
you can add a Tangram specific annotation @Abstract
at the class level (The
org.tangram.annotate.Abstract
annotation) to let Tangram handle this class as
if it were abstract.
package org.tangram.example;
import javax.persistence.Entity;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import lombok.Getter;
import lombok.Setter;
import org.tangram.annotate.Abstract;
import org.tangram.content.Content;
import org.tangram.jpa.JpaContent;
@Entity
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
@Abstract
public class Linkable extends JpaContent {
@Getter
@Setter
private String title;
@Getter
@Setter
private String shortTitle;
@Getter
@Setter
private String keywords;
} // Linkable
Lomboked JPA Example intended for OpenJPA