OPENJPA-1068 Rev 1 of lifecycle validation

git-svn-id: https://svn.apache.org/repos/asf/openjpa/trunk@776009 13f79535-47bb-0310-9956-ffa450edef68
This commit is contained in:
Jeremy Bauer 2009-05-18 17:05:48 +00:00
parent c7a2b9252c
commit e5e4cc122a
9 changed files with 601 additions and 0 deletions

View File

@ -32,6 +32,8 @@ public interface ExceptionInfo {
public static final int STORE = 2;
public static final int UNSUPPORTED = 3;
public static final int USER = 4;
public static final int WRAPPED = 5;
/**
* Exception message.

View File

@ -0,0 +1,41 @@
/*
* 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.util;
@SuppressWarnings("serial")
/**
* Identifiable exception type which wraps an internal runtime exception.
*/
public class WrappedException extends OpenJPAException {
private RuntimeException _wrappedException = null;
public WrappedException(RuntimeException e) {
_wrappedException = e;
}
public RuntimeException getWrapped() {
return _wrappedException;
}
@Override
public int getType() {
return WRAPPED;
}
}

View File

@ -0,0 +1,37 @@
/*
* 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.validation;
/**
* Abstract validation class which provides base validation methods.
*/
public abstract class AbstractValidator implements Validator {
public abstract <T> ValidationException validate(T arg0, int event);
public abstract <T> ValidationException validateProperty(T arg0,
String property, int event);
public abstract <T> ValidationException validateValue(Class<T> arg0,
String arg1, Object arg2, int event);
public <T> boolean validating(T arg0, int event) {
return false;
}
}

View File

@ -0,0 +1,113 @@
/*
* 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.validation;
import org.apache.openjpa.event.LifecycleEvent;
import org.apache.openjpa.event.LifecycleEventManager;
import org.apache.openjpa.meta.ClassMetaData;
/**
* An extension of LifecycleEventManager which adds validation capabilities for
* specific lifecycle events. Validation occurs after firing all lifecycle
* events and callbacks.
*
*/
@SuppressWarnings("serial")
public class ValidatingLifecycleEventManager extends LifecycleEventManager {
private Validator _validator = null;
/**
* Constructor which accepts a reference to the validator to use. If null,
* no validation will occur.
* @param validator
*/
public ValidatingLifecycleEventManager(Validator validator) {
super();
_validator = validator;
}
@Override
public boolean hasUpdateListeners(Object source, ClassMetaData meta) {
if (_validator == null) {
return super.hasUpdateListeners(source, meta);
}
return _validator.validating(source, LifecycleEvent.BEFORE_PERSIST) &&
super.hasUpdateListeners(source, meta);
}
@Override
public boolean hasPersistListeners(Object source, ClassMetaData meta) {
if (_validator == null) {
return super.hasPersistListeners(source, meta);
}
return _validator.validating(source, LifecycleEvent.BEFORE_UPDATE) &&
super.hasPersistListeners(source, meta);
}
@Override
public boolean hasDeleteListeners(Object source, ClassMetaData meta) {
if (_validator == null) {
return super.hasDeleteListeners(source, meta);
}
return _validator.validating(source, LifecycleEvent.BEFORE_DELETE) &&
super.hasDeleteListeners(source, meta);
}
@Override
public Exception[] fireEvent(Object source,
ClassMetaData meta, int type) {
return fireEvent(source, null, meta, type);
}
@Override
public Exception[] fireEvent(Object source, Object related,
ClassMetaData meta, int type) {
// Fire all pre-validation events and handlers.
Exception[] evx = super.fireEvent(source, related, meta, type);
// If there are exceptions and the event manager is marked fail fast
// do not validate
if (evx != null && evx.length > 0 && isFailFast())
return evx;
// If a validator is provided and the source object should be validated,
// validate it and return any exceptions
if (_validator != null && _validator.validating(source, type)) {
ValidationException vex = _validator.validate(source, type);
if (vex != null) {
if (evx == null || evx.length == 0) {
evx = new Exception[1];
evx[0] = vex;
}
else {
// resize the exception array and add the validation
// exception
Exception[] vevx = new Exception[evx.length +1];
System.arraycopy(vevx, 0, evx, 0, evx.length);
vevx[evx.length+1] = vex;
evx = vevx;
}
}
}
return evx;
}
}

View File

@ -0,0 +1,29 @@
/*
* 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.validation;
import org.apache.openjpa.util.WrappedException;
@SuppressWarnings("serial")
public class ValidationException extends WrappedException {
public ValidationException(RuntimeException e) {
super(e);
}
}

View File

@ -0,0 +1,78 @@
/*
* 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.validation;
/**
* Basic validation interface which defines the contract for
* event based validation. Event values are defined in LifeCycleEvent.
*/
public interface Validator {
/**
* Validates a given instance
*
* @param <T> The instance to validate
* @param arg0 The class, of type T to validate
* @param arg1 The property to validate
* @param arg2 The property value to validate
* @param event The event id
* @return A Validation exception if the validator produces one or more
* constraint violations.
*/
public <T> ValidationException validate(T arg0, int event);
/**
* Validates a property of a given instance
*
* @param <T> The instance to validate
* @param arg0 The class, of type T to validate
* @param arg1 The property to validate
* @param arg2 The property value to validate
* @param event The event id
* @return A Validation exception if the validator produces one or more
* constraint violations.
*/
public <T> ValidationException validateProperty(T arg0,
String property, int event);
/**
* Validates a value based upon the constraints applied to a given class
* attribute.
* @param <T> The instance type to base validation upon
* @param arg0 The class of type T to validate
* @param arg1 The property to validate
* @param arg2 The property value to validate
* @param event The event id
* @return A Validation exception if the validator produces one or more
* constraint violations.
*/
public <T> ValidationException validateValue(Class<T> arg0,
String arg1, Object arg2, int event);
/**
* Method for determining whether validation is active for the given
* type and event.
*
* @param <T>
* @param arg0 Type being validated
* @param event event type
* @return true if validation is active for the specified event
*/
public <T> boolean validating(T arg0, int event);
}

View File

@ -43,6 +43,10 @@
<groupId>org.apache.geronimo.specs</groupId>
<artifactId>geronimo-jpa_2.0_spec</artifactId>
</dependency>
<dependency>
<groupId>org.apache.geronimo.specs</groupId>
<artifactId>geronimo-validation_1.0_spec</artifactId>
</dependency>
</dependencies>
<profiles>

View File

@ -0,0 +1,292 @@
/*
* 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.persistence.validation;
import java.util.HashMap;
import java.util.Map;
import java.util.Set;
import javax.persistence.ValidationMode;
import javax.validation.BeanDescriptor;
import javax.validation.ConstraintViolation;
import javax.validation.ConstraintViolationException;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;
import org.apache.openjpa.event.LifecycleEvent;
import org.apache.openjpa.validation.AbstractValidator;
import org.apache.openjpa.validation.ValidationException;
public class ValidatorImpl extends AbstractValidator {
private ValidatorFactory _validatorFactory = null;
private Validator _validator = null;
private ValidationMode _mode = ValidationMode.AUTO;
// A map storing the validation groups to use for a particular event type
private Map<Integer, Class<?>[]> _validationGroups =
new HashMap<Integer,Class<?>[]>();
// Lookup table for event to group property mapping
private static HashMap<String, Integer> _vgMapping =
new HashMap<String, Integer> ();
public static final String VG_PRE_PERSIST =
"javax.persistence.validation.group.pre-persist";
public static final String VG_PRE_REMOVE =
"javax.persistence.validation.group.pre-remove";
public static final String VG_PRE_UPDATE =
"javax.persistence.validation.group.pre-update";
static {
_vgMapping.put(VG_PRE_PERSIST,
LifecycleEvent.BEFORE_STORE);
_vgMapping.put(VG_PRE_REMOVE,
LifecycleEvent.BEFORE_DELETE);
_vgMapping.put(VG_PRE_UPDATE,
LifecycleEvent.BEFORE_UPDATE);
}
/**
* Default constructor. Builds a default validator factory, if available
* and creates the validator.
*/
public ValidatorImpl() {
// Add the default validation groups
_validatorFactory = getDefaultValidatorFactory();
if (_validatorFactory != null)
_validator = _validatorFactory.getValidator();
addDefaultValidationGroups();
}
/**
* Type-specific constructor
* @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 (validatorFactory != null) {
_validatorFactory = validatorFactory;
} else {
_validatorFactory = getDefaultValidatorFactory();
}
if (_validatorFactory != null)
_validator = _validatorFactory.getValidator();
addDefaultValidationGroups();
}
/**
* Generic-type constructor
* @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();
}
/**
* Add a validation group for the specific property. The properties map
* to a specific lifecycle event. To disable validation for a group, set
* the validation group to null.
*
* @param validationGroupName
* @param vgs
*/
public void addValidationGroup(String validationGroupName, Class<?>...vgs) {
Integer event = findEvent(validationGroupName);
if (event != null) {
_validationGroups.put(event, vgs);
return;
}
// TODO: Add a localized exception
throw new IllegalArgumentException();
}
/**
* Add a validation group for a specified event. Event definitions
* are defined in LifecycleEvent. To disable validation for a group, set
* the validation group to null.
*
* @param event
* @param validationGroup
*/
public void addValidationGroup(Integer event, Class<?>... validationGroup) {
_validationGroups.put(event, validationGroup);
}
/**
* Return the validation groups to be validated for a specified event
* @param event Lifecycle event id
* @return An array of validation groups
*/
public Class<?>[] getValidationGroup(Integer event) {
return _validationGroups.get(event);
}
/**
* Returns whether the Validator is validating for the
* specified event. Based on whether validation groups are specified for
* the event.
*
* @param event the event to check for validation
* @return returns true if validating for this particular event
*/
public boolean isValidating(Integer event) {
return _validationGroups.get(event) != null;
}
/**
* Returns the validation constraints for the specified class
*
* @param cls Class for which constraints to return
* @return The validation bean descriptor
*/
public BeanDescriptor getConstraintsForClass(Class<?> cls) {
return _validator.getConstraintsForClass(cls);
}
/**
* Validates a given instance
*
* @param <T> The instance to validate
* @param arg0 The class, of type T to validate
* @param arg1 The property to validate
* @param arg2 The property value to validate
* @param event The event id
* @return A Validation exception if the validator produces one or more
* constraint violations.
*/
@Override
public <T> ValidationException validate(T arg0, int event) {
if (!isValidating(event))
return null;
Set<ConstraintViolation<T>> violations =
_validator.validate(arg0, getValidationGroup(event));
if (violations != null && violations.size() > 0) {
return new ValidationException(
new ConstraintViolationException(
(Set)violations));
}
return null;
}
/**
* Validates a property of a given instance
*
* @param <T> The instance to validate
* @param arg0 The class, of type T to validate
* @param arg1 The property to validate
* @param arg2 The property value to validate
* @param event The event id
* @return A Validation exception if the validator produces one or more
* constraint violations.
*/
@Override
public <T> ValidationException validateProperty(T arg0, String property,
int event) {
if (!isValidating(event))
return null;
Set<ConstraintViolation<T>> violations =
_validator.validateProperty(arg0, property,
getValidationGroup(event));
if (violations != null && violations.size() > 0) {
return new ValidationException(
new ConstraintViolationException(
(Set)violations));
}
return null;
}
/**
* Validates a value based upon the constraints applied to a given class
* attribute.
* @param <T> The instance type to base validation upon
* @param arg0 The class of type T to validate
* @param arg1 The property to validate
* @param arg2 The property value to validate
* @param event The event id
* @return A Validation exception if the validator produces one or more
* constraint violations.
*/
@Override
public <T> ValidationException validateValue(Class<T> arg0,
String arg1, Object arg2, int event) {
if (!isValidating(event))
return null;
Set<ConstraintViolation<T>> violations =
_validator.validateValue(arg0, arg1, arg2,
getValidationGroup(event));
if (violations != null && violations.size() > 0) {
return new ValidationException(
new ConstraintViolationException(
(Set)violations));
}
return null;
}
/**
* Returns whether validation is active for the given event.
*
* @param <T>
* @param arg0 Type being validated
* @param event event type
* @return true if validation is active for the specified event
*/
@Override
public <T> boolean validating(T arg0, int event) {
// TODO: This method will also make a determination based upon which
// groups are validating and the group defined on the class
return isValidating(event);
}
// Lookup the lifecycle event id for the validationProperty
private Integer findEvent(String validationProperty) {
return _vgMapping.get(validationProperty);
}
// Get the default validator factory
private ValidatorFactory getDefaultValidatorFactory() {
ValidatorFactory factory =
Validation.buildDefaultValidatorFactory();
return factory;
}
// Per JSR-317, the pre-persist and pre-update groups will validate using
// the default validation group and pre-remove will not validate (no
// validation group)
private void addDefaultValidationGroups() {
addValidationGroup(VG_PRE_PERSIST,
javax.validation.groups.Default.class);
addValidationGroup(VG_PRE_UPDATE,
javax.validation.groups.Default.class);
}
}

View File

@ -449,6 +449,11 @@
<artifactId>geronimo-jta_1.1_spec</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>org.apache.geronimo.specs</groupId>
<artifactId>geronimo-validation_1.0_spec</artifactId>
<version>1.0-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.apache.derby</groupId>
<artifactId>derby</artifactId>