From c1d81bcdfc948b417964c6b69be2ee5801e5e1c9 Mon Sep 17 00:00:00 2001 From: James Moger Date: Mon, 10 Nov 2014 11:10:01 -0500 Subject: [PATCH] Add support for runtime Mode in the DataTypeAdapters --- releases.moxie | 1 + src/main/java/com/iciql/Db.java | 61 ++++++++++++++++--- src/main/java/com/iciql/Iciql.java | 31 ++++++++++ .../java/com/iciql/SQLDialectDefault.java | 29 +++++---- .../com/iciql/adapter/GsonTypeAdapter.java | 8 +++ .../adapter/JavaSerializationTypeAdapter.java | 11 +++- .../iciql/adapter/SnakeYamlTypeAdapter.java | 8 +++ .../com/iciql/adapter/XStreamTypeAdapter.java | 8 +++ .../adapter/postgresql/JsonStringAdapter.java | 8 +++ .../postgresql/JsonbStringAdapter.java | 8 +++ .../adapter/postgresql/XmlStringAdapter.java | 8 +++ src/site/dta.mkd | 11 ++++ 12 files changed, 171 insertions(+), 21 deletions(-) diff --git a/releases.moxie b/releases.moxie index 6e271c7..b05ae9c 100644 --- a/releases.moxie +++ b/releases.moxie @@ -14,6 +14,7 @@ r23: { - Improved automatic date conversions - Revised data type adapters to be specified separately with the @TypeAdapter annotation additions: + - Add runtime mode support (DEV, TEST, & PROD) - Add a DAO feature similar to JDBI - Added Gson, XStream, and SnakeYaml type adapters dependencyChanges: ~ diff --git a/src/main/java/com/iciql/Db.java b/src/main/java/com/iciql/Db.java index 13c9260..794417e 100644 --- a/src/main/java/com/iciql/Db.java +++ b/src/main/java/com/iciql/Db.java @@ -41,6 +41,7 @@ import com.iciql.DbUpgrader.DefaultDbUpgrader; import com.iciql.Iciql.IQTable; import com.iciql.Iciql.IQVersion; import com.iciql.Iciql.IQView; +import com.iciql.Iciql.Mode; import com.iciql.util.IciqlLogger; import com.iciql.util.JdbcUtils; import com.iciql.util.StringUtils; @@ -64,6 +65,7 @@ public class Db implements AutoCloseable { private static final Map> DIALECTS; private final Connection conn; + private final Mode mode; private final Map, TableDefinition> classMap = Collections .synchronizedMap(new HashMap, TableDefinition>()); private final SQLDialect dialect; @@ -88,8 +90,9 @@ public class Db implements AutoCloseable { DIALECTS.put("SQLite", SQLDialectSQLite.class); } - private Db(Connection conn) { + private Db(Connection conn, Mode mode) { this.conn = conn; + this.mode = mode; String databaseName = null; try { DatabaseMetaData data = conn.getMetaData(); @@ -148,50 +151,81 @@ public class Db implements AutoCloseable { } public static Db open(String url) { + return open(url, Mode.PROD); + } + + public static Db open(String url, Mode mode) { try { Connection conn = JdbcUtils.getConnection(null, url, null, null); - return new Db(conn); + return new Db(conn, mode); } catch (SQLException e) { throw new IciqlException(e); } } public static Db open(String url, String user, String password) { + return open(url, user, password, Mode.PROD); + } + + public static Db open(String url, String user, String password, Mode mode) { try { Connection conn = JdbcUtils.getConnection(null, url, user, password); - return new Db(conn); + return new Db(conn, mode); } catch (SQLException e) { throw new IciqlException(e); } } public static Db open(String url, String user, char[] password) { + return open(url, user, password, Mode.PROD); + } + + public static Db open(String url, String user, char[] password, Mode mode) { try { Connection conn = JdbcUtils.getConnection(null, url, user, password == null ? null : new String(password)); - return new Db(conn); + return new Db(conn, mode); } catch (SQLException e) { throw new IciqlException(e); } } + public static Db open(DataSource ds) { + return open(ds, Mode.PROD); + } + /** * Create a new database instance using a data source. This method is fast, * so that you can always call open() / close() on usage. * * @param ds * the data source + * @param mode + * the runtime mode * @return the database instance. */ - public static Db open(DataSource ds) { + public static Db open(DataSource ds, Mode mode) { try { - return new Db(ds.getConnection()); + return new Db(ds.getConnection(), mode); } catch (SQLException e) { throw new IciqlException(e); } } public static Db open(Connection conn) { - return new Db(conn); + return open(conn, Mode.PROD); + } + + public static Db open(Connection conn, Mode mode) { + return new Db(conn, mode); + } + + /** + * Returns the Iciql runtime mode. + * + * @return the runtime mode + */ + public Mode getMode() { + return mode; } /** @@ -806,4 +840,17 @@ public class Db implements AutoCloseable { return this.autoSavePoint; } + /** + * + * @author James Moger + * + */ + class NoExternalDaoStatements implements DaoStatementProvider { + + @Override + public String getStatement(String idOrStatement) { + return idOrStatement; + } + + } } diff --git a/src/main/java/com/iciql/Iciql.java b/src/main/java/com/iciql/Iciql.java index 524faa8..b303372 100644 --- a/src/main/java/com/iciql/Iciql.java +++ b/src/main/java/com/iciql/Iciql.java @@ -726,6 +726,25 @@ public interface Iciql { public @interface IQIgnore{ } + /** + * The runtime mode for Iciql. + */ + public static enum Mode { + + DEV, TEST, PROD; + + public static Mode fromValue(String value) { + + for (Mode mode : values()) { + if (mode.name().equalsIgnoreCase(value)) { + return mode; + } + } + + return PROD; + } + } + /** * This method is called to let the table define the primary key, indexes, * and the table name. @@ -767,6 +786,18 @@ public interface Iciql { */ Class getJavaType(); + + /** + * Set the runtime mode. + *

+ * Allows type adapters to adapt type mappings based on the runtime + * mode. + *

+ * + * @param mode + */ + void setMode(Mode mode); + /** * Serializes your Java object into a JDBC object. * diff --git a/src/main/java/com/iciql/SQLDialectDefault.java b/src/main/java/com/iciql/SQLDialectDefault.java index 17ee763..d8a9ebd 100644 --- a/src/main/java/com/iciql/SQLDialectDefault.java +++ b/src/main/java/com/iciql/SQLDialectDefault.java @@ -29,6 +29,7 @@ import java.util.concurrent.ConcurrentHashMap; import com.iciql.Iciql.ConstraintDeleteType; import com.iciql.Iciql.ConstraintUpdateType; import com.iciql.Iciql.DataTypeAdapter; +import com.iciql.Iciql.Mode; import com.iciql.TableDefinition.ConstraintForeignKeyDefinition; import com.iciql.TableDefinition.ConstraintUniqueDefinition; import com.iciql.TableDefinition.FieldDefinition; @@ -50,6 +51,7 @@ public class SQLDialectDefault implements SQLDialect { int databaseMinorVersion; String databaseName; String productVersion; + Mode mode; Map>, DataTypeAdapter> typeAdapters; public SQLDialectDefault() { @@ -76,6 +78,8 @@ public class SQLDialectDefault implements SQLDialect { } catch (SQLException e) { throw new IciqlException(e, "failed to retrieve database metadata!"); } + + mode = db.getMode(); } @Override @@ -446,12 +450,13 @@ public class SQLDialectDefault implements SQLDialect { @Override public DataTypeAdapter getAdapter(Class> typeAdapter) { - DataTypeAdapter dtt = typeAdapters.get(typeAdapter); - if (dtt == null) { - dtt = Utils.newObject(typeAdapter); - typeAdapters.put(typeAdapter, dtt); + DataTypeAdapter dta = typeAdapters.get(typeAdapter); + if (dta == null) { + dta = Utils.newObject(typeAdapter); + typeAdapters.put(typeAdapter, dta); } - return dtt; + dta.setMode(mode); + return dta; } @SuppressWarnings("unchecked") @@ -462,19 +467,19 @@ public class SQLDialectDefault implements SQLDialect { return value; } - DataTypeAdapter dtt = (DataTypeAdapter) getAdapter(typeAdapter); - return dtt.serialize(value); + DataTypeAdapter dta = (DataTypeAdapter) getAdapter(typeAdapter); + return dta.serialize(value); } @Override public Object deserialize(Object value, Class> typeAdapter) { - DataTypeAdapter dtt = typeAdapters.get(typeAdapter); - if (dtt == null) { - dtt = Utils.newObject(typeAdapter); - typeAdapters.put(typeAdapter, dtt); + if (typeAdapter == null) { + // pass-through + return value; } - return dtt.deserialize(value); + DataTypeAdapter dta = getAdapter(typeAdapter); + return dta.deserialize(value); } @Override diff --git a/src/main/java/com/iciql/adapter/GsonTypeAdapter.java b/src/main/java/com/iciql/adapter/GsonTypeAdapter.java index b07b7b5..8d23cfd 100644 --- a/src/main/java/com/iciql/adapter/GsonTypeAdapter.java +++ b/src/main/java/com/iciql/adapter/GsonTypeAdapter.java @@ -18,6 +18,7 @@ package com.iciql.adapter; import com.google.gson.Gson; import com.google.gson.GsonBuilder; import com.iciql.Iciql.DataTypeAdapter; +import com.iciql.Iciql.Mode; /** * Base class for inserting/retrieving a Java Object (de)serialized as JSON @@ -39,10 +40,17 @@ import com.iciql.Iciql.DataTypeAdapter; */ public abstract class GsonTypeAdapter implements DataTypeAdapter { + protected Mode mode; + protected Gson gson() { return new GsonBuilder().create(); } + @Override + public void setMode(Mode mode) { + this.mode = mode; + } + @Override public String getDataType() { return "TEXT"; diff --git a/src/main/java/com/iciql/adapter/JavaSerializationTypeAdapter.java b/src/main/java/com/iciql/adapter/JavaSerializationTypeAdapter.java index c475817..df24495 100644 --- a/src/main/java/com/iciql/adapter/JavaSerializationTypeAdapter.java +++ b/src/main/java/com/iciql/adapter/JavaSerializationTypeAdapter.java @@ -25,9 +25,9 @@ import java.io.ObjectOutputStream; import java.sql.Blob; import java.sql.SQLException; -import com.iciql.Iciql; -import com.iciql.IciqlException; import com.iciql.Iciql.DataTypeAdapter; +import com.iciql.Iciql.Mode; +import com.iciql.IciqlException; /** * Base class for inserting/retrieving a Java Object as a BLOB field using Java Serialization. @@ -44,6 +44,13 @@ import com.iciql.Iciql.DataTypeAdapter; */ public abstract class JavaSerializationTypeAdapter implements DataTypeAdapter { + protected Mode mode; + + @Override + public void setMode(Mode mode) { + this.mode = mode; + } + @Override public final String getDataType() { return "BLOB"; diff --git a/src/main/java/com/iciql/adapter/SnakeYamlTypeAdapter.java b/src/main/java/com/iciql/adapter/SnakeYamlTypeAdapter.java index fe4541c..da3b20b 100644 --- a/src/main/java/com/iciql/adapter/SnakeYamlTypeAdapter.java +++ b/src/main/java/com/iciql/adapter/SnakeYamlTypeAdapter.java @@ -21,16 +21,24 @@ import org.yaml.snakeyaml.Yaml; import org.yaml.snakeyaml.nodes.Tag; import com.iciql.Iciql.DataTypeAdapter; +import com.iciql.Iciql.Mode; /** * Base class for inserting/retrieving a Java Object (de)serialized as YAML using SnakeYaml. */ public abstract class SnakeYamlTypeAdapter implements DataTypeAdapter { + protected Mode mode; + protected Yaml yaml() { return new Yaml(); } + @Override + public void setMode(Mode mode) { + this.mode = mode; + } + @Override public String getDataType() { return "TEXT"; diff --git a/src/main/java/com/iciql/adapter/XStreamTypeAdapter.java b/src/main/java/com/iciql/adapter/XStreamTypeAdapter.java index 5e152df..a554724 100644 --- a/src/main/java/com/iciql/adapter/XStreamTypeAdapter.java +++ b/src/main/java/com/iciql/adapter/XStreamTypeAdapter.java @@ -17,6 +17,7 @@ package com.iciql.adapter; import com.iciql.Iciql.DataTypeAdapter; +import com.iciql.Iciql.Mode; import com.thoughtworks.xstream.XStream; /** @@ -24,10 +25,17 @@ import com.thoughtworks.xstream.XStream; */ public class XStreamTypeAdapter implements DataTypeAdapter { + protected Mode mode; + protected XStream xstream() { return new XStream(); } + @Override + public void setMode(Mode mode) { + this.mode = mode; + } + @Override public String getDataType() { return "TEXT"; diff --git a/src/main/java/com/iciql/adapter/postgresql/JsonStringAdapter.java b/src/main/java/com/iciql/adapter/postgresql/JsonStringAdapter.java index c4fbd6a..01d2834 100644 --- a/src/main/java/com/iciql/adapter/postgresql/JsonStringAdapter.java +++ b/src/main/java/com/iciql/adapter/postgresql/JsonStringAdapter.java @@ -20,12 +20,20 @@ import java.sql.SQLException; import org.postgresql.util.PGobject; import com.iciql.Iciql.DataTypeAdapter; +import com.iciql.Iciql.Mode; /** * Handles transforming raw strings to/from the Postgres JSON data type. */ public class JsonStringAdapter implements DataTypeAdapter { + protected Mode mode; + + @Override + public void setMode(Mode mode) { + this.mode = mode; + } + @Override public String getDataType() { return "json"; diff --git a/src/main/java/com/iciql/adapter/postgresql/JsonbStringAdapter.java b/src/main/java/com/iciql/adapter/postgresql/JsonbStringAdapter.java index cc2d9c4..9d7388b 100644 --- a/src/main/java/com/iciql/adapter/postgresql/JsonbStringAdapter.java +++ b/src/main/java/com/iciql/adapter/postgresql/JsonbStringAdapter.java @@ -20,12 +20,20 @@ import java.sql.SQLException; import org.postgresql.util.PGobject; import com.iciql.Iciql.DataTypeAdapter; +import com.iciql.Iciql.Mode; /** * Handles transforming raw strings to/from the Postgres JSONB data type. */ public class JsonbStringAdapter implements DataTypeAdapter { + protected Mode mode; + + @Override + public void setMode(Mode mode) { + this.mode = mode; + } + @Override public String getDataType() { return "jsonb"; diff --git a/src/main/java/com/iciql/adapter/postgresql/XmlStringAdapter.java b/src/main/java/com/iciql/adapter/postgresql/XmlStringAdapter.java index defe9f9..0aea77e 100644 --- a/src/main/java/com/iciql/adapter/postgresql/XmlStringAdapter.java +++ b/src/main/java/com/iciql/adapter/postgresql/XmlStringAdapter.java @@ -20,12 +20,20 @@ import java.sql.SQLException; import org.postgresql.util.PGobject; import com.iciql.Iciql.DataTypeAdapter; +import com.iciql.Iciql.Mode; /** * Handles transforming raw strings to/from the Postgres XML data type. */ public class XmlStringAdapter implements DataTypeAdapter { + protected Mode mode; + + @Override + public void setMode(Mode mode) { + this.mode = mode; + } + @Override public String getDataType() { return "xml"; diff --git a/src/site/dta.mkd b/src/site/dta.mkd index 70fc25e..dc19485 100644 --- a/src/site/dta.mkd +++ b/src/site/dta.mkd @@ -35,6 +35,13 @@ Let's take a look at *InvoiceAdapterImpl*. ---JAVA--- public class InvoiceAdapterImpl implements DataTypeAdapter { + Mode mode; + + @Override + public void setMode(Mode mode) { + this.mode = mode; + } + @Override public String getDataType() { return "jsonb"; @@ -76,6 +83,10 @@ public class InvoiceAdapterImpl implements DataTypeAdapter { Here you can see how the *InvoiceTypeAdapter* defines a [Postgres JSONB data type](http://www.postgresql.org/docs/9.4/static/datatype-json.html) and automatically handles JSON (de)serialization with [Google Gson](https://code.google.com/p/google-gson) so that the database gets the content in a form that it requires but we can continue to work with objects in Java. +### Runtime Mode + +Data type adapters can respond to the Iciql runtime mode (`DEV`, `TEST`, or `PROD`) allowing them to change their behavior. This is useful for targetting a data type that might be available in your production database but may not be available in your development or testing database. + ### Custom annotations It is a little verbose to repeat `@TypeAdapter(InvoiceAdapterImpl.class)` everywhere you want to use your adapter. -- 2.39.5