From d21fb8c1a4e598b9590ae5070492b3b35c08de92 Mon Sep 17 00:00:00 2001 From: Heath Thomann Date: Wed, 23 May 2012 14:52:39 +0000 Subject: [PATCH] OPENJPA-2095: Applied Helen Xu's patch to 2.0.x git-svn-id: https://svn.apache.org/repos/asf/openjpa/branches/2.0.x@1341881 13f79535-47bb-0310-9956-ffa450edef68 --- .../jdbc/kernel/AbstractUpdateManager.java | 13 +- .../apps/TestItemWithFailedExternalizer.java | 121 ++++++++++++++++++ .../TestBatchFlushWithMetadataException.java | 71 ++++++++++ 3 files changed, 203 insertions(+), 2 deletions(-) create mode 100644 openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/common/apps/TestItemWithFailedExternalizer.java create mode 100644 openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/kernel/TestBatchFlushWithMetadataException.java diff --git a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/AbstractUpdateManager.java b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/AbstractUpdateManager.java index fe8c8835a..8636d5aee 100644 --- a/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/AbstractUpdateManager.java +++ b/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/kernel/AbstractUpdateManager.java @@ -34,6 +34,8 @@ import org.apache.openjpa.jdbc.meta.FieldMapping; import org.apache.openjpa.jdbc.meta.Strategy; import org.apache.openjpa.jdbc.meta.Version; import org.apache.openjpa.jdbc.sql.DBDictionary; +import org.apache.openjpa.jdbc.sql.Row; +import org.apache.openjpa.jdbc.sql.RowImpl; import org.apache.openjpa.jdbc.sql.RowManager; import org.apache.openjpa.jdbc.sql.SQLExceptions; import org.apache.openjpa.kernel.OpenJPAStateManager; @@ -156,14 +158,17 @@ public abstract class AbstractUpdateManager protected Collection populateRowManager(OpenJPAStateManager sm, RowManager rowMgr, JDBCStore store, Collection exceps, Collection customs) { + int action = Row.ACTION_UPDATE; try { BitSet dirty; if (sm.getPCState() == PCState.PNEW && !sm.isFlushed()) { - insert(sm, (ClassMapping) sm.getMetaData(), rowMgr, store, + action = Row.ACTION_INSERT; + insert(sm, (ClassMapping) sm.getMetaData(), rowMgr, store, customs); } else if (sm.getPCState() == PCState.PNEWFLUSHEDDELETED || sm.getPCState() == PCState.PDELETED) { - delete(sm, (ClassMapping) sm.getMetaData(), rowMgr, store, + action = Row.ACTION_DELETE; + delete(sm, (ClassMapping) sm.getMetaData(), rowMgr, store, customs); } else if ((dirty = ImplHelper.getUpdateFields(sm)) != null) { update(sm, dirty, (ClassMapping) sm.getMetaData(), rowMgr, @@ -180,6 +185,10 @@ public abstract class AbstractUpdateManager } catch (SQLException se) { exceps = addException(exceps, SQLExceptions.getStore(se, dict)); } catch (OpenJPAException ke) { + RowImpl row = (RowImpl) rowMgr.getRow(((ClassMapping) sm.getMetaData()).getTable(), action, sm, false); + if (row != null) { + row.setFlushed(true); + } exceps = addException(exceps, ke); } return exceps; diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/common/apps/TestItemWithFailedExternalizer.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/common/apps/TestItemWithFailedExternalizer.java new file mode 100644 index 000000000..a7609cac6 --- /dev/null +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/common/apps/TestItemWithFailedExternalizer.java @@ -0,0 +1,121 @@ +/* + * 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.jdbc.common.apps; + +import java.io.Serializable; + +import javax.persistence.Entity; +import javax.persistence.Id; +import javax.persistence.PersistenceException; +import javax.persistence.Table; + +@Entity +@Table(name="TestItemWithFailedExternalizer") +public class TestItemWithFailedExternalizer implements Serializable { + + private static final long serialVersionUID = 1L; + + @Id + private int iref; + + private String name; + + private String data; + + @org.apache.openjpa.persistence.Persistent + @org.apache.openjpa.persistence.Externalizer("check") + private TestExternal ext; + + public static class TestExternal + { + private static final long serialVersionUID = 1L; + public boolean throwEx=false; + + private String value = "test - TE"; + + public TestExternal() { + super(); + } + + public TestExternal(String s) { + value = s; + } + + public String check() throws Exception { + if (throwEx){ + throw new PersistenceException("test exception externalizer"); + } + return value; + } + + public String getValue() { + return value; + } + + public void getValue(String s) { + value = s; + } + } + + public TestItemWithFailedExternalizer() { + super(); + } + + public TestItemWithFailedExternalizer(int iref, String name, String data) { + super(); + this.iref = iref; + this.name = name; + this.data = data; + this.ext = new TestExternal(); + } + + public int getIref() { + return this.iref; + } + + public void setIref(int iref) { + this.iref = iref; + } + + public String getName() { + return this.name; + } + + public void setName(String name) { + this.name = name; + } + + public String getData() { + return this.data; + } + + public void setData(String data) { + this.data = data; + } + + public void setExt(TestExternal te){ + this.ext = te; + return; + } + + public TestExternal getExt(){ + return this.ext; + } +} + diff --git a/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/kernel/TestBatchFlushWithMetadataException.java b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/kernel/TestBatchFlushWithMetadataException.java new file mode 100644 index 000000000..ff613e4a7 --- /dev/null +++ b/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/jdbc/kernel/TestBatchFlushWithMetadataException.java @@ -0,0 +1,71 @@ +/* + * 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.jdbc.kernel; + + +import javax.persistence.EntityManager; +import javax.persistence.EntityTransaction; + +import org.apache.openjpa.persistence.PersistenceException; +import org.apache.openjpa.persistence.RollbackException; +import org.apache.openjpa.persistence.jdbc.common.apps.TestItemWithFailedExternalizer; +import org.apache.openjpa.persistence.test.SQLListenerTestCase; + +/* + * when there is a metadata exception during the flushing for a batch job, the AbstractUpdateManager + * should capture the exception and skip the flushing of the failed object. + */ +public class TestBatchFlushWithMetadataException extends SQLListenerTestCase { + + @Override + public void setUp() throws Exception { + setUp(DROP_TABLES, TestItemWithFailedExternalizer.class); + } + + public void testCreate(){ + EntityManager em = emf.createEntityManager(); + EntityTransaction tx = em.getTransaction(); + + tx.begin(); + TestItemWithFailedExternalizer item1 = new TestItemWithFailedExternalizer(1001, "MyName1", "description1"); + TestItemWithFailedExternalizer item2 = new TestItemWithFailedExternalizer(1002, "MyName2", "description2"); + item1.getExt().throwEx=true; + TestItemWithFailedExternalizer item3 = new TestItemWithFailedExternalizer(1003, "MyName3", "description3"); + + em.persist(item1); + em.persist(item2); + em.persist(item3); + commitAndValidate(tx); + em.close(); + } + + private void commitAndValidate(EntityTransaction tx){ + try { + resetSQL(); + tx.commit(); + fail("RollbackException should have been thrown from the externalizer"); + }catch (RollbackException rollBackException) { + Throwable[] throwables = rollBackException.getNestedThrowables(); + assertTrue(throwables[0] instanceof PersistenceException); + PersistenceException persistentException = (PersistenceException) throwables[0]; + assertNotNull(persistentException); + assertEquals(1, persistentException.getNestedThrowables().length); + } + } +}