Author: allee8285
Date: Tue Apr 26 16:00:52 2011
New Revision: 1096791
URL: http://svn.apache.org/viewvc?rev=1096791&view=rev
Log:
OPENJPA-1984 - Skip non-root object validation when performing remove(root
object). Let's validation provider to perform root object validation so that
the contraint violation can report the correct root bean.
Added:
openjpa/trunk/openjpa-integration/validation/src/test/java/org/apache/openjpa/integration/validation/Image.java
(with props)
openjpa/trunk/openjpa-integration/validation/src/test/java/org/apache/openjpa/integration/validation/Location.java
(with props)
openjpa/trunk/openjpa-integration/validation/src/test/java/org/apache/openjpa/integration/validation/TestConstraintViolation.java
(with props)
Modified:
openjpa/trunk/openjpa-integration/validation/src/test/resources/org/apache/openjpa/integration/validation/persistence.xml
openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/BrokerImpl.java
openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/validation/ValidatingLifecycleEventManager.java
Added:
openjpa/trunk/openjpa-integration/validation/src/test/java/org/apache/openjpa/integration/validation/Image.java
URL:
http://svn.apache.org/viewvc/openjpa/trunk/openjpa-integration/validation/src/test/java/org/apache/openjpa/integration/validation/Image.java?rev=1096791&view=auto
==============================================================================
---
openjpa/trunk/openjpa-integration/validation/src/test/java/org/apache/openjpa/integration/validation/Image.java
(added)
+++
openjpa/trunk/openjpa-integration/validation/src/test/java/org/apache/openjpa/integration/validation/Image.java
Tue Apr 26 16:00:52 2011
@@ -0,0 +1,68 @@
+/*
+ * 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.integration.validation;
+
+import javax.persistence.Embedded;
+import javax.persistence.Entity;
+import javax.persistence.Id;
+import javax.validation.Valid;
+import javax.validation.constraints.NotNull;
+
+/**
+ * Image entity which makes use of several BV constraints.
+ */
+@Entity
+public class Image {
+
+ private int id;
+ private String fileName;
+ private Location location;
+
+ @Id
+ public int getId() {
+ return id;
+ }
+
+ public void setId(int id) {
+ this.id = id;
+ }
+
+ @NotNull(message="Image file name must not be null.")
+ public String getFileName() {
+ return fileName;
+ }
+
+ public void setFileName(String fileName) {
+ this.fileName = fileName;
+ }
+
+ @Valid
+ @Embedded
+ public Location getLocation() {
+ return location;
+ }
+
+ public void setLocation(Location location) {
+ this.location = location;
+ }
+
+ public String toString() {
+ return "[Image:id=" + id + ",filename=" + fileName + "," + location +
']';
+ }
+}
Propchange:
openjpa/trunk/openjpa-integration/validation/src/test/java/org/apache/openjpa/integration/validation/Image.java
------------------------------------------------------------------------------
svn:eol-style = native
Added:
openjpa/trunk/openjpa-integration/validation/src/test/java/org/apache/openjpa/integration/validation/Location.java
URL:
http://svn.apache.org/viewvc/openjpa/trunk/openjpa-integration/validation/src/test/java/org/apache/openjpa/integration/validation/Location.java?rev=1096791&view=auto
==============================================================================
---
openjpa/trunk/openjpa-integration/validation/src/test/java/org/apache/openjpa/integration/validation/Location.java
(added)
+++
openjpa/trunk/openjpa-integration/validation/src/test/java/org/apache/openjpa/integration/validation/Location.java
Tue Apr 26 16:00:52 2011
@@ -0,0 +1,96 @@
+/*
+ * 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.integration.validation;
+
+import javax.persistence.Column;
+import javax.persistence.Embeddable;
+import javax.validation.constraints.NotNull;
+import javax.validation.constraints.Pattern;
+import javax.validation.constraints.Size;
+
+/**
+ * Location embeddable with several BV constraints applied.
+ */
+@Embeddable
+public class Location {
+
+ @NotNull(message="City must be specified.")
+ private String city;
+
+ private String street;
+
+ private String state;
+
+ @NotNull(message="Country must be specified.")
+ @Size(message="Country must be 50 characters or less.", max=50)
+ @Column(length=50)
+ private String country;
+
+ @Size(message="Zip code must be 10 characters or less.", max=10)
+ @Pattern(message="Zip code must be 5 digits or use the 5+4 format.",
+ regexp="^\\d{5}(([\\-]|[\\+])\\d{4})?$")
+ @Column(length=10)
+ private String zipCode;
+
+ public void setCity(String city) {
+ this.city = city;
+ }
+
+ public String getCity() {
+ return city;
+ }
+
+ public void setStreet(String street) {
+ this.street = street;
+ }
+
+ public String getStreet() {
+ return street;
+ }
+
+ public void setState(String state) {
+ this.state = state;
+ }
+
+ public String getState() {
+ return state;
+ }
+
+ public void setCountry(String country) {
+ this.country = country;
+ }
+
+ public String getCountry() {
+ return country;
+ }
+
+ public void setZipCode(String zipCode) {
+ this.zipCode = zipCode;
+ }
+
+ public String getZipCode() {
+ return zipCode;
+ }
+
+ public String toString() {
+ return "[Location:city=" + city + ",street=" + street + ",state=" +
state + ",country=" + country + ",zipCode="
+ + zipCode + ']';
+ }
+}
Propchange:
openjpa/trunk/openjpa-integration/validation/src/test/java/org/apache/openjpa/integration/validation/Location.java
------------------------------------------------------------------------------
svn:eol-style = native
Added:
openjpa/trunk/openjpa-integration/validation/src/test/java/org/apache/openjpa/integration/validation/TestConstraintViolation.java
URL:
http://svn.apache.org/viewvc/openjpa/trunk/openjpa-integration/validation/src/test/java/org/apache/openjpa/integration/validation/TestConstraintViolation.java?rev=1096791&view=auto
==============================================================================
---
openjpa/trunk/openjpa-integration/validation/src/test/java/org/apache/openjpa/integration/validation/TestConstraintViolation.java
(added)
+++
openjpa/trunk/openjpa-integration/validation/src/test/java/org/apache/openjpa/integration/validation/TestConstraintViolation.java
Tue Apr 26 16:00:52 2011
@@ -0,0 +1,309 @@
+/*
+ * 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.integration.validation;
+
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+import javax.persistence.EntityManager;
+import javax.persistence.EntityManagerFactory;
+import javax.validation.ConstraintViolation;
+import javax.validation.ConstraintViolationException;
+
+import org.apache.openjpa.lib.log.Log;
+import org.apache.openjpa.persistence.OpenJPAEntityManagerFactorySPI;
+import org.apache.openjpa.persistence.OpenJPAPersistence;
+import org.apache.openjpa.persistence.test.AbstractPersistenceTestCase;
+
+public class TestConstraintViolation extends AbstractPersistenceTestCase {
+
+ EntityManagerFactory emf2 = null;
+ Log log = null;
+
+ public void setUp() {
+ Map<String, String> props = new HashMap<String, String>();
+ props.put("javax.persistence.validation.group.pre-remove",
"javax.validation.groups.Default");
+
+ // This test case uses a different persistence xml file because
validation require 2.0 xsd.
+ emf2 =
OpenJPAPersistence.createEntityManagerFactory("ConstraintViolationTestPU",
+ "org/apache/openjpa/integration/validation/persistence.xml",
props);
+ log =
((OpenJPAEntityManagerFactorySPI)emf2).getConfiguration().getLog("Tests");
+
+ EntityManager em = emf2.createEntityManager();
+ Image img = em.find(Image.class, 1);
+ if (img != null) {
+ em.getTransaction().begin();
+ em.remove(img);
+ em.getTransaction().commit();
+ }
+ em.close();
+ }
+
+ public void testPersistNormalValidation() {
+ EntityManager em = emf2.createEntityManager();
+
+ // Persist with successful validations
+ Location loc = new Location();
+ loc.setCity("Rochester");
+ loc.setStreet(null);
+ loc.setState("MN");
+ loc.setZipCode("55901");
+ loc.setCountry("USA");
+
+ Image img = new Image();
+ img.setId(1);
+ img.setFileName("Winter_01.gif");
+ img.setLocation(loc);
+
+ try {
+ em.getTransaction().begin();
+ log.trace("------------------------------------------------");
+ log.trace("** Persist with successful validations");
+ em.persist(img);
+ } catch (ConstraintViolationException cve) {
+ // Transaction was marked for rollback, roll it back and start a
new TX
+ Set<ConstraintViolation<?>> cvs = cve.getConstraintViolations();
+ for (ConstraintViolation<?> cv : cvs) {
+ log.trace("Message: " + cv.getMessage());
+ log.trace("RootBean: " + cv.getRootBean());
+ log.trace("LeafBean: " + cv.getLeafBean());
+ log.trace("PropertyPath: " + cv.getPropertyPath());
+ log.trace("Invalid value: " + cv.getInvalidValue());
+ }
+ fail();
+ } finally {
+ em.getTransaction().rollback();
+ em.close();
+ emf2.close();
+ }
+ }
+
+ public void testPersistImageNullValidation() {
+ EntityManager em = emf2.createEntityManager();
+
+ // Persist with null filename in Image
+ Location loc = new Location();
+ loc.setCity("Rochester");
+ loc.setStreet("3605 Hwy 52 N");
+ loc.setState("MN");
+ loc.setZipCode("55901");
+ loc.setCountry("USA");
+
+ Image img = new Image();
+ img.setId(1);
+ img.setFileName(null);
+ img.setLocation(loc);
+
+ try {
+ em.getTransaction().begin();
+ log.trace("------------------------------------------------");
+ log.trace("** Persist with null filename in Image");
+ em.persist(img);
+ fail();
+ } catch (ConstraintViolationException cve) {
+ // Transaction was marked for rollback, roll it back and start a
new TX
+ Set<ConstraintViolation<?>> cvs = cve.getConstraintViolations();
+ assertEquals(1, cvs.size());
+ for (ConstraintViolation<?> cv : cvs) {
+ log.trace("Message: " + cv.getMessage());
+ log.trace("RootBean: " + cv.getRootBean());
+ log.trace("LeafBean: " + cv.getLeafBean());
+ log.trace("PropertyPath: " + cv.getPropertyPath());
+ log.trace("Invalid value: " + cv.getInvalidValue());
+
+ assertEquals("Image file name must not be null.",
cv.getMessage());
+ assertEquals("Image", cv.getRootBeanClass().getSimpleName());
+ assertEquals("Image",
cv.getLeafBean().getClass().getSimpleName());
+ assertTrue(cv.getLeafBean().getClass() ==
cv.getRootBeanClass());
+ assertEquals("fileName", cv.getPropertyPath().toString());
+ assertNull(cv.getInvalidValue());
+ }
+ } finally {
+ em.getTransaction().rollback();
+ em.close();
+ emf2.close();
+ }
+ }
+
+ public void testPersistEmbedCityNullValidation() {
+ EntityManager em = emf2.createEntityManager();
+
+ // Persist with null city name in location
+ Location loc = new Location();
+ loc.setCity(null);
+ loc.setStreet("3605 Hwy 52 N");
+ loc.setState("MN");
+ loc.setZipCode("55901");
+ loc.setCountry("USA");
+
+ Image img = new Image();
+ img.setId(1);
+ img.setFileName("Winter_01.gif");
+ img.setLocation(loc);
+
+ try {
+ em.getTransaction().begin();
+ log.trace("------------------------------------------------");
+ log.trace("** Persist with null city name in location" );
+ em.persist(img);
+ fail();
+ } catch (ConstraintViolationException cve) {
+ // Transaction was marked for rollback, roll it back and start a
new TX
+ Set<ConstraintViolation<?>> cvs = cve.getConstraintViolations();
+ assertEquals(1, cvs.size());
+ for (ConstraintViolation<?> cv : cvs) {
+ log.trace("Message: " + cv.getMessage());
+ log.trace("RootBean: " + cv.getRootBean());
+ log.trace("LeafBean: " + cv.getLeafBean());
+ log.trace("PropertyPath: " + cv.getPropertyPath());
+ log.trace("Invalid value: " + cv.getInvalidValue());
+
+ assertEquals("City must be specified.", cv.getMessage());
+ assertEquals("Image", cv.getRootBeanClass().getSimpleName());
+ // The violation occurred on a leaf bean (embeddable)
+ assertEquals("Location",
cv.getLeafBean().getClass().getSimpleName());
+ assertTrue(cv.getLeafBean().getClass() !=
cv.getRootBeanClass());
+ assertEquals("location.city", cv.getPropertyPath().toString());
+ assertNull(cv.getInvalidValue());
+ }
+ } finally {
+ em.getTransaction().rollback();
+ em.close();
+ emf2.close();
+ }
+ }
+
+ public void testRemoveEmbedCityNullValidation() {
+ EntityManager em = emf2.createEntityManager();
+
+ // Remove with null city name in location
+ Location loc = new Location();
+ loc.setCity("Rochester");
+ loc.setStreet("3605 Hwy 52 N");
+ loc.setState("MN");
+ loc.setZipCode("55901");
+ loc.setCountry("USA");
+
+ Image img = new Image();
+ img.setId(1);
+ img.setFileName("Winter_01.gif");
+ img.setLocation(loc);
+
+ try {
+ em.getTransaction().begin();
+ log.trace("------------------------------------------------");
+ log.trace("** Create normal Image/location" );
+ em.persist(img);
+ em.getTransaction().commit();
+ } catch (ConstraintViolationException cve) {
+ fail();
+ }
+
+ try {
+ em.getTransaction().begin();
+ log.trace("** set null city name in location and remove" );
+ img.getLocation().setCity(null);
+ em.remove(img);
+ fail();
+ } catch (ConstraintViolationException cve) {
+ // Transaction was marked for rollback, roll it back and
+ // start a new TX
+ Set<ConstraintViolation<?>> cvs = cve.getConstraintViolations();
+ assertEquals(1, cvs.size());
+ for (ConstraintViolation<?> cv : cvs) {
+ log.trace("Message: " + cv.getMessage());
+ log.trace("RootBean: " + cv.getRootBean());
+ log.trace("LeafBean: " + cv.getLeafBean());
+ log.trace("PropertyPath: " + cv.getPropertyPath());
+ log.trace("Invalid value: " + cv.getInvalidValue());
+
+ assertEquals("City must be specified.", cv.getMessage());
+ assertEquals("Image", cv.getRootBeanClass().getSimpleName());
+ // The violation occurred on a leaf bean (embeddable)
+ assertEquals("Location",
cv.getLeafBean().getClass().getSimpleName());
+ assertTrue(cv.getLeafBean().getClass() !=
cv.getRootBeanClass());
+ assertEquals("location.city", cv.getPropertyPath().toString());
+ assertNull(cv.getInvalidValue());
+ }
+ } finally {
+ em.getTransaction().rollback();
+ em.close();
+ emf2.close();
+ }
+ }
+
+ public void testFlushEmbedCityNullValidation() {
+ EntityManager em = emf2.createEntityManager();
+
+ // set invalid zipCode in location and flush testing pre-update
+ Location loc = new Location();
+ loc.setCity("Rochester");
+ loc.setStreet("3605 Hwy 52 N");
+ loc.setState("MN");
+ loc.setZipCode("55901");
+ loc.setCountry("USA");
+
+ Image img = new Image();
+ img.setId(1);
+ img.setFileName("Winter_01.gif");
+ img.setLocation(loc);
+
+ try {
+ em.getTransaction().begin();
+ log.trace("------------------------------------------------");
+ log.trace("** Create normal Image/location" );
+ em.persist(img);
+ em.getTransaction().commit();
+ } catch (ConstraintViolationException cve) {
+ fail();
+ }
+
+ try {
+ em.getTransaction().begin();
+ log.trace("** set invalid zipCode and flush testing pre-update" );
+ img.getLocation().setZipCode("abcde");
+ em.flush();
+ fail();
+ } catch (ConstraintViolationException cve) {
+ // Transaction was marked for rollback, roll it back and start a
new TX
+ Set<ConstraintViolation<?>> cvs = cve.getConstraintViolations();
+ assertEquals(1, cvs.size());
+ for (ConstraintViolation<?> cv : cvs) {
+ log.trace("Message: " + cv.getMessage());
+ log.trace("RootBean: " + cv.getRootBean());
+ log.trace("LeafBean: " + cv.getLeafBean());
+ log.trace("PropertyPath: " + cv.getPropertyPath());
+ log.trace("Invalid value: " + cv.getInvalidValue());
+
+ assertEquals("Zip code must be 5 digits or use the 5+4
format.", cv.getMessage());
+ assertEquals("Image", cv.getRootBeanClass().getSimpleName());
+ // The violation occurred on a leaf bean (embeddable)
+ assertEquals("Location",
cv.getLeafBean().getClass().getSimpleName());
+ assertTrue(cv.getLeafBean().getClass() !=
cv.getRootBeanClass());
+ assertEquals("location.zipCode",
cv.getPropertyPath().toString());
+ assertEquals("abcde", cv.getInvalidValue());
+ }
+ } finally {
+ em.getTransaction().rollback();
+ em.close();
+ emf2.close();
+ }
+ }
+}
Propchange:
openjpa/trunk/openjpa-integration/validation/src/test/java/org/apache/openjpa/integration/validation/TestConstraintViolation.java
------------------------------------------------------------------------------
svn:eol-style = native
Modified:
openjpa/trunk/openjpa-integration/validation/src/test/resources/org/apache/openjpa/integration/validation/persistence.xml
URL:
http://svn.apache.org/viewvc/openjpa/trunk/openjpa-integration/validation/src/test/resources/org/apache/openjpa/integration/validation/persistence.xml?rev=1096791&r1=1096790&r2=1096791&view=diff
==============================================================================
---
openjpa/trunk/openjpa-integration/validation/src/test/resources/org/apache/openjpa/integration/validation/persistence.xml
(original)
+++
openjpa/trunk/openjpa-integration/validation/src/test/resources/org/apache/openjpa/integration/validation/persistence.xml
Tue Apr 26 16:00:52 2011
@@ -210,4 +210,16 @@
</properties>
</persistence-unit>
+ <!-- ============================================================ -->
+ <!-- Persistence unit for testing ConstraintViolation object -->
+ <persistence-unit name="ConstraintViolationTestPU">
+ <class>org.apache.openjpa.integration.validation.Image</class>
+ <class>org.apache.openjpa.integration.validation.Location</class>
+ <exclude-unlisted-classes>true</exclude-unlisted-classes>
+ <validation-mode>CALLBACK</validation-mode>
+ <properties>
+ <property name="openjpa.jdbc.SynchronizeMappings"
value="buildSchema(ForeignKeys=true)" />
+ </properties>
+ </persistence-unit>
+
</persistence>
Modified:
openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/BrokerImpl.java
URL:
http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/BrokerImpl.java?rev=1096791&r1=1096790&r2=1096791&view=diff
==============================================================================
---
openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/BrokerImpl.java
(original)
+++
openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/kernel/BrokerImpl.java
Tue Apr 26 16:00:52 2011
@@ -96,6 +96,7 @@ import org.apache.openjpa.util.StoreExce
import org.apache.openjpa.util.UnsupportedException;
import org.apache.openjpa.util.UserException;
import org.apache.openjpa.util.WrappedException;
+import org.apache.openjpa.validation.ValidatingLifecycleEventManager;
/**
* Concrete {@link Broker}. The broker handles object-level behavior,
@@ -2759,7 +2760,18 @@ public class BrokerImpl
throw newDetachedException(obj, "delete");
if ((action & OpCallbacks.ACT_CASCADE) != 0) {
if (!sm.isEmbedded() || !sm.getDereferencedEmbedDependent()) {
- sm.cascadeDelete(call);
+ if
(ValidatingLifecycleEventManager.class.isAssignableFrom(_lifeEventManager.getClass()))
{
+ ValidatingLifecycleEventManager
_validatingLCEventManager =
+ (ValidatingLifecycleEventManager)
_lifeEventManager;
+ boolean saved =
_validatingLCEventManager.setValidationEnabled(false);
+ try {
+ sm.cascadeDelete(call);
+ } finally {
+
_validatingLCEventManager.setValidationEnabled(saved);
+ }
+ } else {
+ sm.cascadeDelete(call);
+ }
}
}
sm.delete();
Modified:
openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/validation/ValidatingLifecycleEventManager.java
URL:
http://svn.apache.org/viewvc/openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/validation/ValidatingLifecycleEventManager.java?rev=1096791&r1=1096790&r2=1096791&view=diff
==============================================================================
---
openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/validation/ValidatingLifecycleEventManager.java
(original)
+++
openjpa/trunk/openjpa-kernel/src/main/java/org/apache/openjpa/validation/ValidatingLifecycleEventManager.java
Tue Apr 26 16:00:52 2011
@@ -37,6 +37,7 @@ public class ValidatingLifecycleEventMan
private OpenJPAConfiguration _conf = null;
private Validator _validator = null;
+ protected boolean _validationEnabled = true;
/**
* Constructor which accepts a reference to the validator to use. If null,
@@ -118,7 +119,7 @@ public class ValidatingLifecycleEventMan
// 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)) {
+ if (_validationEnabled && _validator != null &&
_validator.validating(source, type)) {
ValidationException vex = _validator.validate(source, type);
if (vex != null) {
if (evx == null || evx.length == 0) {
@@ -137,4 +138,14 @@ public class ValidatingLifecycleEventMan
}
return evx;
}
+
+ public boolean isValidationEnabled() {
+ return _validationEnabled;
+ }
+
+ public boolean setValidationEnabled(boolean enabled) {
+ boolean val = _validationEnabled;
+ _validationEnabled = enabled;
+ return val;
+ }
}