Index: api2/src/java/javax/jdo/FetchGroup.java =================================================================== --- api2/src/java/javax/jdo/FetchGroup.java (revision 0) +++ api2/src/java/javax/jdo/FetchGroup.java (revision 0) @@ -0,0 +1,276 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* + * FetchGroup.java + * + */ + +package javax.jdo; + +import java.util.Set; + +/** + * Fetch groups are created and updated using methods on this interface. An + * instance of this interface can be obtained from + * {@link PersistenceManager#getFetchGroup} or + * {@link PersistenceManagerFactory#getFetchGroup}. + *

+ * A FetchGroup can be unscoped or can be in one of two scopes (the + * {@link PersistenceManager} or the {@link PersistenceManagerFactory} scope). + * Unscoped FetchGroups do not affect any behavior. + * A FetchGroup in PersistenceManager scope hides the corresponding + * FetchGroup in the PersistenceManagerFactory scope. + *

+ * @version 2.2 + * @since 2.2 + */ +public interface FetchGroup { + + /** + * For use with {@link #addCategory} and {@link #removeCategory} calls. + * This category includes members defined in the default fetch group + * in xml or annotations. Redefining the default fetch group via the API + * does not affect the members defined by this category. + *

+ * Using this category also sets the fetch-depth for the members in the + * default fetch group.

+ * @since 2.2 + */ + public static final String DEFAULT = "default"; + + /** + * For use with {@link #addCategory} and {@link #removeCategory} calls. + * This category includes members of all relationship types. + * @since 2.2 + */ + public static final String RELATIONSHIP = "relationship"; + + /** + * For use with {@link #addCategory} and {@link #removeCategory} calls. + * This category includes members of all multi-valued types, including + * Collection, array, and Map types of basic and relationship types. + * @since 2.2 + */ + public static final String MULTIVALUED = "multivalued"; + + /** + * For use with {@link #addCategory} and {@link #removeCategory} calls. + * This category includes members of all basic (primitive and immutable + * object class) types as defined in section 6.4 of the specification, + * including String, Date and its jdbc subtypes, Locale, Currency, + * and Enum types. + * @since 2.2 + */ + public static final String BASIC = "basic"; + + /** + * For use with {@link #addCategory} and {@link #removeCategory} calls. + * This category includes all members in the persistent type. + *

+ * Using this category also sets the fetch-depth for the members in the + * default fetch group.

+ * @since 2.2 + */ + public static final String ALL = "all"; + + /** + * Get the name of this FetchGroup. The name is set only in the + * factory method. + * @return the name + * @since 2.2 + */ + String getName(); + + /** + * Get the persistent type (class or interface) of this FetchGroup. + * The persistent type is set only in the factory method(s). + * @return the persistent type + * @since 2.2 + */ + Class getType(); + + /** + * Get the post-load property of this FetchGroup. + * @return the post-load property + * @since 2.2 + */ + boolean getPostLoad(); + + /** + * Set the post-load property of this FetchGroup. + * @return the FetchGroup + * @throws JDOUserException if the FetchGroup is unmodifiable + * @since 2.2 + */ + FetchGroup setPostLoad(boolean postLoad); + + /** + * Add the member (field or property) to the set of members in this + * FetchGroup. + * @param memberName the name of a member to add to the FetchGroup + * @return the FetchGroup + * @throws JDOUserException if the parameter is not a member of the + * persistent type + * @throws JDOUserException if the FetchGroup is unmodifiable + * @since 2.2 + */ + FetchGroup addMember(String memberName); + + /** + * Add the member (field or property) to the set of members in this + * FetchGroup. Duplicates are ignored. + * @param memberNames the names of members to add to the FetchGroup + * @return the FetchGroup + * @throws JDOUserException if any parameter is not a member of the + * persistent type + * @throws JDOUserException if the FetchGroup is unmodifiable + * @since 2.2 + */ + FetchGroup addMembers(String... memberNames); + + /** + * Remove the member (field or property) from the set of members in this + * FetchGroup. + * @return the FetchGroup + * @throws JDOUserException if the parameter is not a member of the + * persistent type + * @throws JDOUserException if the FetchGroup is unmodifiable + * @since 2.2 + */ + FetchGroup removeMember(String memberName); + + /** + * Remove the member (field or property) from the set of members in this + * FetchGroup. Duplicates in the parameter list are eliminated before + * removing them from the membership. + * @return the FetchGroup + * @throws JDOUserException if any parameter is not a member of the + * persistent type + * @throws JDOUserException if the FetchGroup is unmodifiable + * @since 2.2 + */ + FetchGroup removeMembers(String... memberNames); + + /** + * Add the members (fields or properties) of the named category + * to the set of members in this FetchGroup. This method first + * resolves the category name to a set of members and then adds + * the members as if {@link #addMembers} was called. After this + * method executes, the category is not remembered. + * @return the FetchGroup + * @throws JDOUserException if the FetchGroup is unmodifiable + * @since 2.2 + */ + FetchGroup addCategory(String categoryName); + + /** + * Remove the members (fields or properties) of the named category + * from the set of members in this FetchGroup. This method first + * resolves the category name to a set of members and then removes + * the members as if {@link #removeMembers} was called. After this + * method executes, the category is not remembered. + * @return the FetchGroup + * @throws JDOUserException if the FetchGroup is unmodifiable + * @since 2.2 + */ + FetchGroup removeCategory(String categoryName); + + /** + * Set the recursion-depth for this member. The default is 1. A value of 0 + * means don't fetch the member (as if the member were omitted entirely). + * A value of -1 means fetch all instances reachable via this member. + * @return the FetchGroup + * @param memberName the name of the field or property + * @param recursionDepth the value for the recursion-depth property + * @throws JDOUserException if the member does not exist + * @throws JDOUserException if the FetchGroup is unmodifiable + * @since 2.2 + */ + FetchGroup setRecursionDepth(String memberName, int recursionDepth); + + /** + * Get the recursion-depth for this member. + * @param memberName the name of the field or property + * @return the recursion-depth for this member + * @throws JDOUserException if the member is not in the FetchGroup + * @since 2.2 + */ + int getRecursionDepth(String memberName); + + /** + * Return an immutable Set of String containing the names of all members. + * The Set is a copy of the currently defined members and will not change + * based on subsequent changes to the membership in the FetchGroup. + * @return an immutable Set containing the names of all members + * in the FetchGroup + * @since 2.2 + */ + Set getMembers(); + + /** + * Make this FetchGroup unmodifiable. If already unmodifiable, this method + * has no effect. + * @return the FetchGroup + * @since 2.2 + */ + FetchGroup setUnmodifiable(); + + /** + * Return whether this FetchGroup is unmodifiable. If so, methods + * {@link #setPostLoad}, {@link #addMember}, {@link #removeMember}, + * {@link #addMembers}, {@link #removeMembers}, + * {@link #addCategory}, and {@link #removeCategory} + * will throw {@link JDOUserException}. + * @return whether the FetchGroup is unmodifiable + * @since 2.2 + */ + boolean isUnmodifiable(); + + /** + * Return the hashCode for this instance. The hash code should combine both + * the class and fetch group name. The hash codes for two equal instances + * must be identical. + * @return the hash code + * @since 2.2 + */ + int hashCode(); + + /** + * Return whether this instance is equal to the other. The equals method + * must compare the class for identity and the fetch group name for + * equality. + * @return whether this instance is equal to the other + * @since 2.2 + */ + boolean equals(Object other); +} Property changes on: api2/src/java/javax/jdo/FetchGroup.java ___________________________________________________________________ Name: svn:eol-style + LF Index: api2/src/java/javax/jdo/PersistenceManager.java =================================================================== --- api2/src/java/javax/jdo/PersistenceManager.java (revision 681435) +++ api2/src/java/javax/jdo/PersistenceManager.java (working copy) @@ -1222,4 +1222,26 @@ * @since 2.1 */ Set getManagedObjects(EnumSet states, Class... classes); + + /** + * Get a modifiable FetchGroup for the Class and name. + * If a modifiable FetchGroup already exists in the + * PersistenceManager scope, return it. + * If not, create and populate a new FetchGroup from the + * existing definition in the {@link PersistenceManager} or + * {@link PersistenceManagerFactory}. If the definition for the + * FetchGroup is not in scope in either the + * PersistenceManager or + * PersistenceManagerFactory, create it with no members. + * The FetchGroup immediately + * becomes active and in scope of the PersistenceManager, and hides + * the corresponding fetch group in the PersistenceManagerFactory. + * @param cls the class or interface for the FetchGroup + * @param name the name of the fetch group + * @return the FetchGroup + * @throws JDOUserException if the class is not a persistence-capable + * class or interface + * @since 2.2 + */ + FetchGroup getFetchGroup(Class cls, String name); } Index: api2/src/java/javax/jdo/PersistenceManagerFactory.java =================================================================== --- api2/src/java/javax/jdo/PersistenceManagerFactory.java (revision 681435) +++ api2/src/java/javax/jdo/PersistenceManagerFactory.java (working copy) @@ -24,9 +24,11 @@ import javax.jdo.datastore.DataStoreCache; import javax.jdo.listener.InstanceLifecycleListener; +import javax.jdo.spi.JDOPermission; // for getFetchGroups javadoc import java.io.Serializable; import java.util.Collection; import java.util.Properties; +import java.util.Set; /** The PersistenceManagerFactory is the interface to use to obtain * PersistenceManager instances. @@ -584,5 +586,82 @@ */ void removeInstanceLifecycleListener (InstanceLifecycleListener listener); + /** + * Add the FetchGroups to the set of active fetch groups. + * FetchGroups are made unmodifiable before being added. + * FetchGroups that match existing FetchGroups + * replace the corresponding FetchGroups. + * The replaced FetchGroups become unscoped. + * Match is based on identical class and equal name. + * The methods {@link #addFetchGroups}, {@link #removeFetchGroups}, + * {@link #getFetchGroups}, and {@link #removeAllFetchGroups} + * are internally serialized. + * @param groups an array of FetchGroups + * @throws SecurityException if the caller is not authorized for + * {@link JDOPermission} ("manageMetadata") + * @since 2.2 + */ + void addFetchGroups(FetchGroup... groups); + + /** + * Remove the FetchGroups from the set of active + * FetchGroups. Existing FetchGroups that match + * parameter FetchGroups are removed. Parameter + * FetchGroups that do not match any existing + * FetchGroup are ignored. + * Removed FetchGroups become unscoped. + * Match is based on identical class and equal name. + * The methods {@link #addFetchGroups}, {@link #removeFetchGroups}, + * {@link #getFetchGroups}, and {@link #removeAllFetchGroups} + * are internally serialized. + * @param groups an array of FetchGroups + * @throws SecurityException if the caller is not authorized for + * {@link JDOPermission} ("manageMetadata") + * @since 2.2 + */ + void removeFetchGroups(FetchGroup... groups); + + /** + * Remove all FetchGroups from the set of active + * FetchGroups. + * All removed FetchGroups become unscoped. + * The methods {@link #addFetchGroups}, {@link #removeFetchGroups}, + * {@link #getFetchGroups}, and {@link #removeAllFetchGroups} + * are internally serialized. + * @throws SecurityException if the caller is not authorized for + * {@link JDOPermission} ("manageMetadata") + * @since 2.2 + */ + void removeAllFetchGroups(); + + /** + * Create an unscoped, modifiable FetchGroup for the Class and + * name. If a corresponding FetchGroup already exists in + * PersistenceManagerFactory scope, copy its definition + * to a new FetchGroup. + * If the FetchGroup does not already exist, create it + * with no members. The FetchGroup does not become + * in scope until it is added to the current set via + * {@link #addFetchGroups}. + * @param cls the class or interface for the FetchGroup + * @param name the name of the fetch group + * @return the FetchGroup + * @throws JDOUserException if the class is not a persistence-capable + * class or interface + * @since 2.2 + */ + FetchGroup getFetchGroup(Class cls, String name); + + /** + * Get a modifiable Set containing a mutable copy of all currently active + * (in scope) fetch groups. + * The methods {@link #addFetchGroups}, {@link #removeFetchGroups}, + * {@link #getFetchGroups}, and {@link #removeAllFetchGroups} + * are internally serialized. + * @return a copy of all currently active fetch groups + * @throws SecurityException if the caller is not authorized for + * {@link JDOPermission} ("getMetadata") + * @since 2.2 + */ + Set getFetchGroups(); } - Index: tck2/src/java/org/apache/jdo/tck/api/fetchgroup/FetchGroupTest.java =================================================================== --- tck2/src/java/org/apache/jdo/tck/api/fetchgroup/FetchGroupTest.java (revision 0) +++ tck2/src/java/org/apache/jdo/tck/api/fetchgroup/FetchGroupTest.java (revision 0) @@ -0,0 +1,337 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.apache.jdo.tck.api.fetchgroup; + +import java.util.Arrays; +import org.apache.jdo.tck.api.persistencemanager.fetchplan.*; +import java.util.HashMap; +import java.util.HashSet; + +import java.util.Iterator; +import java.util.Map; +import java.util.Set; +import javax.jdo.FetchGroup; + +import org.apache.jdo.tck.JDO_Test; + +import org.apache.jdo.tck.pc.company.Address; +import org.apache.jdo.tck.pc.company.Company; +import org.apache.jdo.tck.pc.company.DentalInsurance; +import org.apache.jdo.tck.pc.company.Department; +import org.apache.jdo.tck.pc.company.Employee; +import org.apache.jdo.tck.pc.company.FullTimeEmployee; +import org.apache.jdo.tck.pc.company.Insurance; +import org.apache.jdo.tck.pc.company.MedicalInsurance; +import org.apache.jdo.tck.pc.company.PartTimeEmployee; +import org.apache.jdo.tck.pc.company.Person; +import org.apache.jdo.tck.pc.company.Project; + +import org.apache.jdo.tck.util.BatchTestRunner; + +/** + * This class is an abstract superclass for the fetch plan tests. + * It contains methods useful for testing the behavior of the + * fetch plan. + */ + +public class FetchGroupTest extends JDO_Test { + + /** + * The main is called when the class + * is directly executed from the command line. + * @param args The arguments passed to the program. + */ + public static void main(String[] args) { + BatchTestRunner.run(FetchGroupTest.class); + } + + /** All fetch groups in this PMF. */ + protected Set allPMFFetchGroups; + + /** All fetch groups in this PMF. */ + protected Map unscopedFetchGroupMap = new HashMap(); + + /** + * SetUp for test. Get all defined fetch groups in the PMF. + */ + public void localSetUp() { + getPM(); // initialize pm field + allPMFFetchGroups = pmf.getFetchGroups(); + unscopedFetchGroupMap.put("Address+default", + pmf.getFetchGroup(Address.class, "default")); + unscopedFetchGroupMap.put("Company+default", + pmf.getFetchGroup(Company.class, "default")); + unscopedFetchGroupMap.put("DentalInsurance+default", + pmf.getFetchGroup(DentalInsurance.class, "default")); + unscopedFetchGroupMap.put("Department+default", + pmf.getFetchGroup(Department.class, "default")); + unscopedFetchGroupMap.put("Employee+default", + pmf.getFetchGroup(Employee.class, "default")); + unscopedFetchGroupMap.put("FullTimeEmployee+default", + pmf.getFetchGroup(FullTimeEmployee.class, "default")); + unscopedFetchGroupMap.put("Insurance+default", + pmf.getFetchGroup(Insurance.class, "default")); + unscopedFetchGroupMap.put("MedicalInsurance+default", + pmf.getFetchGroup(MedicalInsurance.class, "default")); + unscopedFetchGroupMap.put("PartTimeEmployee+default", + pmf.getFetchGroup(PartTimeEmployee.class, "default")); + unscopedFetchGroupMap.put("Person+default", + pmf.getFetchGroup(Person.class, "default")); + unscopedFetchGroupMap.put("Project+default", + pmf.getFetchGroup(Project.class, "default")); + } + + /** + * Test PersistenceManagerFactory factory methods. + */ + public void testPMFGetFetchGroupHashCode() { + FetchGroup scoped = pm.getFetchGroup(Address.class, "default"); + FetchGroup unscoped = + (FetchGroup)unscopedFetchGroupMap.get("Address+default"); + int actual = scoped.hashCode(); + int expected = unscoped.hashCode(); + assertEquals("Scoped hash code does not equal unscoped hash code;" + + "Expected: " + expected + " actual: " + actual, + actual, expected); + } + + public void testPMFGetFetchGroupEquals() { + FetchGroup scoped = pm.getFetchGroup(Address.class, "default"); + FetchGroup unscoped = + (FetchGroup)unscopedFetchGroupMap.get("Address+default"); + assertEquals("Scoped FetchGroup does not equal unscoped FetchGroup;" + + "Unscoped: " + printFetchGroup(unscoped) + + " scoped: " + printFetchGroup(scoped), + unscoped, scoped); + } + + public void testModifiable() { + FetchGroup scoped = pm.getFetchGroup(Address.class, "default"); + assertFalse("Scoped FetchGroup should be modifiable initially", + scoped.isUnmodifiable()); + scoped.setUnmodifiable(); + assertTrue("Scoped FetchGroup should be unmodifiable after setUnmodifiable", + scoped.isUnmodifiable()); + } + + /** + * Employee.java: + private Date hiredate; + private double weeklyhours; + private DentalInsurance dentalInsurance; + private MedicalInsurance medicalInsurance; + private Department department; + private Department fundingDept; + private Employee manager; + private Employee mentor; + private Employee protege; + private Employee hradvisor; + private transient Set reviewedProjects = new HashSet(); // element-type is Project + private transient Set projects = new HashSet(); // element-type is Project + private transient Set team = new HashSet(); // element-type is Employee + private transient Set hradvisees = new HashSet(); // element-type is Employee + * Person.java: + private long personid; + private String firstname; + private String lastname; + private String middlename; + private Date birthdate; + private Address address; + + // maps phone number types ("home", "work", "mobile", etc.) + // to phone numbers specified as String + private Map phoneNumbers = new HashMap(); + + */ + protected String[] basicMembers = new String[]{"hiredate", "weeklyhours", + "personid", "firstname", "lastname", "middlename", "birthdate"}; + protected String[] defaultMembers = new String[]{"hiredate", "weeklyhours", + "personid", "firstname", "lastname", "middlename", "birthdate"}; + protected String[] allMembers = new String[]{"hiredate", "weeklyhours", + "dentalInsurance", "medicalInsurance", "department", "fundingDept", + "manager", "mentor", "protege", "hradvisor", + "reviewedProjects", "projects", "team", "hradvisees", + "personid", "firstname", "lastname", "middlename", "birthdate"}; + protected String[] relationshipMembers = new String[]{ + "dentalInsurance", "medicalInsurance", "department", "fundingDept", + "manager", "mentor", "protege", "hradvisor", + "reviewedProjects", "projects", "team", "hradvisees"}; + protected String[] multivaluedMembers = new String[]{ + "reviewedProjects", "projects", "team", "hradvisees"}; + protected String[] allButMultivaluedMembers = new String[] + {"hiredate", "weeklyhours", + "dentalInsurance", "medicalInsurance", "department", "fundingDept", + "manager", "mentor", "protege", "hradvisor", + "personid", "firstname", "lastname", "middlename", "birthdate"}; + + public void testCategories() { + checkAddCategory(Employee.class, FetchGroup.ALL, allMembers); + checkAddCategory(Employee.class, FetchGroup.BASIC, basicMembers); + checkAddCategory(Employee.class, FetchGroup.DEFAULT, defaultMembers); + checkAddCategory(Employee.class, FetchGroup.RELATIONSHIP, relationshipMembers); + checkAddCategory(Employee.class, FetchGroup.MULTIVALUED, multivaluedMembers); + } + + public void testRemoveCategory() { + FetchGroup fg = pm.getFetchGroup(Employee.class, "testRemoveCategory"); + Set expectedSet = new HashSet(); + expectedSet.addAll(Arrays.asList(allButMultivaluedMembers)); + Set members = fg.getMembers(); + fg.addCategory(FetchGroup.ALL); + fg.removeCategory(FetchGroup.MULTIVALUED); + members = fg.getMembers(); + assertEquals("FetchGroup.removeCategory(multivalued) should contain" + + expectedSet + " but contains " + members, + expectedSet, members); + } + + public void testAddMember() { + FetchGroup fg = pm.getFetchGroup(Employee.class, "testAddMember"); + for (int i = 0; i < allMembers.length; ++i) { + String member = allMembers[i]; + fg.addMember(member); + Set members = fg.getMembers(); + assertTrue("FetchGroup should contain " + member + " but does not; " + + printFetchGroup(fg), + members.contains(member)); + assertEquals("FetchGroup should contain " + i + + "members, but does not; ", + i, members.size()); + } + } + + public void testAddMembers() { + FetchGroup fg = pm.getFetchGroup(Employee.class, "testAddMembers"); + fg.addMembers(basicMembers); + fg.addMembers(relationshipMembers); + Set members = fg.getMembers(); + Set expectedSet = new HashSet(); + expectedSet.addAll(Arrays.asList(allMembers)); + assertEquals("FetchGroup should contain" + + expectedSet + " but contains " + members, + expectedSet, members); + } + + public void testRemoveMembers() { + FetchGroup fg = pm.getFetchGroup(Employee.class, "testRemoveMembers"); + fg.addMembers(allMembers); + fg.removeMembers(relationshipMembers); + Set members = fg.getMembers(); + Set expectedSet = new HashSet(); + expectedSet.addAll(Arrays.asList(basicMembers)); + assertEquals("FetchGroup should contain" + + expectedSet + " but contains " + members, + expectedSet, members); + fg.removeMembers(basicMembers); + members = fg.getMembers(); + expectedSet = new HashSet(); + assertEquals("FetchGroup should contain" + + expectedSet + " but contains " + members, + expectedSet, members); + } + + public void testRemoveMember() { + FetchGroup fg = pm.getFetchGroup(Employee.class, "testRemoveMember"); + fg.addCategory(FetchGroup.ALL); + for (int i = allMembers.length - 1; i >= 0; --i) { + String member = allMembers[i]; + fg.removeMember(member); + Set members = fg.getMembers(); + assertTrue("FetchGroup should not contain " + member + " but does; " + + printFetchGroup(fg), + members.contains(member)); + assertEquals("FetchGroup should contain " + i + + "members, but does not; ", + i, members.size()); + } + } + + public void testRecursionDepth() { + FetchGroup fg = pm.getFetchGroup(Employee.class, "testRecursionDepth"); + fg.addMember("manager"); + int depth = fg.getRecursionDepth("manager"); + assertEquals("Initial recursion depth for manager should be 1." + + printFetchGroup(fg), + 1, depth); + fg.setRecursionDepth("manager", 64); + assertEquals("Recursion depth for manager should be 64." + + printFetchGroup(fg), + 64, fg.getRecursionDepth("manager")); + } + + public void testPostLoad() { + FetchGroup fg = pm.getFetchGroup(Employee.class, "testPostLoad"); + assertFalse("New FetchGroup should have post-load false; " + + printFetchGroup(fg), + fg.getPostLoad()); + fg.setPostLoad(true); + assertTrue("After setPostLoad(true) FetchGroup should have post-load true; " + + printFetchGroup(fg), + fg.getPostLoad()); + fg.setPostLoad(false); + assertFalse("After setPostLoad, FetchGroup should have post-load false; " + + printFetchGroup(fg), + fg.getPostLoad()); + } + + private void checkAddCategory(Class cls, String category, String[] expected) { + FetchGroup fg = pm.getFetchGroup(cls, "test" + category); + Set expectedSet = new HashSet(); + expectedSet.addAll(Arrays.asList(expected)); + Set members = fg.getMembers(); + assertTrue("New FetchGroup should have no members; " + + printFetchGroup(fg), + members.isEmpty()); + fg.addCategory(category); + members = fg.getMembers(); + assertEquals("FetchGroup.addCategory(" + category + ") should contain" + + expectedSet + " but contains " + members, + expectedSet, members); + } + + private String printFetchGroup(FetchGroup fg) { + StringBuffer sb = new StringBuffer("FetchGroup (class: "); + sb.append(fg.getType().getName()); + sb.append("; name: "); + sb.append(fg.getName()); + sb.append("; unmodifiable: "); + sb.append(fg.isUnmodifiable()); + sb.append("; recursionDepth: "); + Set members = fg.getMembers(); + Iterator it = members.iterator(); + if (it.hasNext()) { + sb.append("; members: "); + String member = (String)it.next(); + sb.append(member); + sb.append("["); + sb.append(fg.getRecursionDepth(member)); + sb.append("]"); + } + while (it.hasNext()) { + sb.append(", "); + String member = (String)it.next(); + sb.append(member); + sb.append("["); + sb.append(fg.getRecursionDepth(member)); + sb.append("]"); + } + sb.append(")"); + return sb.toString(); + } + +} Property changes on: tck2/src/java/org/apache/jdo/tck/api/fetchgroup/FetchGroupTest.java ___________________________________________________________________ Name: svn:eol-style + LF