Enterprise Objects Overview

The Enterprise Object technology provides a set of flexible, modular, and mature object-oriented frameworks that allow you to build data-driven applications without needing to worry about an application’s data sources. It allows you to work with objects rather than directly with the data source, which reduces development time, reduces the amount of code you need to write, and allows you to build reusable, portable business objects that can be shared between many different applications.

Enterprise Objects specializes in providing mechanisms to retrieve data from various data sources, such as relational databases via JDBC and JNDI directories, and mechanisms to commit data back to those data sources. These mechanisms are designed in a layered, abstract approach that allows you to think about data retrieval and commitment at a higher level than a specific data source or data source vendor.

In marrying relational databases to object-oriented programming, the fundamental problem is how to define the mapping between each world. To solve this problem, Enterprise Objects provides tools and frameworks for object-relational mapping to allow you to work with data objects, rather than directly with database tables. These data objects are referred to as enterprise objects.

The core element to this mapping is a model file that you build with a tool called EOModeler. This tool is documented in EOModeler User Guide, which you should read before reading this document. By understanding how to build models that Enterprise Objects can use, you'll be better equipped to understand the concepts in this book.

This chapter introduces the major concepts in Enterprise Objects. It is divided into the following sections:

What Does Enterprise Objects Do?

Enterprise Objects is a complex system that does much more than just communicate with data sources. It also includes objects that participate in user interface-to-data source synchronization, it helps you build business logic into Java objects, and it provides an object-oriented framework with which you develop data-driven Web and desktop applications. Enterprise Objects does the following:

Figure 2-1 gives a high-level view of the core layers of Enterprise Objects.

Figure 1-1  High-level view of Enterprise Objects
High-level view of Enterprise Objects

Why Enterprise Objects?

There are two common design patterns in database application development, both of which suffer from the same fault. The first design pattern is to implement business logic in user interface code. The second design pattern is to mix business logic with the logic for accessing business data. A variation of the second pattern is to put business logic rules in the data store using triggers, stored procedures, and the like.

In the first case, Swing user interface code or HTML is mixed in the same class with Java business logic. In the second case, Java business logic and SQL code are mixed within the same class. In both cases, this practice of mixing presentation code with business logic code greatly reduces the reusability of those objects. Aside from violating good object-oriented programming practices, both approaches distract developers from their primary task: building applications that use and profit from custom business logic.

In short, mixing business logic with application logic, user interface logic, or with data access logic results in these consequences:

Fortunately, there is a third approach to database application development that allows you to build clean, reusable, maintainable, and robust business objects without needing to mix SQL, HTML, or Swing code within Java business classes. This is the approach the Enterprise Object technology offers.

It allows you to put business rules in business objects called enterprise objects. Enterprise objects have no knowledge of the data store or data access mechanism from which they derive their data, nor do they have knowledge of the user interfaces that use the data they provide. Enterprise object classes are made up exclusively of Java foundation classes—they contain no SQL, no HTML, and no Swing code. Rather, they work within a hierarchy of other classes that perform specific functions.

This clean separation of business logic, user interface logic, and data access logic allows you to focus on the task of writing business logic and building applications that benefit from that logic.

What Is an Enterprise Object?

An enterprise object is an instance of a class that implements the com.webobjects.eocontrol.EOEnterpriseObject interface. You can think of an enterprise object as a business object. It contains your business rules and represents the data on which your business relies.

An enterprise object is like any other object in that it couples data with the methods for operating on that data. However, an enterprise object has certain characteristics that distinguish it from other classes:

An enterprise object is an instance of a class (such as com.webobjects.eocontrol.EOGenericRecord) that has attributes that correspond to the data values from the database row or record from which the object is instantiated. An enterprise object has a corresponding model that defines the mapping between the class’s object model and the database schema. However, an enterprise object doesn’t explicitly know about its model.

This model (an EOModel) allows Enterprise Objects to map database tables to enterprise objects (Java objects) so that a database row maps to an instance of a particular enterprise object class. For instance, a database table named “LISTING” maps to an enterprise object class, which is usually an instance of or subclass of com.webobjects.eocontrol.EOGenericRecord, which implements the com.webobjects.eocontrol.EOEnterpriseObject interface.

You control what kind of enterprise object class a given database table maps to. Figure 2-2 illustrates the mapping between a database table and an enterprise object.

Figure 1-2  Mapping between a database table and an enterprise object
Mapping between a database table and an enterprise object

You have a good deal of control over how this mapping happens. For example:

One of the most powerful features of Enterprise Objects is that it maps database joins to relationships between objects. Again, you have a great deal of flexibility with regard to how this mapping occurs. You can map to-one, to-many, and many-to-many relationships, and you can control the business rules that govern those relationships, such as delete rule, optionality, and ownership.

Figure 2-3 illustrates the mapping between a database table and an enterprise object. A single row in the LISTING table is related to one or more rows in the LISTING_PHOTO table: there is a to-many relationship between the LISTING table and the LISTING_PHOTO table.

When an enterprise object is instantiated from the LISTING table, placeholder objects (called faults) for related rows in the LISTING_PHOTO table are also instantiated. When a Listing’s photos relationship is accessed, those faults are turned into fully formed enterprise objects, which allows the Listing enterprise object to access data in the ListingPhoto enterprise objects. All the SQL you would normally need to write to resolve the joins is handled for you automatically.

Faulting is explained in more detail in Faulting.

Figure 1-3  Mapping between two joined tables and enterprise object instances
Mapping between two joined tables and enterprise object instances

Core Layers

Now that you understand the basic ideas behind enterprise object instances, you need to understand how those instances work within the Enterprise Objects frameworks.

Enterprise Objects is composed of many layers, each of which is responsible for a particular set of tasks in an application. A layer generally corresponds to a Java package so that the com.webobjects.eoaccess package is referred to as the access layer and the com.webobjects.eointerface package is referred to as the interface layer.

The first layer you work with is referred to throughout the documentation as the control layer and is composed of the classes in the com.webobjects.eocontrol package. Many things happen at the control layer, but the most important thing to remember is that the control layer is where the graph of enterprise objects lives. This layer is not concerned with and has no direct knowledge of how data is collected into it.

The object graph is the organizing principle of Enterprise Objects. The object graph refers to a graph, or structure, of business objects and the objects that support those business objects, such as editing contexts. In an Enterprise Objects application, the object graph is made up of editing contexts, which in turn contain enterprise objects—objects instantiated from classes that implement the EOEnterpriseObject interface. Editing contexts allow enterprise objects to know about each other and also to know when data from other layers arrives at the control layer and affects the data within enterprise object instances.

The advantage of the object graph is that it allows you to work with database content as Java objects, rather than as SQL or another more primitive language. For example, rather than managing a particular data source’s primary keys, you can rely on Enterprise Objects to manage primary keys based on the operations you make within a given object graph. Likewise, rather than managing join tables for a particular database, you simply manipulate related enterprise objects in the object graph and then rely on Enterprise Objects to generate the appropriate SQL to propagate changes to the data source.

The control layer is where you insert new enterprise objects, delete enterprise objects, invoke fetches and commits, manipulate relationships, and most importantly, it is where you implement business logic. The operations you perform at the control layer are eventually transformed into SQL and vendor-specific or vendor-optimized calls at lower levels of the technology, as illustrated in Figure 2-4.

Figure 1-4  Java method invocations map to SQL expressions
Java method invocations map to SQL expressions

Two of the most common challenges new developers face when coming to the Enterprise Object technology from other database development environments is to think at a level higher than SQL and to not think of any particular data source vendor. So, once you begin to trust that Enterprise Objects produces SQL for you and that you can invoke methods on business objects that result in database operations, you are better prepared to understand the technology.

Key Concepts of Object-Oriented Programming

There are a few key concepts you should understand when learning the Enterprise Objects frameworks. They are all rooted in good object-oriented design principles and many of them share ancestry with Apple’s Cocoa object-oriented application framework. Although understanding these concepts isn’t necessary to develop Enterprise Objects applications, familiarity with them helps you gain a better appreciation of how the technology works.

That said, there is a lot of information to digest when learning Enterprise Objects and you won’t need to put these concepts into use until after you know the basics. So you may want to skip this section and come back to it later on.

Key-Value Coding

Key-value coding is a data access mechanism in which the properties of an object are accessed indirectly by key or name, rather than directly as fields or by invocation of accessor methods. It is used throughout Enterprise Objects but is perhaps most useful to you when accessing data in relationships between enterprise objects.

Key-value coding enables the use of keypaths to traverse relationships. For example, if a Person entity has a relationship called toPhoto whose destination entity (called PersonPhoto) contains an attribute called photo, you could access that data by traversing the keypath toPhoto.photo from within a Person object.

Keypaths are just one way key-value coding is an invaluable feature of Enterprise Objects. In general, though, it is most useful in providing a consistent way to access an object's data. Rather than needing to know if an object's data members have accessor methods, what the names of those accessor methods are, or if the data is accessible through fields, all you need to know are the keys that represent an object’s data. Key-value coding automatically finds the data, regardless of how the object provides its data. In this context, key-value coding satisfies the classic design pattern principle to “encapsulate the things that varies.”

Using the previous example, if you're working in a class that has access to a PersonPhoto object, you can get the photo data in the PersonPhoto object by invoking valueForKey("photo"). You don't need to know if the PersonPhoto object returns that data by providing an accessor method called photo or getPhoto, or through a field. Key-value coding is another feature of Enterprise Objects that reduces the amount of code you need to write and helps you write reusable business objects.

Advanced key-value coding concepts are discussed in:

In addition, the API reference for com.webobjects.eocontrol.EOKeyValueCoding and for com.webobjects.foundation.NSKeyValueCoding provide more detailed information on key-value coding.

Delegation

Delegation is a way of extending a class in an object-oriented framework. Whereas subclassing means that you write a new class based on an existing class, delegation means that you make use of hooks that the class provides to change its behavior. In object-oriented design methodology, delegation is a form of class composition.

Delegation does just what it suggests: When you implement an object’s delegate, you are telling the object to use the behavior that your delegate specifies at specific points in an application's execution. So for example, in the case of an editing context object, if you write a delegate for this object, the editing context object checks your delegate at certain points in an application’s execution and uses the logic your delegate specifies instead of or in addition to its own. The pseudocode in Listing 2-1 illustrates delegation.

Listing 1-1  Pseudocode illustrating delegation

if (delegateIsImplemented) {
    useDelegateImplementation();
} else {
    useDefaultImplementation();
}

Compared to subclassing, delegation is usually a more elegant solution to extend or customize the behavior of a class. A class’s delegate provides hooks for those parts of a class that the class’s designer wants to be customizable. Furthermore, subclassing can be a tricky, tedious, and undesirable task for large classes that have many dependencies on other classes. Delegation reduces the amount of code you have to write and better ensures that your custom code will work, even when the delegate’s class is updated.

Notification

The objects in an application are no good on their own. It is the relationships and communications between objects that breathe life into an application. In a complex system like Enterprise Objects, it's common that a single object needs to communicate with multiple objects simultaneously.

There are any number of bad approaches to this problem and one remarkably good one: notifications. Notification allows for a loose coupling of objects—objects that need to communicate with one another don’t need to know about one another in advance. Rather, when objects need to communicate with one another, they rely on a notification center to manage their communications.

Enterprise Objects uses an object called a notification center to broadcast messages to objects in an application. Objects register with the notification center for specific notifications they want to receive. They also post notifications with the notification center when they want to notify other objects that a particular event occurred.

Figure 2-5 illustrates how objects and the notification center interact. A given object tells the notification center which notifications it’s interested in; it posts notifications to the notification center when its state changes; it receives notifications that it is registered to receive.

Figure 1-5  Notification center and its clients
Notification center and its clients

Notifications are particularly important in the control layer. Enterprise objects often have relationships to other enterprise objects in the same editing context. When a value in one enterprise object changes, other enterprise objects in that editing context (and perhaps in other editing contexts, too) need to be told of the change. So, when a value in an enterprise object changes, that enterprise object's editing context posts a notification to let the other enterprise objects in that editing context update their data accordingly.

Notification creates a kind of dynamic nervous system within the object graph with the notification center as the brain of the system. You can think of the object graph as an organic system with many built-in feedback loops. As you begin to work with object graphs, you’ll find them to be a very natural way of thinking about data.

You may wonder about the differences between delegation and notification. With delegation, an object (the delegator) asks another object (the delegate) for a response before it performs a particular action (communication between objects can be forced and synchronous). Notification differs from delegation in that objects that post notifications don’t directly communicate with the objects that receive those notifications (communication between objects can never be forced and synchronous; object communication through notification is always asynchronous). With delegation, the delegate object has the opportunity to affect the tasks of its delegator, whereas in notification, objects don’t directly affect the execution of other objects.

Principal Methods of Enterprise Objects

As discussed in How to Learn About Enterprise Objects, Enterprise Objects includes an extensive API, most of which you never need to know about or use. To help you get started with the API, the appendix Principal Methods describes the 30 most common methods that all Enterprise Objects applications are likely to use.