]> git.aero2k.de Git - tmp/jakarta-migration.git/commitdiff
CSPACE-336,CSPACE-321: Updated JDBC implementation of ID Service and associated tests...
authorAron Roberts <aron@socrates.berkeley.edu>
Tue, 11 Aug 2009 20:02:50 +0000 (20:02 +0000)
committerAron Roberts <aron@socrates.berkeley.edu>
Tue, 11 Aug 2009 20:02:50 +0000 (20:02 +0000)
services/id/service/src/main/java/org/collectionspace/services/id/IDServiceJdbcImpl.java
services/id/service/src/test/java/org/collectionspace/services/id/test/IDServiceJdbcImplTest.java

index bfe0cbcb954c7811993ce779dc8078406dae922a..b835347a40f14ce3d55e80bbaa7743fbe184504c 100644 (file)
 // of the ID Service.  As a result, there will be some naming
 // inconsistencies throughout this source file.
 
-// @TODO: Revise exception handling to return custom Exceptions,
+// @TODO Revise exception handling to return custom Exceptions,
 // perhaps mirroring the subset of HTTP status codes returned.
 //
 // We're currently overloading existing core and extension Java Exceptions
 // in ways that are not consistent with their original semantic meaning.
 
-// @TODO: Retrieve IDGenerators from the database (via JDBC or
+// @TODO Get the JDBC driver classname and database URL from configuration;
+// better yet, substitute Hibernate for JDBC for accessing database-managed persistence.
+
+// @TODO Remove any hard-coded dependencies on MySQL.
+
+// @TODO Determine how to restrict access to ID-related tables by role.
+
+// @TODO Retrieve IDGenerators from the database (via JDBC or
 // Hibernate) at initialization and refresh time.
 
-// @TODO: Handle concurrency.
+// @TODO Remove redundancy.  If we're using JDBC, a great deal of JDBC code
+// is replicated in each method below.
+
+// @TODO Handle concurrency.
 //
 // Right now, with each new request we're simply instantiating
 // a new IDPattern and returning its next ID.  As a result,
 //
 // At that point, we'll also need to add code to handle concurrent requests.
 
-// @TODO: Verify access (public, protected, or private) to service methods.
+// @TODO Verify access (public, protected, or private) to service methods.
 
-// @TODO: As long as we're using JDBC, use PreparedStatements, not Statements.
+// @TODO As long as we're using JDBC, use PreparedStatements, not Statements,
+// throughout the code below.
 
-// @TODO: Re-consider beginnings of method names:
+// @TODO Re-consider beginnings of method names:
 // - "store/get" versus:
 // - "store/retrieve"
 // - "save/read" (appears to be used by Hibernate),
@@ -79,25 +90,123 @@ public class IDServiceJdbcImpl implements IDService {
 
        final Logger logger = LoggerFactory.getLogger(IDServiceJdbcImpl.class);
 
-  // @TODO Get the JDBC driver classname and database URL from configuration;
-  // better yet, substitute Hibernate for JDBC for accessing database-managed persistence.
-  
-  // @TODO: Remove any hard-coded dependencies on MySQL.
-  
-  // @TODO: Determine how to restrict access to ID-related tables by role.
-  
   final String JDBC_DRIVER_CLASSNAME = "com.mysql.jdbc.Driver";
-  final String DATABASE_URL = "jdbc:mysql://localhost:3306/cspace";
+  final String DATABASE_NAME = "cspace";
+  final String DATABASE_URL = "jdbc:mysql://localhost:3306/" + DATABASE_NAME;
   final String DATABASE_USERNAME = "test";
   final String DATABASE_PASSWORD = "test";
+  final String TABLE_NAME = "id_generator";
 
   //////////////////////////////////////////////////////////////////////
   /**
    * Constructor (no-argument).
    */ 
   public void IDServiceJdbcImpl() {
+  
+    // @TODO Decide when and how to fail at startup, or else to correct
+    // failure conditions automatically, when preconditions are not met.
+    
+    // init();
+  }
+  
+  // @TODO init() and hasTable() are currently UNTESTED as of 2009-08-11T13:00-0700.
+
+  //////////////////////////////////////////////////////////////////////
+  /**
+   * Initializes the service.
+   *
+   * @throws  IllegalStateException if one or more of the required preconditions
+   *          for the service is not present, or is not in its required state.
+   */
+  public void init() throws IllegalStateException {
+  
+    try {
+      boolean hasTable = hasTable(TABLE_NAME);
+      if (! hasTable) {
+        throw new IllegalStateException(
+          "Table " + "\'" + TABLE_NAME + "\'" + " could not be found in the database.");
+      }
+    } catch (IllegalStateException e) {
+      throw e;
+    }
+  
   }
 
+  //////////////////////////////////////////////////////////////////////
+  /**
+   * Identifies whether a specified table exists in the database.
+   *
+   * @param   tablename  The name of a database table.
+   *
+   * @return  True if the specified table exists in the database;
+   *          false if the specified table does not exist in the database.
+   *
+   * @throws  IllegalStateException if an error occurs while checking for the
+   *          existence of the specified table.
+   */
+  public boolean hasTable(String tablename) throws IllegalStateException {
+
+               logger.debug("> in hasTable");
+
+               if (tablename == null || tablename.equals("")) {
+                       return false;
+               }
+
+    try {
+      Class.forName(JDBC_DRIVER_CLASSNAME).newInstance();
+    } catch (ClassNotFoundException e) {
+      throw new IllegalStateException(
+        "Error finding JDBC driver class '" +
+        JDBC_DRIVER_CLASSNAME +
+        "' to set up database connection.");
+    } catch (InstantiationException e) {
+      throw new IllegalStateException(
+        "Error instantiating JDBC driver class '" +
+        JDBC_DRIVER_CLASSNAME +
+        "' to set up database connection.");
+     } catch (IllegalAccessException e) {
+      throw new IllegalStateException(
+        "Error accessing JDBC driver class '" +
+        JDBC_DRIVER_CLASSNAME +
+        "' to set up database connection.");
+    }
+    
+    Connection conn = null;
+    try {
+    
+      conn = DriverManager.getConnection(DATABASE_URL, DATABASE_USERNAME, DATABASE_PASSWORD);
+
+      Statement stmt = conn.createStatement();
+      
+      final String CATALOG_NAME = null;
+      final String SCHEMA_NAME_PATTERN = null;
+      final String[] TABLE_TYPES = null;
+      ResultSet tablesMatchingTableName =
+        conn.getMetaData().getTables(
+          CATALOG_NAME, SCHEMA_NAME_PATTERN, tablename, TABLE_TYPES);
+
+                       boolean moreRows = tablesMatchingTableName.next();
+                       if (! moreRows) {
+        return false;
+      } else {
+        return true;
+      }
+
+    } catch (SQLException e) {
+      throw new IllegalStateException(
+        "Error while checking for existance of tablebase table: " + e.getMessage());
+    } finally {
+      try {
+        if (conn != null) {
+          conn.close();
+        }
+      } catch(SQLException e) {
+        // Do nothing here
+      }
+    }
+    
+  }
+        
   //////////////////////////////////////////////////////////////////////
   /**
    * Generates and returns a new ID associated with a specified ID generator.
@@ -108,6 +217,11 @@ public class IDServiceJdbcImpl implements IDService {
    * @param  csid  An identifier for an ID generator.
    *
    * @return  A new ID associated with the specified ID generator.
+   *
+   * @throws  IllegalArgumentException if the provided csid is null or empty,
+   *          or if the specified ID generator can't be found.
+   *
+   * @throws  IllegalStateException if a storage-related error occurred.
    */
        public String newID(String csid) throws
                IllegalArgumentException, IllegalStateException {
index 383572751c08967bd436a3e32b61e5b850ef1926..a1847329f286e8ba558b693b9d0c3acb84180134 100644 (file)
@@ -1,8 +1,4 @@
 /**    
- * IDServiceJdbcImplTest
- *
- * Unit tests for the ID Service's JDBC implementation class, IDServiceJdbcImpl.
- *
  * This document is a part of the source code and related artifacts
  * for CollectionSpace, an open source collections management system
  * for museums and related institutions:
  *
  * You may obtain a copy of the ECL 2.0 License at
  * https://source.collectionspace.org/collection-space/LICENSE.txt
- *
- * $LastChangedBy: aron $
- * $LastChangedRevision: 302 $
- * $LastChangedDate$
  */
 
 package org.collectionspace.services.id.test;
@@ -29,93 +21,121 @@ import org.collectionspace.services.id.*;
 
 import junit.framework.TestCase;
 import static org.junit.Assert.*;
+import org.junit.BeforeClass;
+import org.junit.Test;
 
+/**    
+ * IDServiceJdbcImplTest
+ *
+ * Unit tests for the ID Service's JDBC implementation class, IDServiceJdbcImpl.
+ *
+ * $LastChangedBy: aron $
+ * $LastChangedRevision: 302 $
+ * $LastChangedDate$
+ */
 public class IDServiceJdbcImplTest extends TestCase {
 
+  // *IMPORTANT*
+  // @TODO This class is in an early state of a refactoring to
+  // reflect a change from IDPatterns to IDGenerators at the top level
+  // of the ID Service.  As a result, there will be some naming
+  // inconsistencies throughout this source file.
+
   String csid;
   String nextId;
-  String serializedPattern;
+  String serializedGenerator;
   IDPattern pattern;
   
   IDServiceJdbcImpl jdbc = new IDServiceJdbcImpl();
   IDService service = jdbc;
 
        final static String DEFAULT_CSID = "TEST-1";
+
+  @BeforeClass
+  public static void setUpOnce() { 
+    // @TODO Check for service preconditions before running tests.   
+  }
   
+  @Test
   public void testPlaceholder() {
     // Placeholder test to avoid "org.testng.TestNGException:
     // Failure in JUnit mode ...: could not create/run JUnit test suite"
     // errors until we add working tests to this class.
   }
-/*
 
-  public void testAddIDPattern() {
-    jdbc.addIDPattern(DEFAULT_CSID, generateSpectrumEntryNumberTestPattern());
+/* 
+  @Test
+  public void testAddIDGenerator() {
+    jdbc.addIDGenerator(DEFAULT_CSID, getSpectrumEntryNumberGenerator());
   }
 
-  public void testReadIDPattern() {
+  @Test
+  public void testReadIDGenerator() {
 
-    serializedPattern = jdbc.getIDPattern(DEFAULT_CSID);
-    pattern = IDPatternSerializer.deserialize(serializedPattern);
+    serializedGenerator = jdbc.getIDGenerator(DEFAULT_CSID);
+    pattern = IDPatternSerializer.deserialize(serializedGenerator);
     assertEquals(DEFAULT_CSID, pattern.getCsid());
     
   }
 
-  public void testUpdateIDPattern() {
+  @Test
+  public void testUpdateIDGenerator() {
 
     final String NEW_DESCRIPTION = "new description";
     
-    serializedPattern = jdbc.getIDPattern(DEFAULT_CSID);
-    
-    pattern = IDPatternSerializer.deserialize(serializedPattern);
+    // Retrieve an existing generator, deserialize it,
+    // update its contents, serialize it, and write it back.
+    serializedGenerator = jdbc.getIDGenerator(DEFAULT_CSID);
+    pattern = IDPatternSerializer.deserialize(serializedGenerator);
     pattern.setDescription(NEW_DESCRIPTION);
-    serializedPattern = IDPatternSerializer.serialize(pattern);
+    serializedGenerator = IDPatternSerializer.serialize(pattern);
     
-    jdbc.updateIDPattern(DEFAULT_CSID, serializedPattern);
+    jdbc.updateIDGenerator(DEFAULT_CSID, serializedGenerator);
     
-    serializedPattern = jdbc.getIDPattern(DEFAULT_CSID);
-    pattern = IDPatternSerializer.deserialize(serializedPattern);
+    serializedGenerator = jdbc.getIDGenerator(DEFAULT_CSID);
+    pattern = IDPatternSerializer.deserialize(serializedGenerator);
     
     assertEquals(NEW_DESCRIPTION, pattern.getDescription());
     
   }
 
-  public void testDeleteIDPattern() {
-    jdbc.deleteIDPattern(DEFAULT_CSID);
+  @Test
+  public void testDeleteIDGenerator() {
+    jdbc.deleteIDGenerator(DEFAULT_CSID);
   }
  
-       public void testNextIDValidPattern() {
+  @Test
+       public void testNewIDValidPattern() {
        
     csid = DEFAULT_CSID;
     
     try {
-      jdbc.deleteIDPattern(csid);
+      jdbc.deleteIDGenerator(csid);
     } catch (Exception e) {
       // do nothing
     }
     
-    jdbc.addIDPattern(csid, generateSpectrumEntryNumberTestPattern());
+    jdbc.addIDGenerator(csid, getSpectrumEntryNumberGenerator());
 
-    assertEquals("E1", service.nextID("TEST-1"));
-    assertEquals("E2", service.nextID("TEST-1"));
-    assertEquals("E3", service.nextID("TEST-1"));
+    assertEquals("E1", service.newID("TEST-1"));
+    assertEquals("E2", service.newID("TEST-1"));
+    assertEquals("E3", service.newID("TEST-1"));
     
     try {
-      jdbc.deleteIDPattern(csid);
+      jdbc.deleteIDGenerator(csid);
     } catch (Exception e) {
       // do nothing
     }
     
-    jdbc.addIDPattern(csid, generateChinAccessionNumberTestPattern());
+    jdbc.addIDGenerator(csid, getChinAccessionNumberGenerator());
 
     String currentYear = YearIDGenerator.getCurrentYear();
-    assertEquals(currentYear + ".1.1", service.nextID("TEST-1"));
-    assertEquals(currentYear + ".1.2", service.nextID("TEST-1"));
-    assertEquals(currentYear + ".1.3", service.nextID("TEST-1"));
+    assertEquals(currentYear + ".1.1", service.newID("TEST-1"));
+    assertEquals(currentYear + ".1.2", service.newID("TEST-1"));
+    assertEquals(currentYear + ".1.3", service.newID("TEST-1"));
 
     try {
-      jdbc.deleteIDPattern(csid);
+      jdbc.deleteIDGenerator(csid);
     } catch (Exception e) {
       // do nothing
     }
@@ -126,25 +146,25 @@ public class IDServiceJdbcImplTest extends TestCase {
   // 1. The ID Service is running and accessible to this test; and
   // 2. There is no ID pattern retrievable through that service
   //    with the identifier 'non-existent identifier'.
+  @Test
        public void testNextIDInvalidPattern() {
        
                try {
-      nextId = service.nextID("non-existent identifier");
+      nextId = service.newID("non-existent identifier");
                        fail("Should have thrown IllegalArgumentException here");
                } catch (IllegalArgumentException expected) {
                        // This Exception should be thrown, and thus the test should pass.
                }
                
        }
-       
-*/
 
   // ---------------------------------------------------------------
   // Utility methods used by tests above
   // ---------------------------------------------------------------
 
   // @TODO Read test patterns from external configuration.
-  public String generateSpectrumEntryNumberTestPattern() {
+  
+  public String getSpectrumEntryNumberGenerator() {
     
     pattern = new IDPattern(DEFAULT_CSID);
     pattern.setDescription("SPECTRUM entry number pattern");
@@ -156,8 +176,7 @@ public class IDServiceJdbcImplTest extends TestCase {
     
   }
 
-  // @TODO Read test patterns from external configuration.
-  public String generateChinAccessionNumberTestPattern() {
+  public String getChinAccessionNumberGenerator() {
 
     pattern = new IDPattern(DEFAULT_CSID);
     pattern.setDescription("CHIN accession number pattern, for items without parts");
@@ -171,5 +190,6 @@ public class IDServiceJdbcImplTest extends TestCase {
     return IDPatternSerializer.serialize(pattern);
     
   }
-       
+*/
+
 }