From 02bc52037e9ccccca672d6156d9c325c74fe28b3 Mon Sep 17 00:00:00 2001 From: Benjamin Culkin Date: Mon, 1 Jul 2024 17:27:48 -0400 Subject: Update a whole bunch of things Yeah... not a great commit message. t.b.h, I could maybe've split the commit into more parts; but that would be quite a lot off effort and would have a pretty decent chance of at least one of the commits leaving the repository in a non-working state. For the future, will want to try and commit more often so there aren't these mega-commits where it's just "a whole bunch of stuff changed" --- .../net/wotonomy/jdbcadaptor/EOMapObjectStore.java | 116 +++++++++++++++++++++ .../java/net/wotonomy/jdbcadaptor/JDBCAdaptor.java | 11 +- .../wotonomy/jdbcadaptor/JDBCAdaptorException.java | 4 +- .../java/net/wotonomy/jdbcadaptor/JDBCContext.java | 10 +- .../jdbcadaptor/SimpleJDBCObjectStore.java | 69 ++++++++++++ .../java/net/wotonomy/jdbcadaptor/JDBCDBTest.java | 89 ++++++++++++++++ .../test/java/net/wotonomy/jdbcadaptor/Person.java | 59 +++++++++++ 7 files changed, 349 insertions(+), 9 deletions(-) create mode 100644 projects/net.wotonomy.persistence.adapter.jdbc/src/main/java/net/wotonomy/jdbcadaptor/EOMapObjectStore.java create mode 100644 projects/net.wotonomy.persistence.adapter.jdbc/src/main/java/net/wotonomy/jdbcadaptor/SimpleJDBCObjectStore.java create mode 100644 projects/net.wotonomy.persistence.adapter.jdbc/src/test/java/net/wotonomy/jdbcadaptor/JDBCDBTest.java create mode 100644 projects/net.wotonomy.persistence.adapter.jdbc/src/test/java/net/wotonomy/jdbcadaptor/Person.java (limited to 'projects/net.wotonomy.persistence.adapter.jdbc/src') diff --git a/projects/net.wotonomy.persistence.adapter.jdbc/src/main/java/net/wotonomy/jdbcadaptor/EOMapObjectStore.java b/projects/net.wotonomy.persistence.adapter.jdbc/src/main/java/net/wotonomy/jdbcadaptor/EOMapObjectStore.java new file mode 100644 index 0000000..06dc280 --- /dev/null +++ b/projects/net.wotonomy.persistence.adapter.jdbc/src/main/java/net/wotonomy/jdbcadaptor/EOMapObjectStore.java @@ -0,0 +1,116 @@ +package net.wotonomy.jdbcadaptor; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import net.wotonomy.control.ArrayFault; +import net.wotonomy.control.EOEditingContext; +import net.wotonomy.control.EOFetchSpecification; +import net.wotonomy.control.EOGlobalID; +import net.wotonomy.control.EOObjectStore; +import net.wotonomy.foundation.NSArray; +import net.wotonomy.foundation.internal.WotonomyException; + +/** + * Implementation of EOObjectStore backed by a single map + * @author bjculkin + * + */ +public class EOMapObjectStore extends EOObjectStore { + private Map data; + + public EOMapObjectStore() { + super(); + + data = new HashMap<>(); + } + + public EOMapObjectStore(Map data) { + this.data = data; + } + + public Map getData() { + return data; + } + + public void setData(Map data) { + this.data = data; + } + + @Override + public NSArray arrayFaultWithSourceGlobalID(EOGlobalID aGlobalID, String aRelationship, + EOEditingContext aContext) { + return new ArrayFault(aGlobalID, aRelationship, aContext); + } + + @Override + public Object faultForGlobalID(EOGlobalID aGlobalID, EOEditingContext aContext) { + return data.get(aGlobalID); + } + + @Override + public Object faultForRawRow(Map aDictionary, String anEntityName, EOEditingContext aContext) { + // TODO: faults are not yet supported + throw new WotonomyException("Faults are not yet supported."); + } + + @Override + public void initializeObject(Object eo, EOGlobalID aGlobalID, EOEditingContext aContext) { + // TODO is this right? + data.put(aGlobalID, eo); + aContext.recordObject(eo, aGlobalID); + } + + @Override + public void invalidateAllObjects() { + // Does nothing + } + + @Override + public void invalidateObjectsWithGlobalIDs(List aList) { + // Does nothing + } + + @Override + public boolean isObjectLockedWithGlobalID(EOGlobalID aGlobalID, EOEditingContext aContext) { + // No locking + return false; + } + + @Override + public void lockObjectWithGlobalID(EOGlobalID aGlobalID, EOEditingContext aContext) { + // No locking + } + + @Override + public NSArray objectsForSourceGlobalID(EOGlobalID aGlobalID, String aRelationship, EOEditingContext aContext) { + // TODO: relationships are not yet supported + throw new WotonomyException("Relationships are not yet supported."); + } + + @Override + public NSArray objectsWithFetchSpecification(EOFetchSpecification aFetchSpec, EOEditingContext aContext) { + throw new WotonomyException("Fetchspecs are not yet supported."); + } + + @Override + public void refaultObject(Object anObject, EOGlobalID aGlobalID, EOEditingContext aContext) { + // TODO faults are not supported + initializeObject(anObject, aGlobalID, aContext); + } + + @Override + public void saveChangesInEditingContext(EOEditingContext aContext) { + for (Object obj : aContext.insertedObjects()) { + EOGlobalID key = aContext.globalIDForObject(obj); + data.put(key, obj); + } + for (Object obj : aContext.deletedObjects()) { + EOGlobalID key = aContext.globalIDForObject(obj); + data.remove(key); + } + // No need to handle updates + } + +} diff --git a/projects/net.wotonomy.persistence.adapter.jdbc/src/main/java/net/wotonomy/jdbcadaptor/JDBCAdaptor.java b/projects/net.wotonomy.persistence.adapter.jdbc/src/main/java/net/wotonomy/jdbcadaptor/JDBCAdaptor.java index f3d848c..1a67d6d 100644 --- a/projects/net.wotonomy.persistence.adapter.jdbc/src/main/java/net/wotonomy/jdbcadaptor/JDBCAdaptor.java +++ b/projects/net.wotonomy.persistence.adapter.jdbc/src/main/java/net/wotonomy/jdbcadaptor/JDBCAdaptor.java @@ -34,7 +34,7 @@ public class JDBCAdaptor extends EOAdaptor { protected EOSQLExpressionFactory _expressionFactory; protected String _driverName; - protected NSDictionary _jdbcInfo; + protected NSDictionary _jdbcInfo; /** * Creates a new instance. @@ -45,14 +45,15 @@ public class JDBCAdaptor extends EOAdaptor { super(name); } - public void setConnectionDictionary(NSDictionary dict) { + @SuppressWarnings("unchecked") + public void setConnectionDictionary(NSDictionary dict) { super.setConnectionDictionary(dict); if (dict.objectForKey("driver") != null) _driverName = (String) dict.objectForKey("driver"); else throw new JDBCAdaptorException("Connection dictionary must have a 'driver' key.", null); if (dict.objectForKey("jdbc2Info") != null) - _jdbcInfo = (NSDictionary) dict.objectForKey("jdbc2Info"); + _jdbcInfo = (NSDictionary) dict.objectForKey("jdbc2Info"); else throw new JDBCAdaptorException("Connection dictionary must have a 'jdbc2Info' key.", null); } @@ -85,7 +86,7 @@ public class JDBCAdaptor extends EOAdaptor { * * @see net.wotonomy.access.EOAdaptor#defaultExpressionClass() */ - public Class defaultExpressionClass() { + public Class defaultExpressionClass() { return JDBCExpression.class; } @@ -115,7 +116,7 @@ public class JDBCAdaptor extends EOAdaptor { return _driverName; } - public NSDictionary jdbcInfo() { + public NSDictionary jdbcInfo() { return _jdbcInfo; } diff --git a/projects/net.wotonomy.persistence.adapter.jdbc/src/main/java/net/wotonomy/jdbcadaptor/JDBCAdaptorException.java b/projects/net.wotonomy.persistence.adapter.jdbc/src/main/java/net/wotonomy/jdbcadaptor/JDBCAdaptorException.java index 412c0a1..ea9df38 100644 --- a/projects/net.wotonomy.persistence.adapter.jdbc/src/main/java/net/wotonomy/jdbcadaptor/JDBCAdaptorException.java +++ b/projects/net.wotonomy.persistence.adapter.jdbc/src/main/java/net/wotonomy/jdbcadaptor/JDBCAdaptorException.java @@ -29,7 +29,7 @@ import net.wotonomy.access.EOGeneralAdaptorException; * @version $Revision: 903 $ */ public class JDBCAdaptorException extends EOGeneralAdaptorException { - + private static final long serialVersionUID = -2677311934036267760L; protected SQLException _sqlException; /** @@ -38,6 +38,7 @@ public class JDBCAdaptorException extends EOGeneralAdaptorException { */ public JDBCAdaptorException(String msg, SQLException sqlex) { super(msg); + initCause(sqlex); _sqlException = sqlex; } @@ -47,6 +48,7 @@ public class JDBCAdaptorException extends EOGeneralAdaptorException { */ public JDBCAdaptorException(SQLException sqlex) { super(sqlex.getMessage()); + initCause(sqlex); _sqlException = sqlex; } diff --git a/projects/net.wotonomy.persistence.adapter.jdbc/src/main/java/net/wotonomy/jdbcadaptor/JDBCContext.java b/projects/net.wotonomy.persistence.adapter.jdbc/src/main/java/net/wotonomy/jdbcadaptor/JDBCContext.java index 9e6df6c..87c33fe 100644 --- a/projects/net.wotonomy.persistence.adapter.jdbc/src/main/java/net/wotonomy/jdbcadaptor/JDBCContext.java +++ b/projects/net.wotonomy.persistence.adapter.jdbc/src/main/java/net/wotonomy/jdbcadaptor/JDBCContext.java @@ -25,6 +25,7 @@ import java.sql.SQLException; import net.wotonomy.access.EOAdaptor; import net.wotonomy.access.EOAdaptorChannel; import net.wotonomy.access.EOAdaptorContext; +import net.wotonomy.foundation.NSDictionary; /** * Concrete implementation of EOAdaptorContext for use with JDBC. @@ -51,11 +52,14 @@ public class JDBCContext extends EOAdaptorContext { if (_jdbcConnection != null && !_jdbcConnection.isClosed()) throw new JDBCAdaptorException("Attempt to connect when already connected.", null); Class.forName(((JDBCAdaptor) adaptor()).driverName()); - String url = (String) adaptor().connectionDictionary().objectForKey("URL"); + NSDictionary connectionDictionary = adaptor().connectionDictionary(); + String url = (String) connectionDictionary.objectForKey("URL"); Driver driver = DriverManager.getDriver(url); java.util.Properties props = new java.util.Properties(); - props.setProperty("user", (String) adaptor().connectionDictionary().objectForKey("username")); - props.setProperty("password", (String) adaptor().connectionDictionary().objectForKey("password")); + if (connectionDictionary.containsKey("username")) + props.setProperty("user", (String) connectionDictionary.objectForKey("username")); + if (connectionDictionary.containsKey("password")) + props.setProperty("password", (String) connectionDictionary.objectForKey("password")); _jdbcConnection = driver.connect(url, props); _jdbcConnection.setAutoCommit(false); } catch (SQLException ex) { diff --git a/projects/net.wotonomy.persistence.adapter.jdbc/src/main/java/net/wotonomy/jdbcadaptor/SimpleJDBCObjectStore.java b/projects/net.wotonomy.persistence.adapter.jdbc/src/main/java/net/wotonomy/jdbcadaptor/SimpleJDBCObjectStore.java new file mode 100644 index 0000000..67bbc0c --- /dev/null +++ b/projects/net.wotonomy.persistence.adapter.jdbc/src/main/java/net/wotonomy/jdbcadaptor/SimpleJDBCObjectStore.java @@ -0,0 +1,69 @@ +package net.wotonomy.jdbcadaptor; + +import java.util.Collection; +import java.util.List; +import java.util.Map; + +import net.wotonomy.control.AbstractObjectStore; +import net.wotonomy.control.EOEditingContext; +import net.wotonomy.control.EOFetchSpecification; +import net.wotonomy.control.EOGlobalID; +import net.wotonomy.control.EOObjectStore; +import net.wotonomy.foundation.NSArray; +import net.wotonomy.foundation.internal.WotonomyException; + +/** + * A simple EOObjectStore that uses JDBC + * @author bjculkin + * + */ +public class SimpleJDBCObjectStore extends AbstractObjectStore { + + @Override + protected Comparable timestampForData(Map aDataMap) { + return null; + } + + @Override + protected EOGlobalID globalIDForData(Map aDataMap) { + // TODO Auto-generated method stub + return null; + } + + @Override + protected String entityForGlobalIDOrObject(EOGlobalID aGlobalID, Object anObject) { + // TODO Auto-generated method stub + return null; + } + + @Override + protected Collection changedKeysForObject(Object anObject) { + // TODO Auto-generated method stub + return null; + } + + @Override + protected Map readObject(EOGlobalID aGlobalID, Collection keys) { + // TODO Auto-generated method stub + return null; + } + + @Override + protected Map insertObject(EOGlobalID aGlobalID, Map aDataMap) { + // TODO Auto-generated method stub + return null; + } + + @Override + protected Object updateObject(EOGlobalID aGlobalID, Map aDataMap) { + // TODO Auto-generated method stub + return null; + } + + @Override + protected Object deleteObject(EOGlobalID aGlobalID) { + // TODO Auto-generated method stub + return null; + } + +} diff --git a/projects/net.wotonomy.persistence.adapter.jdbc/src/test/java/net/wotonomy/jdbcadaptor/JDBCDBTest.java b/projects/net.wotonomy.persistence.adapter.jdbc/src/test/java/net/wotonomy/jdbcadaptor/JDBCDBTest.java new file mode 100644 index 0000000..5af3bff --- /dev/null +++ b/projects/net.wotonomy.persistence.adapter.jdbc/src/test/java/net/wotonomy/jdbcadaptor/JDBCDBTest.java @@ -0,0 +1,89 @@ +package net.wotonomy.jdbcadaptor; + +import java.sql.SQLException; + +import junit.framework.TestCase; +import net.wotonomy.access.EODatabase; +import net.wotonomy.access.EODatabaseContext; +import net.wotonomy.control.EOClassDescription; +import net.wotonomy.control.EOEditingContext; +import net.wotonomy.control.EOTemporaryGlobalID; +import net.wotonomy.foundation.NSDictionary; + +public class JDBCDBTest extends TestCase { + public void testJDBCContextH2() throws SQLException, ClassNotFoundException { + String jdbcURL = "jdbc:h2:mem:test"; + + // Feels a bit weird not to put anything here, but I don't think we need to + NSDictionary jdbcInfo = new NSDictionary<>(); + + NSDictionary connDict = new NSDictionary<>(); + connDict.put("driver", "org.h2.Driver"); + connDict.put("jdbc2Info", jdbcInfo); + connDict.put("URL", jdbcURL); + JDBCAdaptor adaptor = new JDBCAdaptor("JDBC"); + adaptor.setConnectionDictionary(connDict); + adaptor.assertConnectionDictionaryIsValid(); + + EODatabase db = new EODatabase(adaptor); + EODatabaseContext dbCtx = new EODatabaseContext(db); + ((JDBCContext)dbCtx.adaptorContext()).connect(); + + EOEditingContext editCtx = new EOEditingContext(dbCtx); + + EOClassDescription personDesc = EOClassDescription.classDescriptionForClass(Person.class); + EOTemporaryGlobalID tempGID = new EOTemporaryGlobalID(); + Person person = personDesc.createInstanceWithEditingContext(editCtx, tempGID); + + person.setFirstName("John"); + person.setLastName("Doe"); + person.setAge(25); + + editCtx.saveChanges(); + + Person newPerson = (Person) editCtx.objectForGlobalID(tempGID); + assertEquals(person, newPerson); + } + + public void testJDBCContextPostgres() throws SQLException, ClassNotFoundException { + String jdbcURL = "jdbc:postgresql:wotonomy"; + + // Feels a bit weird not to put anything here, but I don't think we need to + NSDictionary jdbcInfo = new NSDictionary<>(); + + NSDictionary connDict = new NSDictionary<>(); + connDict.put("driver", "org.postgresql.Driver"); + connDict.put("jdbc2Info", jdbcInfo); + connDict.put("URL", jdbcURL); + connDict.put("username", "wotonomy"); + connDict.put("password", "wotonomy"); + + JDBCAdaptor adaptor = new JDBCAdaptor("JDBC"); + adaptor.setConnectionDictionary(connDict); + adaptor.assertConnectionDictionaryIsValid(); + + EODatabase db = new EODatabase(adaptor); + EODatabaseContext dbCtx = new EODatabaseContext(db); + ((JDBCContext)dbCtx.adaptorContext()).connect(); + + EOEditingContext editCtx = new EOEditingContext(dbCtx); + + EOClassDescription personDesc = EOClassDescription.classDescriptionForClass(Person.class); + + EOTemporaryGlobalID tempGID = new EOTemporaryGlobalID(); + Person person = personDesc.createInstanceWithEditingContext(editCtx, tempGID); + + person.setFirstName("John"); + person.setLastName("Doe"); + person.setAge(25); + + editCtx.saveChanges(); + editCtx.invalidateAllObjects(); + + ((JDBCContext)dbCtx.adaptorContext()).commitTransaction(); + //editCtx.reset(); + + Person newPerson = (Person) editCtx.objectForGlobalID(tempGID); + assertEquals(person, newPerson); + } +} \ No newline at end of file diff --git a/projects/net.wotonomy.persistence.adapter.jdbc/src/test/java/net/wotonomy/jdbcadaptor/Person.java b/projects/net.wotonomy.persistence.adapter.jdbc/src/test/java/net/wotonomy/jdbcadaptor/Person.java new file mode 100644 index 0000000..d42c77c --- /dev/null +++ b/projects/net.wotonomy.persistence.adapter.jdbc/src/test/java/net/wotonomy/jdbcadaptor/Person.java @@ -0,0 +1,59 @@ +package net.wotonomy.jdbcadaptor; + +import java.util.Objects; + +public class Person { + private String firstName; + private String lastName; + + private int age; + + public String getFirstName() { + return firstName; + } + + public void setFirstName(String firstName) { + this.firstName = firstName; + } + + public String getLastName() { + return lastName; + } + + public void setLastName(String lastName) { + this.lastName = lastName; + } + + public int getAge() { + return age; + } + + public void setAge(int age) { + this.age = age; + } + + @Override + public int hashCode() { + return Objects.hash(age, firstName, lastName); + } + + @Override + public boolean equals(Object obj) { + if (this == obj) + return true; + if (obj == null) + return false; + if (getClass() != obj.getClass()) + return false; + Person other = (Person) obj; + return age == other.age && Objects.equals(firstName, other.firstName) + && Objects.equals(lastName, other.lastName); + } + + @Override + public String toString() { + return "Person [firstName=" + firstName + ", lastName=" + lastName + ", age=" + age + "]"; + } + + +} \ No newline at end of file -- cgit v1.2.3