You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openjpa.apache.org by ss...@apache.org on 2008/09/05 22:24:40 UTC

svn commit: r692529 - in /openjpa/branches/0.9.7-r547073: openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/ openjpa-kernel/src/main/java/org/apache/openjpa/util/ openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/exception/ ope...

Author: ssegu
Date: Fri Sep  5 13:24:39 2008
New Revision: 692529

URL: http://svn.apache.org/viewvc?rev=692529&view=rev
Log:
OPENJPA-462
 - Narrow StoreException by SQLException.getSQLState() 
 - Adding SQLState in DerbyDictionary to demonstrate specialization 
 - Adding a Test case to verify correct exception type

Added:
    openjpa/branches/0.9.7-r547073/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/exception/
      - copied from r603032, openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/exception/
    openjpa/branches/0.9.7-r547073/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/exception/PObject.java
      - copied unchanged from r603032, openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/exception/PObject.java
    openjpa/branches/0.9.7-r547073/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/exception/TestException.java
      - copied unchanged from r603032, openjpa/trunk/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/exception/TestException.java
Modified:
    openjpa/branches/0.9.7-r547073/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java
    openjpa/branches/0.9.7-r547073/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DerbyDictionary.java
    openjpa/branches/0.9.7-r547073/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/SQLExceptions.java
    openjpa/branches/0.9.7-r547073/openjpa-kernel/src/main/java/org/apache/openjpa/util/ObjectExistsException.java
    openjpa/branches/0.9.7-r547073/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/test/PersistenceTestCase.java
    openjpa/branches/0.9.7-r547073/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/PersistenceExceptions.java

Modified: openjpa/branches/0.9.7-r547073/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java
URL: http://svn.apache.org/viewvc/openjpa/branches/0.9.7-r547073/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java?rev=692529&r1=692528&r2=692529&view=diff
==============================================================================
--- openjpa/branches/0.9.7-r547073/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java (original)
+++ openjpa/branches/0.9.7-r547073/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DBDictionary.java Fri Sep  5 13:24:39 2008
@@ -94,7 +94,6 @@
 import org.apache.openjpa.meta.JavaTypes;
 import org.apache.openjpa.util.GeneralException;
 import org.apache.openjpa.util.OpenJPAException;
-import org.apache.openjpa.util.ReferentialIntegrityException;
 import org.apache.openjpa.util.Serialization;
 import org.apache.openjpa.util.StoreException;
 import org.apache.openjpa.util.UnsupportedException;
@@ -144,6 +143,16 @@
     private static final String ZERO_TIMESTAMP_STR =
         "'" + new Timestamp(0) + "'";
 
+    public static final List EMPTY_STRING_LIST = Arrays.asList(new String[]{});
+    public static final List[] SQL_STATE_CODES = 
+    	{EMPTY_STRING_LIST,                     // 0: Default
+    	 Arrays.asList(new String[]{"41000"}),  // 1: LOCK
+    	 EMPTY_STRING_LIST,                     // 2: OBJECT_NOT_FOUND
+    	 EMPTY_STRING_LIST,                     // 3: OPTIMISTIC
+    	 Arrays.asList(new String[]{"23000"}),  // 4: REFERENTIAL_INTEGRITY
+    	 EMPTY_STRING_LIST                      // 5: OBJECT_EXISTS
+    	}; 
+                                              
     private static final Localizer _loc = Localizer.forPackage
         (DBDictionary.class);
 
@@ -3778,12 +3787,35 @@
      */
     public OpenJPAException newStoreException(String msg, SQLException[] causes,
         Object failed) {
-        if (causes.length > 0 && "23000".equals(causes[0].getSQLState()))
-            return new ReferentialIntegrityException(msg).
-                setFailedObject(failed).setNestedThrowables(causes);
+    	if (causes != null && causes.length > 0) {
+    		OpenJPAException ret = SQLExceptions.narrow(msg, causes[0], this);
+    		ret.setFailedObject(failed).setNestedThrowables(causes);
+    		return ret;
+    	}
         return new StoreException(msg).setFailedObject(failed).
             setNestedThrowables(causes);
     }
+    
+    /**
+     * Gets the list of String, each represents an error that can help 
+     * to narrow down a SQL exception to specific type of StoreException.<br>
+     * For example, error code <code>"23000"</code> represents referential
+     * integrity violation and hence can be narrowed down to 
+     * {@link ReferentialIntegrityException} rather than more general
+     * {@link StoreException}.<br>
+     * JDBC Drivers are not uniform in return values of SQLState for the same
+     * error and hence each database specific Dictionary can specialize.<br>
+     * 
+     * 
+     * @return an <em>unmodifiable</em> list of Strings representing supposedly 
+     * uniform SQL States for a given type of StoreException. 
+     * Default behavior is to return an empty list.
+     */
+    public List/*<String>*/ getSQLStates(int exceptionType) {
+    	if (exceptionType>=0 && exceptionType<SQL_STATE_CODES.length)
+    		return SQL_STATE_CODES[exceptionType];
+    	return EMPTY_STRING_LIST;
+    }
 
     /**
      * Closes the specified {@link DataSource} and releases any

Modified: openjpa/branches/0.9.7-r547073/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DerbyDictionary.java
URL: http://svn.apache.org/viewvc/openjpa/branches/0.9.7-r547073/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DerbyDictionary.java?rev=692529&r1=692528&r2=692529&view=diff
==============================================================================
--- openjpa/branches/0.9.7-r547073/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DerbyDictionary.java (original)
+++ openjpa/branches/0.9.7-r547073/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/DerbyDictionary.java Fri Sep  5 13:24:39 2008
@@ -20,9 +20,14 @@
 
 import java.sql.DriverManager;
 import java.sql.SQLException;
+import java.util.ArrayList;
 import java.util.Arrays;
+import java.util.List;
+
 import javax.sql.DataSource;
 
+import org.apache.openjpa.util.StoreException;
+
 /**
  * Dictionary for Apache Derby (formerly Cloudscape).
  */
@@ -93,4 +98,26 @@
             }
         }
     }
+    
+    /**
+     * Adds extra SQLState code that Derby JDBC Driver uses. In JDBC 4.0,
+     * SQLState will follow either XOPEN or SQL 2003 convention. A compliant
+     * driver can be queries via DatabaseMetaData.getSQLStateType() to detect
+     * the convention type.<br>
+     * This method is overwritten to highlight that a) the SQL State is ideally
+     * uniform across JDBC Drivers but not practically and b) the overwritten
+     * method must crate a new list to return as the super classes list is
+     * unmodifable.
+     */
+    public List getSQLStates(int exceptionType) {
+    	List original = super.getSQLStates(exceptionType);
+    	if (exceptionType == StoreException.LOCK) {
+    		// Can not add new codes to unmodifable list of the super class
+    		List newStates = new ArrayList(original);
+    		newStates.add("40XL1");
+    		return newStates;
+    	}
+    	return original;
+    }
+    
 }

Modified: openjpa/branches/0.9.7-r547073/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/SQLExceptions.java
URL: http://svn.apache.org/viewvc/openjpa/branches/0.9.7-r547073/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/SQLExceptions.java?rev=692529&r1=692528&r2=692529&view=diff
==============================================================================
--- openjpa/branches/0.9.7-r547073/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/SQLExceptions.java (original)
+++ openjpa/branches/0.9.7-r547073/openjpa-jdbc/src/main/java/org/apache/openjpa/jdbc/sql/SQLExceptions.java Fri Sep  5 13:24:39 2008
@@ -23,7 +23,12 @@
 import java.util.List;
 
 import org.apache.openjpa.lib.util.Localizer.Message;
+import org.apache.openjpa.util.LockException;
+import org.apache.openjpa.util.ObjectExistsException;
+import org.apache.openjpa.util.ObjectNotFoundException;
 import org.apache.openjpa.util.OpenJPAException;
+import org.apache.openjpa.util.OptimisticException;
+import org.apache.openjpa.util.ReferentialIntegrityException;
 import org.apache.openjpa.util.StoreException;
 
 /**
@@ -96,7 +101,7 @@
                 setNestedThrowables(ses);
         return dict.newStoreException(msg, ses, failed);
     }
-
+    
     /**
      * Returns an array of {@link SQLException} instances for the
      * specified exception.
@@ -112,4 +117,32 @@
         }
         return (SQLException[]) errs.toArray(new SQLException[errs.size()]);
     }
+    
+    /**
+     * Narrows the given SQLException to a specific type of 
+     * {@link StoreException#getSubtype() StoreException} by analyzing the
+     * SQLState code supplied by SQLException. Each database-specific 
+     * {@link DBDictionary dictionary} can supply a set of error codes that will
+     * map to a specific specific type of StoreException via 
+     * {@link DBDictionary#getSQLStates(int) getSQLStates()} method.
+     * The default behavior is to return generic {@link StoreException 
+     * StoreException}.
+     */
+    public static OpenJPAException narrow(String msg, SQLException se, 
+    		DBDictionary dict) {
+        String e = se.getSQLState();
+        if (dict.getSQLStates(StoreException.LOCK).contains(e)) 
+            return new LockException(msg);
+        else if (dict.getSQLStates(StoreException.OBJECT_EXISTS).contains(e))
+            return new ObjectExistsException(msg);
+        else if (dict.getSQLStates(StoreException.OBJECT_NOT_FOUND).contains(e))
+            return new ObjectNotFoundException(msg);
+        else if (dict.getSQLStates(StoreException.OPTIMISTIC).contains(e))
+            return new OptimisticException(msg);
+        else if (dict.getSQLStates(StoreException.REFERENTIAL_INTEGRITY)
+        		.contains(e)) 
+            return new ReferentialIntegrityException(msg);
+        else
+            return new StoreException(msg);
+    }
 }

Modified: openjpa/branches/0.9.7-r547073/openjpa-kernel/src/main/java/org/apache/openjpa/util/ObjectExistsException.java
URL: http://svn.apache.org/viewvc/openjpa/branches/0.9.7-r547073/openjpa-kernel/src/main/java/org/apache/openjpa/util/ObjectExistsException.java?rev=692529&r1=692528&r2=692529&view=diff
==============================================================================
--- openjpa/branches/0.9.7-r547073/openjpa-kernel/src/main/java/org/apache/openjpa/util/ObjectExistsException.java (original)
+++ openjpa/branches/0.9.7-r547073/openjpa-kernel/src/main/java/org/apache/openjpa/util/ObjectExistsException.java Fri Sep  5 13:24:39 2008
@@ -28,6 +28,10 @@
 public class ObjectExistsException
     extends StoreException {
 
+    public ObjectExistsException(String msg) {
+		super(msg);
+    }
+	
     public ObjectExistsException(Message msg) {
         super(msg);
     }

Modified: openjpa/branches/0.9.7-r547073/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/test/PersistenceTestCase.java
URL: http://svn.apache.org/viewvc/openjpa/branches/0.9.7-r547073/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/test/PersistenceTestCase.java?rev=692529&r1=692528&r2=692529&view=diff
==============================================================================
--- openjpa/branches/0.9.7-r547073/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/test/PersistenceTestCase.java (original)
+++ openjpa/branches/0.9.7-r547073/openjpa-persistence-jdbc/src/test/java/org/apache/openjpa/persistence/test/PersistenceTestCase.java Fri Sep  5 13:24:39 2008
@@ -167,4 +167,13 @@
         ClassMetaData meta = OpenJPAPersistence.getMetaData(emf, c);
         return (meta == null) ? null : meta.getTypeAlias();
     }
+
+    public static void assertNotEquals(Object o1, Object o2) {
+        if (o1 == o2)
+            fail("expected args to be different; were the same instance.");
+        else if (o1 == null || o2 == null)
+            return;
+        else if (o1.equals(o2))
+            fail("expected args to be different; compared equal.");
+    }
 }

Modified: openjpa/branches/0.9.7-r547073/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/PersistenceExceptions.java
URL: http://svn.apache.org/viewvc/openjpa/branches/0.9.7-r547073/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/PersistenceExceptions.java?rev=692529&r1=692528&r2=692529&view=diff
==============================================================================
--- openjpa/branches/0.9.7-r547073/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/PersistenceExceptions.java (original)
+++ openjpa/branches/0.9.7-r547073/openjpa-persistence/src/main/java/org/apache/openjpa/persistence/PersistenceExceptions.java Fri Sep  5 13:24:39 2008
@@ -146,6 +146,7 @@
                         getFailedObject(ke), ke.isFatal());
                 break;
             case StoreException.OPTIMISTIC:
+            case StoreException.LOCK:
                 e = new org.apache.openjpa.persistence.OptimisticLockException
                     (ke.getMessage(), getNestedThrowables(ke),
                         getFailedObject(ke), ke.isFatal());