Index: api2/test/java/javax/jdo/EnhancerTest.java =================================================================== --- api2/test/java/javax/jdo/EnhancerTest.java (revision 0) +++ api2/test/java/javax/jdo/EnhancerTest.java (revision 0) @@ -0,0 +1,343 @@ +/* + * 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 javax.jdo; + +import java.io.IOException; +import java.io.InputStream; + +import java.io.InputStreamReader; +import java.io.Reader; +import java.nio.CharBuffer; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.Set; +import java.util.Map.Entry; + +import javax.jdo.util.AbstractTest; +import javax.jdo.util.BatchTestRunner; + + +/** + * Tests class javax.jdo.Enhancer (Enhancer main class). + *

+ */ +public class EnhancerTest extends AbstractTest implements Constants { + + /** The path delimiter for constructing classpaths. */ + private static String pathDelimiter = System.getProperty("path.separator"); + + /** The maven basedir identifying the directory of the execution environment. */ + private static String basedir = System.getProperty("basedir"); + + /** */ + public static void main(String args[]) { + BatchTestRunner.run(EnhancerTest.class); + } + + public void testUsageOption() { + // invoke enhancer with a usage option + InvocationResult result = invokeEnhancer("?"); + String outputString = result.getOutputString(); + String errorString = result.getErrorString(); + assertEquals("Wrong exit code from Enhancer with stderr:\n" + errorString, 0, result.getExitValue()); + assertTrue("Expected Usage message from out:\n" + outputString + " with err:\n" + errorString, outputString.contains("javax.jdo.Enhancer")); + } + + public void testHelpOption() { + // invoke enhancer with a usage option + InvocationResult result = invokeEnhancer("-help"); + String outputString = result.getOutputString(); + String errorString = result.getErrorString(); + assertEquals("Wrong exit code from Enhancer with stderr:\n" + errorString, 0, result.getExitValue()); + assertTrue("Expected Usage message from out:\n" + outputString + " with err:\n" + errorString, outputString.contains("javax.jdo.Enhancer")); + } + + public void testHOption() { + // invoke enhancer with a usage option + InvocationResult result = invokeEnhancer("-h"); + String outputString = result.getOutputString(); + String errorString = result.getErrorString(); + assertEquals("Wrong exit code from Enhancer with stderr:\n" + errorString, 0, result.getExitValue()); + assertTrue("Expected Usage message from out:\n" + outputString + " with err:\n" + errorString, outputString.contains("javax.jdo.Enhancer")); + } + + public void testInvalidOption() { + // invoke enhancer with an invalid option + InvocationResult result = invokeEnhancer("-poo"); + assertEquals("Wrong return value ", ENHANCER_USAGE_ERROR, result.getExitValue()); + String errorString = result.getErrorString(); + assertTrue("Expected Usage message from err:\n" + errorString, errorString.contains("javax.jdo.Enhancer")); + } + + public void testProperties() { + // invoke enhancer with verbose option + InvocationResult result = invokeEnhancer("-v"); + String outputString = result.getOutputString(); + String errorString = result.getErrorString(); + assertEquals("Wrong exit code from Enhancer with stderr:\n" + errorString, 0, result.getExitValue()); + assertTrue("Expected MockEnhancer vendor message from out:\n" + outputString + " with err:\n" + errorString, outputString.contains(PROPERTY_ENHANCER_VENDOR_NAME)); + assertTrue("Expected MockEnhancer version message from out:\n" + outputString + " with err:\n" + errorString, outputString.contains(PROPERTY_ENHANCER_VERSION_NUMBER)); + assertTrue("Expected MockEnhancer vendor message from out:\n" + outputString + " with err:\n" + errorString, outputString.contains("Mock Enhancer")); + assertTrue("Expected MockEnhancer vendor message from out:\n" + outputString + " with err:\n" + errorString, outputString.contains("2.3.0")); + assertTrue("Expected MockEnhancer properties message from out:\n" + outputString + " with err:\n" + errorString, outputString.contains("MockKey")); + } + + public void testVOption() { + // invoke enhancer with verbose option + InvocationResult result = invokeEnhancer("-v"); + String outputString = result.getOutputString(); + String errorString = result.getErrorString(); + assertEquals("Wrong exit code from Enhancer with stderr:\n" + errorString, 0, result.getExitValue()); + assertTrue("Expected Enhancer class message from out:\n" + outputString + " with err:\n" + errorString, outputString.contains("javax.jdo.MockEnhancer")); + } + + public void testVerboseOption() { + // invoke enhancer with verbose option + InvocationResult result = invokeEnhancer("-verbose"); + String outputString = result.getOutputString(); + String errorString = result.getErrorString(); + assertEquals("Wrong exit code from Enhancer with stderr:\n" + errorString, 0, result.getExitValue()); + assertTrue("Expected Enhancer class message from out:\n" + outputString + " with err:\n" + errorString, outputString.contains("javax.jdo.MockEnhancer")); + } + + public void testVerboseClasses() { + // invoke enhancer with .class parameter + InvocationResult result = invokeEnhancer("-v some.class"); + String outputString = result.getOutputString(); + String errorString = result.getErrorString(); + assertEquals("Wrong exit code from Enhancer with stderr:\n" + errorString, 0, result.getExitValue()); + assertTrue("Expected class message from out:\n" + outputString + " with err:\n" + errorString, outputString.contains("some.class")); + assertTrue("Expected number of classes from out:\n" + outputString + " with err:\n" + errorString, outputString.contains("1")); + } + + public void testVerboseJars() { + // invoke enhancer with a .jar parameter + InvocationResult result = invokeEnhancer("-v some.jar"); + String outputString = result.getOutputString(); + String errorString = result.getErrorString(); + assertEquals("Wrong exit code from Enhancer with stderr:\n" + errorString, 0, result.getExitValue()); + assertTrue("Expected jar message from out:\n" + outputString + " with err:\n" + errorString, outputString.contains("some.jar")); + assertTrue("Expected number of jars from out:\n" + outputString + " with err:\n" + errorString, outputString.contains("1")); + } + + public void testVerboseJDOs() { + // invoke enhancer with a .jdo parameter + InvocationResult result = invokeEnhancer("-v some.jdo"); + String outputString = result.getOutputString(); + String errorString = result.getErrorString(); + assertEquals("Wrong exit code from Enhancer with stderr:\n" + errorString, 0, result.getExitValue()); + assertTrue("Expected jdo message from out:\n" + outputString + " with err:\n" + errorString, outputString.contains("some.jdo")); + assertTrue("Expected number of jdos from out:\n" + outputString + " with err:\n" + errorString, outputString.contains("1")); + } + + public void testVerboseAll() { + // invoke enhancer with multiple parameters + InvocationResult result = invokeEnhancer("-v some.class some.jar some.jdo"); + String outputString = result.getOutputString(); + String errorString = result.getErrorString(); + assertEquals("Wrong exit code from Enhancer with stderr:\n" + errorString, 0, result.getExitValue()); + assertTrue("Expected jdo message from out:\n" + outputString + " with err:\n" + errorString, outputString.contains("some.jdo")); + assertTrue("Expected jar message from out:\n" + outputString + " with err:\n" + errorString, outputString.contains("some.jar")); + assertTrue("Expected class message from out:\n" + outputString + " with err:\n" + errorString, outputString.contains("some.class")); + assertTrue("Expected number of elements from out:\n" + outputString + " with err:\n" + errorString, outputString.contains("3")); + } + + public void testVerboseCheckonlyAll() { + // invoke enhancer with a checkonly option + InvocationResult result = invokeEnhancer("-v -checkonly some.class some.jar some.jdo"); + String outputString = result.getOutputString(); + String errorString = result.getErrorString(); + assertEquals("Wrong exit code from Enhancer with stderr:\n" + errorString, 0, result.getExitValue()); + assertTrue("Expected jdo message from out:\n" + outputString + " with err:\n" + errorString, outputString.contains("some.jdo")); + assertTrue("Expected jar message from out:\n" + outputString + " with err:\n" + errorString, outputString.contains("some.jar")); + assertTrue("Expected class message from out:\n" + outputString + " with err:\n" + errorString, outputString.contains("some.class")); + assertTrue("Expected number of elements from out:\n" + outputString + " with err:\n" + errorString, outputString.contains("3")); + } + + public void testMissingPU() { + // invoke enhancer with missing parameter + InvocationResult result = invokeEnhancer("-v -pu"); + assertEquals("Wrong return value ", 3, result.getExitValue()); + } + + public void testVerbosePU() { + // invoke enhancer with a pu parameter + InvocationResult result = invokeEnhancer("-v -pu myPU -pu yourPU"); + String outputString = result.getOutputString(); + String errorString = result.getErrorString(); + assertEquals("Wrong exit code from Enhancer with stderr:\n" + errorString, 0, result.getExitValue()); + assertTrue("Expected pu message from out:\n" + outputString + " with err:\n" + errorString, outputString.contains("myPU")); + assertTrue("Expected pu message from out:\n" + outputString + " with err:\n" + errorString, outputString.contains("yourPU")); + assertTrue("Expected number of elements from out:\n" + outputString + " with err:\n" + errorString, outputString.contains("2")); + } + + public void testClasspath() { + // invoke enhancer with a classpath parameter + // JDOHelper must be loadable from this path + // the File.toURI should append "/" to the path, so only "target/classes" is needed + InvocationResult result = invokeEnhancer("-v -cp " + basedir + "/target/classes"); + String outputString = result.getOutputString(); + String errorString = result.getErrorString(); + assertEquals("Wrong exit code from Enhancer with stderr:\n" + errorString, 0, result.getExitValue()); + assertTrue("Expected classpath message from out:\n" + outputString + " with err:\n" + errorString, outputString.contains("target/classes")); + } + + public void testBadClasspath() { + // invoke enhancer with a bad classpath parameter + // JDOHelper is not loadable from this path + InvocationResult result = invokeEnhancer("-v -cp target"); + String outputString = result.getOutputString(); + String errorString = result.getErrorString(); + assertEquals("Wrong exit code from Enhancer with stderr:\n" + errorString, 1, result.getExitValue()); + assertTrue("Expected classpath error message from out:\n" + outputString + " with err:\n" + errorString, errorString.contains("JDOHelper")); + } + + public void testClasspathJar() throws IOException, InterruptedException { + // invoke enhancer with a classpath parameter + // JDOHelper must be loadable from this path + // create the jar file from the target/classes directory + Process create = Runtime.getRuntime().exec("jar -cf " + basedir + "/target/enhancer-test.jar -C " + basedir + "/target/classes ."); + int returnCode = create.waitFor(); + assertEquals("jar command returned wrong return code.", 0, returnCode); + // find the jdo.jar in target + InvocationResult result = invokeEnhancer("-v -cp " + basedir + "/target/enhancer-test.jar"); + String outputString = result.getOutputString(); + String errorString = result.getErrorString(); + assertEquals("Wrong exit code from Enhancer with stderr:\n" + errorString, 0, result.getExitValue()); + assertTrue("Expected classpath message from out:\n" + outputString + " with err:\n" + errorString, outputString.contains("target/enhancer-test.jar")); + // remove the jar file if successful + Runtime.getRuntime().exec("rm target/enhancer-test.jar").waitFor(); + } + + public void testOutputDirectory() { + // invoke enhancer with an output directory parameter + InvocationResult result = invokeEnhancer("-v -d some/output/directory"); + String outputString = result.getOutputString(); + String errorString = result.getErrorString(); + assertEquals("Wrong exit code from Enhancer with stderr:\n" + errorString, 0, result.getExitValue()); + assertTrue("Expected directory message from out:\n" + outputString + " with err:\n" + errorString, outputString.contains("some/output/directory")); + } + + public void testMissingOutputDirectory() { + // invoke enhancer with missing parameter + InvocationResult result = invokeEnhancer("-v -d"); + assertEquals("Wrong return value ", 3, result.getExitValue()); + } + + private InvocationResult invokeEnhancer(String string) { + InvocationResult result = new InvocationResult(); + try { + // create the java command to invoke the Enhancer + List commands = new ArrayList(); + // find the java command in the user's path + commands.add("java"); + commands.add("-cp"); + commands.add("" + basedir + "/target/classes" + pathDelimiter + "" + basedir + "/target/test-classes"); + commands.add("javax.jdo.Enhancer"); + // add the test options (from the method parameter) to the java command + String[] optionArray = string.split(" "); + for (String option: optionArray) { + commands.add(option); + } + String[] cmdarray = commands.toArray(new String[commands.size()]); + ProcessBuilder builder = new ProcessBuilder(cmdarray); + Process proc = builder.start(); + InputStream stdout = proc.getInputStream(); + InputStream stderr = proc.getErrorStream(); + CharBuffer outBuffer = CharBuffer.allocate(1000000); + CharBuffer errBuffer = CharBuffer.allocate(1000000); + Thread outputThread = createReaderThread(stdout, outBuffer); + Thread errorThread = createReaderThread(stderr, errBuffer); + int exitValue = proc.waitFor(); + result.setExitValue(exitValue); + errorThread.join(10000); // wait ten seconds to get stderr after process terminates + outputThread.join(10000); // wait ten seconds to get stdout after process terminates + result.setErrorString(errBuffer.toString()); + result.setOutputString(outBuffer.toString()); + // wait until the Enhancer command finishes + } catch (InterruptedException ex) { + throw new RuntimeException("InterruptedException", ex); + } catch (IOException ex) { + throw new RuntimeException("IOException", ex); + } catch (JDOException jdoex) { + jdoex.printStackTrace(); + Throwable[] throwables = jdoex.getNestedExceptions(); + System.out.println("Exception throwables of size: " + throwables.length); + for (Throwable throwable: throwables) { + throwable.printStackTrace(); + } + } + return result; + } + + private Thread createReaderThread(final InputStream input, final CharBuffer output) { + final Reader reader = new InputStreamReader(input); + Thread thread = new Thread( + new Runnable() { + public void run() { + int count = 0; + int outputBytesRead = 0; + try { + while (-1 != (outputBytesRead = reader.read(output))) { + count += outputBytesRead; + } + } catch (IOException e) { + e.printStackTrace(); + } finally { + output.flip(); + } + } + }); + thread.start(); + return thread; + } + + class InvocationResult { + private int exitValue; + private String errorString; + private String outputString; + + int getExitValue() { + return exitValue; + } + + private void setExitValue(int exitValue) { + this.exitValue = exitValue; + } + + private void setErrorString(String errorString) { + this.errorString = errorString; + } + + String getErrorString() { + return errorString; + } + + private void setOutputString(String outputString) { + this.outputString = outputString; + } + + String getOutputString() { + return outputString; + } + + } + +} Property changes on: api2/test/java/javax/jdo/EnhancerTest.java ___________________________________________________________________ Name: svn:eol-style + LF Index: api2/test/java/javax/jdo/MockEnhancer.java =================================================================== --- api2/test/java/javax/jdo/MockEnhancer.java (revision 0) +++ api2/test/java/javax/jdo/MockEnhancer.java (revision 0) @@ -0,0 +1,133 @@ +/* + * 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 javax.jdo; + + +import java.lang.instrument.IllegalClassFormatException; +import java.security.ProtectionDomain; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Properties; + +import javax.jdo.metadata.JDOMetadata; + + +/** + * Tests class javax.jdo.Enhancer (main class). + *

+ */ +public class MockEnhancer implements JDOEnhancer, Constants { + + static Properties props = new Properties(); + static { + props.put(PROPERTY_ENHANCER_VENDOR_NAME, "Mock Enhancer"); + props.put(PROPERTY_ENHANCER_VERSION_NUMBER, "2.3.0"); + props.put("MockKey", "MockValue"); + } + @SuppressWarnings("unused") + private boolean verbose; + private int numberOfElements; + private List classNames = new ArrayList(); + private List jarNames = new ArrayList(); + private List jdoNames = new ArrayList(); + private List puNames = new ArrayList(); + @SuppressWarnings("unused") + private String outputDirectory = null; + + public MockEnhancer(){ + } + + public Properties getProperties() { + return props; + } + + public JDOEnhancer setVerbose(boolean flag) { + this.verbose = flag; + return this; + } + + public JDOEnhancer setOutputDirectory(String dirName) { + outputDirectory = dirName; + return this; + } + + public JDOEnhancer setClassLoader(ClassLoader loader) { + // check to see if JDOHelper is loadable from the loader + try { + loader.loadClass("javax.jdo.JDOHelper"); + } catch (ClassNotFoundException ex) { + // bad + throw new JDOFatalInternalException("Should be able to load JDOHelper from the class loader"); + } + return this; + } + + public JDOEnhancer addPersistenceUnit(String persistenceUnit) { + numberOfElements++; + this.puNames.add(persistenceUnit); + return this; + } + + public JDOEnhancer addClass(String className, byte[] bytes) { + throw new UnsupportedOperationException("Not supported yet."); + } + + public JDOEnhancer addClasses(String... classNames) { + numberOfElements += classNames.length; + this.classNames.addAll(Arrays.asList(classNames)); + return this; + } + + public JDOEnhancer addFiles(String... metadataFiles) { + numberOfElements += metadataFiles.length; + this.jdoNames.addAll(Arrays.asList(metadataFiles)); + return this; + } + + public JDOEnhancer addJar(String jarFileName) { + numberOfElements++; + this.jarNames.add(jarFileName); + return this; + } + + public int enhance() { + return numberOfElements; + } + + public int validate() { + return numberOfElements; + } + + public byte[] getEnhancedBytes(String className) { + throw new UnsupportedOperationException("Not supported yet."); + } + + public void registerMetadata(JDOMetadata metadata) { + throw new UnsupportedOperationException("Not supported yet."); + } + + public JDOMetadata newMetadata() { + throw new UnsupportedOperationException("Not supported yet."); + } + + public byte[] transform(ClassLoader loader, String className, Class classBeingRedefined, ProtectionDomain protectionDomain, byte[] classfileBuffer) throws IllegalClassFormatException { + throw new UnsupportedOperationException("Not supported yet."); + } +} + Property changes on: api2/test/java/javax/jdo/MockEnhancer.java ___________________________________________________________________ Name: svn:eol-style + LF Index: api2/test/resources/META-INF/services/javax.jdo.JDOEnhancer =================================================================== --- api2/test/resources/META-INF/services/javax.jdo.JDOEnhancer (revision 0) +++ api2/test/resources/META-INF/services/javax.jdo.JDOEnhancer (revision 0) @@ -0,0 +1 @@ +javax.jdo.MockEnhancer Index: api2/project.xml =================================================================== --- api2/project.xml (revision 811080) +++ api2/project.xml (working copy) @@ -85,12 +85,18 @@ ${basedir}/test/schema - **/*.jdo - **/*.jdoquery - **/*.orm - **/jdoconfig.xml + **/*.jdo + **/*.jdoquery + **/*.orm + **/jdoconfig.xml + + ${basedir}/test/resources + + **/* + + jar:install Index: api2/src/java/javax/jdo/Constants.java =================================================================== --- api2/src/java/javax/jdo/Constants.java (revision 811080) +++ api2/src/java/javax/jdo/Constants.java (working copy) @@ -565,6 +565,39 @@ = "javax.jdo.PersistenceManagerFactoryClass"; /** + * "VendorName" + * + * @see JDOEnhancer#getProperties() + * @since 2.3 + */ + static String PROPERTY_ENHANCER_VENDOR_NAME + = "VendorName"; + + /** + * "VersionNumber" + * + * @see JDOEnhancer#getProperties() + * @since 2.3 + */ + static String PROPERTY_ENHANCER_VERSION_NUMBER + = "VersionNumber"; + + /** Exit value for no enhancer found + * @since 2.3 + * */ + public static int ENHANCER_NO_JDO_ENHANCER_FOUND = 2; + + /** Exit value for usage error + * @since 2.3 + * */ + public static int ENHANCER_USAGE_ERROR = 3; + + /** Exit value for an exception from the JDOEnhancer + * @since 2.3 + * */ + public static int ENHANCER_EXCEPTION = 1; + + /** * "javax.jdo.option.Optimistic" * * @see PersistenceManagerFactory#getOptimistic() Index: api2/src/java/javax/jdo/JDOHelper.java =================================================================== --- api2/src/java/javax/jdo/JDOHelper.java (revision 811080) +++ api2/src/java/javax/jdo/JDOHelper.java (working copy) @@ -89,7 +89,7 @@ /** * A mapping from jdoconfig.xsd element attributes to PMF properties. */ - static final Map ATTRIBUTE_PROPERTY_XREF + static final Map ATTRIBUTE_PROPERTY_XREF = createAttributePropertyXref(); /** The Internationalization message helper. @@ -102,8 +102,8 @@ * @return An unmodifiable Map of jdoconfig.xsd element attributes to PMF * properties. */ - static Map createAttributePropertyXref() { - Map xref = new HashMap(); + static Map createAttributePropertyXref() { + Map xref = new HashMap(); xref.put( PMF_ATTRIBUTE_CLASS, @@ -396,7 +396,7 @@ */ public static Collection getObjectIds(Collection pcs) { ArrayList result = new ArrayList(); - for (Iterator it = pcs.iterator(); it.hasNext();) { + for (Iterator it = pcs.iterator(); it.hasNext();) { result.add(getObjectId(it.next())); } return result; @@ -694,7 +694,7 @@ * @see #getPersistenceManagerFactory(java.util.Map,ClassLoader) */ public static PersistenceManagerFactory getPersistenceManagerFactory - (Map props) { + (Map props) { return getPersistenceManagerFactory( null, props, getContextClassLoader()); } @@ -714,7 +714,7 @@ * @since 1.0 */ public static PersistenceManagerFactory getPersistenceManagerFactory - (Map props, ClassLoader pmfClassLoader) { + (Map props, ClassLoader pmfClassLoader) { return getPersistenceManagerFactory( null, props, pmfClassLoader); } @@ -788,20 +788,20 @@ * @since 2.1 */ protected static PersistenceManagerFactory getPersistenceManagerFactory - (Map overrides, Map props, ClassLoader pmfClassLoader) { + (Map overrides, Map props, ClassLoader pmfClassLoader) { List exceptions = new ArrayList(); if (pmfClassLoader == null) throw new JDOFatalUserException (msg.msg ( "EXC_GetPMFNullLoader")); //NOI18N - // first try to get the class name from the properties object. + // first try to get the class name from the properties object. String pmfClassName = (String) props.get ( PROPERTY_PERSISTENCE_MANAGER_FACTORY_CLASS); if (!isNullOrBlank(pmfClassName)) { - // a valid name was returned from the properties. + // a valid name was returned from the properties. return invokeGetPersistenceManagerFactoryOnImplementation( - pmfClassName, overrides, props, pmfClassLoader); + pmfClassName, overrides, props, pmfClassLoader); } else { /* @@ -820,7 +820,7 @@ * Otherwise add the exception thrown to * an exception list. */ - Enumeration urls = null; + Enumeration urls = null; try { urls = getResources(pmfClassLoader, SERVICE_LOOKUP_PMF_RESOURCE_NAME); @@ -949,7 +949,7 @@ * @see #getPersistenceManagerFactory(Map,String,ClassLoader,ClassLoader) */ public static PersistenceManagerFactory getPersistenceManagerFactory - (Map overrides, String name) { + (Map overrides, String name) { ClassLoader cl = getContextClassLoader(); return getPersistenceManagerFactory(overrides, name, cl, cl); @@ -963,7 +963,7 @@ * @see #getPersistenceManagerFactory(Map,String,ClassLoader,ClassLoader) */ public static PersistenceManagerFactory getPersistenceManagerFactory - (Map overrides, String name, ClassLoader resourceLoader) { + (Map overrides, String name, ClassLoader resourceLoader) { return getPersistenceManagerFactory( overrides, name, resourceLoader, resourceLoader); @@ -1048,7 +1048,7 @@ * @see Constants#ANONYMOUS_PERSISTENCE_MANAGER_FACTORY_NAME */ public static PersistenceManagerFactory getPersistenceManagerFactory( - Map overrides, + Map overrides, String name, ClassLoader resourceLoader, ClassLoader pmfLoader) { @@ -1110,11 +1110,11 @@ */ protected static PersistenceManagerFactory invokeGetPersistenceManagerFactoryOnImplementation( - String pmfClassName, Map overrides, Map properties, ClassLoader cl) { + String pmfClassName, Map overrides, Map properties, ClassLoader cl) { if (overrides != null) { // overrides is not null; use getPersistenceManagerFactory(Map overrides, Map props) try { - Class implClass = forName(pmfClassName, true, cl); + Class implClass = forName(pmfClassName, true, cl); Method m = getMethod(implClass, "getPersistenceManagerFactory", //NOI18N new Class[]{Map.class, Map.class}); @@ -1152,7 +1152,7 @@ } else { // overrides is null; use getPersistenceManagerFactory(Map props) try { - Class implClass = forName(pmfClassName, true, cl); + Class implClass = forName(pmfClassName, true, cl); Method m = getMethod(implClass, "getPersistenceManagerFactory", //NOI18N new Class[]{Map.class}); @@ -1460,7 +1460,7 @@ // check for duplicate properties among atts & elems if (requestedPMFName.equals(pmfName)) { - Iterator it = + Iterator it = pmfPropertiesFromAttributes.keySet().iterator(); while (it.hasNext()) { String property = (String) it.next(); @@ -1833,7 +1833,7 @@ * @since 2.3 */ public static JDOEnhancer getEnhancer() { - return getEnhancer(getContextClassLoader()); + return getEnhancer(getContextClassLoader()); } /** @@ -1845,43 +1845,45 @@ * @since 2.3 */ public static JDOEnhancer getEnhancer(ClassLoader loader) { - ClassLoader ctrLoader = loader; - if (ctrLoader == null) { - ctrLoader = Thread.currentThread().getContextClassLoader(); - } + ClassLoader ctrLoader = loader; + if (ctrLoader == null) { + ctrLoader = Thread.currentThread().getContextClassLoader(); + } - /* - * If you have a jar file that provides the jdo enhancer implementation, - * a file naming the implementation goes into the file - * packaged into the jar file, called "META-INF/services/javax.jdo.JDOEnhancer". - * The contents of the file is a string that is the enhancer class name. - * For each file in the class loader named "META-INF/services/javax.jdo.JDOEnhancer", - * this method will invoke the default constructor of the implementation class. - * Return the enhancer if a valid class name is extracted from resources and - * the invocation returns an instance. - * Otherwise add the exception thrown to an exception list. - */ - ArrayList exceptions = new ArrayList(); - try { - Enumeration urls = getResources(loader, SERVICE_LOOKUP_ENHANCER_RESOURCE_NAME); - if (urls != null) { - while (urls.hasMoreElements()) { - try { + /* + * If you have a jar file that provides the jdo enhancer implementation, + * a file naming the implementation goes into the file + * packaged into the jar file, called "META-INF/services/javax.jdo.JDOEnhancer". + * The contents of the file is a string that is the enhancer class name. + * For each file in the class loader named "META-INF/services/javax.jdo.JDOEnhancer", + * this method will invoke the default constructor of the implementation class. + * Return the enhancer if a valid class name is extracted from resources and + * the invocation returns an instance. + * Otherwise add the exception thrown to an exception list. + */ + ArrayList exceptions = new ArrayList(); + int numberOfJDOEnhancers = 0; + try { + Enumeration urls = getResources(loader, SERVICE_LOOKUP_ENHANCER_RESOURCE_NAME); + if (urls != null) { + while (urls.hasMoreElements()) { + numberOfJDOEnhancers++; + try { String enhancerClassName = getClassNameFromURL((URL)urls.nextElement()); - Class enhancerClass = forName(enhancerClassName, true, ctrLoader); + Class enhancerClass = forName(enhancerClassName, true, ctrLoader); JDOEnhancer enhancer = (JDOEnhancer)enhancerClass.newInstance(); return enhancer; - } catch (Throwable ex) { - // remember exceptions from failed enhancer invocations - exceptions.add(ex); - } - } - } - } catch (Throwable ex) { - exceptions.add(ex); - } + } catch (Throwable ex) { + // remember exceptions from failed enhancer invocations + exceptions.add(ex); + } + } + } + } catch (Throwable ex) { + exceptions.add(ex); + } - throw new JDOFatalUserException(msg.msg("EXC_GetEnhancerNoValidEnhancerAvailable"), + throw new JDOFatalUserException(msg.msg("EXC_GetEnhancerNoValidEnhancerAvailable", numberOfJDOEnhancers), (Throwable[])exceptions.toArray(new Throwable[exceptions.size()])); } @@ -1924,9 +1926,9 @@ * @return the Method instance */ private static Method getMethod( - final Class implClass, + final Class implClass, final String methodName, - final Class[] parameterTypes) + final Class[] parameterTypes) throws NoSuchMethodException { try { return AccessController.doPrivileged( @@ -1997,15 +1999,15 @@ * @param loader which class loader to use * @return the class */ - private static Class forName( + private static Class forName( final String name, final boolean init, final ClassLoader loader) throws ClassNotFoundException { try { return AccessController.doPrivileged( - new PrivilegedExceptionAction() { - public Class run() throws ClassNotFoundException { + new PrivilegedExceptionAction>() { + public Class run() throws ClassNotFoundException { return Class.forName(name, init, loader); } } Index: api2/src/java/javax/jdo/Enhancer.java =================================================================== --- api2/src/java/javax/jdo/Enhancer.java (revision 0) +++ api2/src/java/javax/jdo/Enhancer.java (revision 0) @@ -0,0 +1,442 @@ +/* + * 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 javax.jdo; + +import java.io.File; +import java.net.MalformedURLException; +import java.net.URI; +import java.net.URL; +import java.net.URLClassLoader; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; +import java.util.Properties; +import java.util.Set; +import java.util.Map.Entry; + +import javax.jdo.spi.I18NHelper; + +/** + * Main class to invoke a JDO Enhancer. + * The enhancer is invoked with the following command line: + * + * java -cp <classpath> javax.jdo.Enhancer <options> <directory, file, or resource names> + * + * <classpath> must contain the jdo specification jar, the implementation jar and any + * implementation dependencies, the statically-compiled classes, and the jdo + * metadata files loadable as resources. + * + *

<options> include: + *

  • ? : print usage to stderr and exit + *
  • -h : print usage to stderr and exit + *
  • -help : print usage to stderr and exit + *
  • -pu <persistence-unit-name> : the name of a persistence unit + *
  • -d <target directory> : write the enhanced classes to the specified directory + *
  • -checkonly : just check the classes for enhancement status + *
  • -v : verbose output + *
  • -r : recurse through directories to find all classes and metadata files to enhance + *
  • -cp <enhancer class loader path> : if not already included in the java class loader, + * this parameter must contain the statically-compiled classes, and the jdo metadata + * files loadable as resources + *
<directory, file, or resource names> + *
  • Directory names must not end in ".jdo", ".jar", or ".class" + *
  • Directories will be searched for files with suffixes ".jdo", ".jar", and ".class" + *
  • Directories will be searched recursively if the -r option is set + *
+ * + * @since 2.3 + */ +public class Enhancer implements Constants { + + /** The Internationalization message helper. */ + private final static I18NHelper msg = + I18NHelper.getInstance ("javax.jdo.Bundle"); //NOI18N + + /** New Line */ + private char NL = '\n'; //NOI18N + /** Jar file suffix */ + private String JAR_FILE_SUFFIX = ".jar"; //NOI18N + /** JDO Metadata file suffix */ + private String JDO_FILE_SUFFIX = ".jdo"; //NOI18N + /** Class file suffix */ + private String CLASS_FILE_SUFFIX = ".class"; //NOI18N + + /** Error indicator */ + private boolean error = false; + /** If set, process parameters, print usage, and exit. */ + private boolean printAndExit = false; + + /** Persistence Units */ + private List persistenceUnitNames = new ArrayList(); + /** Target Directory Parameter */ + private String directoryName = null; + /** ClassLoader for JDOEnhancer */ + private ClassLoader loader = null; + /** Classpath (-cp) parameter */ + private String classPath = null; + /** Check Only flag */ + private boolean checkOnly = false; + /** Verbose flag */ + private boolean verbose = false; + /** Recurse flag */ + private boolean recurse = false; + /** Error messages should be empty unless there is an error */ + private StringBuilder errorBuffer = new StringBuilder(); + /** Verbose messages are always collected but only output if verbose flag is set */ + private StringBuilder verboseBuffer = new StringBuilder(); + /** File Names */ + private List fileNames = new ArrayList(); + /** Class File Names */ + private List classFileNames = new ArrayList(); + /** JDO File Names */ + private List jdoFileNames = new ArrayList(); + /** Jar File Names */ + private List jarFileNames = new ArrayList(); + /** The number of classes validated by the JDOEnhancer */ + private int numberOfValidatedClasses = 0; + /** The number of classes enhanced by the JDOEnhancer */ + private int numberOfEnhancedClasses = 0; + + /** The properties from the JDOEnhancer */ + private Properties properties; + + /** Run the enhancer from the command line. + * + * @param args command line arguments + */ + public static void main (String[] args) { + Enhancer enhancerMain = new Enhancer(); + enhancerMain.run(args); + } + + /** Execute the enhancer. + * + * @param args the command line arguments + */ + private void run(String[] args) { + // processArgs will exit if errors or help + processArgs(args); + JDOEnhancer enhancer = null; + try { + enhancer = JDOHelper.getEnhancer(); + } catch (JDOException jdoex) { + jdoex.printStackTrace(); // outputs to stderr + exit(ENHANCER_NO_JDO_ENHANCER_FOUND); + } + + try { + // provide verbose property settings of the JDOEnhancer we just loaded + properties = enhancer.getProperties(); + addVerboseMessage("MSG_EnhancerClass", enhancer.getClass().getName()); //NOI18N + addVerboseMessage("MSG_EnhancerProperty", PROPERTY_ENHANCER_VENDOR_NAME, properties.getProperty(PROPERTY_ENHANCER_VENDOR_NAME)); + addVerboseMessage("MSG_EnhancerProperty", PROPERTY_ENHANCER_VERSION_NUMBER, properties.getProperty(PROPERTY_ENHANCER_VERSION_NUMBER)); + Set> props = properties.entrySet(); + Iterator> entries = props.iterator(); + while (entries.hasNext()) { + Entry entry = entries.next(); + if (!(PROPERTY_ENHANCER_VENDOR_NAME.equals(entry.getKey()) || + PROPERTY_ENHANCER_VERSION_NUMBER.equals(entry.getKey()))) { + addVerboseMessage("MSG_EnhancerProperty", (String)entry.getKey(), (String)entry.getValue()); + } + } + enhancer.setVerbose(verbose); + if (loader != null) { + enhancer.setClassLoader(loader); + } + + int numberOfClasses = classFileNames.size(); + if (numberOfClasses != 0) { + enhancer.addClasses(classFileNames.toArray(new String[numberOfClasses])); + } + int numberOfFiles = jdoFileNames.size(); + if (numberOfFiles != 0) { + enhancer.addFiles(jdoFileNames.toArray(new String[numberOfFiles])); + } + if (0 < jarFileNames.size()) { + for (String jarFileName : jarFileNames) { + enhancer.addJar(jarFileName); + } + } + if (persistenceUnitNames != null) { + for (String persistenceUnitName: persistenceUnitNames) { + enhancer.addPersistenceUnit(persistenceUnitName); + } + } + if (directoryName != null) { + enhancer.setOutputDirectory(directoryName); + } + if (checkOnly) { + numberOfValidatedClasses = enhancer.validate(); + addVerboseMessage("MSG_EnhancerValidatedClasses", numberOfValidatedClasses); //NOI18N + } else { + numberOfEnhancedClasses = enhancer.enhance(); + addVerboseMessage("MSG_EnhancerEnhancedClasses", numberOfEnhancedClasses); //NOI18N + } + exit(0); // good exit + } catch (Exception ex) { + ex.printStackTrace(); // outputs to stderr + exit(ENHANCER_EXCEPTION); // error exit + } + } + + /** Process the command line arguments and exit if there is a usage request or an error. + * + * @param args the command line arguments + */ + private void processArgs(String[] args) { + parseArgs(args); + parseFiles(fileNames.toArray(new String[fileNames.size()]), true, recurse); + loader = prepareClassLoader(classPath); + if (error) { + addErrorMessage(msg.msg("MSG_EnhancerUsage")); //NOI18N + exit(ENHANCER_USAGE_ERROR); // error exit + } + if (printAndExit) { + addVerboseMessage("MSG_EnhancerUsage"); //NOI18N + exit(0); // good exit + } + } + + /** Parse the command line arguments. Put the results into fields. + * + * @param args the command line arguments + */ + private void parseArgs(String[] args) { + boolean doneWithOptions = false; + fileNames = new ArrayList(); + for (int i = 0; i < args.length; ++i) { + String arg = args[i]; + // if first argument is ? then simply print usage and return. + if ("?".equals(arg)) { + printAndExit = true; + return; + } + if (!doneWithOptions) { + if (arg.startsWith("-")) { //NOI18N + String option = arg.substring(1); + if ("help".equals(option)) { //NOI18N + addVerboseMessage("MSG_EnhancerProcessing", "-help"); //NOI18N + setPrintAndExit(); + } else if ("h".equals(option)) { //NOI18N + addVerboseMessage("MSG_EnhancerProcessing", "-h"); //NOI18N + setPrintAndExit(); + } else if ("v".equals(option)) { //NOI18N + addVerboseMessage("MSG_EnhancerProcessing", "-v"); //NOI18N + verbose = true; + } else if ("verbose".equals(option)) { //NOI18N + addVerboseMessage("MSG_EnhancerProcessing", "-verbose"); //NOI18N + verbose = true; + } else if ("pu".equals(option)) { //NOI18N + if (hasNextArgument("MSG_EnhancerProcessing", "-pu", i, args.length)) { //NOI18N + String puName = args[++i]; + addVerboseMessage("MSG_EnhancerPersistenceUnitName", puName); //NOI18N + persistenceUnitNames.add(puName); + } else { + setError(); + } + } else if ("cp".equals(option)) { //NOI18N + if (hasNextArgument("MSG_EnhancerProcessing", "-cp", i, args.length)) { //NOI18N + classPath = args[++i]; + addVerboseMessage("MSG_EnhancerClassPath", classPath); //NOI18N + } else { + setError(); + } + } else if ("d".equals(option)) { //NOI18N + if (hasNextArgument("MSG_EnhancerProcessing", "-d", i, args.length)) { //NOI18N + directoryName = args[++i]; + addVerboseMessage("MSG_EnhancerOutputDirectory", directoryName); //NOI18N + } else { + setError(); + } + } else if ("checkonly".equals(option)) { //NOI18N + addVerboseMessage("MSG_EnhancerProcessing", "-checkonly"); //NOI18N + checkOnly = true; + } else if ("r".equals(option)) { //NOI18N + addVerboseMessage("MSG_EnhancerProcessing", "-r"); //NOI18N + recurse = true; + } else { + setError(); + addErrorMessage(msg.msg("ERR_EnhancerUnrecognizedOption", option)); //NOI18N + } + } else { + doneWithOptions = true; + fileNames.add(arg); + } + } else { + fileNames.add(arg); + } + } + } + + /** Check whether there is another parameter (the argument for an option + * that requires an argument). + * @param msgId the message id for an error message + * @param where the parameter for the message + * @param i the index into the parameter array + * @param length the length of the parameter array + * @return + */ + private boolean hasNextArgument(String msgId, String where, int i, int length) { + if (i + 1 >= length) { + setError(); + addErrorMessage(msg.msg(msgId, where)); + addErrorMessage(msg.msg("ERR_EnhancerRequiredArgumentMissing")); //NOI18N + return false; + } + return true; + } + + /** + * Files can be one of four types: + *
  1. directory: the directory is examined for files of the following types + *
  2. .class: this is a java class file + *
  3. .jdo: this is a jdo metadata file + *
  4. .jar: this is a jar file + *
+ * If the recursion flag is set, directories contained in directories are examined, + * recursively. + */ + private void parseFiles(String[] fileNames, boolean search, boolean recurse) { + for (String fileName: fileNames) { + if (fileName.endsWith(JAR_FILE_SUFFIX)) { + // add to jar file names + jarFileNames.add(fileName); + addVerboseMessage("MSG_EnhancerJarFileName", fileName); //NOI18N + } else if (fileName.endsWith(JDO_FILE_SUFFIX)) { + // add to jdo file names + jdoFileNames.add(fileName); + addVerboseMessage("MSG_EnhancerJDOFileName", fileName); //NOI18N + } else if (fileName.endsWith(CLASS_FILE_SUFFIX)) { + // add to class file names + classFileNames.add(fileName); + addVerboseMessage("MSG_EnhancerClassFileName", fileName); //NOI18N + } else { + // assume a directory if no suffix + File directory = new File(fileName); + if (directory.isDirectory() && search) { + String[] files = directory.list(); + if (files != null) { + parseFiles(files, recurse, recurse); + } + } + } + } + } + + /** Prepare the class loader from the classPath specified + * + * @param classPath the classPath string from the "-cp classPath" option + * @return the class loader + */ + private ClassLoader prepareClassLoader(String classPath) { + if (classPath == null) + return null; + ClassLoader result = null; + // separate classPath using system class path separator + String separator = System.getProperty("path.separator"); + String[] paths = classPath.split(separator); + List urls = new ArrayList(); + for (String path: paths) { + // for each path construct a URL from the File + File file = new File(path); + URI uri = file.toURI(); + try { + URL url = uri.toURL(); + addVerboseMessage("MSG_EnhancerClassPath", url.toString()); + urls.add(url); + } catch (MalformedURLException e) { + setError(); + addErrorMessage(msg.msg("ERR_EnhancerBadClassPath", file)); + } + } + result = new URLClassLoader(urls.toArray(new URL[urls.size()]), null); + return result; + } + + /** Add a message to stderr. + * + * @param message the internationalized message to add + */ + private void addErrorMessage(String message) { + errorBuffer.append(message); + errorBuffer.append(NL); + } + + /** Set the error flag. + * + */ + private void setError() { + error = true; + } + + /** Set the print-and-exit flag. + * + */ + private void setPrintAndExit() { + printAndExit = true; + } + + /** Exit this process. + * + * @param exitValue the process exit value + */ + private void exit(int exitValue) { + System.out.print(verboseBuffer.toString()); + System.err.print(errorBuffer.toString()); + System.exit(exitValue); + } + + /** Add a message to the verbose message buffer. + * + * @param msgId the message id + * @param where the parameter + */ + private void addVerboseMessage(String msgId, String... where) { + verboseBuffer.append(msg.msg(msgId, where)); + verboseBuffer.append(NL); + } + + /** Add a message to the verbose message buffer. + * + * @param msgId the message id + * @param where the parameter + */ + private void addVerboseMessage(String msgId, String where) { + verboseBuffer.append(msg.msg(msgId, where)); + verboseBuffer.append(NL); + } + + /** Add a message to the verbose message buffer. + * + * @param msgId the message id + */ + private void addVerboseMessage(String msgId) { + verboseBuffer.append(msg.msg(msgId)); + verboseBuffer.append(NL); + } + + /** Add a message to the verbose message buffer. + * + * @param msgId the message id + * @param where the parameter + */ + private void addVerboseMessage(String msgId, int where) { + addVerboseMessage(msgId, String.valueOf(where)); + } + +} \ No newline at end of file Property changes on: api2/src/java/javax/jdo/Enhancer.java ___________________________________________________________________ Name: svn:eol-style + LF Index: api2/src/java/javax/jdo/Bundle.properties =================================================================== --- api2/src/java/javax/jdo/Bundle.properties (revision 811080) +++ api2/src/java/javax/jdo/Bundle.properties (working copy) @@ -122,5 +122,35 @@ or the given persistence unit name "{0}" was not found. EXC_GetEnhancerNoValidEnhancerAvailable=\ -There were no valid JDOEnhancer implementations identified in the CLASSPATH. \ +There are {0} services entries for the JDOEnhancer; \ +there were no valid JDOEnhancer implementations found in the CLASSPATH. \ The file META-INF/services/javax.jdo.JDOEnhancer should name the implementation class. +MSG_EnhancerUsage=\ +Usage: java -cp javax.jdo.Enhancer \n\ +options:\n\ + \t? (print this message and exit)\n\ + \t-h (print this message and exit)\n\ + \t-help (print this message and exit)\n\ + \t-cp (use the class path with its own class loader)\n\ + \t-pu (look for the persistence unit in META-INF/persistence.xml)\n\ + \t-d (write enhanced classes with package structure into this directory)\n\ + \t-checkonly (do not enhance; just check)\n\ + \t-verbose (output detail information)\n\ + \t-v (output detail information)\n\ + \t-r (recursively descend into parameter directories)\n\ +files:\n\ + \tfiles and directories to be enhanced, including .class and .jdo files +ERR_EnhancerRequiredArgumentMissing=Required Argument Missing. +ERR_EnhancerUnrecognizedOption=Enhancer unrecognized option {0}. +MSG_EnhancerProcessing=Enhancer Processing {0}. +MSG_EnhancerValidatedClasses=Enhancer validated {0} classes. +MSG_EnhancerEnhancedClasses=Enhancer enhanced {0} classes. +MSG_EnhancerClass=Enhancer found JDOEnhancer of class {0}. +MSG_EnhancerJarFileName=Enhancer adding jar file {0}. +MSG_EnhancerJDOFileName=Enhancer adding jdo file {0}. +MSG_EnhancerClassFileName=Enhancer adding class file {0}. +MSG_EnhancerPersistenceUnitName=Enhancer adding Persistence Unit {0}. +MSG_EnhancerClassPath=Enhancer processing classpath {0}. +MSG_EnhancerOutputDirectory=Enhancer processing output directory {0}. +ERR_EnhancerBadClassPath=Enhancer cannot construct URL from path {0}. +MSG_EnhancerProperty:Enhancer property key:{0} value:{1}. Index: api2/pom.xml =================================================================== --- api2/pom.xml (revision 811080) +++ api2/pom.xml (working copy) @@ -50,6 +50,9 @@ + ${basedir}/test/resources + + ${basedir}/test/schema **/*.jdo Index: tck2/project.properties =================================================================== --- tck2/project.properties (revision 811114) +++ tck2/project.properties (working copy) @@ -84,8 +84,8 @@ # JDORI enhancer jdori.enhanced.dir = ${maven.build.dir}/enhanced/jdori -jdori.enhancer.main = org.datanucleus.enhancer.DataNucleusEnhancer -jdori.enhancer.options = -enhancerName asm -v -d "${enhanced.dir}" +jdori.enhancer.main = javax.jdo.Enhancer +jdori.enhancer.options = -v -d "${enhanced.dir}" jdori.enhancer.args = ${jdo.tck.jdometadata.files} # connection pooling dependencies Index: tck2/src/conf/jdo-2_3-signatures.txt =================================================================== --- tck2/src/conf/jdo-2_3-signatures.txt (revision 811114) +++ tck2/src/conf/jdo-2_3-signatures.txt (working copy) @@ -245,6 +245,13 @@ public static final String TX_REPEATABLE_READ = "repeatable-read"; public static final String TX_SNAPSHOT = "snapshot"; public static final String TX_SERIALIZABLE = "serializable"; + static String PROPERTY_ENHANCER_VENDOR_NAME + = "VendorName"; + static String PROPERTY_ENHANCER_VERSION_NUMBER + = "VersionNumber"; + public static int ENHANCER_EXCEPTION = 1; + public static int ENHANCER_NO_JDO_ENHANCER_FOUND = 2; + public static int ENHANCER_USAGE_ERROR = 3; } public interface javax.jdo.datastore.DataStoreCache {