| ||||||||||||||||||
Resin 3.1 Documentation Examples Changes Quercus Database Amber EJB SOA/ESB IoC JMS Servlet JMX Hessian Security Field Property Create Query Many-to-One One-to-Many Many-to-Many Inherit Sessions |
Amber's persistence supports a field-based relational model: each Java field represents a database column. The tutorial shows the configuration, classes, and client code for a single-table entity. OverviewAmber provides a Java model for a relational database, following the Java Persistence standard. A typical project starts planning with the relational database schema and matching the Java model to that schema. This data-driven approach contrasts with a transparent persistent object approach which starts with Java classes and then tries to create storage to match the Java model, an approach more typical of object-oriented databases. While the transparent persistence model may be appropriate for some applications, the persistence specification wisely leaves transparent persistence to other products and specifications, and concentrates on the relational database model. In a way, Amber simply provides an extension to SQL queries, returning fully-populated Java objects instead of just returning primitive values like Strings. That somewhat understates Amber's capabilities since the Java objects are live, updating the database in a object-oriented fashion, and also provides caching. Still, viewing Amber as a SQL extension supporting relations and objects is a good starting model. The tutorial uses "entity" to mean a persistent object. Amber's entities are far simpler than the "EntityBean" of EJB 2.1. Files in this tutorial
Database ModelThe tutorial's design begins with its database model. The table is a collection of school courses, each with an assigned teacher. The table has an integer primary key "id" and two string data fields, "course" and "teacher". CREATE TABLE amber_basic_courses ( id INTEGER PRIMARY KEY auto_increment, course VARCHAR(250), teacher VARCHAR(250) ); INSERT INTO amber_basic_courses VALUES('Potions', 'Severus Snape'); INSERT INTO amber_basic_courses VALUES('Transfiguration', 'Minerva McGonagall'); To judge the complexity of Amber, it's useful to compare the Amber
Java model to the simplest possible Java model. The simple model
has a single class, package example; public class Course { private int id; private String course; private String teacher; } The minimal class is missing any description of its intended use as a persistent object, information needed for maintainable code. In theory, a persistent object tool could use the minimal class automatically, but without more information, the source doesn't properly describe the class behavior. Fortunately, the JDK 1.5 metadata annotations can describe the persistence information in a maintainable, self-documenting way. Of course, those annotations might have default values and should be overridable by an optional XML configuration file, but it's necessary to annotate the intended function of the entity in the Java source itself to properly document and validate the Java code. OverviewTo find and enhance a persistent Java bean, Amber follows the following procedure.
By the end of initialization time, Amber has enhanced CourseBean and made it available to the application in the persistence-unit "example". A servlet will then lookup the CourseBean with the following procedure:
Persistent Object ImplementationThe minimal Java class needs the following annotations to produce a maintainable persistent object:
The following code shows the Amber annotations for the course entity. As a quick comparison with the minimal Java class shows, Amber is close to the simplest possible implementation of the Java model which provides the necessary annotations in the list. package example; import javax.persistence.*; @Entity@Table(name="amber_basic_course") public class Course { @Id@Column(name="id") @GeneratedValue private int _id; @Basic@Column(name="course") private String _course; @Basic@Column(name="teacher") private String _teacher; public String course() { return _course; } public String teacher() { return _teacher; } } The example uses the @Entity - marking the class as persistentCourse uses the @Entity to mark the Java class as a field-based persistent object. @javax.persistence.Entity @javax.persistence.Entity declares a Java class as an entity bean. Since the @Id annotation marks a field, the bean's fields are persistent, as in JDO. Unlike JDO, only the bean itself or its children may access the fields. Other classes must use the bean's methods, like getters or setters, to indirectly access the fields. If the @Id annotation had marked a property method, the methods would be enhanced. @Table - naming the table@javax.persistence.Table specifies
the SQL database table name to be used. If @javax.persistence.Table(name="amber_basic_course") @Id - marking the primary keyThe @Id attribute marks the
bean's primary key. The @Id @Column(name="id") @GeneratedValue private int _id; The optional The optional @Column annotation specifies the SQL column name. The default SQL column for an @Id is the property name. @Basic - marking a persistent fieldThe @Basic attribute marks a basic data column like a string or integer or double. @Basic @Column (name="course") private String _course; @Column - naming the columnThe optional @Column annotation specifies SQL column name. For a @Basic field, the default column name is the field name. Under the covers: bytecode enhancementAmber processes the bean's class to implement field-enhancement. In practice, this means replacing setting a field with a Resin setter and getting a field with an Amber getter. public String course() { return _course; } For example, Resin would process the above method and produce something like: public String course() { return __caucho_get_course(); } Client ServletThe client servlet queries the database for all courses and lists
them. It uses the public class CourseServlet extends HttpServlet { @PersistenceUnit(name="example") private EntityManager _manager; public void service(HttpServletRequest req, HttpServletResponse res) throws java.io.IOException, ServletException { PrintWriter out = res.getWriter(); res.setContentType("text/html"); out.println("<h3>Course Details</h3>"); Query query = _manager.createQuery("SELECT o FROM Course o"); for (Course course : (List<Course>) query.listResults()) { out.println("course: " + course.course() + "<br>"); out.println("teacher: " + course.teacher() + "<br>"); out.println("<br>"); } } } <h3>Course Details</h3> course: Potions instructor: Severus Snape course: Transfiguration instructor: Minerva McGonagall EntityManager
@PersistenceContext(name="example") The example uses dependency injection to configure the entity manager. <servlet servlet-name="basic" servlet-class="example.CourseServlet"> </servlet> Query
Query query = _manager.createQuery("SELECT o FROM Course o"); The SQL used for EJB 3.0 is an enhanced database SQL. The query can return objects directly ("SELECT o") and it can traverse relations ("o.next.data"). In most other respects, it can be thought of as regular SQL. List list = query.listResults(); The query returns its values with Resin ConfigurationThe Resin configuration is fairly straightforward. Resin needs to start the ejb-server, configure the JDBC data-source, and list the beans that will be used. <web-app> <!-- server configuration --> <ejb-server data-source="jdbc/resin"/> <servlet servlet-name="basic" servlet-class="example.CourseServlet"/> <servlet-mapping url-pattern="/basic" servlet-name="basic"/> </web-app> The <ejb-server> configures Amber support. persistence.xmlThe persistence.xml lives in META-INF/persistence.xml. Since we're developing in WEB-INF/classes, the file will be in WEB-INF/classes/persistence.xml. <persistence xmlns="http://java.sun.com/xml/ns/persistence" version="1.0"> <persistence-unit name="example"> <class>example.CourseBean</class> <exclude-unlisted-classes/> </persistence-unit> </persistence>
|