Composite entity pattern
Composite entity is a Java EE Software design pattern and it is used to model, represent, and manage a set of interrelated persistent objects rather than representing them as individual fine-grained entity beans, and also a composite entity bean represents a graph of objects.[1]
Structure
There are a number of strategies to implement composite entity pattern. This pattern mainly composites of composite entity, coarse-grained object, and dependent objects.[1]
Composite entity component
Composite entity is the coarse-grained entity bean which may be the coarse-grained object, or may contain a reference to the coarse-grained object.[1]
Coarse-grained object
A coarse-grained object is an object with its own life cycle manages its own relationships to other objects. It can be an object contained in the composite entity, or, composite entity itself can be the coarse-grained object which holds dependent objects.[1]
Dependent objects
It is an object, which can contain other dependent objects (there may be a tree of objects within the composite entity), that depends on the coarse-grained object and has its life cycle managed by the coarse-grained object.[1]
Consequences
According to Oracle description of the pattern, consequences include eliminating inter-entity relationships, improving manageability by reducing entity beans, improving network performance, reducing database schema dependency, increasing object granularity, facilitating composite transfer object creation and overhead of multi-level dependent object graphs.[1]
Drawbacks
The fatal drawback is the requirement of bean-managed persistent (BMP) bean. This involves more work for developers, and create some problems as follows:
- materializing all the data in a coarse-grained entity whenever it is accessed, is unacceptably expensive
- In Java, implementation of the ejbStore() method needs to be smart enough to avoid issuing all the updates required to persist the entire state of the object, unless the data has changed in all the persistent objects.
Composite entity pattern can only be implemented using BMP or by adding more hand-coded persistence logic to container managed persistence (CMP) beans. These both approaches reduce the maintainability.[2]
Sample code
Sample code for a Professional Service Automation application (PSA) in which the resource object is implemented via composite entity pattern, may look like as follows (entity implements coarse-grained object):
package corepatterns.apps.psa.ejb; import corepatterns.apps.psa.core.*; import corepatterns.apps.psa.dao.*; import java.sql.*; import javax.sql.*; import java.util.*; import javax.ejb.*; import javax.naming.*; public class ResourceEntity implements EntityBean { public String employeeId; public String lastName; public String firstName; public String departmentId; public String practiceGroup; public String title; public String grade; public String email; public String phone; public String cell; public String pager; public String managerId; // Collection of BlockOutTime Dependent objects public Collection blockoutTimes; // Collection of SkillSet Dependent objects public Collection skillSets; ... private EntityContext context; // Entity Bean methods implementation public String ejbCreate(ResourceTO resource) throws CreateException { try { this.employeeId = resource.employeeId; setResourceData(resource); getResourceDAO().create(resource); } catch(Exception ex) { throw new EJBException("Reason:" + ...); } return this.employeeId; } public String ejbFindByPrimaryKey(String primaryKey) throws FinderException { boolean result; try { ResourceDAO resourceDAO = getResourceDAO(); result = resourceDAO.selectByPrimaryKey(primaryKey); } catch(Exception ex) { throw new EJBException("Reason:" + ...); } if (result) { return primaryKey; } else { throw new ObjectNotFoundException(...); } } public void ejbRemove() { try { // Remove dependent objects if (this.skillSets != null) { SkillSetDAO skillSetDAO = getSkillSetDAO(); skillSetDAO.setResourceID(employeeId); skillSetDAO.deleteAll(); skillSets = null; } if (this.blockoutTime != null) { BlockOutTimeDAO blockouttimeDAO = getBlockOutTimeDAO(); blockouttimeDAO.setResourceID(employeeId); blockouttimeDAO.deleteAll(); blockOutTimes = null; } // Remove the resource from the persistent store ResourceDAO resourceDAO = new ResourceDAO(employeeId); resourceDAO.delete(); } catch(ResourceException ex) { throw new EJBException("Reason:"+...); } catch(BlockOutTimeException ex) { throw new EJBException("Reason:"+...); } catch(Exception exception) { ... } } public void setEntityContext(EntityContext context) { this.context = context; } public void unsetEntityContext() { context = null; } public void ejbActivate() { employeeId = (String)context.getPrimaryKey(); } public void ejbPassivate() { employeeId = null; } public void ejbLoad() { try { // load the resource info from ResourceDAO resourceDAO = getResourceDAO(); setResourceData((ResourceTO) resourceDAO.load(employeeId)); // Load other dependent objects, if necessary ... } catch(Exception ex) { throw new EJBException("Reason:" + ...); } } public void ejbStore() { try { // Store resource information getResourceDAO().update(getResourceData()); // Store dependent objects as needed ... } catch(SkillSetException ex) { throw new EJBException("Reason:" + ...); } catch(BlockOutTimeException ex) { throw new EJBException("Reason:" + ...); } ... } public void ejbPostCreate(ResourceTO resource) { } // Method to Get Resource Transfer Object public ResourceTO getResourceTO() { // create a new Resource Transfer Object ResourceTO resourceTO = new ResourceTO(employeeId); // copy all values resourceTO.lastName = lastName; resourceTO.firstName = firstName; resourceTO.departmentId = departmentId; ... return resourceTO; } public void setResourceData(ResourceTO resourceTO) { // copy values from Transfer Object into entity bean employeeId = resourceTO.employeeId; lastName = resourceTO.lastName; ... } // Method to get dependent Transfer Objects public Collection getSkillSetsData() { // If skillSets is not loaded, load it first. // See Lazy Load strategy implementation. return skillSets; } ... // other get and set methods as needed ... // Entity bean business methods public void addBlockOutTimes(Collection moreBOTs) throws BlockOutTimeException { // Note: moreBOTs is a collection of // BlockOutTimeTO objects try { Iterator moreIter = moreBOTs.iterator(); while (moreIter.hasNext()) { BlockOutTimeTO botTO = (BlockOutTimeTO) moreIter.next(); if (! (blockOutTimeExists(botTO))) { // add BlockOutTimeTO to collection botTO.setNew(); blockOutTime.add(botTO); } else { // BlockOutTimeTO already exists, cannot add throw new BlockOutTimeException(...); } } } catch(Exception exception) { throw new EJBException(...); } } public void addSkillSet(Collection moreSkills) throws SkillSetException { // similar to addBlockOutTime() implementation ... } ... public void updateBlockOutTime(Collection updBOTs) throws BlockOutTimeException { try { Iterator botIter = blockOutTimes.iterator(); Iterator updIter = updBOTs.iterator(); while (updIter.hasNext()) { BlockOutTimeTO botTO = (BlockOutTimeTO) updIter.next(); while (botIter.hasNext()) { BlockOutTimeTO existingBOT = (BlockOutTimeTO) botIter.next(); // compare key values to locate BlockOutTime if (existingBOT.equals(botTO)) { // Found BlockOutTime in collection // replace old BlockOutTimeTO with new one botTO.setDirty(); //modified old dependent botTO.resetNew(); //not a new dependent existingBOT = botTO; } } } } catch (Exception exc) { throw new EJBException(...); } } public void updateSkillSet(Collection updSkills) throws CommitmentException { // similar to updateBlockOutTime... ... } ... }
See also
References
- ↑ 1.0 1.1 1.2 1.3 1.4 1.5 1.6 "Core J2EE Patterns - Composite Entity". Oracle. http://www.oracle.com/technetwork/java/compositeentity-141992.html.
- ↑ Johnson, R. (2003). Expert One-on-One J2EE Design and Development. Indianapolis: Wiley Publishing, Inc. pp. 290.
Original source: https://en.wikipedia.org/wiki/Composite entity pattern.
Read more |