From 634bdc5c921382bbc0f5e5c90569b087f61138ba Mon Sep 17 00:00:00 2001 From: Patrick Linskey Date: Fri, 16 Nov 2007 00:51:07 +0000 Subject: [PATCH] OPENJPA-9 git-svn-id: https://svn.apache.org/repos/asf/openjpa/trunk@595508 13f79535-47bb-0310-9956-ffa450edef68 --- .../jdbc/kernel/ClassTableJDBCSeq.java | 22 ++- .../openjpa/jdbc/kernel/NativeJDBCSeq.java | 22 ++- .../openjpa/jdbc/kernel/TableJDBCSeq.java | 22 ++- .../jdbc/kernel/ValueTableJDBCSeq.java | 22 ++- .../apache/openjpa/jdbc/meta/MappingTool.java | 24 +-- .../openjpa/jdbc/meta/ReverseMappingTool.java | 22 ++- .../openjpa/jdbc/schema/SchemaTool.java | 22 ++- .../jdbc/schema/TableSchemaFactory.java | 22 ++- .../openjpa/enhance/ApplicationIdTool.java | 25 +-- .../apache/openjpa/enhance/PCEnhancer.java | 40 +++-- .../org/apache/openjpa/meta/MetaDataTool.java | 22 ++- .../lib/conf/AbstractProductDerivation.java | 14 ++ .../openjpa/lib/conf/Configurations.java | 74 ++++++++- .../openjpa/lib/conf/ProductDerivation.java | 35 ++++ .../openjpa/lib/conf/ProductDerivations.java | 62 +++++++ .../TestEnhancementWithMultiplePUs.java | 151 ++++++++++++++++++ .../enhance/UnenhancedBootstrapInstance.java | 28 ++++ .../enhance/UnenhancedBootstrapInstance2.java | 28 ++++ .../openjpa/lib/conf/TestAnchorParsing.java | 63 ++++++++ .../persistence/test/PersistenceTestCase.java | 18 ++- .../test/resources/META-INF/persistence.xml | 10 +- .../PersistenceProductDerivation.java | 27 ++++ .../src/doc/manual/ref_guide_conf.xml | 12 ++ 23 files changed, 687 insertions(+), 100 deletions(-) create mode 100644 openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/enhance/TestEnhancementWithMultiplePUs.java create mode 100644 openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/enhance/UnenhancedBootstrapInstance.java create mode 100644 openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/enhance/UnenhancedBootstrapInstance2.java create mode 100644 openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/lib/conf/TestAnchorParsing.java diff --git a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/ClassTableJDBCSeq.java b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/ClassTableJDBCSeq.java index 377e937bd..2182caae1 100644 --- a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/ClassTableJDBCSeq.java +++ b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/ClassTableJDBCSeq.java @@ -168,14 +168,20 @@ public class ClassTableJDBCSeq */ public static void main(String[] args) throws Exception { Options opts = new Options(); - args = opts.setFromCmdLine(args); - JDBCConfiguration conf = new JDBCConfigurationImpl(); - try { - if (!run(conf, args, opts)) - System.out.println(_loc.get("clstable-seq-usage")); - } finally { - conf.close(); - } + final String[] arguments = opts.setFromCmdLine(args); + boolean ret = Configurations.runAgainstAllAnchors(opts, + new Configurations.Runnable() { + public boolean run(Options opts) throws Exception { + JDBCConfiguration conf = new JDBCConfigurationImpl(); + try { + return ClassTableJDBCSeq.run(conf, arguments, opts); + } finally { + conf.close(); + } + } + }); + if (!ret) + System.out.println(_loc.get("clstable-seq-usage")); } /** diff --git a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/NativeJDBCSeq.java b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/NativeJDBCSeq.java index 13fc8338c..776c6e9dd 100644 --- a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/NativeJDBCSeq.java +++ b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/NativeJDBCSeq.java @@ -315,14 +315,20 @@ public class NativeJDBCSeq public static void main(String[] args) throws Exception { Options opts = new Options(); - args = opts.setFromCmdLine(args); - JDBCConfiguration conf = new JDBCConfigurationImpl(); - try { - if (!run(conf, args, opts)) - System.out.println(_loc.get("native-seq-usage")); - } finally { - conf.close(); - } + final String[] arguments = opts.setFromCmdLine(args); + boolean ret = Configurations.runAgainstAllAnchors(opts, + new Configurations.Runnable() { + public boolean run(Options opts) throws Exception { + JDBCConfiguration conf = new JDBCConfigurationImpl(); + try { + return NativeJDBCSeq.run(conf, arguments, opts); + } finally { + conf.close(); + } + } + }); + if (!ret) + System.out.println(_loc.get("native-seq-usage")); } /** diff --git a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/TableJDBCSeq.java b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/TableJDBCSeq.java index 25b2bd67b..238505a8f 100644 --- a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/TableJDBCSeq.java +++ b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/TableJDBCSeq.java @@ -614,14 +614,20 @@ public class TableJDBCSeq public static void main(String[] args) throws Exception { Options opts = new Options(); - args = opts.setFromCmdLine(args); - JDBCConfiguration conf = new JDBCConfigurationImpl(); - try { - if (!run(conf, args, opts)) - System.out.println(_loc.get("seq-usage")); - } finally { - conf.close(); - } + final String[] arguments = opts.setFromCmdLine(args); + boolean ret = Configurations.runAgainstAllAnchors(opts, + new Configurations.Runnable() { + public boolean run(Options opts) throws Exception { + JDBCConfiguration conf = new JDBCConfigurationImpl(); + try { + return TableJDBCSeq.run(conf, arguments, opts); + } finally { + conf.close(); + } + } + }); + if (!ret) + System.out.println(_loc.get("seq-usage")); } /** diff --git a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/ValueTableJDBCSeq.java b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/ValueTableJDBCSeq.java index a8868c11c..38d76d92a 100644 --- a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/ValueTableJDBCSeq.java +++ b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/ValueTableJDBCSeq.java @@ -120,14 +120,20 @@ public class ValueTableJDBCSeq public static void main(String[] args) throws Exception { Options opts = new Options(); - args = opts.setFromCmdLine(args); - JDBCConfiguration conf = new JDBCConfigurationImpl(); - try { - if (!run(conf, args, opts)) - System.out.println(_loc.get("clstable-seq-usage")); - } finally { - conf.close(); - } + final String[] arguments = opts.setFromCmdLine(args); + boolean ret = Configurations.runAgainstAllAnchors(opts, + new Configurations.Runnable() { + public boolean run(Options opts) throws Exception { + JDBCConfiguration conf = new JDBCConfigurationImpl(); + try { + return ValueTableJDBCSeq.run(conf, arguments, opts); + } finally { + conf.close(); + } + } + }); + if (!ret) + System.out.println(_loc.get("clstable-seq-usage")); } /** diff --git a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/MappingTool.java b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/MappingTool.java index 84af12c02..91533e548 100644 --- a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/MappingTool.java +++ b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/MappingTool.java @@ -912,17 +912,23 @@ public class MappingTool * -f mypackage.orm -a export mypackage.jdo * */ - public static void main(String[] args) + public static void main(String[] arguments) throws IOException, SQLException { Options opts = new Options(); - args = opts.setFromCmdLine(args); - JDBCConfiguration conf = new JDBCConfigurationImpl(); - try { - if (!run(conf, args, opts)) - System.err.println(_loc.get("tool-usage")); - } finally { - conf.close(); - } + final String[] args = opts.setFromCmdLine(arguments); + boolean ret = Configurations.runAgainstAllAnchors(opts, + new Configurations.Runnable() { + public boolean run(Options opts) throws IOException, SQLException { + JDBCConfiguration conf = new JDBCConfigurationImpl(); + try { + return MappingTool.run(conf, args, opts); + } finally { + conf.close(); + } + } + }); + if (!ret) + System.err.println(_loc.get("tool-usage")); } /** diff --git a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/ReverseMappingTool.java b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/ReverseMappingTool.java index 1db9dad62..f0860efc9 100644 --- a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/ReverseMappingTool.java +++ b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/meta/ReverseMappingTool.java @@ -1819,14 +1819,20 @@ public class ReverseMappingTool public static void main(String[] args) throws IOException, SQLException { Options opts = new Options(); - args = opts.setFromCmdLine(args); - JDBCConfiguration conf = new JDBCConfigurationImpl(); - try { - if (!run(conf, args, opts)) - System.out.println(_loc.get("revtool-usage")); - } finally { - conf.close(); - } + final String[] arguments = opts.setFromCmdLine(args); + boolean ret = Configurations.runAgainstAllAnchors(opts, + new Configurations.Runnable() { + public boolean run(Options opts) throws Exception { + JDBCConfiguration conf = new JDBCConfigurationImpl(); + try { + return ReverseMappingTool.run(conf, arguments, opts); + } finally { + conf.close(); + } + } + }); + if (!ret) + System.out.println(_loc.get("revtool-usage")); } /** diff --git a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/schema/SchemaTool.java b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/schema/SchemaTool.java index 199b624d4..3ea7dea1d 100644 --- a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/schema/SchemaTool.java +++ b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/schema/SchemaTool.java @@ -1333,14 +1333,20 @@ public class SchemaTool { public static void main(String[] args) throws IOException, SQLException { Options opts = new Options(); - args = opts.setFromCmdLine(args); - JDBCConfiguration conf = new JDBCConfigurationImpl(); - try { - if (!run(conf, args, opts)) - System.out.println(_loc.get("tool-usage")); - } finally { - conf.close(); - } + final String[] arguments = opts.setFromCmdLine(args); + boolean ret = Configurations.runAgainstAllAnchors(opts, + new Configurations.Runnable() { + public boolean run(Options opts) throws Exception { + JDBCConfiguration conf = new JDBCConfigurationImpl(); + try { + return SchemaTool.run(conf, arguments, opts); + } finally { + conf.close(); + } + } + }); + if (!ret) + System.out.println(_loc.get("tool-usage")); } /** diff --git a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/schema/TableSchemaFactory.java b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/schema/TableSchemaFactory.java index 13d2913e1..53d33dc60 100644 --- a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/schema/TableSchemaFactory.java +++ b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/schema/TableSchemaFactory.java @@ -449,14 +449,20 @@ public class TableSchemaFactory public static void main(String[] args) throws IOException, SQLException { Options opts = new Options(); - args = opts.setFromCmdLine(args); - JDBCConfiguration conf = new JDBCConfigurationImpl(); - try { - if (!run(conf, args, opts)) - System.out.println(_loc.get("sch-usage")); - } finally { - conf.close(); - } + final String[] arguments = opts.setFromCmdLine(args); + boolean ret = Configurations.runAgainstAllAnchors(opts, + new Configurations.Runnable() { + public boolean run(Options opts) throws Exception { + JDBCConfiguration conf = new JDBCConfigurationImpl(); + try { + return TableSchemaFactory.run(conf, arguments, opts); + } finally { + conf.close(); + } + } + }); + if (!ret) + System.out.println(_loc.get("sch-usage")); } /** diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/ApplicationIdTool.java b/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/ApplicationIdTool.java index 6e437883a..274fde1d2 100644 --- a/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/ApplicationIdTool.java +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/ApplicationIdTool.java @@ -75,7 +75,7 @@ public class ApplicationIdTool { private static final String TOKENIZER_CUSTOM = "Tokenizer"; private static final String TOKENIZER_STD = "StringTokenizer"; - private static Localizer _loc = Localizer.forPackage + private static final Localizer _loc = Localizer.forPackage (ApplicationIdTool.class); private final Log _log; @@ -1282,14 +1282,21 @@ public class ApplicationIdTool { public static void main(String[] args) throws IOException, ClassNotFoundException { Options opts = new Options(); - args = opts.setFromCmdLine(args); - OpenJPAConfiguration conf = new OpenJPAConfigurationImpl(); - try { - if (!run(conf, args, opts)) - System.err.println(_loc.get("appid-usage")); - } finally { - conf.close(); - } + final String[] arguments = opts.setFromCmdLine(args); + boolean ret = Configurations.runAgainstAllAnchors(opts, + new Configurations.Runnable() { + public boolean run(Options opts) + throws ClassNotFoundException, IOException { + OpenJPAConfiguration conf = new OpenJPAConfigurationImpl(); + try { + return ApplicationIdTool.run(conf, arguments, opts); + } finally { + conf.close(); + } + } + }); + if (!ret) + System.err.println(_loc.get("appid-usage")); } /** diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/PCEnhancer.java b/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/PCEnhancer.java index 666293ac1..e57b4acae 100644 --- a/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/PCEnhancer.java +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/enhance/PCEnhancer.java @@ -4254,17 +4254,29 @@ public class PCEnhancer { * not be enhanced. Thus, it is safe to invoke the enhancer on classes * that are already enhanced. */ - public static void main(String[] args) - throws IOException { + public static void main(String[] args) { Options opts = new Options(); args = opts.setFromCmdLine(args); - OpenJPAConfiguration conf = new OpenJPAConfigurationImpl(); - try { - if (!run(conf, args, opts)) - System.err.println(_loc.get("enhance-usage")); - } finally { - conf.close(); - } + if (!run(args, opts)) + System.err.println(_loc.get("enhance-usage")); + } + + /** + * Run the tool. Returns false if invalid options given. Runs against all + * the persistence units defined in the resource to parse. + */ + public static boolean run(final String[] args, Options opts) { + return Configurations.runAgainstAllAnchors(opts, + new Configurations.Runnable() { + public boolean run(Options opts) throws IOException { + OpenJPAConfiguration conf = new OpenJPAConfigurationImpl(); + try { + return PCEnhancer.run(conf, args, opts); + } finally { + conf.close(); + } + } + }); } /** @@ -4287,8 +4299,12 @@ public class PCEnhancer { ("enforcePropertyRestrictions", "epr", flags.enforcePropertyRestrictions); + // for unit testing + BytecodeWriter writer = (BytecodeWriter) opts.get( + PCEnhancer.class.getName() + "#bytecodeWriter"); + Configurations.populateConfiguration(conf, opts); - return run(conf, args, flags, null, null, null); + return run(conf, args, flags, null, writer, null); } /** @@ -4312,7 +4328,7 @@ public class PCEnhancer { Log log = conf.getLog(OpenJPAConfiguration.LOG_TOOL); Collection classes; - if (args.length == 0) { + if (args == null || args.length == 0) { log.info(_loc.get("running-all-classes")); classes = repos.getPersistentTypeNames(true, loader); if (classes == null) { @@ -4327,7 +4343,7 @@ public class PCEnhancer { for (int i = 0; i < args.length; i++) classes.addAll(Arrays.asList(cap.parseTypes(args[i]))); } - + Project project = new Project(); BCClass bc; PCEnhancer enhancer; diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/meta/MetaDataTool.java b/openjpa-kernel/src/main/java/org/apache/openjpa/meta/MetaDataTool.java index 4c2170a5e..2b19b7dfc 100644 --- a/openjpa-kernel/src/main/java/org/apache/openjpa/meta/MetaDataTool.java +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/meta/MetaDataTool.java @@ -250,14 +250,20 @@ public class MetaDataTool public static void main(String[] args) throws IOException { Options opts = new Options(); - args = opts.setFromCmdLine(args); - OpenJPAConfiguration conf = new OpenJPAConfigurationImpl(); - try { - if (!run(conf, args, opts)) - System.err.println(_loc.get("tool-usage")); - } finally { - conf.close(); - } + final String[] arguments = opts.setFromCmdLine(args); + boolean ret = Configurations.runAgainstAllAnchors(opts, + new Configurations.Runnable() { + public boolean run(Options opts) throws Exception { + OpenJPAConfiguration conf = new OpenJPAConfigurationImpl(); + try { + return MetaDataTool.run(conf, arguments, opts); + } finally { + conf.close(); + } + } + }); + if (!ret) + System.err.println(_loc.get("tool-usage")); } /** diff --git a/openjpa-lib/src/main/java/org/apache/openjpa/lib/conf/AbstractProductDerivation.java b/openjpa-lib/src/main/java/org/apache/openjpa/lib/conf/AbstractProductDerivation.java index 010900f47..4700dbe2d 100644 --- a/openjpa-lib/src/main/java/org/apache/openjpa/lib/conf/AbstractProductDerivation.java +++ b/openjpa-lib/src/main/java/org/apache/openjpa/lib/conf/AbstractProductDerivation.java @@ -19,6 +19,8 @@ package org.apache.openjpa.lib.conf; import java.io.File; +import java.io.IOException; +import java.util.List; /** * Abstract no-op product derivation for easy extension. @@ -58,6 +60,18 @@ public abstract class AbstractProductDerivation return null; } + public String getDefaultResourceLocation() { + return null; + } + + public List getAnchorsInFile(File file) throws Exception { + return null; + } + + public List getAnchorsInResource(String resource) throws Exception { + return null; + } + public boolean beforeConfigurationConstruct(ConfigurationProvider cp) { return false; } diff --git a/openjpa-lib/src/main/java/org/apache/openjpa/lib/conf/Configurations.java b/openjpa-lib/src/main/java/org/apache/openjpa/lib/conf/Configurations.java index 5e17ef96b..e7dd57b70 100644 --- a/openjpa-lib/src/main/java/org/apache/openjpa/lib/conf/Configurations.java +++ b/openjpa-lib/src/main/java/org/apache/openjpa/lib/conf/Configurations.java @@ -21,14 +21,15 @@ package org.apache.openjpa.lib.conf; import java.io.File; import java.security.AccessController; import java.security.PrivilegedActionException; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.Iterator; +import java.util.List; import java.util.Map; import java.util.MissingResourceException; import java.util.Properties; import java.util.TreeSet; - import javax.naming.Context; import javax.naming.InitialContext; import javax.naming.NamingException; @@ -43,7 +44,6 @@ import org.apache.openjpa.lib.util.ParseException; import org.apache.openjpa.lib.util.StringDistance; import org.apache.openjpa.lib.util.concurrent.ConcurrentHashMap; import org.apache.openjpa.lib.util.concurrent.ConcurrentReferenceHashMap; - import serp.util.Strings; /** @@ -57,7 +57,7 @@ public class Configurations { private static final Localizer _loc = Localizer.forPackage (Configurations.class); - private static ConcurrentReferenceHashMap _loaders = new + private static final ConcurrentReferenceHashMap _loaders = new ConcurrentReferenceHashMap(ConcurrentReferenceHashMap.WEAK, ConcurrentReferenceHashMap.HARD); @@ -277,6 +277,35 @@ public class Configurations { return loader; } + /** + * Return a List of all the fully-qualified anchors specified in the + * properties location listed in opts. If no properties + * location is listed in opts, this returns whatever the + * product derivations can find in their default configurations. + * If the properties location specified in opts already + * contains an anchor spec, this returns that anchor. Note that in this + * fully-qualified-input case, the logic involving product derivations + * and resource parsing is short-circuited, so this method + * should not be used as a means to test that a particular anchor is + * defined in a given location by invoking with a fully-qualified anchor. + * + * This does not mutate opts. + * + * @since 1.1.0 + */ + public static List getFullyQualifiedAnchorsInPropertiesLocation( + Options opts) { + String props = opts.getProperty("properties", "p", null); + if (props != null) { + int anchorPosition = props.indexOf("#"); + if (anchorPosition > -1) + return Arrays.asList(new String[] { props }); + } + + return ProductDerivations.getFullyQualifiedAnchorsInPropertiesLocation( + props); + } + /** * Set the given {@link Configuration} instance from the command line * options provided. All property names of the given configuration are @@ -630,4 +659,43 @@ public class Configurations { return props.remove(ProductDerivations.getConfigurationKey(partialKey, props)); } + + /** + * Runs runnable against all the anchors in the configuration + * pointed to by opts. Each invocation gets a fresh clone of + * opts with the properties option set + * appropriately. + * + * @since 1.1.0 + */ + public static boolean runAgainstAllAnchors(Options opts, + Configurations.Runnable runnable) { + List anchors = + Configurations.getFullyQualifiedAnchorsInPropertiesLocation(opts); + + // We use 'properties' below; get rid of 'p' to avoid conflicts. This + // relies on knowing what getFullyQualifiedAnchorsInPropertiesLocation + // looks for. + if (opts.containsKey("p")) + opts.remove("p"); + + boolean ret = true; + for (Iterator iter = anchors.iterator(); iter.hasNext(); ) { + Options clonedOptions = (Options) opts.clone(); + clonedOptions.setProperty("properties", iter.next().toString()); + try { + ret &= runnable.run(clonedOptions); + } catch (Exception e) { + if (!(e instanceof RuntimeException)) + throw new RuntimeException(e); + else + throw (RuntimeException) e; + } + } + return ret; + } + + public interface Runnable { + public boolean run(Options opts) throws Exception; + } } diff --git a/openjpa-lib/src/main/java/org/apache/openjpa/lib/conf/ProductDerivation.java b/openjpa-lib/src/main/java/org/apache/openjpa/lib/conf/ProductDerivation.java index b1c603135..92ad60fba 100644 --- a/openjpa-lib/src/main/java/org/apache/openjpa/lib/conf/ProductDerivation.java +++ b/openjpa-lib/src/main/java/org/apache/openjpa/lib/conf/ProductDerivation.java @@ -19,6 +19,8 @@ package org.apache.openjpa.lib.conf; import java.io.File; +import java.io.IOException; +import java.util.List; /** * Hooks for deriving products with additional functionality. @@ -90,6 +92,39 @@ public interface ProductDerivation { */ public ConfigurationProvider load(File file, String anchor) throws Exception; + + /** + * Return a string identifying the default resource location for this + * product derivation, if one exists. If there is no default location, + * returns null. + * + * @since 1.1.0 + */ + public String getDefaultResourceLocation(); + + /** + * Return a List of all the anchors defined in file. + * The returned names are not fully-qualified, so must be used in + * conjunction with file in calls + * to {@link #load(java.io.File, String)}. + * + * Returns null or an empty list if no anchors could be found. + * + * @since 1.1.0 + */ + public List getAnchorsInFile(File file) throws IOException, Exception; + + /** + * Return a List of all the anchors defined in + * resource. The returned names are not + * fully-qualified, so must be used in conjunction with + * resource in calls to {@link #load(java.io.File, String)}. + * + * Returns null or an empty list if no anchors could be found. + * + * @since 1.1.0 + */ + public List getAnchorsInResource(String resource) throws Exception; /** * Provides the instance with a callback to mutate the initial properties diff --git a/openjpa-lib/src/main/java/org/apache/openjpa/lib/conf/ProductDerivations.java b/openjpa-lib/src/main/java/org/apache/openjpa/lib/conf/ProductDerivations.java index 13869b506..413e77f0a 100644 --- a/openjpa-lib/src/main/java/org/apache/openjpa/lib/conf/ProductDerivations.java +++ b/openjpa-lib/src/main/java/org/apache/openjpa/lib/conf/ProductDerivations.java @@ -22,8 +22,10 @@ import java.io.File; import java.security.AccessController; import java.security.PrivilegedActionException; import java.util.ArrayList; +import java.util.Collection; import java.util.Collections; import java.util.Comparator; +import java.util.Iterator; import java.util.List; import java.util.Map; import java.util.MissingResourceException; @@ -352,6 +354,66 @@ public class ProductDerivations { ProductDerivations.class.getName(), resource); } + /** + * Return a List of all the fully-qualified anchors specified in + * propertiesLocation. The return values must be used in + * conjunction with propertiesLocation. If there are no + * product derivations or if no product derivations could find anchors, + * this returns an empty list. + * + * @since 1.1.0 + */ + public static List getFullyQualifiedAnchorsInPropertiesLocation( + final String propertiesLocation) { + List fqAnchors = new ArrayList(); + StringBuffer errs = null; + for (int i = _derivations.length - 1; i >= 0; i--) { + try { + if (propertiesLocation == null) { + String loc = _derivations[i].getDefaultResourceLocation(); + addAll(fqAnchors, loc, + _derivations[i].getAnchorsInResource(loc)); + continue; + } + + File f = new File(propertiesLocation); + if (((Boolean) J2DoPrivHelper.isFileAction(f).run()) + .booleanValue()) { + addAll(fqAnchors, propertiesLocation, + _derivations[i].getAnchorsInFile(f)); + } else { + f = new File("META-INF" + File.separatorChar + + propertiesLocation); + if (((Boolean) J2DoPrivHelper.isFileAction(f).run()) + .booleanValue()) { + addAll(fqAnchors, propertiesLocation, + _derivations[i].getAnchorsInFile(f)); + } else { + addAll(fqAnchors, propertiesLocation, + _derivations[i].getAnchorsInResource( + propertiesLocation)); + } + } + } catch (Throwable t) { + errs = (errs == null) ? new StringBuffer() : errs.append("\n"); + errs.append(_derivations[i].getClass().getName() + ":" + t); + } + } + reportErrors(errs, propertiesLocation); + return fqAnchors; + } + + private static void addAll(Collection collection, String base, + Collection newMembers) { + if (newMembers == null || collection == null) + return; + for (Iterator iter = newMembers.iterator(); iter.hasNext(); ) { + String fqLoc = base + "#" + iter.next(); + if (!collection.contains(fqLoc)) + collection.add(fqLoc); + } + } + /** * Compare {@link ProductDerivation}s. */ diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/enhance/TestEnhancementWithMultiplePUs.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/enhance/TestEnhancementWithMultiplePUs.java new file mode 100644 index 000000000..10e797373 --- /dev/null +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/enhance/TestEnhancementWithMultiplePUs.java @@ -0,0 +1,151 @@ +/* + * 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.openjpa.enhance; + +import java.io.IOException; +import java.security.AccessController; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +import org.apache.openjpa.conf.OpenJPAConfiguration; +import org.apache.openjpa.conf.OpenJPAConfigurationImpl; +import org.apache.openjpa.lib.conf.Configurations; +import org.apache.openjpa.lib.util.BytecodeWriter; +import org.apache.openjpa.lib.util.J2DoPrivHelper; +import org.apache.openjpa.lib.util.Options; +import org.apache.openjpa.meta.MetaDataRepository; +import org.apache.openjpa.persistence.test.PersistenceTestCase; +import serp.bytecode.BCClass; +import serp.bytecode.Project; + +public class TestEnhancementWithMultiplePUs + extends PersistenceTestCase { + + public void testExplicitEnhancementWithClassNotInFirstPU() + throws ClassNotFoundException { + OpenJPAConfiguration conf = new OpenJPAConfigurationImpl(); + Configurations.populateConfiguration(conf, new Options()); + MetaDataRepository repos = conf.getMetaDataRepositoryInstance(); + ClassLoader loader = (ClassLoader) AccessController + .doPrivileged(J2DoPrivHelper.newTemporaryClassLoaderAction( + getClass().getClassLoader())); + Project project = new Project(); + + String className = + "org.apache.openjpa.enhance.UnenhancedBootstrapInstance"; + BCClass bc = assertNotPC(loader, project, className); + + PCEnhancer enhancer = new PCEnhancer(conf, bc, repos, loader); + + assertEquals(PCEnhancer.ENHANCE_PC, enhancer.run()); + assertTrue(Arrays.asList(bc.getInterfaceNames()).contains( + PersistenceCapable.class.getName())); + } + + private BCClass assertNotPC(ClassLoader loader, Project project, + String className) { + BCClass bc = project.loadClass(className, loader); + assertFalse(className + " must not be enhanced already; it was.", + Arrays.asList(bc.getInterfaceNames()).contains( + PersistenceCapable.class.getName())); + return bc; + } + + public void testEnhancementOfSecondPUWithClassNotInFirstPU() + throws IOException { + OpenJPAConfiguration conf = new OpenJPAConfigurationImpl(); + Options opts = new Options(); + opts.setProperty("p", + "META-INF/persistence.xml#second-persistence-unit"); + Configurations.populateConfiguration(conf, opts); + MetaDataRepository repos = conf.getMetaDataRepositoryInstance(); + ClassLoader loader = (ClassLoader) AccessController + .doPrivileged(J2DoPrivHelper.newTemporaryClassLoaderAction( + getClass().getClassLoader())); + Project project = new Project(); + + // make sure that the class is not already enhanced for some reason + String className = + "org.apache.openjpa.enhance.UnenhancedBootstrapInstance"; + BCClass bc = assertNotPC(loader, project, className); + + // build up a writer that just stores to a list so that we don't + // mutate the disk. + final List written = new ArrayList(); + BytecodeWriter writer = new BytecodeWriter() { + + public void write(BCClass type) throws IOException { + assertTrue(Arrays.asList(type.getInterfaceNames()).contains( + PersistenceCapable.class.getName())); + written.add(type.getName()); + } + }; + + PCEnhancer.run(conf, null, new PCEnhancer.Flags(), repos, writer, + loader); + + // ensure that we don't attempt to process classes listed in other PUs + assertEquals(1, written.size()); + + // ensure that we do process the classes listed in the PU + assertTrue(written.contains(className)); + } + + public void testEnhancementOfAllPUsWithinAResource() + throws IOException { + OpenJPAConfiguration conf = new OpenJPAConfigurationImpl(); + Options opts = new Options(); + opts.setProperty("p", "META-INF/persistence.xml"); + Configurations.populateConfiguration(conf, opts); + MetaDataRepository repos = conf.getMetaDataRepositoryInstance(); + ClassLoader loader = (ClassLoader) AccessController + .doPrivileged(J2DoPrivHelper.newTemporaryClassLoaderAction( + getClass().getClassLoader())); + Project project = new Project(); + + // make sure that the classes is not already enhanced for some reason + assertNotPC(loader, project, + "org.apache.openjpa.enhance.UnenhancedBootstrapInstance"); + assertNotPC(loader, project, + "org.apache.openjpa.enhance.UnenhancedBootstrapInstance2"); + + // build up a writer that just stores to a list so that we don't + // mutate the disk. + final List written = new ArrayList(); + BytecodeWriter writer = new BytecodeWriter() { + + public void write(BCClass type) throws IOException { + assertTrue(Arrays.asList(type.getInterfaceNames()).contains( + PersistenceCapable.class.getName())); + written.add(type.getName()); + } + }; + + opts = new Options(); + opts.put(PCEnhancer.class.getName() + "#bytecodeWriter", writer); + PCEnhancer.run(null, opts); + + // ensure that we do process the classes listed in the PUs + assertTrue(written.contains( + "org.apache.openjpa.enhance.UnenhancedBootstrapInstance")); + assertTrue(written.contains( + "org.apache.openjpa.enhance.UnenhancedBootstrapInstance2")); + } +} diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/enhance/UnenhancedBootstrapInstance.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/enhance/UnenhancedBootstrapInstance.java new file mode 100644 index 000000000..95a0e4a54 --- /dev/null +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/enhance/UnenhancedBootstrapInstance.java @@ -0,0 +1,28 @@ +/* + * 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.openjpa.enhance; + +import javax.persistence.Entity; +import javax.persistence.Id; + +@Entity +public class UnenhancedBootstrapInstance { + @Id + private int id; +} diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/enhance/UnenhancedBootstrapInstance2.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/enhance/UnenhancedBootstrapInstance2.java new file mode 100644 index 000000000..3db77b857 --- /dev/null +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/enhance/UnenhancedBootstrapInstance2.java @@ -0,0 +1,28 @@ +/* + * 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.openjpa.enhance; + +import javax.persistence.Entity; +import javax.persistence.Id; + +@Entity +public class UnenhancedBootstrapInstance2 { + @Id + private int id; +} diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/lib/conf/TestAnchorParsing.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/lib/conf/TestAnchorParsing.java new file mode 100644 index 000000000..42d82ffc4 --- /dev/null +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/lib/conf/TestAnchorParsing.java @@ -0,0 +1,63 @@ +/* + * 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.openjpa.lib.conf; + +import java.util.List; + +import junit.framework.TestCase; +import org.apache.openjpa.lib.util.Options; + +public class TestAnchorParsing extends TestCase { + + public void testFQAnchor() { + String fqLoc = "META-INF/persistence.xml#test"; + Options opts = new Options(); + opts.setProperty("p", fqLoc); + List locs = + Configurations.getFullyQualifiedAnchorsInPropertiesLocation(opts); + assertNotNull(locs); + assertEquals(1, locs.size()); + assertEquals(fqLoc, locs.get(0)); + } + + public void testNoResource() { + allHelper(null); + } + + public void testNoAnchor() { + allHelper("META-INF/persistence.xml"); + } + + private void allHelper(String resource) { + Options opts = new Options(); + if (resource != null) + opts.setProperty("p", resource); + List locs = + Configurations.getFullyQualifiedAnchorsInPropertiesLocation(opts); + assertNotNull(locs); + // approximate so that if someone adds more units, this doesn't break + assertTrue(locs.size() >= 4); + assertTrue(locs.contains("META-INF/persistence.xml#test")); + assertTrue(locs.contains( + "META-INF/persistence.xml#second-persistence-unit")); + assertTrue(locs.contains( + "META-INF/persistence.xml#third-persistence-unit")); + assertTrue(locs.contains("META-INF/persistence.xml#invalid")); + } +} diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/test/PersistenceTestCase.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/test/PersistenceTestCase.java index ca4bb7e84..e78332ea2 100644 --- a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/test/PersistenceTestCase.java +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/test/PersistenceTestCase.java @@ -52,10 +52,24 @@ public abstract class PersistenceTestCase * this list to tell the test framework to delete all table contents * before running the tests. * - * @param props list of persistent types used in testing and/or + * @param props list of persistent types used in testing and/or * configuration values in the form key,value,key,value... */ protected OpenJPAEntityManagerFactorySPI createEMF(Object... props) { + return createNamedEMF("test", props); + } + + /** + * Create an entity manager factory for persistence unit pu. + * Put {@link #CLEAR_TABLES} in + * this list to tell the test framework to delete all table contents + * before running the tests. + * + * @param props list of persistent types used in testing and/or + * configuration values in the form key,value,key,value... + */ + protected OpenJPAEntityManagerFactorySPI createNamedEMF(String pu, + Object... props) { Map map = new HashMap(System.getProperties()); List types = new ArrayList(); boolean prop = false; @@ -85,7 +99,7 @@ public abstract class PersistenceTestCase } return (OpenJPAEntityManagerFactorySPI) Persistence. - createEntityManagerFactory("test", map); + createEntityManagerFactory(pu, map); } public void tearDown() throws Exception { diff --git a/openjpa-persistence-jdbc/src/test/resources/META-INF/persistence.xml b/openjpa-persistence-jdbc/src/test/resources/META-INF/persistence.xml index e2704009c..b37c42f4b 100644 --- a/openjpa-persistence-jdbc/src/test/resources/META-INF/persistence.xml +++ b/openjpa-persistence-jdbc/src/test/resources/META-INF/persistence.xml @@ -54,7 +54,15 @@ value="buildSchema(ForeignKeys=true)"/> - + + + org.apache.openjpa.enhance.UnenhancedBootstrapInstance + + + + org.apache.openjpa.enhance.UnenhancedBootstrapInstance2 + + getUnitNames(ConfigurationParser parser) { + List units = parser.getResults(); + List names = new ArrayList(); + for (PersistenceUnitInfoImpl unit : units) + names.add(unit.getPersistenceUnitName()); + return names; + } + + @Override + public List getAnchorsInResource(String resource) throws Exception { + ConfigurationParser parser = new ConfigurationParser(null); + parser.parse(resource); + return getUnitNames(parser); + } + @Override public ConfigurationProvider loadGlobals(ClassLoader loader) throws IOException { diff --git a/openjpa-project/src/doc/manual/ref_guide_conf.xml b/openjpa-project/src/doc/manual/ref_guide_conf.xml index 51150b8c8..75234b4fe 100644 --- a/openjpa-project/src/doc/manual/ref_guide_conf.xml +++ b/openjpa-project/src/doc/manual/ref_guide_conf.xml @@ -167,6 +167,18 @@ META-INF/my-persistence.xml, you can use: <tool> -p my-persistence.xml + + +If you want to run a tool against just one particular persistence unit in +a configuration file, you can do so by specifying an anchor along with the +resource. If you do not specify an anchor, the tools will run against all +the persistence units defined within the specified resource, or the default +resource if none is specified. If the persistence unit is defined within +the default resource location, then you can just specify the raw anchor itself: + + +<tool> -p my-persistence.xml#sales-persistence-unit +<tool> -p #invoice-persistence-unit