summaryrefslogtreecommitdiffstats
path: root/src/com
diff options
context:
space:
mode:
authorJames Moger <james.moger@gmail.com>2011-08-15 16:44:14 -0400
committerJames Moger <james.moger@gmail.com>2011-08-15 16:44:14 -0400
commit66e810aaf212c5e37b0a1702b6c33480595408ce (patch)
tree2babeea368dec0023b9a2add5b3ddc2c1aaaeea8 /src/com
parent3622ae0026718ac8466e13e8011f8db309d89106 (diff)
downloadiciql-66e810aaf212c5e37b0a1702b6c33480595408ce.tar.gz
iciql-66e810aaf212c5e37b0a1702b6c33480595408ce.zip
Added Derby dialect. Finished HSQL dialect. Documentation.
* Improved DEFAULT value specifications. * Fixed bug in buildObjects where the ResultSet could be closed by the automatic create table attempt. * DbInspector now uses the dialect's reported DATETIME class preference. * Improved IciqlException SQLState code checks. * Integrated LIMIT and OFFSET expression appending in dialects. * Updated to H2 1.3.159 * Allow reopening of a memory database in the test suite.
Diffstat (limited to 'src/com')
-rw-r--r--src/com/iciql/Constants.java4
-rw-r--r--src/com/iciql/Db.java22
-rw-r--r--src/com/iciql/DbInspector.java11
-rw-r--r--src/com/iciql/Iciql.java7
-rw-r--r--src/com/iciql/IciqlException.java53
-rw-r--r--src/com/iciql/ModelUtils.java12
-rw-r--r--src/com/iciql/Query.java17
-rw-r--r--src/com/iciql/QueryBetween.java1
-rw-r--r--src/com/iciql/QueryWhere.java1
-rw-r--r--src/com/iciql/SQLDialect.java31
-rw-r--r--src/com/iciql/SQLDialectDefault.java32
-rw-r--r--src/com/iciql/SQLDialectDerby.java151
-rw-r--r--src/com/iciql/SQLDialectH2.java7
-rw-r--r--src/com/iciql/SQLDialectHSQL.java99
-rw-r--r--src/com/iciql/SQLDialectMySQL.java11
-rw-r--r--src/com/iciql/SQLStatement.java9
-rw-r--r--src/com/iciql/TableDefinition.java27
-rw-r--r--src/com/iciql/TableInspector.java3
-rw-r--r--src/com/iciql/UpdateColumnSet.java1
-rw-r--r--src/com/iciql/build/Build.java13
-rw-r--r--src/com/iciql/build/BuildSite.java23
-rw-r--r--src/com/iciql/bytecode/ClassReader.java17
-rw-r--r--src/com/iciql/util/GenerateModels.java6
-rw-r--r--src/com/iciql/util/JdbcUtils.java2
-rw-r--r--src/com/iciql/util/Slf4jStatementListener.java6
-rw-r--r--src/com/iciql/util/StatementBuilder.java3
-rw-r--r--src/com/iciql/util/StringUtils.java74
-rw-r--r--src/com/iciql/util/Utils.java10
28 files changed, 529 insertions, 124 deletions
diff --git a/src/com/iciql/Constants.java b/src/com/iciql/Constants.java
index e8ac70a..1eeef47 100644
--- a/src/com/iciql/Constants.java
+++ b/src/com/iciql/Constants.java
@@ -25,11 +25,11 @@ public class Constants {
// The build script extracts this exact line so be careful editing it
// and only use A-Z a-z 0-9 .-_ in the string.
- public static final String VERSION = "0.6.5";
+ public static final String VERSION = "0.6.6-SNAPSHOT";
// The build script extracts this exact line so be careful editing it
// and only use A-Z a-z 0-9 .-_ in the string.
- public static final String VERSION_DATE = "2011-08-12";
+ public static final String VERSION_DATE = "PENDING";
// The build script extracts this exact line so be careful editing it
// and only use A-Z a-z 0-9 .-_ in the string.
diff --git a/src/com/iciql/Db.java b/src/com/iciql/Db.java
index cbc1ed4..bb087e4 100644
--- a/src/com/iciql/Db.java
+++ b/src/com/iciql/Db.java
@@ -74,6 +74,7 @@ public class Db {
DIALECTS.put("H2", SQLDialectH2.class);
DIALECTS.put("MySQL", SQLDialectMySQL.class);
DIALECTS.put("HSQL Database Engine", SQLDialectHSQL.class);
+ DIALECTS.put("Apache Derby", SQLDialectDerby.class);
}
private Db(Connection conn) {
@@ -192,13 +193,30 @@ public class Db {
* does exist. Not all databases support MERGE and the syntax varies with
* the database.
*
+ * If the database does not support a MERGE syntax the dialect can try to
+ * simulate a merge by implementing:
+ * <p>
+ * INSERT INTO foo... (SELECT ?,... FROM foo WHERE pk=? HAVING count(*)=0)
+ * <p>
+ * iciql will check the affected row count returned by the internal merge
+ * method and if the affected row count = 0, it will issue an update.
+ * <p>
+ * See the Derby dialect for an implementation of this technique.
+ * <p>
* If the dialect does not support merge an IciqlException will be thrown.
*
* @param t
*/
public <T> void merge(T t) {
Class<?> clazz = t.getClass();
- define(clazz).createTableIfRequired(this).merge(this, t);
+ TableDefinition<?> def = define(clazz).createTableIfRequired(this);
+ int rc = def.merge(this, t);
+ if (rc == 0) {
+ rc = def.update(this, t);
+ }
+ if (rc == 0) {
+ throw new IciqlException("merge failed");
+ }
}
public <T> int update(T t) {
@@ -220,7 +238,7 @@ public class Db {
@SuppressWarnings("unchecked")
public <T> List<T> buildObjects(Class<? extends T> modelClass, ResultSet rs) {
List<T> result = new ArrayList<T>();
- TableDefinition<T> def = (TableDefinition<T>) define(modelClass).createTableIfRequired(this);
+ TableDefinition<T> def = (TableDefinition<T>) define(modelClass);
try {
while (rs.next()) {
T item = Utils.newObject(modelClass);
diff --git a/src/com/iciql/DbInspector.java b/src/com/iciql/DbInspector.java
index fb1e5d6..c30bbb1 100644
--- a/src/com/iciql/DbInspector.java
+++ b/src/com/iciql/DbInspector.java
@@ -42,6 +42,7 @@ public class DbInspector {
public DbInspector(Db db) {
this.db = db;
+ setPreferredDateTimeClass(db.getDialect().getDateTimeClass());
}
/**
@@ -73,8 +74,8 @@ public class DbInspector {
* (trims strings to maxLength of column)
* @return a list of complete model classes as strings, each element a class
*/
- public List<String> generateModel(String schema, String table, String packageName, boolean annotateSchema,
- boolean trimStrings) {
+ public List<String> generateModel(String schema, String table, String packageName,
+ boolean annotateSchema, boolean trimStrings) {
try {
List<String> models = Utils.newArrayList();
List<TableInspector> tables = getTables(schema, table);
@@ -130,7 +131,8 @@ public class DbInspector {
Class<T> clazz = (Class<T>) model.getClass();
TableDefinition<T> def = db.define(clazz);
boolean forceUpperCase = getMetaData().storesUpperCaseIdentifiers();
- String schema = (forceUpperCase && def.schemaName != null) ? def.schemaName.toUpperCase() : def.schemaName;
+ String schema = (forceUpperCase && def.schemaName != null) ? def.schemaName.toUpperCase()
+ : def.schemaName;
String table = forceUpperCase ? def.tableName.toUpperCase() : def.tableName;
List<TableInspector> tables = getTables(schema, table);
return tables.get(0);
@@ -167,7 +169,8 @@ public class DbInspector {
while (rs.next()) {
String t = rs.getString("TABLE_NAME");
if (!t.equalsIgnoreCase(iciqlTables)) {
- tables.add(new TableInspector(s, t, getMetaData().storesUpperCaseIdentifiers(), dateTimeClass));
+ tables.add(new TableInspector(s, t, getMetaData().storesUpperCaseIdentifiers(),
+ dateTimeClass));
}
}
}
diff --git a/src/com/iciql/Iciql.java b/src/com/iciql/Iciql.java
index 2917882..7a0b58f 100644
--- a/src/com/iciql/Iciql.java
+++ b/src/com/iciql/Iciql.java
@@ -72,7 +72,8 @@ import java.lang.annotation.Target;
* </tr>
* <tr>
* <td>java.math.BigDecimal</td>
- * <td>DECIMAL (length == 0)<br/>DECIMAL(length, scale) (length > 0)</td>
+ * <td>DECIMAL (length == 0)<br/>
+ * DECIMAL(length, scale) (length > 0)</td>
* </tr>
* <tr>
* <td>java.sql.Date</td>
@@ -400,8 +401,8 @@ public interface Iciql {
* Scale is used during the CREATE TABLE phase to define the scale of a
* DECIMAL(precision, scale) expression.
* <p>
- * Any scale set in define() may override this annotation setting if
- * the model class is not annotated with IQTable. Default: 0.
+ * Any scale set in define() may override this annotation setting if the
+ * model class is not annotated with IQTable. Default: 0.
*/
int scale() default 0;
diff --git a/src/com/iciql/IciqlException.java b/src/com/iciql/IciqlException.java
index 5a99c5e..7d6f152 100644
--- a/src/com/iciql/IciqlException.java
+++ b/src/com/iciql/IciqlException.java
@@ -28,9 +28,10 @@ public class IciqlException extends RuntimeException {
public static final int CODE_UNMAPPED_FIELD = 1;
public static final int CODE_DUPLICATE_KEY = 2;
public static final int CODE_TABLE_NOT_FOUND = 3;
- public static final int CODE_INDEX_ALREADY_EXISTS = 4;
+ public static final int CODE_TABLE_ALREADY_EXISTS = 4;
+ public static final int CODE_INDEX_ALREADY_EXISTS = 5;
- private static final String TOKEN_UNMAPPED_FIELD = "\\? (=|\\>|\\<|\\<\\>|!=|\\>=|\\<=|LIKE|BETWEEN) \\?";
+ private static final String TOKEN_UNMAPPED_FIELD = "\\? (=|\\>|\\<|\\<\\>|!=|\\>=|\\<=|LIKE|BETWEEN) \\?";
private static final long serialVersionUID = 1L;
@@ -51,7 +52,7 @@ public class IciqlException extends RuntimeException {
super(parameters.length > 0 ? MessageFormat.format(message, parameters) : message, t);
configureCode(t);
}
-
+
public static void checkUnmappedField(String sql) {
if (Pattern.compile(IciqlException.TOKEN_UNMAPPED_FIELD).matcher(sql).find()) {
IciqlException e = new IciqlException("unmapped field in statement!");
@@ -60,7 +61,7 @@ public class IciqlException extends RuntimeException {
throw e;
}
}
-
+
public static IciqlException fromSQL(String sql, Throwable t) {
if (Pattern.compile(TOKEN_UNMAPPED_FIELD).matcher(sql).find()) {
IciqlException e = new IciqlException(t, "unmapped field in statement!");
@@ -73,7 +74,7 @@ public class IciqlException extends RuntimeException {
return e;
}
}
-
+
public void setSQL(String sql) {
this.sql = sql;
}
@@ -85,7 +86,7 @@ public class IciqlException extends RuntimeException {
public int getIciqlCode() {
return iciqlCode;
}
-
+
private void configureCode(Throwable t) {
if (t == null) {
return;
@@ -96,29 +97,39 @@ public class IciqlException extends RuntimeException {
String state = s.getSQLState();
if ("23505".equals(state)) {
iciqlCode = CODE_DUPLICATE_KEY;
- } else if ("42501".equals(state)) {
+ } else if ("42X05".equals(state)) {
+ // Derby
iciqlCode = CODE_TABLE_NOT_FOUND;
} else if ("42S02".equals(state)) {
+ // H2
iciqlCode = CODE_TABLE_NOT_FOUND;
- } else if ("42504".equals(state)) {
- iciqlCode = CODE_INDEX_ALREADY_EXISTS;
+ } else if ("42501".equals(state)) {
+ // HSQL
+ iciqlCode = CODE_TABLE_NOT_FOUND;
+ } else if ("X0Y32".equals(state)) {
+ // Derby
+ iciqlCode = CODE_TABLE_ALREADY_EXISTS;
} else if ("42S11".equals(state)) {
+ // H2
+ iciqlCode = CODE_INDEX_ALREADY_EXISTS;
+ } else if ("42504".equals(state)) {
+ // HSQL
iciqlCode = CODE_INDEX_ALREADY_EXISTS;
}
}
}
-
+
@Override
- public String toString() {
+ public String toString() {
StringBuilder sb = new StringBuilder();
- sb.append(getClass().getName());
- String message = getLocalizedMessage();
- if (message != null) {
- sb.append(": ").append(message);
- }
- if (sql != null) {
- sb.append('\n').append(sql);
- }
- return sb.toString();
- }
+ sb.append(getClass().getName());
+ String message = getLocalizedMessage();
+ if (message != null) {
+ sb.append(": ").append(message);
+ }
+ if (sql != null) {
+ sb.append('\n').append(sql);
+ }
+ return sb.toString();
+ }
}
diff --git a/src/com/iciql/ModelUtils.java b/src/com/iciql/ModelUtils.java
index 048ce8d..5613d00 100644
--- a/src/com/iciql/ModelUtils.java
+++ b/src/com/iciql/ModelUtils.java
@@ -253,7 +253,10 @@ class ModelUtils {
String value = null;
if (Number.class.isAssignableFrom(objectClass)) {
// NUMBER
- value = ((Number) o).toString();
+ return ((Number) o).toString();
+ } else if (Boolean.class.isAssignableFrom(objectClass)) {
+ // BOOLEAN
+ return o.toString();
} else if (java.sql.Date.class.isAssignableFrom(objectClass)) {
// DATE
value = new SimpleDateFormat("yyyy-MM-dd").format((Date) o);
@@ -266,9 +269,6 @@ class ModelUtils {
} else if (String.class.isAssignableFrom(objectClass)) {
// STRING
value = o.toString();
- } else if (Boolean.class.isAssignableFrom(objectClass)) {
- // BOOLEAN
- value = o.toString();
}
if (value == null) {
return "''";
@@ -313,10 +313,6 @@ class ModelUtils {
return true;
}
- // TODO H2 single-quotes literal values, which is useful.
- // MySQL does not single-quote literal values so its hard to
- // differentiate a FUNCTION/VARIABLE from a literal value.
-
// function / variable
Pattern functionDefault = Pattern.compile("[^'].*[^']");
if (functionDefault.matcher(defaultValue).matches()) {
diff --git a/src/com/iciql/Query.java b/src/com/iciql/Query.java
index 699574d..8f34761 100644
--- a/src/com/iciql/Query.java
+++ b/src/com/iciql/Query.java
@@ -193,7 +193,7 @@ public class Query<T> {
public UpdateColumnIncrement<T, Byte> increment(byte field) {
return incrementPrimitive(field);
}
-
+
public UpdateColumnIncrement<T, Short> increment(short field) {
return incrementPrimitive(field);
}
@@ -511,13 +511,13 @@ public class Query<T> {
}
return orderBy(alias);
}
-
+
public Query<T> orderBy(Object expr) {
OrderExpression<T> e = new OrderExpression<T>(this, expr, false, false, false);
addOrderBy(e);
return this;
}
-
+
/**
* Order by a number of columns.
*
@@ -575,12 +575,12 @@ public class Query<T> {
}
return groupBy(alias);
}
-
+
public Query<T> groupBy(Object expr) {
groupByExpressions.add(expr);
return this;
}
-
+
public Query<T> groupBy(Object... groupBy) {
this.groupByExpressions.addAll(Arrays.asList(groupBy));
return this;
@@ -712,12 +712,7 @@ public class Query<T> {
stat.appendSQL(" ");
}
}
- if (limit > 0) {
- db.getDialect().appendLimit(stat, limit);
- }
- if (offset > 0) {
- db.getDialect().appendOffset(stat, offset);
- }
+ db.getDialect().appendLimitOffset(stat, limit, offset);
StatementLogger.select(stat.getSQL());
}
diff --git a/src/com/iciql/QueryBetween.java b/src/com/iciql/QueryBetween.java
index 8628f40..72d19dc 100644
--- a/src/com/iciql/QueryBetween.java
+++ b/src/com/iciql/QueryBetween.java
@@ -18,6 +18,7 @@ package com.iciql;
/**
* This class represents a "between y and z" condition.
+ *
* @param <T>
* the return type of the query
* @param <A>
diff --git a/src/com/iciql/QueryWhere.java b/src/com/iciql/QueryWhere.java
index 727285d..c1e3b03 100644
--- a/src/com/iciql/QueryWhere.java
+++ b/src/com/iciql/QueryWhere.java
@@ -344,6 +344,7 @@ public class QueryWhere<T> {
query.orderBy(field);
return this;
}
+
/**
* Order by a number of Object columns.
*
diff --git a/src/com/iciql/SQLDialect.java b/src/com/iciql/SQLDialect.java
index 7821c3f..97d9fe9 100644
--- a/src/com/iciql/SQLDialect.java
+++ b/src/com/iciql/SQLDialect.java
@@ -62,7 +62,7 @@ public interface SQLDialect {
* @param def
*/
<T> void prepareCreateTable(SQLStatement stat, TableDefinition<T> def);
-
+
/**
* Get the CREATE INDEX statement.
*
@@ -90,24 +90,16 @@ public interface SQLDialect {
Object obj);
/**
- * Append "LIMIT limit" to the SQL statement.
+ * Append "LIMIT limit OFFSET offset" to the SQL statement.
*
* @param stat
* the statement
* @param limit
* the limit
- */
- void appendLimit(SQLStatement stat, long limit);
-
- /**
- * Append "OFFSET offset" to the SQL statement.
- *
- * @param stat
- * the statement
* @param offset
* the offset
*/
- void appendOffset(SQLStatement stat, long offset);
+ void appendLimitOffset(SQLStatement stat, long limit, long offset);
/**
* Whether memory tables are supported.
@@ -115,7 +107,14 @@ public interface SQLDialect {
* @return true if they are
*/
boolean supportsMemoryTables();
-
+
+ /**
+ * Whether IF NOT EXISTS notation is supported.
+ *
+ * @return true if they are
+ */
+ boolean supportsIfNotExists();
+
/**
* Whether LIMIT/OFFSET notation is supported.
*
@@ -123,4 +122,12 @@ public interface SQLDialect {
*/
boolean supportsLimitOffset();
+ /**
+ * Returns the preferred DATETIME class for the database.
+ * <p>
+ * Either java.util.Date or java.sql.Timestamp
+ *
+ * @return preferred DATETIME class
+ */
+ Class<? extends java.util.Date> getDateTimeClass();
}
diff --git a/src/com/iciql/SQLDialectDefault.java b/src/com/iciql/SQLDialectDefault.java
index 7786829..69502c3 100644
--- a/src/com/iciql/SQLDialectDefault.java
+++ b/src/com/iciql/SQLDialectDefault.java
@@ -62,11 +62,21 @@ public class SQLDialectDefault implements SQLDialect {
}
@Override
+ public Class<? extends java.util.Date> getDateTimeClass() {
+ return java.util.Date.class;
+ }
+
+ @Override
public boolean supportsMemoryTables() {
return false;
}
@Override
+ public boolean supportsIfNotExists() {
+ return true;
+ }
+
+ @Override
public boolean supportsLimitOffset() {
return true;
}
@@ -88,9 +98,13 @@ public class SQLDialectDefault implements SQLDialect {
public <T> void prepareCreateTable(SQLStatement stat, TableDefinition<T> def) {
StatementBuilder buff;
if (def.memoryTable && supportsMemoryTables()) {
- buff = new StatementBuilder("CREATE MEMORY TABLE IF NOT EXISTS ");
+ buff = new StatementBuilder("CREATE MEMORY TABLE ");
} else {
- buff = new StatementBuilder("CREATE TABLE IF NOT EXISTS ");
+ buff = new StatementBuilder("CREATE TABLE ");
+ }
+
+ if (supportsIfNotExists()) {
+ buff.append("IF NOT EXISTS ");
}
buff.append(prepareTableName(def.schemaName, def.tableName)).append('(');
@@ -183,12 +197,12 @@ public class SQLDialectDefault implements SQLDialect {
}
@Override
- public void appendLimit(SQLStatement stat, long limit) {
- stat.appendSQL(" LIMIT " + limit);
- }
-
- @Override
- public void appendOffset(SQLStatement stat, long offset) {
- stat.appendSQL(" OFFSET " + offset);
+ public void appendLimitOffset(SQLStatement stat, long limit, long offset) {
+ if (limit > 0) {
+ stat.appendSQL(" LIMIT " + limit);
+ }
+ if (offset > 0) {
+ stat.appendSQL(" OFFSET " + offset);
+ }
}
} \ No newline at end of file
diff --git a/src/com/iciql/SQLDialectDerby.java b/src/com/iciql/SQLDialectDerby.java
new file mode 100644
index 0000000..42f8cfd
--- /dev/null
+++ b/src/com/iciql/SQLDialectDerby.java
@@ -0,0 +1,151 @@
+/*
+ * Copyright 2011 James Moger.
+ *
+ * Licensed 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 com.iciql;
+
+import java.text.MessageFormat;
+
+import com.iciql.TableDefinition.FieldDefinition;
+import com.iciql.TableDefinition.IndexDefinition;
+import com.iciql.util.StatementBuilder;
+
+/**
+ * Derby database dialect.
+ */
+public class SQLDialectDerby extends SQLDialectDefault {
+
+ @Override
+ public Class<? extends java.util.Date> getDateTimeClass() {
+ return java.sql.Timestamp.class;
+ }
+
+ @Override
+ protected String convertSqlType(String sqlType) {
+ if ("TINYINT".equals(sqlType)) {
+ // Derby does not have a TINYINT/BYTE type
+ return "SMALLINT";
+ }
+ return sqlType;
+ }
+
+ @Override
+ public boolean supportsMemoryTables() {
+ return false;
+ }
+
+ @Override
+ public boolean supportsIfNotExists() {
+ return false;
+ }
+
+ @Override
+ public boolean supportsLimitOffset() {
+ // FETCH/OFFSET added in 10.5
+ return databaseVersion >= 10.5f;
+ }
+
+ @Override
+ public void appendLimitOffset(SQLStatement stat, long limit, long offset) {
+ if (offset > 0) {
+ stat.appendSQL(" OFFSET " + offset + (offset == 1 ? " ROW" : " ROWS"));
+ }
+ if (limit > 0) {
+ stat.appendSQL(" FETCH NEXT " + limit + (limit == 1 ? " ROW" : " ROWS") + " ONLY");
+ }
+ }
+
+ @Override
+ public String prepareColumnName(String name) {
+ return name;
+ }
+
+ @Override
+ protected boolean prepareColumnDefinition(StatementBuilder buff, boolean isAutoIncrement,
+ boolean isPrimaryKey) {
+ if (isAutoIncrement) {
+ buff.append(" GENERATED BY DEFAULT AS IDENTITY");
+ }
+ return false;
+ }
+
+ @Override
+ public void prepareCreateIndex(SQLStatement stat, String schema, String table, IndexDefinition index) {
+ StatementBuilder buff = new StatementBuilder();
+ buff.append("CREATE ");
+ switch (index.type) {
+ case UNIQUE:
+ buff.append("UNIQUE ");
+ break;
+ case UNIQUE_HASH:
+ buff.append("UNIQUE ");
+ break;
+ }
+ buff.append("INDEX ");
+ buff.append(index.indexName);
+ buff.append(" ON ");
+ buff.append(table);
+ buff.append("(");
+ for (String col : index.columnNames) {
+ buff.appendExceptFirst(", ");
+ buff.append(prepareColumnName(col));
+ }
+ buff.append(") ");
+
+ stat.setSQL(buff.toString().trim());
+ }
+
+ /**
+ * Derby does not support the SQL2003 MERGE syntax, but we can use a trick
+ * to insert a row if it does not exist and call update() in Db.merge() if
+ * the affected row count is 0;
+ *
+ * http://stackoverflow.com/questions/407688
+ */
+ @Override
+ public <T> void prepareMerge(SQLStatement stat, String schemaName, String tableName,
+ TableDefinition<T> def, Object obj) {
+ StatementBuilder buff = new StatementBuilder("INSERT INTO ");
+ buff.append(prepareTableName(schemaName, tableName));
+ buff.append(" (");
+ buff.resetCount();
+ for (FieldDefinition field : def.fields) {
+ buff.appendExceptFirst(", ");
+ buff.append(prepareColumnName(field.columnName));
+ }
+ buff.append(") (SELECT ");
+ buff.resetCount();
+ for (FieldDefinition field : def.fields) {
+ buff.appendExceptFirst(", ");
+ buff.append('?');
+ Object value = def.getValue(obj, field);
+ stat.addParameter(value);
+ }
+ buff.append(" FROM ");
+ buff.append(prepareTableName(schemaName, tableName));
+ buff.append(" WHERE ");
+ buff.resetCount();
+ for (FieldDefinition field : def.fields) {
+ if (field.isPrimaryKey) {
+ buff.appendExceptFirst(" AND ");
+ buff.append(MessageFormat.format("{0} = ?", prepareColumnName(field.columnName)));
+ Object value = def.getValue(obj, field);
+ stat.addParameter(value);
+ }
+ }
+ buff.append(" HAVING count(*)=0)");
+ stat.setSQL(buff.toString());
+ }
+} \ No newline at end of file
diff --git a/src/com/iciql/SQLDialectH2.java b/src/com/iciql/SQLDialectH2.java
index 80786f9..ab08475 100644
--- a/src/com/iciql/SQLDialectH2.java
+++ b/src/com/iciql/SQLDialectH2.java
@@ -57,11 +57,12 @@ public class SQLDialectH2 extends SQLDialectDefault {
buff.append(col);
}
buff.append(")");
- stat.setSQL(buff.toString());
+ stat.setSQL(buff.toString());
}
-
+
@Override
- public <T> void prepareMerge(SQLStatement stat, String schemaName, String tableName, TableDefinition<T> def, Object obj) {
+ public <T> void prepareMerge(SQLStatement stat, String schemaName, String tableName,
+ TableDefinition<T> def, Object obj) {
StatementBuilder buff = new StatementBuilder("MERGE INTO ");
buff.append(prepareTableName(schemaName, tableName)).append(" (");
buff.resetCount();
diff --git a/src/com/iciql/SQLDialectHSQL.java b/src/com/iciql/SQLDialectHSQL.java
index e617758..566bb23 100644
--- a/src/com/iciql/SQLDialectHSQL.java
+++ b/src/com/iciql/SQLDialectHSQL.java
@@ -16,6 +16,9 @@
package com.iciql;
+import java.text.MessageFormat;
+
+import com.iciql.TableDefinition.FieldDefinition;
import com.iciql.TableDefinition.IndexDefinition;
import com.iciql.util.StatementBuilder;
@@ -23,14 +26,15 @@ import com.iciql.util.StatementBuilder;
* HyperSQL database dialect.
*/
public class SQLDialectHSQL extends SQLDialectDefault {
-
+
@Override
public boolean supportsMemoryTables() {
return true;
}
-
+
@Override
- protected boolean prepareColumnDefinition(StatementBuilder buff, boolean isAutoIncrement, boolean isPrimaryKey) {
+ protected boolean prepareColumnDefinition(StatementBuilder buff, boolean isAutoIncrement,
+ boolean isPrimaryKey) {
boolean isIdentity = false;
if (isAutoIncrement && isPrimaryKey) {
buff.append(" IDENTITY");
@@ -44,8 +48,6 @@ public class SQLDialectHSQL extends SQLDialectDefault {
StatementBuilder buff = new StatementBuilder();
buff.append("CREATE ");
switch (index.type) {
- case STANDARD:
- break;
case UNIQUE:
buff.append("UNIQUE ");
break;
@@ -65,4 +67,91 @@ public class SQLDialectHSQL extends SQLDialectDefault {
buff.append(")");
stat.setSQL(buff.toString());
}
+
+ @Override
+ public <T> void prepareMerge(SQLStatement stat, String schemaName, String tableName,
+ TableDefinition<T> def, Object obj) {
+ final String valuePrefix = "v";
+ StatementBuilder buff = new StatementBuilder("MERGE INTO ");
+ buff.append(prepareTableName(schemaName, tableName));
+ // a, b, c....
+ buff.append(" USING (VALUES(");
+ for (FieldDefinition field : def.fields) {
+ buff.appendExceptFirst(", ");
+ buff.append("CAST(? AS ");
+ String dataType = convertSqlType(field.dataType);
+ buff.append(dataType);
+ if ("VARCHAR".equals(dataType)) {
+ if (field.length > 0) {
+ // VARCHAR(x)
+ buff.append(MessageFormat.format("({0})", field.length));
+ }
+ } else if ("DECIMAL".equals(dataType)) {
+ if (field.length > 0) {
+ if (field.scale > 0) {
+ // DECIMAL(x,y)
+ buff.append(MessageFormat.format("({0},{1})", field.length, field.scale));
+ } else {
+ // DECIMAL(x)
+ buff.append(MessageFormat.format("({0})", field.length));
+ }
+ }
+ }
+ buff.append(')');
+ Object value = def.getValue(obj, field);
+ stat.addParameter(value);
+ }
+
+ // map to temporary table
+ buff.resetCount();
+ buff.append(")) AS vals (");
+ for (FieldDefinition field : def.fields) {
+ buff.appendExceptFirst(", ");
+ buff.append(prepareColumnName(valuePrefix + field.columnName));
+ }
+
+ buff.append(") ON ");
+
+ // create the ON condition
+ // (va, vb) = (va,vb)
+ String[] prefixes = { "", valuePrefix };
+ for (int i = 0; i < prefixes.length; i++) {
+ String prefix = prefixes[i];
+ buff.resetCount();
+ buff.append('(');
+ for (FieldDefinition field : def.fields) {
+ if (field.isPrimaryKey) {
+ buff.appendExceptFirst(", ");
+ buff.append(prepareColumnName(prefix + field.columnName));
+ }
+ }
+ buff.append(")");
+ if (i == 0) {
+ buff.append('=');
+ }
+ }
+
+ // UPDATE
+ // set a=va
+ buff.append(" WHEN MATCHED THEN UPDATE SET ");
+ buff.resetCount();
+ for (FieldDefinition field : def.fields) {
+ buff.appendExceptFirst(", ");
+ buff.append(prepareColumnName(field.columnName));
+ buff.append('=');
+ buff.append(prepareColumnName(valuePrefix + field.columnName));
+ }
+
+ // INSERT
+ // insert va, vb, vc....
+ buff.append(" WHEN NOT MATCHED THEN INSERT ");
+ buff.resetCount();
+ buff.append(" VALUES (");
+ for (FieldDefinition field : def.fields) {
+ buff.appendExceptFirst(", ");
+ buff.append(prepareColumnName(valuePrefix + field.columnName));
+ }
+ buff.append(')');
+ stat.setSQL(buff.toString());
+ }
} \ No newline at end of file
diff --git a/src/com/iciql/SQLDialectMySQL.java b/src/com/iciql/SQLDialectMySQL.java
index 2593e0a..a6c1218 100644
--- a/src/com/iciql/SQLDialectMySQL.java
+++ b/src/com/iciql/SQLDialectMySQL.java
@@ -31,7 +31,7 @@ public class SQLDialectMySQL extends SQLDialectDefault {
}
return sqlType;
}
-
+
@Override
public boolean supportsMemoryTables() {
return false;
@@ -41,15 +41,16 @@ public class SQLDialectMySQL extends SQLDialectDefault {
public String prepareColumnName(String name) {
return "`" + name + "`";
}
-
+
@Override
- protected boolean prepareColumnDefinition(StatementBuilder buff, boolean isAutoIncrement, boolean isPrimaryKey) {
+ protected boolean prepareColumnDefinition(StatementBuilder buff, boolean isAutoIncrement,
+ boolean isPrimaryKey) {
if (isAutoIncrement) {
buff.append(" AUTO_INCREMENT");
}
return false;
}
-
+
@Override
public void prepareCreateIndex(SQLStatement stat, String schema, String table, IndexDefinition index) {
StatementBuilder buff = new StatementBuilder();
@@ -74,7 +75,7 @@ public class SQLDialectMySQL extends SQLDialectDefault {
buff.append(prepareColumnName(col));
}
buff.append(") ");
-
+
// USING
switch (index.type) {
case HASH:
diff --git a/src/com/iciql/SQLStatement.java b/src/com/iciql/SQLStatement.java
index 4962502..a33fe6c 100644
--- a/src/com/iciql/SQLStatement.java
+++ b/src/com/iciql/SQLStatement.java
@@ -65,6 +65,12 @@ public class SQLStatement {
}
public SQLStatement addParameter(Object o) {
+ // Automatically convert java.util.Date to java.sql.Timestamp
+ // if the dialect requires java.sql.Timestamp objects (e.g. Derby)
+ if (o != null && o.getClass().equals(java.util.Date.class)
+ && db.getDialect().getDateTimeClass().equals(java.sql.Timestamp.class)) {
+ o = new java.sql.Timestamp(((java.util.Date) o).getTime());
+ }
params.add(o);
return this;
}
@@ -112,7 +118,8 @@ public class SQLStatement {
try {
prep.setObject(parameterIndex, x);
} catch (SQLException e) {
- IciqlException ix = new IciqlException(e, "error setting parameter {0} as {1}", parameterIndex, x.getClass().getSimpleName());
+ IciqlException ix = new IciqlException(e, "error setting parameter {0} as {1}", parameterIndex, x
+ .getClass().getSimpleName());
ix.setSQL(getSQL());
throw ix;
}
diff --git a/src/com/iciql/TableDefinition.java b/src/com/iciql/TableDefinition.java
index ec79756..4d9fec2 100644
--- a/src/com/iciql/TableDefinition.java
+++ b/src/com/iciql/TableDefinition.java
@@ -447,30 +447,35 @@ public class TableDefinition<T> {
}
private boolean skipInsertField(FieldDefinition field, Object obj) {
- // skip uninitialized primitive autoincrement values
- if (field.isAutoIncrement && field.isPrimitive) {
+ if (field.isAutoIncrement) {
Object value = getValue(obj, field);
- if (value.toString().equals("0")) {
+ if (field.isPrimitive) {
+ // skip uninitialized primitive autoincrement values
+ if (value.toString().equals("0")) {
+ return true;
+ }
+ } else if (value == null) {
+ // skip null object autoincrement values
return true;
}
}
return false;
}
- void merge(Db db, Object obj) {
+ int merge(Db db, Object obj) {
if (primaryKeyColumnNames == null || primaryKeyColumnNames.size() == 0) {
- throw new IllegalStateException("No primary key columns defined " + "for table " + obj.getClass()
+ throw new IllegalStateException("No primary key columns defined for table " + obj.getClass()
+ " - no update possible");
}
SQLStatement stat = new SQLStatement(db);
db.getDialect().prepareMerge(stat, schemaName, tableName, this, obj);
StatementLogger.merge(stat.getSQL());
- stat.executeUpdate();
+ return stat.executeUpdate();
}
int update(Db db, Object obj) {
if (primaryKeyColumnNames == null || primaryKeyColumnNames.size() == 0) {
- throw new IllegalStateException("No primary key columns defined " + "for table " + obj.getClass()
+ throw new IllegalStateException("No primary key columns defined for table " + obj.getClass()
+ " - no update possible");
}
SQLStatement stat = new SQLStatement(db);
@@ -552,7 +557,13 @@ public class TableDefinition<T> {
SQLStatement stat = new SQLStatement(db);
db.getDialect().prepareCreateTable(stat, this);
StatementLogger.create(stat.getSQL());
- stat.executeUpdate();
+ try {
+ stat.executeUpdate();
+ } catch (IciqlException e) {
+ if (e.getIciqlCode() != IciqlException.CODE_TABLE_ALREADY_EXISTS) {
+ throw e;
+ }
+ }
// create indexes
for (IndexDefinition index : indexes) {
diff --git a/src/com/iciql/TableInspector.java b/src/com/iciql/TableInspector.java
index e682f2f..dc28956 100644
--- a/src/com/iciql/TableInspector.java
+++ b/src/com/iciql/TableInspector.java
@@ -120,7 +120,8 @@ public class TableInspector {
IndexInspector info = new IndexInspector(rs);
if (info.type.equals(IndexType.UNIQUE)) {
String name = info.name.toLowerCase();
- if (name.startsWith("primary") || name.startsWith("sys_idx_sys_pk")) {
+ if (name.startsWith("primary") || name.startsWith("sys_idx_sys_pk")
+ || name.startsWith("sql")) {
// skip primary key indexes
continue;
}
diff --git a/src/com/iciql/UpdateColumnSet.java b/src/com/iciql/UpdateColumnSet.java
index f2322e3..8c30982 100644
--- a/src/com/iciql/UpdateColumnSet.java
+++ b/src/com/iciql/UpdateColumnSet.java
@@ -17,7 +17,6 @@
package com.iciql;
-
/**
* This class represents "SET column = value" in an UPDATE statement.
*
diff --git a/src/com/iciql/build/Build.java b/src/com/iciql/build/Build.java
index cc3895c..0102739 100644
--- a/src/com/iciql/build/Build.java
+++ b/src/com/iciql/build/Build.java
@@ -57,6 +57,7 @@ public class Build {
downloadFromApache(MavenObject.H2, BuildType.RUNTIME);
downloadFromApache(MavenObject.H2, BuildType.COMPILETIME);
downloadFromApache(MavenObject.HSQLDB, BuildType.RUNTIME);
+ downloadFromApache(MavenObject.DERBY, BuildType.RUNTIME);
downloadFromApache(MavenObject.JCOMMANDER, BuildType.RUNTIME);
downloadFromApache(MavenObject.JCOMMANDER, BuildType.COMPILETIME);
downloadFromApache(MavenObject.MARKDOWNPAPERS, BuildType.RUNTIME);
@@ -169,13 +170,15 @@ public class Build {
"219a3540f3b27d7cc3b1d91d6ea046cd8723290e", "0bb50eec177acf0e94d58e0cf07262fe5164331d",
"c7adc475ca40c288c93054e0f4fe58f3a98c0cb5");
- public static final MavenObject H2 = new MavenObject("com/h2database", "h2", "1.3.158",
- "4bac13427caeb32ef6e93b70101e61f370c7b5e2", "6bb165156a0831879fa7797df6e18bdcd4421f2d",
- "446d3f58c44992534cb54f67134532d95961904a");
+ public static final MavenObject H2 = new MavenObject("com/h2database", "h2", "1.3.159",
+ "dd89f939661eb5593909584e1c243db0c25de130", "4d953bf765e8a13c7e06ca51165438338966c698",
+ "4c79ed03f994820a1a873150c8a9f13c667784d3");
public static final MavenObject HSQLDB = new MavenObject("org/hsqldb", "hsqldb", "2.2.4",
- "6a6e040b07f5ee409fc825f1c5e5b574b1fa1428", "",
- "");
+ "6a6e040b07f5ee409fc825f1c5e5b574b1fa1428", "", "");
+
+ public static final MavenObject DERBY = new MavenObject("org/apache/derby", "derby", "10.8.1.2",
+ "2f8717d96eafe3eef3de445ba653f142d54ddab1", "", "");
public static final MavenObject JUNIT = new MavenObject("junit", "junit", "4.8.2",
"c94f54227b08100974c36170dcb53329435fe5ad", "", "");
diff --git a/src/com/iciql/build/BuildSite.java b/src/com/iciql/build/BuildSite.java
index 4ff5e68..81863ee 100644
--- a/src/com/iciql/build/BuildSite.java
+++ b/src/com/iciql/build/BuildSite.java
@@ -87,8 +87,8 @@ public class BuildSite {
aliasMap.put(values[0], values[1]);
}
- System.out.println(MessageFormat.format("Generating site from {0} Markdown Docs in {1} ", markdownFiles.length,
- sourceFolder.getAbsolutePath()));
+ System.out.println(MessageFormat.format("Generating site from {0} Markdown Docs in {1} ",
+ markdownFiles.length, sourceFolder.getAbsolutePath()));
String linkPattern = "<a href=''{0}''>{1}</a>";
StringBuilder sb = new StringBuilder();
for (File file : markdownFiles) {
@@ -168,7 +168,8 @@ public class BuildSite {
// get remainder of text
if (endCode < markdownContent.length()) {
- strippedContent.append(markdownContent.substring(endCode, markdownContent.length()));
+ strippedContent.append(markdownContent.substring(endCode,
+ markdownContent.length()));
}
markdownContent = strippedContent.toString();
nmd++;
@@ -193,9 +194,16 @@ public class BuildSite {
String[] kv = token.split("!!!", 2);
content = content.replaceAll(kv[0], kv[1]);
}
+ for (String alias : params.loads) {
+ String[] kv = alias.split("=", 2);
+ String loadedContent = StringUtils.readContent(new File(kv[1]), "\n");
+ loadedContent = StringUtils.escapeForHtml(loadedContent, false);
+ loadedContent = StringUtils.breakLinesForHtml(loadedContent);
+ content = content.replace(kv[0], loadedContent);
+ }
- OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(new File(destinationFolder,
- fileName)), Charset.forName("UTF-8"));
+ OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(new File(
+ destinationFolder, fileName)), Charset.forName("UTF-8"));
writer.write(header);
if (!StringUtils.isNullOrEmpty(htmlAdSnippet)) {
writer.write(htmlAdSnippet);
@@ -317,9 +325,12 @@ public class BuildSite {
@Parameter(names = { "--substitute" }, description = "%TOKEN%=value", required = false)
public List<String> substitutions = new ArrayList<String>();
+ @Parameter(names = { "--load" }, description = "%TOKEN%=filename", required = false)
+ public List<String> loads = new ArrayList<String>();
+
@Parameter(names = { "--nomarkdown" }, description = "%STARTTOKEN%:%ENDTOKEN%", required = false)
public List<String> nomarkdown = new ArrayList<String>();
-
+
@Parameter(names = { "--regex" }, description = "searchPattern!!!replacePattern", required = false)
public List<String> regex = new ArrayList<String>();
diff --git a/src/com/iciql/bytecode/ClassReader.java b/src/com/iciql/bytecode/ClassReader.java
index 35e94e9..38fd2f5 100644
--- a/src/com/iciql/bytecode/ClassReader.java
+++ b/src/com/iciql/bytecode/ClassReader.java
@@ -65,7 +65,8 @@ public class ClassReader {
debug("class name " + className);
ByteArrayOutputStream buff = new ByteArrayOutputStream();
try {
- InputStream in = clazz.getClassLoader().getResource(className.replace('.', '/') + ".class").openStream();
+ InputStream in = clazz.getClassLoader().getResource(className.replace('.', '/') + ".class")
+ .openStream();
while (true) {
int x = in.read();
if (x < 0) {
@@ -108,7 +109,8 @@ public class ClassReader {
}
case 6: {
long x = readLong();
- constantPool[i] = ConstantNumber.get("" + Double.longBitsToDouble(x), x, Constant.Type.DOUBLE);
+ constantPool[i] = ConstantNumber
+ .get("" + Double.longBitsToDouble(x), x, Constant.Type.DOUBLE);
i++;
break;
}
@@ -1380,8 +1382,8 @@ public class ClassReader {
int field = constantPool[fieldRef].intValue();
int classIndex = field >>> 16;
int nameAndType = constantPool[field & 0xffff].intValue();
- String className = constantPool[constantPool[classIndex].intValue()] + "." + constantPool[nameAndType >>> 16]
- + " " + constantPool[nameAndType & 0xffff];
+ String className = constantPool[constantPool[classIndex].intValue()] + "."
+ + constantPool[nameAndType >>> 16] + " " + constantPool[nameAndType & 0xffff];
return className;
}
@@ -1389,8 +1391,8 @@ public class ClassReader {
int method = constantPool[methodRef].intValue();
int classIndex = method >>> 16;
int nameAndType = constantPool[method & 0xffff].intValue();
- String className = constantPool[constantPool[classIndex].intValue()] + "." + constantPool[nameAndType >>> 16]
- + " " + constantPool[nameAndType & 0xffff];
+ String className = constantPool[constantPool[classIndex].intValue()] + "."
+ + constantPool[nameAndType >>> 16] + " " + constantPool[nameAndType & 0xffff];
return className;
}
@@ -1444,7 +1446,8 @@ public class ClassReader {
private int readInt() {
byte[] buff = data;
- return (buff[pos++] << 24) + ((buff[pos++] & 0xff) << 16) + ((buff[pos++] & 0xff) << 8) + (buff[pos++] & 0xff);
+ return (buff[pos++] << 24) + ((buff[pos++] & 0xff) << 16) + ((buff[pos++] & 0xff) << 8)
+ + (buff[pos++] & 0xff);
}
private long readLong() {
diff --git a/src/com/iciql/util/GenerateModels.java b/src/com/iciql/util/GenerateModels.java
index 69ce852..ce98105 100644
--- a/src/com/iciql/util/GenerateModels.java
+++ b/src/com/iciql/util/GenerateModels.java
@@ -128,13 +128,15 @@ public class GenerateModels {
* automatically trim strings that exceed maxLength
*/
public static void execute(String url, String user, String password, String schema, String table,
- String packageName, String folder, boolean annotateSchema, boolean trimStrings) throws SQLException {
+ String packageName, String folder, boolean annotateSchema, boolean trimStrings)
+ throws SQLException {
Connection conn = null;
try {
conn = DriverManager.getConnection(url, user, password);
Db db = Db.open(url, user, password.toCharArray());
DbInspector inspector = new DbInspector(db);
- List<String> models = inspector.generateModel(schema, table, packageName, annotateSchema, trimStrings);
+ List<String> models = inspector.generateModel(schema, table, packageName, annotateSchema,
+ trimStrings);
File parentFile;
if (StringUtils.isNullOrEmpty(folder)) {
parentFile = new File(System.getProperty("user.dir"));
diff --git a/src/com/iciql/util/JdbcUtils.java b/src/com/iciql/util/JdbcUtils.java
index 4ef006e..4a4a2b6 100644
--- a/src/com/iciql/util/JdbcUtils.java
+++ b/src/com/iciql/util/JdbcUtils.java
@@ -206,7 +206,7 @@ public class JdbcUtils {
return ds.getConnection(user, password);
} catch (SQLException e) {
throw e;
- } catch (Exception e) {
+ } catch (Exception e) {
throw new SQLException("Failed to get connection for " + url, e);
}
} else {
diff --git a/src/com/iciql/util/Slf4jStatementListener.java b/src/com/iciql/util/Slf4jStatementListener.java
index 2398ade..f46099c 100644
--- a/src/com/iciql/util/Slf4jStatementListener.java
+++ b/src/com/iciql/util/Slf4jStatementListener.java
@@ -60,7 +60,7 @@ public class Slf4jStatementListener implements StatementListener {
/**
* Sets the logging level for a particular statement type.
- *
+ *
* @param type
* @param level
*/
@@ -84,10 +84,10 @@ public class Slf4jStatementListener implements StatementListener {
case DEBUG:
logger.debug(statement);
break;
- case TRACE:
+ case TRACE:
logger.trace(statement);
break;
- case OFF:
+ case OFF:
break;
}
}
diff --git a/src/com/iciql/util/StatementBuilder.java b/src/com/iciql/util/StatementBuilder.java
index 65c0679..47e8054 100644
--- a/src/com/iciql/util/StatementBuilder.java
+++ b/src/com/iciql/util/StatementBuilder.java
@@ -99,9 +99,10 @@ public class StatementBuilder {
builder.append(x);
return this;
}
-
+
/**
* Returns the current value of the loop counter.
+ *
* @return the loop counter
*/
public int getCount() {
diff --git a/src/com/iciql/util/StringUtils.java b/src/com/iciql/util/StringUtils.java
index 2a8c297..dd3f180 100644
--- a/src/com/iciql/util/StringUtils.java
+++ b/src/com/iciql/util/StringUtils.java
@@ -17,7 +17,12 @@
package com.iciql.util;
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.InputStreamReader;
import java.io.UnsupportedEncodingException;
+import java.nio.charset.Charset;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
@@ -305,4 +310,73 @@ public class StringUtils {
}
return count;
}
+
+ /**
+ * Prepare text for html presentation. Replace sensitive characters with
+ * html entities.
+ *
+ * @param inStr
+ * @param changeSpace
+ * @return plain text escaped for html
+ */
+ public static String escapeForHtml(String inStr, boolean changeSpace) {
+ StringBuffer retStr = new StringBuffer();
+ int i = 0;
+ while (i < inStr.length()) {
+ if (inStr.charAt(i) == '&') {
+ retStr.append("&amp;");
+ } else if (inStr.charAt(i) == '<') {
+ retStr.append("&lt;");
+ } else if (inStr.charAt(i) == '>') {
+ retStr.append("&gt;");
+ } else if (inStr.charAt(i) == '\"') {
+ retStr.append("&quot;");
+ } else if (changeSpace && inStr.charAt(i) == ' ') {
+ retStr.append("&nbsp;");
+ } else if (changeSpace && inStr.charAt(i) == '\t') {
+ retStr.append(" &nbsp; &nbsp;");
+ } else {
+ retStr.append(inStr.charAt(i));
+ }
+ i++;
+ }
+ return retStr.toString();
+ }
+
+ /**
+ * Replaces carriage returns and line feeds with html line breaks.
+ *
+ * @param string
+ * @return plain text with html line breaks
+ */
+ public static String breakLinesForHtml(String string) {
+ return string.replace("\r\n", "<br/>").replace("\r", "<br/>").replace("\n", "<br/>");
+ }
+
+ /**
+ * Returns the string content of the specified file.
+ *
+ * @param file
+ * @param lineEnding
+ * @return the string content of the file
+ */
+ public static String readContent(File file, String lineEnding) {
+ StringBuilder sb = new StringBuilder();
+ try {
+ InputStreamReader is = new InputStreamReader(new FileInputStream(file), Charset.forName("UTF-8"));
+ BufferedReader reader = new BufferedReader(is);
+ String line = null;
+ while ((line = reader.readLine()) != null) {
+ sb.append(line);
+ if (lineEnding != null) {
+ sb.append(lineEnding);
+ }
+ }
+ reader.close();
+ } catch (Throwable t) {
+ System.err.println("Failed to read content of " + file.getAbsolutePath());
+ t.printStackTrace();
+ }
+ return sb.toString();
+ }
}
diff --git a/src/com/iciql/util/Utils.java b/src/com/iciql/util/Utils.java
index d9e065c..566c6f4 100644
--- a/src/com/iciql/util/Utils.java
+++ b/src/com/iciql/util/Utils.java
@@ -116,7 +116,9 @@ public class Utils {
}
}
}
- throw new IciqlException(e, "Missing default constructor? Exception trying to instantiate {0}: {1}", clazz.getName(), e.getMessage());
+ throw new IciqlException(e,
+ "Missing default constructor? Exception trying to instantiate {0}: {1}",
+ clazz.getName(), e.getMessage());
}
}
};
@@ -194,7 +196,9 @@ public class Utils {
}
}
}
- throw new IciqlException(e, "Missing default constructor?! Exception trying to instantiate {0}: {1}", clazz.getName(), e.getMessage());
+ throw new IciqlException(e,
+ "Missing default constructor?! Exception trying to instantiate {0}: {1}",
+ clazz.getName(), e.getMessage());
}
}
@@ -242,7 +246,7 @@ public class Utils {
float f = 0f;
try {
f = Float.parseFloat(s);
- } catch (Exception e) {
+ } catch (Exception e) {
}
return f > 0 || s.equals("true") || s.equals("yes");
}