diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/conf/OpenJPAConfiguration.java b/openjpa-kernel/src/main/java/org/apache/openjpa/conf/OpenJPAConfiguration.java index fa6da82d3..1ff700695 100644 --- a/openjpa-kernel/src/main/java/org/apache/openjpa/conf/OpenJPAConfiguration.java +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/conf/OpenJPAConfiguration.java @@ -26,6 +26,7 @@ import org.apache.openjpa.datacache.DataCacheManager; import org.apache.openjpa.ee.ManagedRuntime; import org.apache.openjpa.enhance.RuntimeUnenhancedClasssesModes; import org.apache.openjpa.event.BrokerFactoryEventManager; +import org.apache.openjpa.event.LifecycleEventManager; import org.apache.openjpa.event.OrphanedKeyAction; import org.apache.openjpa.event.RemoteCommitEventManager; import org.apache.openjpa.event.RemoteCommitProvider; @@ -1676,7 +1677,7 @@ public interface OpenJPAConfiguration * * @since 2.0.0 */ - public Object getValidationFactory(); + public Object getValidationFactoryInstance(); /** * Set the container or application provided ValidatorFactory instance. @@ -1685,4 +1686,18 @@ public interface OpenJPAConfiguration * @since 2.0.0 */ public void setValidationFactory(Object factory); + + /** + * Gets the lifecycle event manager instance + * + * @since 2.0.0 + */ + public LifecycleEventManager getLifecycleEventManagerInstance(); + + /** + * Sets the lifecycle event manager instance. + * + * @since 2.0.0 + */ + public void setLifecycleEventManager(LifecycleEventManager eventMgr); } diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/conf/OpenJPAConfigurationImpl.java b/openjpa-kernel/src/main/java/org/apache/openjpa/conf/OpenJPAConfigurationImpl.java index b3970db91..8cb085c34 100644 --- a/openjpa-kernel/src/main/java/org/apache/openjpa/conf/OpenJPAConfigurationImpl.java +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/conf/OpenJPAConfigurationImpl.java @@ -31,6 +31,7 @@ import org.apache.openjpa.ee.ManagedRuntime; import org.apache.openjpa.enhance.PCEnhancerAgent; import org.apache.openjpa.enhance.RuntimeUnenhancedClasssesModes; import org.apache.openjpa.event.BrokerFactoryEventManager; +import org.apache.openjpa.event.LifecycleEventManager; import org.apache.openjpa.event.OrphanedKeyAction; import org.apache.openjpa.event.RemoteCommitEventManager; import org.apache.openjpa.event.RemoteCommitProvider; @@ -155,6 +156,8 @@ public class OpenJPAConfigurationImpl public ObjectValue specification; public StringValue validationMode; public ObjectValue validationFactory; + public ObjectValue lifecycleEventManager; + // custom values public BrokerFactoryValue brokerFactoryPlugin; @@ -557,17 +560,8 @@ public class OpenJPAConfigurationImpl queryTimeout.setDynamic(true); // kernel can't access javax.persistence.ValidationMode enums here + // so the config will be done in PersistenceProductDerivation validationMode = addString("javax.persistence.validation.mode"); - aliases = - new String[] { - "AUTO", "auto", - "CALLBACK", "callback", - "NONE", "none" - }; - validationMode.setAliases(aliases); - validationMode.setAliasListComprehensive(true); - validationMode.setDefault(aliases[0]); - validationMode.set(aliases[0]); validationMode.setDynamic(true); validationFactory = addObject("javax.persistence.validation.factory"); @@ -575,6 +569,10 @@ public class OpenJPAConfigurationImpl "getValidationFactoryInstance"); validationFactory.setDynamic(true); + lifecycleEventManager = addObject("LifecycleEventManager"); + lifecycleEventManager.setInstantiatingGetter( + "getLifecycleEventManagerInstance"); + dynamicEnhancementAgent = addBoolean("DynamicEnhancementAgent"); dynamicEnhancementAgent.setDefault("true"); dynamicEnhancementAgent.set(true); @@ -1538,11 +1536,15 @@ public class OpenJPAConfigurationImpl } public void setValidationMode(String mode) { + Thread.dumpStack(); validationMode.setString(mode); } public String getValidationMode() { - return validationMode.getString(); + String mode = validationMode.getString(); + if (mode == null) + mode = validationMode.getDefault(); + return mode; } public void instantiateAll() { @@ -1601,10 +1603,6 @@ public class OpenJPAConfigurationImpl return (FinderCache)finderCachePlugin.get(); } - public Object getValidationFactory() { - return validationFactory.get(); - } - public Object getValidationFactoryInstance() { return validationFactory.get(); } @@ -1612,10 +1610,24 @@ public class OpenJPAConfigurationImpl public void setValidationFactory(Object factory) { validationFactory.set(factory); } + + public LifecycleEventManager getLifecycleEventManagerInstance() { + if (lifecycleEventManager.get() == null) { + lifecycleEventManager.set(new LifecycleEventManager()); + } + return (LifecycleEventManager)lifecycleEventManager.get(); + } + + public void setLifecycleEventManager(LifecycleEventManager eventMgr) { + lifecycleEventManager.set(eventMgr); + } + public boolean getDynamicEnhancementAgent() { return dynamicEnhancementAgent.get(); } + public void setDynamicEnhancementAgent(boolean dynamic) { dynamicEnhancementAgent.set(dynamic); } } + diff --git a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/BrokerImpl.java b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/BrokerImpl.java index 8ef9289d2..58dd46926 100644 --- a/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/BrokerImpl.java +++ b/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/BrokerImpl.java @@ -89,6 +89,7 @@ import org.apache.openjpa.util.RuntimeExceptionTranslator; import org.apache.openjpa.util.StoreException; import org.apache.openjpa.util.UnsupportedException; import org.apache.openjpa.util.UserException; +import org.apache.openjpa.util.WrappedException; /** * Concrete {@link Broker}. The broker handles object-level behavior, @@ -301,7 +302,7 @@ public class BrokerImpl _runtime = new LocalManagedRuntime(this); if (!fromDeserialization) { - _lifeEventManager = new LifecycleEventManager(); + _lifeEventManager = _conf.getLifecycleEventManagerInstance(); _transEventManager = new TransactionEventManager(); int cmode = _conf.getMetaDataRepositoryInstance(). getMetaDataFactory().getDefaults().getCallbackMode(); @@ -315,7 +316,7 @@ public class BrokerImpl // make sure to do this after configuring broker so that store manager // can look to broker configuration; we set both store and lock managers // before initializing them because they may each try to access the - // other in thier initialization + // other in their initialization _store = sm; _lm = _conf.newLockManagerInstance(); _im = _conf.newInverseManagerInstance(); @@ -800,11 +801,17 @@ public class BrokerImpl return; OpenJPAException ce; - if (exceps.length == 1) - ce = new CallbackException(exceps[0]); - else + if (exceps.length == 1) { + // If the exception is already a wrapped exception throw the + // exception instead of wrapping it with a callback exception + if (exceps[0] instanceof WrappedException) + throw (WrappedException)exceps[0]; + else + ce = new CallbackException(exceps[0]); + } else { ce = new CallbackException(_loc.get("callback-err")). setNestedThrowables(exceps); + } if ((mode & CALLBACK_ROLLBACK) != 0 && (_flags & FLAG_ACTIVE) != 0) { ce.setFatal(true); setRollbackOnlyInternal(ce); diff --git a/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/PersistenceProductDerivation.java b/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/PersistenceProductDerivation.java index 48ff89174..a56bf9553 100644 --- a/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/PersistenceProductDerivation.java +++ b/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/PersistenceProductDerivation.java @@ -44,7 +44,6 @@ import org.apache.openjpa.conf.OpenJPAConfiguration; import org.apache.openjpa.conf.OpenJPAConfigurationImpl; import org.apache.openjpa.conf.OpenJPAProductDerivation; import org.apache.openjpa.conf.Specification; -import org.apache.openjpa.kernel.LockLevels; import org.apache.openjpa.kernel.MixedLockLevels; import org.apache.openjpa.lib.conf.AbstractProductDerivation; import org.apache.openjpa.lib.conf.Configuration; @@ -57,6 +56,10 @@ import org.apache.openjpa.lib.meta.XMLMetaDataParser; import org.apache.openjpa.lib.meta.XMLVersionParser; import org.apache.openjpa.lib.util.J2DoPrivHelper; import org.apache.openjpa.lib.util.Localizer; +import org.apache.openjpa.persistence.validation.ValidatorImpl; +import org.apache.openjpa.validation.Validator; +import org.apache.openjpa.validation.ValidationException; +import org.apache.openjpa.validation.ValidatingLifecycleEventManager; import org.xml.sax.Attributes; import org.xml.sax.SAXException; @@ -142,6 +145,18 @@ public class PersistenceProductDerivation conf.lockManagerPlugin.setAlias("mixed", "org.apache.openjpa.jdbc.kernel.MixedLockManager"); + String[] aliases = new String[] { + String.valueOf(ValidationMode.AUTO), + String.valueOf(ValidationMode.AUTO).toLowerCase(), + String.valueOf(ValidationMode.CALLBACK), + String.valueOf(ValidationMode.CALLBACK).toLowerCase(), + String.valueOf(ValidationMode.NONE), + String.valueOf(ValidationMode.NONE).toLowerCase() + }; + conf.validationMode.setAliases(aliases); + conf.validationMode.setAliasListComprehensive(true); + conf.validationMode.setDefault(aliases[0]); + return true; } @@ -164,6 +179,39 @@ public class PersistenceProductDerivation Compatibility compatibility = conf.getCompatibilityInstance(); compatibility.setFlushBeforeDetach(true); compatibility.setCopyOnDetach(true); + } else { + // only try creating a ValidatingLifecycleEventManager if needed + if (!ValidatorImpl.skipValidation(conf.getValidationMode())) { + try { + Validator val = new ValidatorImpl( + conf.getValidationFactoryInstance(), + conf.getValidationMode()); + // we have a Validator, so try to create a VLEM + conf.setLifecycleEventManager( + new ValidatingLifecycleEventManager(val)); + } catch (RuntimeException e) { + if (ValidatorImpl.validationRequired( + conf.getValidationMode())) { + // fatal error - ValidationMode requires a Validator + conf.getConfigurationLog().error( + _loc.get("vlem-creation-error"), e); + // rethrow as a WrappedException + throw new ValidationException(e); + } else { + // unexpected, but validation is optional, + // so just log it as a warning + conf.getConfigurationLog().warn( + _loc.get("vlem-creation-warn")); + // if tracing, log the exception details + conf.getConfigurationLog().trace(e); + } + } + } else { + conf.getConfigurationLog().trace( + "Validation has been disabled by supplied mode."); + } + // make sure we have at least a LifecycleEventManager created + conf.getLifecycleEventManagerInstance(); } return true; } diff --git a/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/validation/ValidatorImpl.java b/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/validation/ValidatorImpl.java index c9db365c8..0f9652fd6 100644 --- a/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/validation/ValidatorImpl.java +++ b/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/validation/ValidatorImpl.java @@ -64,55 +64,104 @@ public class ValidatorImpl extends AbstractValidator { LifecycleEvent.BEFORE_UPDATE); } + /** + * Is a Validator required based on the given validation mode? + * Keeping validation mode logic in a single class... + * @param mode + * @return true if a Validator is required + */ + public static boolean validationRequired(String mode) { + return String.valueOf(ValidationMode.CALLBACK).equalsIgnoreCase(mode); + } + + /** + * Skip creating a Validator based on the given validation mode? + * Keeping validation mode logic in a single class... + * @param mode + * @return true if a Validator should not be created + */ + public static boolean skipValidation(String mode) { + return String.valueOf(ValidationMode.NONE).equalsIgnoreCase(mode); + } + /** * Default constructor. Builds a default validator factory, if available * and creates the validator. + * Returns an Exception if a Validator could not be created. */ public ValidatorImpl() { - // Add the default validation groups - _validatorFactory = getDefaultValidatorFactory(); - if (_validatorFactory != null) - _validator = _validatorFactory.getValidator(); - addDefaultValidationGroups(); + initialize(); } /** * Type-specific constructor + * Returns an Exception if a Validator could not be created. * @param validatorFactory Instance of validator factory to use. Specify * null to use the default factory. * @param mode ValdiationMode enum value */ public ValidatorImpl(ValidatorFactory validatorFactory, ValidationMode mode) { + if (mode != null) { + _mode = mode; + } if (validatorFactory != null) { _validatorFactory = validatorFactory; - } else { - _validatorFactory = getDefaultValidatorFactory(); } - if (_validatorFactory != null) - _validator = _validatorFactory.getValidator(); - addDefaultValidationGroups(); + initialize(); } /** * Generic-type constructor + * Returns an Exception if a Validator could not be created. * @param validatorFactory an instance to the validatorFactory * @param mode validation mode enum as string value */ public ValidatorImpl(Object validatorFactory, String mode) { - if (validatorFactory != null && validatorFactory instanceof - ValidatorFactory) { - _validatorFactory = (ValidatorFactory)validatorFactory; - } else { - _validatorFactory = getDefaultValidatorFactory(); - } _mode = Enum.valueOf(ValidationMode.class, mode); - if (_validatorFactory != null) - _validator = _validatorFactory.getValidator(); - addDefaultValidationGroups(); + if (validatorFactory != null) { + if (validatorFactory instanceof ValidatorFactory) { + _validatorFactory = (ValidatorFactory)validatorFactory; + } else { + // TODO: Add a localized exception + throw new IllegalArgumentException(); + } + } + initialize(); } + /** + * Common setup code factored out of the constructors + */ + private void initialize() { + // only try setting up a validator if mode is not NONE + if (_mode != ValidationMode.NONE) { + if (_validatorFactory == null) { + _validatorFactory = getDefaultValidatorFactory(); + } + if (_validatorFactory != null) { + _validator = _validatorFactory.getValidator(); + } else { + // TODO: Add a localized exception + throw new RuntimeException("No default ValidatorFactory"); + } + + // throw an exception if we have no Validator + if (_validator == null) { + // TODO: Add a localized exception + throw new RuntimeException("No Validator provider"); + } + + // add in default validation groups, which can be over-ridden later + addDefaultValidationGroups(); + } else { + // TODO: Add a localized exception + throw new RuntimeException("No Validator should be created based " + + "on the supplied Validation Mode."); + } + } + /** * Add a validation group for the specific property. The properties map * to a specific lifecycle event. To disable validation for a group, set @@ -126,9 +175,11 @@ public class ValidatorImpl extends AbstractValidator { if (event != null) { _validationGroups.put(event, vgs); return; + } else { + // TODO: Add a localized exception + throw new IllegalArgumentException("There were no events found " + + "for the supplied group name."); } - // TODO: Add a localized exception - throw new IllegalArgumentException(); } /** @@ -161,7 +212,7 @@ public class ValidatorImpl extends AbstractValidator { * @return returns true if validating for this particular event */ public boolean isValidating(Integer event) { - return _validationGroups.get(event) != null; + return (_validationGroups.get(event) != null); } /** @@ -275,8 +326,12 @@ public class ValidatorImpl extends AbstractValidator { // Get the default validator factory private ValidatorFactory getDefaultValidatorFactory() { - ValidatorFactory factory = - Validation.buildDefaultValidatorFactory(); + ValidatorFactory factory = null; + try { + factory = Validation.buildDefaultValidatorFactory(); + } catch (javax.validation.ValidationException e) { + // no validation providers found + } return factory; } diff --git a/openjpa-persistence/src/main/resources/org/apache/openjpa/persistence/localizer.properties b/openjpa-persistence/src/main/resources/org/apache/openjpa/persistence/localizer.properties index b5f27a135..c2aef7d06 100644 --- a/openjpa-persistence/src/main/resources/org/apache/openjpa/persistence/localizer.properties +++ b/openjpa-persistence/src/main/resources/org/apache/openjpa/persistence/localizer.properties @@ -195,4 +195,8 @@ invalid-orderBy: This is not a valid OrderBy annotation. The property or \ for "{0}". dynamic-agent: OpenJPA dynamically loaded the class enhancer. Any classes \ that were not enhanced at build time will be enhanced when the are \ - loaded by the JVM + loaded by the JVM. +vlem-creation-warn: Failed to create the optional Validation Provider. +vlem-creation-error: A fatal error occurred while trying to \ + create the required Validation Provider. +