Javadogs, Here's the latest work in progress. I've incorporated all the feedback received from the previous discussion. Craig Fetch Plan A fetch plan defines rules for instantiating the loaded state for an object graph. It specifies fields to be loaded for all of the instances in the graph. Using fetch plans, users can control the field fetching behavior of many JDO APIs. A fetch plan can be associated with a PersistenceManager and, independently, with a Query and with an Extent. A fetch plan also defines rules for creating the detached object graph for the detach APIs and for automatic detachment at commit with DetachAllOnCommit set to true. A fetch plan consists of a number of fetch groups that are combined additively for each affected class; a fetch size that governs the number of instances of multi-valued fields retrieved by queries; a fetch-depth per field that governs the depth of the object graph fetched for that field; and flags that govern the behavior of detachment. The default fetch plan contains exactly one fetch group, "default". It has a fetch size of 0, and detachment option DETACH_LOAD_FIELDS. The default fetch plan is in effect when the PersistenceManager is first acquired from the PersistenceManagerFactory. With the default fetch plan in effect, the behavior of JDO 2 is very similar to the behavior of JDO 1. That is, when instances are loaded into memory in response to queries or navigation, fields in the default fetch group are loaded, and the jdoPostLoad callback is executed the first time an instance is fetched from the datastore. The implementation is allowed to load additional fields, as in JDO 1. Upon detachment, fields that are have been loaded into the detached instances are preserved, regardless of whether they were loaded automatically by the implementation or loaded in response to application access; and fields that have not been loaded are marked in the detached instances as not loaded. This behavior is sufficient for the most basic use case for detachment, where the detached instances are simply “data transfer objects” containing primitive fields. The detached instances can be modified in place or serialized and sent to another tier to be changed and sent back. Upon being received back, the instances can be attached and if there are no version conflicts, the changes can be applied to the datastore. The most common use case for fetch groups is to restrict the fields loaded for an instance to the primitive values and avoid loading related instances for queries. For more control over the default behavior, the “default” fetch group can simply be redefined for specific classes. For example, a String field that contains a typically large document can be defined as not part of the default fetch group, and the field will be loaded only when accessed by the application. Similarly, the Order field associated with OrderLine might be defined as part of the default fetch group of OrderLine, and queries on OrderLine will always load the corresponding Order instance as well. This can easily improve the performance of applications that always need the Order whenever OrderLine instances are loaded. For explicit detachment, the parameters of the detach method are each treated as roots for the purpose of determining the detached object graph. The fetch plan is applied to each of the roots as if no other roots were also being detached. The roots and their corresponding object graphs are combined and the resulting object graph is detached in its entirety. Fetch Groups Fetch groups are used to identify the list of fields and the associated field recursion-depth for each class for which the fetch plan is applied. Fetch groups are identified by name and apply to one or more classes. Names have global scope so the same fetch group name can be used for any number of classes. This makes it possible to specify fetch groups per PersistenceManager instead of per extent. This greatly simplifies the use of fetch groups in an application. The default fetch group (named "default") for each class is created by the JDO implementation according to the rules in the JDO 1.0.1 specification. That is, it includes all fields that by default belong to the default fetch group (i.e. single-valued fields), and causes the jdoPostLoad method to be called the first time fields are loaded. It may also be defined by the user in the metadata like any other fetch group, in order to make use of JDO 2 features. The implementation must also define another fetch group named "all" for each class. The "all" group contains all fields in the class, but can be redefined by the user, for example to add fetch-depth to certain fields, or to exclude some fields from being loaded. If a fetch plan other than the default fetch plan is active for a PersistenceManager, the behavior of several APIs changes: For detachCopy the JDO implementation must ensure that the graph specified by the active fetch groups is copied, based on the DETACH_LOAD_FIELDS and DETACH_UNLOAD_FIELDS flags. For refresh, after clearing fields in the instances, the JDO implementation uses the fetch plan to determine which fields to load from the datastore. For retrieve with FGonly true, the implementation uses the fetch plan to determine which fields are loaded from the datastore. With FGonly false, the implementation reverts to JDO 1 behavior, which loads all fields from the datastore; in this case, no related instances are loaded. When executing a query the JDO implementation loads the fields as specified in the fetch plan associated with the Query instance. When the application dereferences an unloaded field, the JDO implementation uses the current fetch plan and the load-fetch-group of the field to create the fetch strategy for the field. The specific behavior depends on whether the unloaded field is a relation to another persistence-capable class. for non-relation fields, the current fetch plan is applied to the field’s owning instance, and the fields in the field’s load-fetch-group, plus the field itself are added to the list of fields. for relation fields, the fields in the owning instance are fetched as immediately above, and additionally the instances referred by the field are loaded using the current fetch plan plus the field’s load-fetch-group. A12.7-3 [FetchPlan getFetchPlan(); This method retrieves the fetch plan associated with the PersistenceManager. It always returns the identical instance for the same PersistenceManager.] MaxFetchDepth When relationship fields are included in the active fetch plan, it may be possible to retrieve the entire contents of the datastore, which might not be the desired effect. To avoid this behavior, and to allow the application to control the amount of data retrieved from the datastore, the MaxFetchDepth property of the fetch plan is used. The MaxFetchDepth is the depth of references (fields of relationship types) to instantiate, starting with the root instances. Setting MaxFetchDepth to 1 limits the instances retrieved to the root instances and instances directly reachable from the root instances through a field in the fetch plan for the root class(es). Setting MaxFetchDepth to 0 has no meaning, and JDOUserException will be thrown. Setting MaxFetchDepth to -1 does not limit the instances retrieved via relationship fields in the fetch plan. Caution should be exercised to avoid retrieving more instances than desired. For example, assume the class Employee defines field dept of type Department, and class Department defines field comp of type Company. When a query for Employee is executed, with a fetch plan that includes Employee.dept and Department.comp and with MaxFetchDepth set to 1, the Departments referenced by Employees returned from the query are instantiated, but the Company field is not instantiated. With the MaxFetchDepth set to 2, Departments and their corresponding Companys are instantiated for the Employee instances returned by the query. Root instances Root instances are parameter instances for retrieve, detachCopy, and refresh; result instances for queries. Root instances for DetachAllOnCommit are defined explicitly by the user via the FetchPlan property DetachmentRoots or DetachmentRootClasses. If not set explicitly, the detachment roots consist of the union of all root instances of methods executed since the last commit or rollback. Once set explicitly, the detachment roots will not be changed until commit, at which time the detachment roots will be set to the empty collection. Recursion-depth For object models with bidirectional relationships or self-referencing relationships, it is useful to limit the depth of the object graph retrieved through these relationships recursively. The recursion-depth attribute of the field element is used for this purpose. The recursion-depth for a relationship field specifies the number of times an instance of the same class, subclass, or superclass can be fetched via traversing this field. A value of -1 means that the recursion-depth is not limited by traversing this field. If a field is defined in multiple fetch groups, the recursion-depth is the largest of the values specified, treating -1 as a very large positive number. If not specified in any fetch group or in the base field definition, the default is 1. For example, assume a class Directory with a field parent of type Directory and a field children of type Set<Directory>, and assume the recursion-depth of the parent field is set to -1 and the recursion-depth of the children field is set to 2. When a query for a Directory is executed, all parents of the selected Directory instances will be retrieved, and all of the parents’ parents until a parent is found with a null parent. Additionally, all children of the selected Directory will be retrieved and all children of the children of the selected Directory. The FetchPlan interface Fetch groups are activated using methods on the interface FetchPlan. PersistenceManager and Query have getFetchPlan() methods. When a Query is retrieved from a PersistenceManager, its FetchPlan is initialized to the same settings as that of the PersistenceManager. Subsequent modifications of the Query FetchPlan are not reflected in the FetchPlan of the PersistenceManager. When an Extent is created, the FetchPlan of the PersistenceManager initializes the FetchPlan for the Extent. Mutating FetchPlan methods return the FetchPlan instance to allow method chaining. package javax.jdo; public interface FetchPlan { String DEFAULT = “default”; String ALL = “all”; int FETCH_SIZE_GREEDY = -1; int FETCH_SIZE_OPTIMAL = 0; int DETACH_LOAD_FIELDS = 1; int DETACH_UNLOAD_FIELDS = 2; A12.7.1-1 [/** Add the fetchgroup to the set of active fetch groups. Duplicate names will be removed.*/ FetchPlan addGroup(String fetchGroupName); /** Remove the fetch group from the set active fetch groups. */ FetchPlan removeGroup(String fetchGroupName); /** Remove all active groups, including the default fetch group. */ FetchPlan clearGroups(); /** Return an immutable Set of the names of all active fetch groups. */ Set getGroups(); /** Set a Collection of group names to replace the current groups. Duplicate names will be removed.*/ FetchPlan setGroups(Collection fetchGroupNames); /** Set an array of group names to replace the current groups. Duplicate names will be removed.*/ FetchPlan setGroups(String[] fetchGroupNames); /** Set a single group to replace the current groups. */ FetchPlan setGroup(String fetchGroupName);] /** Set the roots for DetachAllOnCommit */ FetchPlan setDetachmentRoots(Collection roots); /** Get the roots for DetachAllOnCommit */ Collection getDetachmentRoots(); /** Set the roots for DetachAllOnCommit */ FetchPlan setDetachmentRootClasses(Class[] rootClasses); /** Get the roots for DetachAllOnCommit */ Class[] getDetachmentRootClasses(); A12.7.1-2 [/** Set the fetch size for large result set support. */ FetchPlan setFetchSize(int fetchSize); /** Return the fetch size; 0 if not set; -1 for greedy fetching. */ int getFetchSize();] A12.7.1-3 [/** Set detachment options */ FetchPlan setDetachmentOptions(int options); /** Return the detachment options */ int getDetachmentOptions();] The getGroups method returns a collection of names. After a call to clearGroups() this method returns an empty Set. It is legal to remove the default fetch group explicitly via pm.getFetchPlan().removeGroup("default"), or to use setGroups() with a collection that does not contain "default". This makes it possible to have only a given fetch group active without the default fetch group. If no fetch groups are active then a Set with no elements is returned. In this case, loading an instance might not result in loading the default fetch group fields and the jdoPostLoad method will only be called if there is an active fetch group that declares post-load=”true”. The fetch size allows users to explicitly control the number of instances retrieved from queries. A positive value is the number of result instances to be fetched. A value of FETCH_SIZE_GREEDY indicates that all results should be obtained immediately. A value of FETCH_SIZE_OPTIMAL indicates that the JDO implementation should try to optimize the fetching of results. Note that the graph and fields specified by a FetchPlan is strictly the union of all the active fetch groups not based on any complicated set mathematics. So, if a field f1 is in fetch groups A and B, and both A and B are added to the FetchPlan,and subsequently B is removed from the active fetch groups and the instance is loaded, then the field f1 will be loaded, because it is in fetch group A. Craig Russell Architect, Sun Java Enterprise System http://java.sun.com/products/jdo 408 276-5638 mailto:[EMAIL PROTECTED] P.S. A good JDO? O, Gasp! |
smime.p7s
Description: S/MIME cryptographic signature
