| Red Hat Docs > Manuals > Red Hat Web Application Framework > |
This document contains a list of the most frequently asked questions concerning the Red Hat Web Application Framework persistence layer. For terminology and definitions, please see the the section called Persistence Glossary.
Q: Why does Red Hat Web Application Framework have a persistence layer? Why does it not just create the SQL when and where it is needed?
A: A persistence layer has been developed as part of Red Hat Web Application Framework for the purpose of encapsulating database access routines. This is desirable for at least two reasons: abstraction and database independence. By encompassing the SQL statements in Java objects, the database access routines are developed in a scalable environment. Also, the applications are isolated from the schema changes (which may occur in future versions) since the database access routines are encapsulated by a standard API. The second reason, database independence, is desirable because it means that the Java code can easily be ported from one database to another by changing a small set of centrally located files (as opposed to modifying every file that interacts with the database). In addition, our persistence layer makes database specific query optimizations that takes advantage of our application-specific domain logic (for example, setting hints appropriately).
Q: Why does the Red Hat Web Application Framework have a persistence layer instead of just using standard EJB? Is Red Hat reinventing the wheel?
A: Although we are not adopting EJB, Red Hat is closely following the development of the Java Data Objects specification, and there is a strong possibility that future versions of the persistence engine will follow the JDO specification.
Red Hat Web Application Framework is primarily a framework for building web applications, and Red Hat's reasoning for its current architectural direction is best summarized by Sun's own J2EE Blueprints:
http://java.sun.com/blueprints/corej2eepatterns/Patterns/DataAccessObject.html
In addition, there are numerous examples that one could concoct where an EJB server (at least initially) could be deemed to be an overkill given the problem being tackled. This is the sledge-hammer-to-crack-a-nut problem. In essence, the J2EE specification does not mandate a 2, 3, or multitier application model, nor realistically could it do so. The point is that it is important to use appropriate tools for a given problem space.
Given that the most common usage for Red Hat Web Application Framework deployment is, to use Sun's term, the "Web-centric application scenario", Red Hat opted for the "3-tier Web-centric" architecture, in which "[t]he Web container is essentially hosting both presentation and business logic, and it is assumed that JDBC (and connectors in the future) will be used to access the EIS resources."
Coarse-grained interoperation of Red Hat Web Application Framework with other systems would certainly be a sound application of EJB or JMS. However, Red Hat does not currently have clear requirements in this area. More activity is anticipated in this area during future Red Hat Web Application Framework implementations, initiated both by Red Hat and by others building on top of Red Hat Web Application Framework.
(As an aside, commercial J2EE containers such as WebLogic and Oracle's 9i typically make it a goal to provide a "simple mechanism for balancing load across several machines without too much thinking," even when you are only using the Servlet API, as opposed to EJBs.)
Regarding the other reasons for using EJBs outside of distributed objects, the following points should clarify the extent to which Red Hat is "reinventing the wheel":
Persistence: There are two standard types of persistence: Bean-Managed Persistence (BMP) and Container-Managed Persistence (CMP). BMP does not provide much advantage, and CMP, unfortunately, does not provide automatic SQL generation. In short, the Red Hat Web Application Framework persistence layer is designed to address a different set of requirements than CMP.
Connection pooling: Red Hat is not reinventing connection pooling; rather, its code is written against the J2EE-standard API for connection pooling, the JDBC 2.0 Optional Package.
Transaction monitoring: EJB's declarative-style transaction management is one of its more attractive features, but not compelling enough for Red Hat to make it the deciding factor in using EJBs. Red Hat does not "reinvent" transaction management, either; it simply leaves the applications responsible for managing transactions.
Red Hat has found, through input from prospective customers, partners, and analysts, that the market perspective on the necessity and appeal of the "full J2EE architecture" is not clear-cut. Being able to run Red Hat Web Application Framework atop a J2EE web container alone has benefits of its own: simplicity of development and deployment, low run-time overhead, and broad availability of stable open-source/affordable implementations. In other words, 3-tier Web-centric is the appropriate tool for Red Hat's primary problem space.
A: The Persistence API provides the following benefits:
It provides an abstraction for physical data models for greater database independence.
It isolates the java classes from data model changes (for example, if a column is renamed, no Java code must be changed).
It provides support for user-defined object types.
It decreases the amount of time it takes to implement a new object type.
It can automatically generate SQL statements that can be run on different databases. Thus, it is possible to write one PDL file that can be used on N databases. Without persistence, a developer may be required to write N different DDL scripts and then N different sets of SQL statements to use the tables.
A: Start with this book's table of contents which lists all available persistence documents. In addition, the the section called Domain Objects Tutorial in Chapter 5 introduces the API used by Red Hat Web Application Framework and provides you with code samples for implementing your own Domain Objects.
Additionally, you may want to consult the document on the section called Beginning with Data Objects, as well as material on the section called Filtering, Ordering, and Binding Parameters.
A: The best place to find a full explanation and examples is in the the section called Defining an Object Type in PDL. However, as a short summary, you must specify the following:
For each attribute:
A mapping of the attribute to the database column in which it resides.
The SQL type of the attribute. For instance, if the data type of the attribute is a string, the SQL type might be VARCHAR(20) or VARCHAR(4000) or even CLOB.
For each association, it is important to specify the Join Paths so that the persistence layer will know how to join the SQL tables to each other.
For each data query, a mapping from the returned attribute name to the data type of the attribute is required. This allows the code to know whether an INTEGER SQL type should be an INTEGER data type or actually a BigDecimal data type.
All of the metadata is required so that the persistence layer can successfully generate a data model as well as all of the events to manipulate the object.
A: At the top level of any project you will find a pdl directory. In there, you will find many PDL files that should provide plenty of examples.
A: PDL files should be kept in a directory at the same level as the SQL and src files. If the PDL does not contain any database specific queries (for example, something containing a "connect by" statement) then it should be placed in the default directory (/pdl/default/). Otherwise, you should create a copy of the query for each database and place it in the database specific directory and not in the default directory. Placing it in both the default directory and your database directory will cause a compile error. Also, it is common practice to place all database independent code in the default directory and break off database specific code into their own files. For instance, if my PDL file ACSObject.pdl contained an object type definition, a couple of associations, and a query that contained an outer join named allNamedObjects, it is common to place the file ACSObject.pdl without the query in the correct subdirectory of /pdl/default/ and place the query itself in the database specific directories in a file named query-<query_name>.pdl. In this example, the file would be named query-allNamedObjects.pdl
A: If you have a standard Object Type, you do not need to specify any events. The purpose of allowing Event declarations is to allow developers to override the dynamically generated SQL when the circumstances surrounding the event need to be special-cased, or when the developer wishes to write a more efficient query.
A: When you extend an object type, the new object type will inherit all the properties (attributes and role references) of the super type. A child object type can override the parent's attributes (but not role references), as long as the new attribute does not violate any constraints placed on the supertype's attribute. For example, suppose that the parties object type defines an email attribute that is required. That is, parties.email has multiplicity of 1..1. You can create a persons object type that extends parties. You cannot make the email address optional in the persons object type because it is already required by the supertype.
Suppose you are defining an object type named "ChewingGum" that extends ACSObject. To specify that an object type extends another, do the following:
Before defining your object type but after declaring your model, make sure to import the ACSObject type.
import com.arsdigita.kernel.*; |
When defining your object type, specify that the supertype of the "Chewing Gum" object type is "ACSObject" and import the namespace for ACSObject. In the PDL file, you currently write:
object type ChewingGum extends ACSObject {
---
} |
When you define your table in the database, make the primary key reference the acs_objects table. This is only required, however, when you manually specify your SQL. In most cases, defining the PDL will be enough to get your started (you must, however, still load the auto-generated table). The following shows how to manually define the table.
create table acs_objects (
object_id integer primary key
);
create table chewing_gum (
gum_id integer primary key
references acs_objects(object_id)
); |
When you create your Java class, you can extend the ACSObject class in the com.arsdigita.kernel package.
See the section called Object Type Inheritance for a longer example.
A: In CCM 4, ACSObject provided the following major benefits:
Universal identity for objects.
A means to focus common behaviors.
Red Hat Web Application Framework still provides both benefits, but there is no real need for the ACSObject domain class to not be abstract. The ACSObject Domain Class and object type continue to provide a single, unique object ID for all objects as well as a consistent interface for dealing with DomainObjects.
In addition, if you know the object_id of the ACSObject, it is possible to specialize the Domain Object to the correct type by using the DomainObjectFactory; for more information, refer to:
http://ccm.redhat.com/doc/core-platform/5.0/api/com/arsdigita/domain/DomainObjectFactory.html
A: A DataQuery can be seen as a named query. In TCL and JSPs, developers used to place the DataQuery directly in the code. Now, the persistence layer gives the query a name and puts it in the PDL file.
A DataQuery encapsulates SQL queries. You can retrieve a DataQuery by name from the PDL file, set filters on its attributes, execute the event, iterate over the result set, and access the attribute values.
Underneath, the actual SQL query and data model used are hidden from application code.
For more information, see the documentation on the section called Data Queries.
A: You can create a DataQuery by specifying an SQL query and as many attribute/column mappings as you like. You can then define bind variables or set filters on that query to gain the final query you wish.
A: The object key (Object Key) declared in the PDL files is used by the persistence system to uniquely identify a particular object in the database. For instance, the object key for acs_object is "id", which is the name of the attribute that maps to the object_id column in the acs_objects table.
Object keys can contain single values or they can be compound (they can be specified using 1 to N attributes). For more information, see the section called Object Key.
Q: How do I retrieve a DataQuery, DataCollection, or DataAssociation in the order I want (for example, there is a sort_order link attribute that I want to sort by)?
A: To do this, use the setOrder() method. For further information, see the section called Ordering.
A: The OID class encapsulates the details of the primary key of an object. You use instances of OID for retrieving an object from the database and you set the OID to a known value. You can also get an OID object from a DataObject.
Q: I would like to retrieve all instances of a particular object type (for example, com.arsdigita.kernel.User). How do I do this?
A: There is a method on com.arsdigita.persistence.Session (http://ccm.redhat.com/doc/core-platform/5.0/api/com/arsdigita/persistence/Session.html) that retrieves a DataCollection for all instances of a data object type. The DataCollection can be filtered to narrow the results. It is possible to request individual properties of the collection without instantiating an object. You can also instantiate the data object, and if you use the DomainObjectFactory, you can get a DomainObject from the data object. It is recommended, however, that you do not instantiate the object unless absolutely necessary, because creating the object consumes extra memory resources as compared to iterating through the DomainCollection.
As a specific example, to get all users in the system, you can execute the following line:
DataCollection authors =
SessionManager.getSession().retrieve("com.arsdigita.kernel.User"); |
For more information, see the section called Creating and Retrieving Objects in Java.