From 7f76e4f876de7fcd0a5772eca388f6a2afa4efaf Mon Sep 17 00:00:00 2001 From: samskivert Date: Sun, 16 Nov 2008 07:49:17 +0000 Subject: [PATCH] Depot now lives in its own project. git-svn-id: https://samskivert.googlecode.com/svn/trunk@2480 6335cc39-0255-0410-8fd6-9bcaacd3b74c --- build.xml | 20 - etc/depends-incl.xml | 24 - src/java/com/samskivert/Utils.gwt.xml | 1 - .../samskivert/jdbc/depot/BindVisitor.java | 307 ----- .../samskivert/jdbc/depot/BuildVisitor.java | 611 --------- .../com/samskivert/jdbc/depot/ByteEnum.java | 39 - .../samskivert/jdbc/depot/CacheAdapter.java | 77 -- .../jdbc/depot/CacheInvalidator.java | 61 - .../com/samskivert/jdbc/depot/CacheKey.java | 42 - .../samskivert/jdbc/depot/DataMigration.java | 73 -- .../jdbc/depot/DatabaseException.java | 53 - .../jdbc/depot/DepotMarshaller.java | 1137 ----------------- .../depot/DepotMigrationHistoryRecord.java | 73 -- .../jdbc/depot/DepotRepository.java | 988 -------------- .../com/samskivert/jdbc/depot/DepotTypes.java | 221 ---- .../jdbc/depot/DuplicateKeyException.java | 33 - .../samskivert/jdbc/depot/EHCacheAdapter.java | 169 --- .../jdbc/depot/FieldMarshaller.java | 477 ------- .../samskivert/jdbc/depot/FindAllQuery.java | 303 ----- .../samskivert/jdbc/depot/FindOneQuery.java | 110 -- .../jdbc/depot/IdentityValueGenerator.java | 65 - src/java/com/samskivert/jdbc/depot/Key.java | 246 ---- .../com/samskivert/jdbc/depot/KeySet.java | 160 --- .../com/samskivert/jdbc/depot/KeyUtil.java | 59 - src/java/com/samskivert/jdbc/depot/Log.java | 32 - .../com/samskivert/jdbc/depot/Modifier.java | 144 --- .../com/samskivert/jdbc/depot/MultiKey.java | 155 --- .../samskivert/jdbc/depot/MySQLBuilder.java | 276 ---- .../com/samskivert/jdbc/depot/Operation.java | 38 - .../jdbc/depot/PersistenceContext.java | 607 --------- .../jdbc/depot/PersistentRecord.java | 41 - .../jdbc/depot/PostgreSQLBuilder.java | 297 ----- src/java/com/samskivert/jdbc/depot/Query.java | 73 -- .../com/samskivert/jdbc/depot/SQLBuilder.java | 230 ---- .../jdbc/depot/SchemaMigration.java | 246 ---- .../samskivert/jdbc/depot/SimpleCacheKey.java | 113 -- .../jdbc/depot/TableValueGenerator.java | 174 --- .../depot/ValidatingCacheInvalidator.java | 38 - .../samskivert/jdbc/depot/ValueGenerator.java | 124 -- .../samskivert/jdbc/depot/WhereClause.java | 60 - .../jdbc/depot/annotation/Column.java | 71 - .../jdbc/depot/annotation/Computed.java | 64 - .../jdbc/depot/annotation/Entity.java | 48 - .../jdbc/depot/annotation/FullTextIndex.java | 44 - .../jdbc/depot/annotation/GeneratedValue.java | 64 - .../jdbc/depot/annotation/GenerationType.java | 51 - .../samskivert/jdbc/depot/annotation/Id.java | 35 - .../jdbc/depot/annotation/Index.java | 42 - .../jdbc/depot/annotation/TableGenerator.java | 66 - .../jdbc/depot/annotation/Transient.java | 36 - .../depot/annotation/UniqueConstraint.java | 39 - .../jdbc/depot/clause/DeleteClause.java | 67 - .../jdbc/depot/clause/FieldDefinition.java | 89 -- .../jdbc/depot/clause/FieldOverride.java | 52 - .../jdbc/depot/clause/ForUpdate.java | 43 - .../jdbc/depot/clause/FromOverride.java | 72 -- .../samskivert/jdbc/depot/clause/GroupBy.java | 59 - .../jdbc/depot/clause/InsertClause.java | 76 -- .../samskivert/jdbc/depot/clause/Join.java | 103 -- .../samskivert/jdbc/depot/clause/Limit.java | 65 - .../samskivert/jdbc/depot/clause/OrderBy.java | 98 -- .../jdbc/depot/clause/QueryClause.java | 30 - .../jdbc/depot/clause/SelectClause.java | 226 ---- .../jdbc/depot/clause/UpdateClause.java | 114 -- .../samskivert/jdbc/depot/clause/Where.java | 99 -- .../jdbc/depot/expression/ColumnExp.java | 67 - .../jdbc/depot/expression/EpochSeconds.java | 59 - .../depot/expression/ExpressionVisitor.java | 79 -- .../jdbc/depot/expression/FunctionExp.java | 70 - .../jdbc/depot/expression/LiteralExp.java | 57 - .../jdbc/depot/expression/SQLExpression.java | 48 - .../jdbc/depot/expression/ValueExp.java | 56 - .../jdbc/depot/operator/Arithmetic.java | 145 --- .../jdbc/depot/operator/Conditionals.java | 336 ----- .../samskivert/jdbc/depot/operator/Logic.java | 107 -- .../jdbc/depot/operator/SQLOperator.java | 122 -- .../jdbc/depot/tests/TestRecord.java | 128 -- .../jdbc/depot/tests/TestRepository.java | 126 -- .../jdbc/depot/tools/GenRecordTask.java | 493 ------- .../jdbc/depot/tools/record_column.tmpl | 3 - .../jdbc/depot/tools/record_key.tmpl | 11 - .../jdbc/depot/tools/record_name.tmpl | 2 - 82 files changed, 11659 deletions(-) delete mode 100644 src/java/com/samskivert/jdbc/depot/BindVisitor.java delete mode 100644 src/java/com/samskivert/jdbc/depot/BuildVisitor.java delete mode 100644 src/java/com/samskivert/jdbc/depot/ByteEnum.java delete mode 100644 src/java/com/samskivert/jdbc/depot/CacheAdapter.java delete mode 100644 src/java/com/samskivert/jdbc/depot/CacheInvalidator.java delete mode 100644 src/java/com/samskivert/jdbc/depot/CacheKey.java delete mode 100644 src/java/com/samskivert/jdbc/depot/DataMigration.java delete mode 100644 src/java/com/samskivert/jdbc/depot/DatabaseException.java delete mode 100644 src/java/com/samskivert/jdbc/depot/DepotMarshaller.java delete mode 100644 src/java/com/samskivert/jdbc/depot/DepotMigrationHistoryRecord.java delete mode 100644 src/java/com/samskivert/jdbc/depot/DepotRepository.java delete mode 100644 src/java/com/samskivert/jdbc/depot/DepotTypes.java delete mode 100644 src/java/com/samskivert/jdbc/depot/DuplicateKeyException.java delete mode 100644 src/java/com/samskivert/jdbc/depot/EHCacheAdapter.java delete mode 100644 src/java/com/samskivert/jdbc/depot/FieldMarshaller.java delete mode 100644 src/java/com/samskivert/jdbc/depot/FindAllQuery.java delete mode 100644 src/java/com/samskivert/jdbc/depot/FindOneQuery.java delete mode 100644 src/java/com/samskivert/jdbc/depot/IdentityValueGenerator.java delete mode 100644 src/java/com/samskivert/jdbc/depot/Key.java delete mode 100644 src/java/com/samskivert/jdbc/depot/KeySet.java delete mode 100644 src/java/com/samskivert/jdbc/depot/KeyUtil.java delete mode 100644 src/java/com/samskivert/jdbc/depot/Log.java delete mode 100644 src/java/com/samskivert/jdbc/depot/Modifier.java delete mode 100644 src/java/com/samskivert/jdbc/depot/MultiKey.java delete mode 100644 src/java/com/samskivert/jdbc/depot/MySQLBuilder.java delete mode 100644 src/java/com/samskivert/jdbc/depot/Operation.java delete mode 100644 src/java/com/samskivert/jdbc/depot/PersistenceContext.java delete mode 100644 src/java/com/samskivert/jdbc/depot/PersistentRecord.java delete mode 100644 src/java/com/samskivert/jdbc/depot/PostgreSQLBuilder.java delete mode 100644 src/java/com/samskivert/jdbc/depot/Query.java delete mode 100644 src/java/com/samskivert/jdbc/depot/SQLBuilder.java delete mode 100644 src/java/com/samskivert/jdbc/depot/SchemaMigration.java delete mode 100644 src/java/com/samskivert/jdbc/depot/SimpleCacheKey.java delete mode 100644 src/java/com/samskivert/jdbc/depot/TableValueGenerator.java delete mode 100644 src/java/com/samskivert/jdbc/depot/ValidatingCacheInvalidator.java delete mode 100644 src/java/com/samskivert/jdbc/depot/ValueGenerator.java delete mode 100644 src/java/com/samskivert/jdbc/depot/WhereClause.java delete mode 100644 src/java/com/samskivert/jdbc/depot/annotation/Column.java delete mode 100644 src/java/com/samskivert/jdbc/depot/annotation/Computed.java delete mode 100644 src/java/com/samskivert/jdbc/depot/annotation/Entity.java delete mode 100644 src/java/com/samskivert/jdbc/depot/annotation/FullTextIndex.java delete mode 100644 src/java/com/samskivert/jdbc/depot/annotation/GeneratedValue.java delete mode 100644 src/java/com/samskivert/jdbc/depot/annotation/GenerationType.java delete mode 100644 src/java/com/samskivert/jdbc/depot/annotation/Id.java delete mode 100644 src/java/com/samskivert/jdbc/depot/annotation/Index.java delete mode 100644 src/java/com/samskivert/jdbc/depot/annotation/TableGenerator.java delete mode 100644 src/java/com/samskivert/jdbc/depot/annotation/Transient.java delete mode 100644 src/java/com/samskivert/jdbc/depot/annotation/UniqueConstraint.java delete mode 100644 src/java/com/samskivert/jdbc/depot/clause/DeleteClause.java delete mode 100644 src/java/com/samskivert/jdbc/depot/clause/FieldDefinition.java delete mode 100644 src/java/com/samskivert/jdbc/depot/clause/FieldOverride.java delete mode 100644 src/java/com/samskivert/jdbc/depot/clause/ForUpdate.java delete mode 100644 src/java/com/samskivert/jdbc/depot/clause/FromOverride.java delete mode 100644 src/java/com/samskivert/jdbc/depot/clause/GroupBy.java delete mode 100644 src/java/com/samskivert/jdbc/depot/clause/InsertClause.java delete mode 100644 src/java/com/samskivert/jdbc/depot/clause/Join.java delete mode 100644 src/java/com/samskivert/jdbc/depot/clause/Limit.java delete mode 100644 src/java/com/samskivert/jdbc/depot/clause/OrderBy.java delete mode 100644 src/java/com/samskivert/jdbc/depot/clause/QueryClause.java delete mode 100644 src/java/com/samskivert/jdbc/depot/clause/SelectClause.java delete mode 100644 src/java/com/samskivert/jdbc/depot/clause/UpdateClause.java delete mode 100644 src/java/com/samskivert/jdbc/depot/clause/Where.java delete mode 100644 src/java/com/samskivert/jdbc/depot/expression/ColumnExp.java delete mode 100644 src/java/com/samskivert/jdbc/depot/expression/EpochSeconds.java delete mode 100644 src/java/com/samskivert/jdbc/depot/expression/ExpressionVisitor.java delete mode 100644 src/java/com/samskivert/jdbc/depot/expression/FunctionExp.java delete mode 100644 src/java/com/samskivert/jdbc/depot/expression/LiteralExp.java delete mode 100644 src/java/com/samskivert/jdbc/depot/expression/SQLExpression.java delete mode 100644 src/java/com/samskivert/jdbc/depot/expression/ValueExp.java delete mode 100644 src/java/com/samskivert/jdbc/depot/operator/Arithmetic.java delete mode 100644 src/java/com/samskivert/jdbc/depot/operator/Conditionals.java delete mode 100644 src/java/com/samskivert/jdbc/depot/operator/Logic.java delete mode 100644 src/java/com/samskivert/jdbc/depot/operator/SQLOperator.java delete mode 100644 src/java/com/samskivert/jdbc/depot/tests/TestRecord.java delete mode 100644 src/java/com/samskivert/jdbc/depot/tests/TestRepository.java delete mode 100644 src/java/com/samskivert/jdbc/depot/tools/GenRecordTask.java delete mode 100644 src/java/com/samskivert/jdbc/depot/tools/record_column.tmpl delete mode 100644 src/java/com/samskivert/jdbc/depot/tools/record_key.tmpl delete mode 100644 src/java/com/samskivert/jdbc/depot/tools/record_name.tmpl diff --git a/build.xml b/build.xml index 08582137..1f14d016 100644 --- a/build.xml +++ b/build.xml @@ -40,22 +40,6 @@ - - - - - - - - - - - - - - @@ -76,8 +60,6 @@ - - @@ -104,7 +86,6 @@ - @@ -143,7 +124,6 @@ - diff --git a/etc/depends-incl.xml b/etc/depends-incl.xml index df84d075..c6d99a38 100644 --- a/etc/depends-incl.xml +++ b/etc/depends-incl.xml @@ -59,14 +59,6 @@ --------------- Other libraries --------------- - - Ant: ${ant.present} - - - EH Cache: ${ehcache.present} - JUnit: ${junit.present} @@ -100,22 +92,6 @@ com.samskivert.jdbc: ${build.jdbc} - - - - - - - com.samskivert.jdbc.depot.ehcace: ${build.depot.ehcache} - - - - - - - - com.samskivert.jdbc.depot.tools: ${build.depot.tools} - diff --git a/src/java/com/samskivert/Utils.gwt.xml b/src/java/com/samskivert/Utils.gwt.xml index 78eee9b0..fd6381bf 100644 --- a/src/java/com/samskivert/Utils.gwt.xml +++ b/src/java/com/samskivert/Utils.gwt.xml @@ -1,6 +1,5 @@ - diff --git a/src/java/com/samskivert/jdbc/depot/BindVisitor.java b/src/java/com/samskivert/jdbc/depot/BindVisitor.java deleted file mode 100644 index 41eea4fe..00000000 --- a/src/java/com/samskivert/jdbc/depot/BindVisitor.java +++ /dev/null @@ -1,307 +0,0 @@ -// -// $Id$ -// -// samskivert library - useful routines for java programs -// Copyright (C) 2006-2007 Michael Bayne, Pär Winzell -// -// This library is free software; you can redistribute it and/or modify it -// under the terms of the GNU Lesser General Public License as published -// by the Free Software Foundation; either version 2.1 of the License, or -// (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -package com.samskivert.jdbc.depot; - -import java.nio.ByteBuffer; -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.SQLException; -import java.util.Map; -import java.util.Set; - -import com.samskivert.jdbc.depot.clause.DeleteClause; -import com.samskivert.jdbc.depot.clause.FieldDefinition; -import com.samskivert.jdbc.depot.clause.ForUpdate; -import com.samskivert.jdbc.depot.clause.FromOverride; -import com.samskivert.jdbc.depot.clause.GroupBy; -import com.samskivert.jdbc.depot.clause.InsertClause; -import com.samskivert.jdbc.depot.clause.Join; -import com.samskivert.jdbc.depot.clause.Limit; -import com.samskivert.jdbc.depot.clause.OrderBy; -import com.samskivert.jdbc.depot.clause.SelectClause; -import com.samskivert.jdbc.depot.clause.UpdateClause; -import com.samskivert.jdbc.depot.expression.ColumnExp; -import com.samskivert.jdbc.depot.expression.EpochSeconds; -import com.samskivert.jdbc.depot.expression.ExpressionVisitor; -import com.samskivert.jdbc.depot.expression.FunctionExp; -import com.samskivert.jdbc.depot.expression.LiteralExp; -import com.samskivert.jdbc.depot.expression.SQLExpression; -import com.samskivert.jdbc.depot.expression.ValueExp; -import com.samskivert.jdbc.depot.operator.Conditionals.Exists; -import com.samskivert.jdbc.depot.operator.Conditionals.FullTextMatch; -import com.samskivert.jdbc.depot.operator.Conditionals.In; -import com.samskivert.jdbc.depot.operator.Conditionals.IsNull; -import com.samskivert.jdbc.depot.operator.Logic.Not; -import com.samskivert.jdbc.depot.operator.SQLOperator.BinaryOperator; -import com.samskivert.jdbc.depot.operator.SQLOperator.MultiOperator; - -import com.samskivert.util.StringUtil; - -/** - * Implements the base functionality of the argument-binding pass of {@link SQLBuilder}. Dialectal - * subclasses of this should be created and returned from {@link SQLBuilder#getBindVisitor}. - * - * This class is intimately paired with {#link BuildVisitor}. - */ -public class BindVisitor implements ExpressionVisitor -{ - public void visit (FromOverride override) - { - // nothing needed - } - - public void visit (FieldDefinition fieldOverride) - { - // nothing needed - } - - public void visit (Key.Expression key) - { - for (Comparable value : key.getValues()) { - if (value != null) { - writeValueToStatement(value); - } - } - } - - public void visit (MultiKey key) - { - for (Map.Entry> entry : key.getSingleFieldsMap().entrySet()) { - if (entry.getValue() != null) { - writeValueToStatement(entry.getValue()); - } - } - Comparable[] values = key.getMultiValues(); - for (int ii = 0; ii < values.length; ii++) { - writeValueToStatement(values[ii]); - } - } - - public void visit (FunctionExp functionExp) - { - visit(functionExp.getArguments()); - } - - public void visit (EpochSeconds epochSeconds) - { - epochSeconds.getArgument().accept(this); - } - - public void visit (MultiOperator multiOperator) - { - visit(multiOperator.getConditions()); - } - - public void visit (BinaryOperator binaryOperator) - { - binaryOperator.getLeftHandSide().accept(this); - binaryOperator.getRightHandSide().accept(this); - } - - public void visit (IsNull isNull) - { - } - - public void visit (In in) - { - Comparable[] values = in.getValues(); - for (int ii = 0; ii < values.length; ii++) { - writeValueToStatement(values[ii]); - } - } - - public void visit (FullTextMatch match) - { - // we never get here - } - - public void visit (ColumnExp columnExp) - { - // no arguments - } - - public void visit (Not not) - { - not.getCondition().accept(this); - } - - public void visit (GroupBy groupBy) - { - visit(groupBy.getValues()); - } - - public void visit (ForUpdate forUpdate) - { - // do nothing - } - - public void visit (OrderBy orderBy) - { - visit(orderBy.getValues()); - } - - public void visit (WhereClause where) - { - where.getWhereExpression().accept(this); - } - - public void visit (Join join) - { - join.getJoinCondition().accept(this); - } - - public void visit (Limit limit) - { - try { - _stmt.setInt(_argIdx++, limit.getCount()); - _stmt.setInt(_argIdx++, limit.getOffset()); - } catch (SQLException sqe) { - throw new DatabaseException("Failed to configure statement with limit clause " + - "[count=" + limit.getCount() + - ", offset=" + limit.getOffset() + "]", sqe); - } - } - - public void visit (LiteralExp literalExp) - { - // do nothing - } - - public void visit (ValueExp valueExp) - { - writeValueToStatement(valueExp.getValue()); - } - - public void visit (Exists exists) - { - exists.getSubClause().accept(this); - } - - public void visit (SelectClause selectClause) - { - for (Join clause : selectClause.getJoinClauses()) { - clause.accept(this); - } - if (selectClause.getWhereClause() != null) { - selectClause.getWhereClause().accept(this); - } - if (selectClause.getGroupBy() != null) { - selectClause.getGroupBy().accept(this); - } - if (selectClause.getOrderBy() != null) { - selectClause.getOrderBy().accept(this); - } - if (selectClause.getLimit() != null) { - selectClause.getLimit().accept(this); - } - if (selectClause.getForUpdate() != null) { - selectClause.getForUpdate().accept(this); - } - } - - public void visit (UpdateClause updateClause) - { - DepotMarshaller marsh = _types.getMarshaller(updateClause.getPersistentClass()); - - // bind the update arguments - Object pojo = updateClause.getPojo(); - if (pojo != null) { - for (String field : updateClause.getFields()) { - try { - marsh.getFieldMarshaller(field).getAndWriteToStatement(_stmt, _argIdx++, pojo); - } catch (Exception e) { - throw new DatabaseException( - "Failed to read field from persistent record and write it to prepared " + - "statement [field=" + field + "]", e); - } - } - } else { - visit(updateClause.getValues()); - } - updateClause.getWhereClause().accept(this); - } - - public void visit (InsertClause insertClause) - { - DepotMarshaller marsh = _types.getMarshaller(insertClause.getPersistentClass()); - Object pojo = insertClause.getPojo(); - Set idFields = insertClause.getIdentityFields(); - for (String field : marsh.getColumnFieldNames()) { - if (!idFields.contains(field)) { - try { - marsh.getFieldMarshaller(field).getAndWriteToStatement(_stmt, _argIdx++, pojo); - } catch (Exception e) { - throw new DatabaseException( - "Failed to read field from persistent record and write it to prepared " + - "statement [field=" + field + "]", e); - } - } - } - } - - public void visit (DeleteClause deleteClause) - { - deleteClause.getWhereClause().accept(this); - } - - protected BindVisitor (DepotTypes types, Connection conn, PreparedStatement stmt) - { - _types = types; - _conn = conn; - _stmt = stmt; - _argIdx = 1; - } - - protected void visit (SQLExpression[] expressions) - { - for (int ii = 0; ii < expressions.length; ii ++) { - expressions[ii].accept(this); - } - } - - // write the value to the next argument slot in the prepared statement - protected void writeValueToStatement (Object value) - { - try { - // TODO: how can we abstract this fieldless marshalling - if (value instanceof ByteEnum) { - // byte enums require special conversion - _stmt.setByte(_argIdx++, ((ByteEnum)value).toByte()); - } else if (value instanceof int[]) { - // int arrays require conversion to byte arrays - int[] data = (int[])value; - ByteBuffer bbuf = ByteBuffer.allocate(data.length * 4); - bbuf.asIntBuffer().put(data); - _stmt.setObject(_argIdx++, bbuf.array()); - } else { - _stmt.setObject(_argIdx++, value); - } - } catch (SQLException sqe) { - throw new DatabaseException("Failed to write value to statement [idx=" + (_argIdx-1) + - ", value=" + StringUtil.safeToString(value) + "]", sqe); - } - } - - protected DepotTypes _types; - protected Connection _conn; - protected PreparedStatement _stmt; - protected int _argIdx; -} diff --git a/src/java/com/samskivert/jdbc/depot/BuildVisitor.java b/src/java/com/samskivert/jdbc/depot/BuildVisitor.java deleted file mode 100644 index 13141d87..00000000 --- a/src/java/com/samskivert/jdbc/depot/BuildVisitor.java +++ /dev/null @@ -1,611 +0,0 @@ -// -// $Id$ -// -// samskivert library - useful routines for java programs -// Copyright (C) 2006-2007 Michael Bayne, Pär Winzell -// -// This library is free software; you can redistribute it and/or modify it -// under the terms of the GNU Lesser General Public License as published -// by the Free Software Foundation; either version 2.1 of the License, or -// (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -package com.samskivert.jdbc.depot; - -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import com.samskivert.jdbc.depot.annotation.Computed; -import com.samskivert.jdbc.depot.clause.DeleteClause; -import com.samskivert.jdbc.depot.clause.FieldDefinition; -import com.samskivert.jdbc.depot.clause.FieldOverride; -import com.samskivert.jdbc.depot.clause.ForUpdate; -import com.samskivert.jdbc.depot.clause.FromOverride; -import com.samskivert.jdbc.depot.clause.GroupBy; -import com.samskivert.jdbc.depot.clause.InsertClause; -import com.samskivert.jdbc.depot.clause.Join; -import com.samskivert.jdbc.depot.clause.Limit; -import com.samskivert.jdbc.depot.clause.OrderBy; -import com.samskivert.jdbc.depot.clause.SelectClause; -import com.samskivert.jdbc.depot.clause.UpdateClause; -import com.samskivert.jdbc.depot.expression.ColumnExp; -import com.samskivert.jdbc.depot.expression.EpochSeconds; -import com.samskivert.jdbc.depot.expression.ExpressionVisitor; -import com.samskivert.jdbc.depot.expression.FunctionExp; -import com.samskivert.jdbc.depot.expression.LiteralExp; -import com.samskivert.jdbc.depot.expression.SQLExpression; -import com.samskivert.jdbc.depot.expression.ValueExp; -import com.samskivert.jdbc.depot.operator.Conditionals.Exists; -import com.samskivert.jdbc.depot.operator.Conditionals.FullTextMatch; -import com.samskivert.jdbc.depot.operator.Conditionals.In; -import com.samskivert.jdbc.depot.operator.Conditionals.IsNull; -import com.samskivert.jdbc.depot.operator.Logic.Not; -import com.samskivert.jdbc.depot.operator.SQLOperator.BinaryOperator; -import com.samskivert.jdbc.depot.operator.SQLOperator.MultiOperator; - -/** - * Implements the base functionality of the SQL-building pass of {@link SQLBuilder}. Dialectal - * subclasses of this should be created and returned from {@link SQLBuilder#getBuildVisitor()}. - * - * This class is intimately paired with {#link BindVisitor}. - */ -public abstract class BuildVisitor implements ExpressionVisitor -{ - public String getQuery () - { - return _builder.toString(); - } - - public void visit (FromOverride override) - { - _builder.append(" from " ); - List> from = override.getFromClasses(); - for (int ii = 0; ii < from.size(); ii++) { - if (ii > 0) { - _builder.append(", "); - } - appendTableName(from.get(ii)); - _builder.append(" as "); - appendTableAbbreviation(from.get(ii)); - } - } - - public void visit (FieldDefinition definition) - { - definition.getDefinition().accept(this); - if (_enableAliasing) { - _builder.append(" as "); - appendIdentifier(definition.getField()); - } - } - - public void visit (WhereClause where) - { - _builder.append(" where "); - where.getWhereExpression().accept(this); - } - - public void visit (Key.Expression key) - { - Class pClass = key.getPersistentClass(); - String[] keyFields = KeyUtil.getKeyFields(pClass); - List> values = key.getValues(); - for (int ii = 0; ii < keyFields.length; ii ++) { - if (ii > 0) { - _builder.append(" and "); - } - // A Key's WHERE clause must mirror what's actually retrieved for the persistent - // object, so we turn on overrides here just as we do when expanding SELECT fields - boolean saved = _enableOverrides; - _enableOverrides = true; - appendRhsColumn(pClass, keyFields[ii]); - _enableOverrides = saved; - _builder.append(values.get(ii) == null ? " is null " : " = ? "); - } - } - - public void visit (MultiKey key) - { - _builder.append(" where "); - boolean first = true; - for (Map.Entry> entry : key.getSingleFieldsMap().entrySet()) { - if (first) { - first = false; - } else { - _builder.append(" and "); - } - // A MultiKey's WHERE clause must mirror what's actually retrieved for the persistent - // object, so we turn on overrides here just as we do when expanding SELECT fields - boolean saved = _enableOverrides; - _enableOverrides = true; - appendRhsColumn(key.getPersistentClass(), entry.getKey()); - _enableOverrides = saved; - _builder.append(entry.getValue() == null ? " is null " : " = ? "); - } - if (!first) { - _builder.append(" and "); - } - appendRhsColumn(key.getPersistentClass(), key.getMultiField()); - _builder.append(" in ("); - - Comparable[] values = key.getMultiValues(); - for (int ii = 0; ii < values.length; ii ++) { - if (ii > 0) { - _builder.append(", "); - } - _builder.append("?"); - } - _builder.append(")"); - } - - public void visit (FunctionExp functionExp) - { - _builder.append(functionExp.getFunction()); - _builder.append("("); - SQLExpression[] arguments = functionExp.getArguments(); - for (int ii = 0; ii < arguments.length; ii ++) { - if (ii > 0) { - _builder.append(", "); - } - arguments[ii].accept(this); - } - _builder.append(")"); - } - - public void visit (MultiOperator multiOperator) - { - SQLExpression[] conditions = multiOperator.getConditions(); - for (int ii = 0; ii < conditions.length; ii++) { - if (ii > 0) { - _builder.append(" ").append(multiOperator.operator()).append(" "); - } - _builder.append("("); - conditions[ii].accept(this); - _builder.append(")"); - } - } - - public void visit (BinaryOperator binaryOperator) - { - _builder.append('('); - binaryOperator.getLeftHandSide().accept(this); - _builder.append(binaryOperator.operator()); - binaryOperator.getRightHandSide().accept(this); - _builder.append(')'); - } - - public void visit (IsNull isNull) - { - isNull.getColumn().accept(this); - _builder.append(" is null"); - } - - public void visit (In in) - { - in.getColumn().accept(this); - _builder.append(" in ("); - Comparable[] values = in.getValues(); - for (int ii = 0; ii < values.length; ii ++) { - if (ii > 0) { - _builder.append(", "); - } - _builder.append("?"); - } - _builder.append(")"); - } - - public abstract void visit (EpochSeconds seconds); - - public abstract void visit (FullTextMatch match); - - public void visit (ColumnExp columnExp) - { - appendRhsColumn(columnExp.getPersistentClass(), columnExp.getField()); - } - - public void visit (Not not) - { - _builder.append(" not ("); - not.getCondition().accept(this); - _builder.append(")"); - } - - public void visit (GroupBy groupBy) - { - _builder.append(" group by "); - - SQLExpression[] values = groupBy.getValues(); - for (int ii = 0; ii < values.length; ii++) { - if (ii > 0) { - _builder.append(", "); - } - values[ii].accept(this); - } - } - - public void visit (ForUpdate forUpdate) - { - _builder.append(" for update "); - } - - public void visit (OrderBy orderBy) - { - _builder.append(" order by "); - - SQLExpression[] values = orderBy.getValues(); - OrderBy.Order[] orders = orderBy.getOrders(); - for (int ii = 0; ii < values.length; ii++) { - if (ii > 0) { - _builder.append(", "); - } - values[ii].accept(this); - _builder.append(" ").append(orders[ii]); - } - } - - public void visit (Join join) - { - switch (join.getType()) { - case INNER: - _builder.append(" inner join " ); - break; - case LEFT_OUTER: - _builder.append(" left outer join " ); - break; - case RIGHT_OUTER: - _builder.append(" right outer join " ); - break; - } - appendTableName(join.getJoinClass()); - _builder.append(" as "); - appendTableAbbreviation(join.getJoinClass()); - _builder.append(" on "); - join.getJoinCondition().accept(this); - } - - public void visit (Limit limit) - { - _builder.append(" limit ? offset ? "); - } - - public void visit (LiteralExp literalExp) - { - _builder.append(literalExp.getText()); - } - - public void visit (ValueExp valueExp) - { - _builder.append("?"); - } - - public void visit (Exists exists) - { - _builder.append("exists "); - exists.getSubClause().accept(this); - } - - public void visit (SelectClause selectClause) - { - Class pClass = selectClause.getPersistentClass(); - boolean isInner = _innerClause; - _innerClause = true; - - if (isInner) { - _builder.append("("); - } - _builder.append("select "); - - if (_definitions.containsKey(pClass)) { - throw new IllegalArgumentException( - "Can not yet nest SELECTs on the same persistent record."); - } - - Map definitionMap = new HashMap(); - for (FieldDefinition definition : selectClause.getFieldDefinitions()) { - definitionMap.put(definition.getField(), definition); - } - _definitions.put(pClass, definitionMap); - - try { - // iterate over the fields we're filling in and figure out whence each one comes - boolean skip = true; - - // while expanding column names in the SELECT query, do aliasing and expansion - _enableAliasing = _enableOverrides = true; - - for (String field : selectClause.getFields()) { - if (!skip) { - _builder.append(", "); - } - skip = false; - - int len = _builder.length(); - appendRhsColumn(pClass, field); - - // if nothing was added, don't add a comma - if (_builder.length() == len) { - skip = true; - } - } - - // then stop - _enableAliasing = _enableOverrides = false; - - if (selectClause.getFromOverride() != null) { - selectClause.getFromOverride().accept(this); - - } else { - Computed computed = _types.getMarshaller(pClass).getComputed(); - Class tClass; - if (computed != null && !PersistentRecord.class.equals(computed.shadowOf())) { - tClass = computed.shadowOf(); - } else if (_types.getTableName(pClass) != null) { - tClass = pClass; - } else { - throw new IllegalStateException( - "Query on @Computed entity with no FromOverrideClause."); - } - _builder.append(" from "); - appendTableName(tClass); - _builder.append(" as "); - appendTableAbbreviation(tClass); - } - - for (Join clause : selectClause.getJoinClauses()) { - clause.accept(this); - } - if (selectClause.getWhereClause() != null) { - selectClause.getWhereClause().accept(this); - } - if (selectClause.getGroupBy() != null) { - selectClause.getGroupBy().accept(this); - } - if (selectClause.getOrderBy() != null) { - selectClause.getOrderBy().accept(this); - } - if (selectClause.getLimit() != null) { - selectClause.getLimit().accept(this); - } - if (selectClause.getForUpdate() != null) { - selectClause.getForUpdate().accept(this); - } - - } finally { - _definitions.remove(pClass); - } - if (isInner) { - _builder.append(")"); - } - } - - public void visit (UpdateClause updateClause) - { - if (updateClause.getWhereClause() == null) { - throw new IllegalArgumentException( - "I dare not currently perform UPDATE without a WHERE clause."); - } - Class pClass = updateClause.getPersistentClass(); - _innerClause = true; - - _builder.append("update "); - appendTableName(pClass); - _builder.append(" as "); - appendTableAbbreviation(pClass); - _builder.append(" set "); - - String[] fields = updateClause.getFields(); - Object pojo = updateClause.getPojo(); - SQLExpression[] values = updateClause.getValues(); - for (int ii = 0; ii < fields.length; ii ++) { - if (ii > 0) { - _builder.append(", "); - } - appendLhsColumn(pClass, fields[ii]); - - _builder.append(" = "); - if (pojo != null) { - _builder.append("?"); - } else { - values[ii].accept(this); - } - } - updateClause.getWhereClause().accept(this); - } - - public void visit (DeleteClause deleteClause) - { - _builder.append("delete from "); - appendTableName(deleteClause.getPersistentClass()); - _builder.append(" as "); - appendTableAbbreviation(deleteClause.getPersistentClass()); - _builder.append(" "); - deleteClause.getWhereClause().accept(this); - } - - public void visit (InsertClause insertClause) - { - Class pClass = insertClause.getPersistentClass(); - DepotMarshaller marsh = _types.getMarshaller(pClass); - _innerClause = true; - - String[] fields = marsh.getColumnFieldNames(); - - _builder.append("insert into "); - appendTableName(insertClause.getPersistentClass()); - _builder.append(" ("); - for (int ii = 0; ii < fields.length; ii ++) { - if (ii > 0) { - _builder.append(", "); - } - appendLhsColumn(pClass, fields[ii]); - } - _builder.append(") values("); - - Set idFields = insertClause.getIdentityFields(); - for (int ii = 0; ii < fields.length; ii++) { - if (ii > 0) { - _builder.append(", "); - } - if (idFields.contains(fields[ii])) { - _builder.append("DEFAULT"); - } else { - _builder.append("?"); - } - } - _builder.append(")"); - } - - protected abstract void appendIdentifier (String field); - - protected void appendTableName (Class type) - { - appendIdentifier(_types.getTableName(type)); - } - - protected void appendTableAbbreviation (Class type) - { - appendIdentifier(_types.getTableAbbreviation(type)); - } - - // Constructs a name used for assignment in e.g. INSERT/UPDATE. This is the SQL - // equivalent of an lvalue; something that can appear to the left of an equals sign. - // We do not prepend this identifier with a table abbreviation, nor do we expand - // field overrides, shadowOf declarations, or the like: it is just a column name. - protected void appendLhsColumn (Class type, String field) - { - DepotMarshaller dm = _types.getMarshaller(type); - if (dm == null) { - throw new IllegalArgumentException( - "Unknown field on persistent record [record=" + type + ", field=" + field + "]"); - } - - FieldMarshaller fm = dm.getFieldMarshaller(field); - appendIdentifier(fm.getColumnName()); - } - - // Appends an expression for the given field on the given persistent record; this can - // appear in a SELECT list, in WHERE clauses, etc, etc. - protected void appendRhsColumn (Class type, String field) - { - DepotMarshaller dm = _types.getMarshaller(type); - if (dm == null) { - throw new IllegalArgumentException( - "Unknown field on persistent record [record=" + type + ", field=" + field + "]"); - } - - // first, see if there's a field definition - FieldMarshaller fm = dm.getFieldMarshaller(field); - Map fieldDefs = _definitions.get(type); - if (fieldDefs != null) { - FieldDefinition fieldDef = fieldDefs.get(field); - if (fieldDef != null) { - boolean useOverride; - if (fieldDef instanceof FieldOverride) { - if (fm.getComputed() != null && dm.getComputed() != null) { - throw new IllegalArgumentException( - "FieldOverride cannot be used on @Computed field: " + field); - } - useOverride = _enableOverrides; - } else if (fm.getComputed() == null && dm.getComputed() == null) { - throw new IllegalArgumentException( - "FieldDefinition must not be used on concrete field: " + field); - } else { - useOverride = true; - } - - if (useOverride) { - // If a FieldOverride's target is in turn another FieldOverride, the second one - // is ignored. As an example, when creating ItemRecords from CloneRecords, we - // make Item.itemId = Clone.itemId. We also make Item.parentId = Item.itemId - // and would be dismayed to find Item.parentID = Item.itemId = Clone.itemId. - boolean saved = _enableOverrides; - _enableOverrides = false; - fieldDef.accept(this); - _enableOverrides = saved; - return; - } - } - } - - Computed entityComputed = dm.getComputed(); - - // figure out the class we're selecting from unless we're otherwise overriden: - // for a concrete record, simply use the corresponding table; for a computed one, - // default to the shadowed concrete record, or null if there isn't one - Class tableClass; - if (entityComputed == null) { - tableClass = type; - } else if (!PersistentRecord.class.equals(entityComputed.shadowOf())) { - tableClass = entityComputed.shadowOf(); - } else { - tableClass = null; - } - - // handle the field-level @Computed annotation, if there is one - Computed fieldComputed = fm.getComputed(); - if (fieldComputed != null) { - // check if the computed field has a literal SQL definition - if (fieldComputed.fieldDefinition().length() > 0) { - _builder.append(fieldComputed.fieldDefinition()); - if (_enableAliasing) { - _builder.append(" as "); - appendIdentifier(field); - } - return; - } - - // or if we can simply ignore the field - if (!fieldComputed.required()) { - return; - } - - // else see if there's an overriding shadowOf definition - if (fieldComputed.shadowOf() != null) { - tableClass = fieldComputed.shadowOf(); - } - } - - // if we get this far we hopefully have a table to select from - if (tableClass != null) { - appendTableAbbreviation(tableClass); - _builder.append("."); - appendIdentifier(fm.getColumnName()); - return; - } - - // else owie - throw new IllegalArgumentException( - "Persistent field has no definition [class=" + type + ", field=" + field + "]"); - } - - protected BuildVisitor (DepotTypes types) - { - _types = types; - } - - protected DepotTypes _types; - - /** A StringBuilder to hold the constructed SQL. */ - protected StringBuilder _builder = new StringBuilder(); - - /** A mapping of field overrides per persistent record. */ - protected Map, Map> _definitions= - new HashMap, Map>(); - - /** A flag that's set to true for inner SELECT's */ - protected boolean _innerClause = false; - - protected boolean _enableOverrides = false; - - protected boolean _enableAliasing = false; -} diff --git a/src/java/com/samskivert/jdbc/depot/ByteEnum.java b/src/java/com/samskivert/jdbc/depot/ByteEnum.java deleted file mode 100644 index 77df3231..00000000 --- a/src/java/com/samskivert/jdbc/depot/ByteEnum.java +++ /dev/null @@ -1,39 +0,0 @@ -// -// $Id$ -// -// samskivert library - useful routines for java programs -// Copyright (C) 2006-2007 Michael Bayne, Pär Winzell -// -// This library is free software; you can redistribute it and/or modify it -// under the terms of the GNU Lesser General Public License as published -// by the Free Software Foundation; either version 2.1 of the License, or -// (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -package com.samskivert.jdbc.depot; - -/** - * An enum value can be used as a field in a persistent object if it implements this interface and - * also declares a public static method with the following signature: - * - * - * public static YourEnum fromByte (byte value) - * - * - * which must return the appropriate instance of your enum for the supplied byte. - */ -public interface ByteEnum -{ - /** - * Returns the byte value to which to map this enum value. - */ - public byte toByte (); -} diff --git a/src/java/com/samskivert/jdbc/depot/CacheAdapter.java b/src/java/com/samskivert/jdbc/depot/CacheAdapter.java deleted file mode 100644 index 3ab935fa..00000000 --- a/src/java/com/samskivert/jdbc/depot/CacheAdapter.java +++ /dev/null @@ -1,77 +0,0 @@ -// -// $Id$ -// -// samskivert library - useful routines for java programs -// Copyright (C) 2006-2007 Michael Bayne, Pär Winzell -// -// This library is free software; you can redistribute it and/or modify it -// under the terms of the GNU Lesser General Public License as published -// by the Free Software Foundation; either version 2.1 of the License, or -// (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -package com.samskivert.jdbc.depot; - -import java.io.Serializable; - -/** - * Implementations of this interface are responsible for all the caching needs of Depot. - * - * The cache consists of many {@link CacheBin}s. Each bin its own key space. Look-ups and storage - * occur on a per-bin per-key basis. - */ -public interface CacheAdapter -{ - /** The encapsulated result of a cache lookup. */ - public interface CachedValue - { - /** Returns the cached value, which can be null. */ - public T getValue (); - } - - /** - * A reference to a specific bin within the cache; this is the type where most of the actual - * caching functionality occurs. - */ - public interface CacheBin - { - /** - * Searches this bin using the given key and returns the resulting {@link CachedValue}, or - * null if nothing exists in the cache for this key. - */ - public CachedValue lookup (Serializable key); - - /** - * Stores a new value in this cache bin under the given key. - */ - public void store (Serializable key, T value); - - /** - * Removes the cache entry, if any, associated with the given key. - */ - public void remove (Serializable key); - - /** - * Provides a way to enumerate the currently cached entries in this bin. - */ - public Iterable enumerateKeys (); - } - - /** - * Fetch the {@link CacheBin} associated with the given ID, creating one on the fly if needed. - */ - public CacheBin getCache (String id); - - /** - * Shut down all operations, e.g. persisting memory contents to disk. - */ - public void shutdown (); -} diff --git a/src/java/com/samskivert/jdbc/depot/CacheInvalidator.java b/src/java/com/samskivert/jdbc/depot/CacheInvalidator.java deleted file mode 100644 index 525ef60d..00000000 --- a/src/java/com/samskivert/jdbc/depot/CacheInvalidator.java +++ /dev/null @@ -1,61 +0,0 @@ -// -// $Id$ -// -// samskivert library - useful routines for java programs -// Copyright (C) 2006-2007 Michael Bayne, Pär Winzell -// -// This library is free software; you can redistribute it and/or modify it -// under the terms of the GNU Lesser General Public License as published -// by the Free Software Foundation; either version 2.1 of the License, or -// (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -package com.samskivert.jdbc.depot; - -import java.io.Serializable; - -/** - * Implementors of this interface performs perform cache invalidation for calls to - * {@link DepotRepository#updateLiteral}, {@link DepotRepository#updatePartial} and - * {@link DepotRepository#deleteAll}. - */ -public interface CacheInvalidator -{ - public static abstract class TraverseWithFilter - implements CacheInvalidator - { - public TraverseWithFilter (Class pClass) { - this(pClass.getName()); - } - - public TraverseWithFilter (String cacheId) { - _cacheId = cacheId; - } - - public void invalidate (PersistenceContext ctx) { - ctx.cacheTraverse(_cacheId, new PersistenceContext.CacheEvictionFilter() { - @Override protected boolean testForEviction (Serializable key, T record) { - return TraverseWithFilter.this.testForEviction(key, record); - } - }); - } - - protected abstract boolean testForEviction (Serializable key, T record); - - protected String _cacheId; - } - - /** - * Must invalidate all cache entries that depend on the records being modified or deleted. - * This method is called just before the database statement is executed. - */ - public void invalidate (PersistenceContext ctx); -} diff --git a/src/java/com/samskivert/jdbc/depot/CacheKey.java b/src/java/com/samskivert/jdbc/depot/CacheKey.java deleted file mode 100644 index 271d528c..00000000 --- a/src/java/com/samskivert/jdbc/depot/CacheKey.java +++ /dev/null @@ -1,42 +0,0 @@ -// -// $Id$ -// -// samskivert library - useful routines for java programs -// Copyright (C) 2006-2007 Michael Bayne, Pär Winzell -// -// This library is free software; you can redistribute it and/or modify it -// under the terms of the GNU Lesser General Public License as published -// by the Free Software Foundation; either version 2.1 of the License, or -// (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -package com.samskivert.jdbc.depot; - -import java.io.Serializable; - -/** - * This interface uniquely identifies a single persistent entry for caching purposes. - * Queries that are given a {@link CacheKey} consult the cache before they hit the - * database. - */ -public interface CacheKey -{ - /** - * Returns the id of the cache in whose scope this key makes sense. - */ - public String getCacheId (); - - /** - * Returns the actual opaque serializable cache key under which results are stored - * in the cache identified by {@link #getCacheId}. - */ - public Serializable getCacheKey (); -} diff --git a/src/java/com/samskivert/jdbc/depot/DataMigration.java b/src/java/com/samskivert/jdbc/depot/DataMigration.java deleted file mode 100644 index c05548f8..00000000 --- a/src/java/com/samskivert/jdbc/depot/DataMigration.java +++ /dev/null @@ -1,73 +0,0 @@ -// -// $Id$ -// -// samskivert library - useful routines for java programs -// Copyright (C) 2001-2008 Michael Bayne -// -// This library is free software; you can redistribute it and/or modify it -// under the terms of the GNU Lesser General Public License as published -// by the Free Software Foundation; either version 2.1 of the License, or -// (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -package com.samskivert.jdbc.depot; - -/** - * Encapsulates a migration of data between entities that should be run only once and using the - * same safeguards applied to entity migrations. Note: this should not be used for schema - * migrations, use {@link SchemaMigration} for that. Data migrations are registered on a specific - * repository via {@link DepotRepository#registerMigration} and should be registered in the - * repository's constructor as they will be invoked (if appropriate) in the repository's {@link - * DepotRepository#init} method. - * - *

In general one will register an anonymous inner class in a repository's constructor and can - * then access methods in the repository directly: - * - *

- * public class FooRepository extends DepotRepository {
- *     public FooRepository (PersistenceContext ctx) {
- *         super(ctx);
- *         registerMigration(new DataMigration("2008_09_25_referral_to_tracking_id") {
- *             public void invoke () throws DatabaseException {
- *                 // feel free to use load() findAll(), update(), etc.
- *             }
- *         });
- *     }
- * 
- */ -public abstract class DataMigration -{ - /** - * Creates a data migration with the specified unique identifier. The identifier must be unique - * across all users of the database and for all time, so be careful. Best to include the date - * and pertintent information, e.g. "2008_09_25_referral_to_tracking_id". - */ - public DataMigration (String ident) - { - _ident = ident; - } - - /** - * Returns the identifier of this migration. - */ - public String getIdent () - { - return _ident; - } - - /** - * Effects the data migration. - */ - public abstract void invoke () throws DatabaseException; - - /** The unique identifier for this migration. */ - protected String _ident; -} diff --git a/src/java/com/samskivert/jdbc/depot/DatabaseException.java b/src/java/com/samskivert/jdbc/depot/DatabaseException.java deleted file mode 100644 index 8d2e524b..00000000 --- a/src/java/com/samskivert/jdbc/depot/DatabaseException.java +++ /dev/null @@ -1,53 +0,0 @@ -// -// $Id$ -// -// samskivert library - useful routines for java programs -// Copyright (C) 2001-2008 Michael Bayne -// -// This library is free software; you can redistribute it and/or modify it -// under the terms of the GNU Lesser General Public License as published -// by the Free Software Foundation; either version 2.1 of the License, or -// (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -package com.samskivert.jdbc.depot; - -/** - * Represents a failure reported by the underlying database. - */ -public class DatabaseException extends RuntimeException -{ - /** - * Constructs a database exception with the specified error message. - */ - public DatabaseException (String message) - { - super(message); - } - - /** - * Constructs a database exception with the specified error message and the chained causing - * event. - */ - public DatabaseException (String message, Throwable cause) - { - super(message); - initCause(cause); - } - - /** - * Constructs a database exception with the specified chained causing event. - */ - public DatabaseException (Throwable cause) - { - initCause(cause); - } -} diff --git a/src/java/com/samskivert/jdbc/depot/DepotMarshaller.java b/src/java/com/samskivert/jdbc/depot/DepotMarshaller.java deleted file mode 100644 index 187f7786..00000000 --- a/src/java/com/samskivert/jdbc/depot/DepotMarshaller.java +++ /dev/null @@ -1,1137 +0,0 @@ -// -// $Id$ -// -// samskivert library - useful routines for java programs -// Copyright (C) 2006-2007 Michael Bayne, Pär Winzell -// -// This library is free software; you can redistribute it and/or modify it -// under the terms of the GNU Lesser General Public License as published -// by the Free Software Foundation; either version 2.1 of the License, or -// (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -package com.samskivert.jdbc.depot; - -import java.lang.reflect.Field; - -import java.sql.Connection; -import java.sql.DatabaseMetaData; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.ResultSetMetaData; -import java.sql.SQLException; -import java.sql.Statement; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - -import com.samskivert.jdbc.depot.annotation.Computed; -import com.samskivert.jdbc.depot.annotation.Entity; -import com.samskivert.jdbc.depot.annotation.FullTextIndex; -import com.samskivert.jdbc.depot.annotation.GeneratedValue; -import com.samskivert.jdbc.depot.annotation.Id; -import com.samskivert.jdbc.depot.annotation.Index; -import com.samskivert.jdbc.depot.annotation.TableGenerator; -import com.samskivert.jdbc.depot.annotation.Transient; -import com.samskivert.jdbc.depot.annotation.UniqueConstraint; - -import com.samskivert.jdbc.ColumnDefinition; -import com.samskivert.jdbc.DatabaseLiaison; -import com.samskivert.util.ArrayUtil; - -import static com.samskivert.jdbc.depot.Log.log; - -/** - * Handles the marshalling and unmarshalling of persistent instances to JDBC primitives ({@link - * PreparedStatement} and {@link ResultSet}). - */ -public class DepotMarshaller -{ - /** The name of a private static field that must be defined for all persistent object classes. - * It is used to handle schema migration. If automatic schema migration is not desired, define - * this field and set its value to -1. */ - public static final String SCHEMA_VERSION_FIELD = "SCHEMA_VERSION"; - - /** - * Creates a marshaller for the specified persistent object class. - */ - public DepotMarshaller (Class pClass, PersistenceContext context) - { - _pClass = pClass; - - Entity entity = pClass.getAnnotation(Entity.class); - - // see if this is a computed entity - _computed = pClass.getAnnotation(Computed.class); - if (_computed == null) { - // if not, this class has a corresponding SQL table - _tableName = _pClass.getName(); - _tableName = _tableName.substring(_tableName.lastIndexOf(".")+1); - - // see if there are Entity values specified - if (entity != null) { - if (entity.name().length() > 0) { - _tableName = entity.name(); - } - } - } - - // if the entity defines a new TableGenerator, map that in our static table as those are - // shared across all entities - TableGenerator generator = pClass.getAnnotation(TableGenerator.class); - if (generator != null) { - context.tableGenerators.put(generator.name(), generator); - } - - boolean seenIdentityGenerator = false; - - // introspect on the class and create marshallers for persistent fields - ArrayList fields = new ArrayList(); - for (Field field : _pClass.getFields()) { - int mods = field.getModifiers(); - - // check for a static constant schema version - if (java.lang.reflect.Modifier.isStatic(mods) && - field.getName().equals(SCHEMA_VERSION_FIELD)) { - try { - _schemaVersion = (Integer)field.get(null); - } catch (Exception e) { - log.warning("Failed to read schema version [class=" + _pClass + "].", e); - } - } - - // the field must be public, non-static and non-transient - if (!java.lang.reflect.Modifier.isPublic(mods) || - java.lang.reflect.Modifier.isStatic(mods) || - field.getAnnotation(Transient.class) != null) { - continue; - } - - FieldMarshaller fm = FieldMarshaller.createMarshaller(field); - _fields.put(field.getName(), fm); - fields.add(field.getName()); - - // check to see if this is our primary key - if (field.getAnnotation(Id.class) != null) { - if (_pkColumns == null) { - _pkColumns = new ArrayList>(); - } - _pkColumns.add(fm); - } - - // check if this field defines a new TableGenerator - generator = field.getAnnotation(TableGenerator.class); - if (generator != null) { - context.tableGenerators.put(generator.name(), generator); - } - - // check if this field is auto-generated - GeneratedValue gv = fm.getGeneratedValue(); - if (gv != null) { - // we can only do this on numeric fields - Class ftype = field.getType(); - boolean isNumeric = ( - ftype.equals(Byte.TYPE) || ftype.equals(Byte.class) || - ftype.equals(Short.TYPE) || ftype.equals(Short.class) || - ftype.equals(Integer.TYPE) || ftype.equals(Integer.class) || - ftype.equals(Long.TYPE) || ftype.equals(Long.class)); - if (!isNumeric) { - throw new IllegalArgumentException( - "Cannot use @GeneratedValue on non-numeric column: " + field.getName()); - } - switch(gv.strategy()) { - case AUTO: - case IDENTITY: - if (seenIdentityGenerator) { - throw new IllegalArgumentException( - "Persistent records can have at most one AUTO/IDENTITY generator."); - } - _valueGenerators.put(field.getName(), new IdentityValueGenerator(gv, this, fm)); - seenIdentityGenerator = true; - break; - - case TABLE: - String name = gv.generator(); - generator = context.tableGenerators.get(name); - if (generator == null) { - throw new IllegalArgumentException( - "Unknown generator [generator=" + name + "]"); - } - _valueGenerators.put( - field.getName(), new TableValueGenerator(generator, gv, this, fm)); - break; - - case SEQUENCE: // TODO - throw new IllegalArgumentException( - "SEQUENCE key generation strategy not yet supported."); - } - } - - } - - // if we did not find a schema version field, freak out (but not for computed records, for - // whom there is no table) - if (_tableName != null && _schemaVersion <= 0) { - throw new IllegalStateException( - pClass.getName() + "." + SCHEMA_VERSION_FIELD + " must be greater than zero."); - } - - // generate our full list of fields/columns for use in queries - _allFields = fields.toArray(new String[fields.size()]); - - // now check for @Entity annotations on the entire superclass chain - Class iterClass = pClass; - do { - entity = iterClass.getAnnotation(Entity.class); - if (entity != null) { - for (UniqueConstraint constraint : entity.uniqueConstraints()) { - String[] conFields = constraint.fieldNames(); - Set colSet = new HashSet(); - for (int ii = 0; ii < conFields.length; ii ++) { - FieldMarshaller fm = _fields.get(conFields[ii]); - if (fm == null) { - throw new IllegalArgumentException( - "Unknown unique constraint field: " + conFields[ii]); - } - colSet.add(fm.getColumnName()); - } - _uniqueConstraints.add(colSet); - } - - for (Index index : entity.indices()) { - if (_indexes.containsKey(index.name())) { - continue; - } - _indexes.put(index.name(), index); - } - - // if there are FTS indexes in the Table, map those out here for future use - for (FullTextIndex fti : entity.fullTextIndices()) { - if (_fullTextIndexes.containsKey(fti.name())) { - continue; - } - _fullTextIndexes.put(fti.name(), fti); - } - } - - iterClass = iterClass.getSuperclass(); - - } while (PersistentRecord.class.isAssignableFrom(iterClass) && - !PersistentRecord.class.equals(iterClass)); - } - - /** - * Returns the persistent class this is object is a marshaller for. - */ - public Class getPersistentClass () - { - return _pClass; - } - - /** - * Returns the @Computed annotation definition of this entity, or null if none. - */ - - public Computed getComputed () - { - return _computed; - } - - /** - * Returns the name of the table in which persistent instances of our class are stored. By - * default this is the classname of the persistent object without the package. - */ - public String getTableName () - { - return _tableName; - } - - /** - * Returns all the persistent fields of our class, in definition order. - */ - public String[] getFieldNames () - { - return _allFields; - } - - /** - * Returns all the persistent fields that correspond to concrete table columns. - */ - public String[] getColumnFieldNames () - { - return _columnFields; - } - - /** - * Return the {@link FullTextIndex} registered under the given name. - * - * @exception IllegalArgumentException thrown if the requested full text index does not exist - * on this record. - */ - public FullTextIndex getFullTextIndex (String name) - { - FullTextIndex fti = _fullTextIndexes.get(name); - if (fti == null) { - throw new IllegalStateException("Persistent class missing full text index " + - "[class=" + _pClass + ", index=" + name + "]"); - } - return fti; - } - - /** - * Returns the {@link FieldMarshaller} for a named field on our persistent class. - */ - public FieldMarshaller getFieldMarshaller (String fieldName) - { - return _fields.get(fieldName); - } - - /** - * Returns true if our persistent object defines a primary key. - */ - public boolean hasPrimaryKey () - { - return (_pkColumns != null); - } - - /** - * Returns the {@link ValueGenerator} objects used to automatically generate field values for - * us when a new record is inserted. - */ - public Iterable getValueGenerators () - { - return _valueGenerators.values(); - } - - /** - * Return the names of the columns that constitute the primary key of our associated persistent - * record. - */ - public String[] getPrimaryKeyFields () - { - String[] pkcols = new String[_pkColumns.size()]; - for (int ii = 0; ii < pkcols.length; ii ++) { - pkcols[ii] = _pkColumns.get(ii).getField().getName(); - } - return pkcols; - } - - /** - * Returns a key configured with the primary key of the supplied object. If all the fields are - * null, this method returns null. An exception is thrown if some of the fields are null and - * some are not, or if the object does not declare a primary key. - */ - public Key getPrimaryKey (Object object) - { - return getPrimaryKey(object, true); - } - - /** - * Returns a key configured with the primary key of the supplied object. If all the fields are - * null, this method returns null. If some of the fields are null and some are not, an - * exception is thrown. If the object does not declare a primary key and the second argument is - * true, this method throws an exception; if it's false, the method returns null. - */ - public Key getPrimaryKey (Object object, boolean requireKey) - { - if (!hasPrimaryKey()) { - if (requireKey) { - throw new UnsupportedOperationException( - _pClass.getName() + " does not define a primary key"); - } - return null; - } - - try { - Comparable[] values = new Comparable[_pkColumns.size()]; - int nulls = 0, zeros = 0; - for (int ii = 0; ii < _pkColumns.size(); ii++) { - FieldMarshaller field = _pkColumns.get(ii); - values[ii] = (Comparable)field.getField().get(object); - if (values[ii] == null) { - nulls++; - } else if (values[ii] instanceof Number && ((Number)values[ii]).intValue() == 0) { - nulls++; // zeros are considered nulls; see below - zeros++; - } - } - - // make sure the keys are all null or all non-null - if (nulls == 0) { - return makePrimaryKey(values); - } else if (nulls == values.length) { - return null; - } else if (nulls == zeros) { - // we also allow primary keys where there are zero-valued primitive primary key - // columns as along as there is at least one non-zero valued additional key column; - // this is a compromise that allows sensible things like (id=99, type=0) but - // unfortunately also allows less sensible things like (id=0, type=5) while - // continuing to disallow the dangerous (id=0) - return makePrimaryKey(values); - } - - // throw an informative error message - StringBuilder keys = new StringBuilder(); - for (int ii = 0; ii < _pkColumns.size(); ii++) { - keys.append(", ").append(_pkColumns.get(ii).getField().getName()); - keys.append("=").append(values[ii]); - } - throw new IllegalArgumentException("Primary key fields are mixed null and non-null " + - "[class=" + _pClass.getName() + keys + "]."); - - } catch (IllegalAccessException iae) { - throw new RuntimeException(iae); - } - } - - /** - * Creates a primary key record for the type of object handled by this marshaller, using the - * supplied primary key value. - */ - public Key makePrimaryKey (Comparable... values) - { - if (!hasPrimaryKey()) { - throw new UnsupportedOperationException( - getClass().getName() + " does not define a primary key"); - } - String[] fields = new String[_pkColumns.size()]; - for (int ii = 0; ii < _pkColumns.size(); ii++) { - fields[ii] = _pkColumns.get(ii).getField().getName(); - } - return new Key(_pClass, fields, values); - } - - /** - * Creates a primary key record for the type of object handled by this marshaller, using the - * supplied result set. - */ - public Key makePrimaryKey (ResultSet rs) - throws SQLException - { - if (!hasPrimaryKey()) { - throw new UnsupportedOperationException( - getClass().getName() + " does not define a primary key"); - } - Comparable[] values = new Comparable[_pkColumns.size()]; - for (int ii = 0; ii < _pkColumns.size(); ii++) { - Object keyValue = _pkColumns.get(ii).getFromSet(rs); - if (!(keyValue instanceof Comparable)) { - throw new IllegalArgumentException("Key field must be Comparable [field=" + - _pkColumns.get(ii).getColumnName() + "]"); - } - values[ii] = (Comparable) keyValue; - } - return makePrimaryKey(values); - } - - /** - * Returns true if this marshaller has been initialized ({@link #init} has been called), its - * migrations run and it is ready for operation. False otherwise. - */ - public boolean isInitialized () - { - return _initialized; - } - - /** - * Creates a persistent object from the supplied result set. The result set must have come from - * a properly constructed query (see {@link BuildVisitor}). - */ - public T createObject (ResultSet rs) - throws SQLException - { - try { - // first, build a set of the fields that we actually received - Set fields = new HashSet(); - ResultSetMetaData metadata = rs.getMetaData(); - for (int ii = 1; ii <= metadata.getColumnCount(); ii ++) { - fields.add(metadata.getColumnName(ii)); - } - - // then create and populate the persistent object - T po = _pClass.newInstance(); - for (FieldMarshaller fm : _fields.values()) { - if (!fields.contains(fm.getColumnName())) { - // this field was not in the result set, make sure that's OK - if (fm.getComputed() != null && !fm.getComputed().required()) { - continue; - } - throw new SQLException("ResultSet missing field: " + fm.getField().getName()); - } - fm.getAndWriteToObject(rs, po); - } - return po; - - } catch (SQLException sqe) { - // pass this on through - throw sqe; - - } catch (Exception e) { - String errmsg = "Failed to unmarshall persistent object [class=" + - _pClass.getName() + "]"; - throw (SQLException)new SQLException(errmsg).initCause(e); - } - } - - /** - * Go through the registered {@link ValueGenerator}s for our persistent object and run the ones - * that match the current postFactum phase, filling in the fields on the supplied object while - * we go. - * - * The return value is only non-empty for the !postFactum phase, in which case it is a set of - * field names that are associated with {@link IdentityValueGenerator}, because these need - * special handling in the INSERT (specifically, 'DEFAULT' must be supplied as a value in the - * eventual SQL). - */ - public Set generateFieldValues ( - Connection conn, DatabaseLiaison liaison, Object po, boolean postFactum) - { - Set idFields = new HashSet(); - - for (ValueGenerator vg : _valueGenerators.values()) { - if (!postFactum && vg instanceof IdentityValueGenerator) { - idFields.add(vg.getFieldMarshaller().getField().getName()); - } - if (vg.isPostFactum() != postFactum) { - continue; - } - - try { - int nextValue = vg.nextGeneratedValue(conn, liaison); - vg.getFieldMarshaller().getField().set(po, nextValue); - - } catch (Exception e) { - throw new IllegalStateException( - "Failed to assign primary key [type=" + _pClass + "]", e); - } - } - return idFields; - } - - /** - * This is called by the persistence context to register a migration for the entity managed by - * this marshaller. - */ - protected void registerMigration (SchemaMigration migration) - { - _schemaMigs.add(migration); - } - - /** - * Initializes the table used by this marshaller. This is called automatically by the {@link - * PersistenceContext} the first time an entity is used. If the table does not exist, it will - * be created. If the schema version specified by the persistent object is newer than the - * database schema, it will be migrated. - */ - protected void init (PersistenceContext ctx) - throws DatabaseException - { - if (_initialized) { // sanity check - throw new IllegalStateException( - "Cannot re-initialize marshaller [type=" + _pClass + "]."); - } - _initialized = true; - - final SQLBuilder builder = ctx.getSQLBuilder(new DepotTypes(ctx, _pClass)); - - // perform the context-sensitive initialization of the field marshallers - for (FieldMarshaller fm : _fields.values()) { - fm.init(builder); - } - - // if we have no table (i.e. we're a computed entity), we have nothing to create - if (getTableName() == null) { - return; - } - - // figure out the list of fields that correspond to actual table columns and generate the - // SQL used to create and migrate our table (unless we're a computed entity) - _columnFields = new String[_allFields.length]; - ColumnDefinition[] declarations = new ColumnDefinition[_allFields.length]; - int jj = 0; - for (int ii = 0; ii < _allFields.length; ii++) { - FieldMarshaller fm = _fields.get(_allFields[ii]); - // include all persistent non-computed fields - ColumnDefinition colDef = fm.getColumnDefinition(); - if (colDef != null) { - _columnFields[jj] = _allFields[ii]; - declarations[jj] = colDef; - jj ++; - } - } - _columnFields = ArrayUtil.splice(_columnFields, jj); - declarations = ArrayUtil.splice(declarations, jj); - - // check to see if our schema version table exists, create it if not - ctx.invoke(new Modifier() { - @Override - public Integer invoke (Connection conn, DatabaseLiaison liaison) throws SQLException { - liaison.createTableIfMissing( - conn, SCHEMA_VERSION_TABLE, - new String[] { P_COLUMN, V_COLUMN, MV_COLUMN }, - new ColumnDefinition[] { - new ColumnDefinition("VARCHAR(255)", false, true, null), - new ColumnDefinition("INTEGER", false, false, null), - new ColumnDefinition("INTEGER", false, false, null) - }, - null, - new String[] { P_COLUMN }); - // add our new "migratingVersion" column if it's not already there - liaison.addColumn(conn, SCHEMA_VERSION_TABLE, MV_COLUMN, - "integer not null default 0", true); - return 0; - } - }); - - // fetch all relevant information regarding our table from the database - TableMetaData metaData = TableMetaData.load(ctx, getTableName()); - - // determine whether or not this record has ever been seen - int currentVersion = ctx.invoke(new ReadVersion()); - if (currentVersion == -1) { - log.info("Creating initial version record for " + _pClass.getName() + "."); - // if not, create a version entry with version zero - ctx.invoke(new SimpleModifier() { - protected int invoke (DatabaseLiaison liaison, Statement stmt) throws SQLException { - try { - return stmt.executeUpdate( - "insert into " + liaison.tableSQL(SCHEMA_VERSION_TABLE) + - " values('" + getTableName() + "', 0 , 0)"); - } catch (SQLException e) { - // someone else might be doing this at the exact same time which is OK, - // we'll coordinate with that other process in the next phase - if (liaison.isDuplicateRowException(e)) { - return 0; - } else { - throw e; - } - } - } - }); - } - - // now check whether we need to migrate our database schema - boolean gotMigrationLock = false; - while (!gotMigrationLock) { - currentVersion = ctx.invoke(new ReadVersion()); - if (currentVersion >= _schemaVersion) { - checkForStaleness(metaData, ctx, builder); - return; - } - - // try to update migratingVersion to the new version to indicate to other processes - // that we are handling the migration and that they should wait - if (ctx.invoke(new UpdateMigratingVersion(_schemaVersion, 0)) > 0) { - break; // we got the lock, let's go - } - - // we didn't get the lock, so wait 5 seconds and then check to see if the other process - // finished the update or failed in which case we'll try to grab the lock ourselves - try { - log.info("Waiting on migration lock for " + _pClass.getName() + "."); - Thread.sleep(5000); - } catch (InterruptedException ie) { - throw new DatabaseException("Interrupted while waiting on migration lock."); - } - } - - try { - if (!metaData.tableExists) { - // if the table does not exist, create it - createTable(ctx, builder, declarations); - metaData = TableMetaData.load(ctx, getTableName()); - } else { - // if it does exist, run our migrations - metaData = runMigrations(ctx, metaData, builder, currentVersion); - } - - // check for stale columns now that the table is up to date - checkForStaleness(metaData, ctx, builder); - - // and update our version in the schema version table - ctx.invoke(new SimpleModifier() { - protected int invoke (DatabaseLiaison liaison, Statement stmt) throws SQLException { - return stmt.executeUpdate( - "update " + liaison.tableSQL(SCHEMA_VERSION_TABLE) + - " set " + liaison.columnSQL(V_COLUMN) + " = " + _schemaVersion + - " where " + liaison.columnSQL(P_COLUMN) + " = '" + getTableName() + "'"); - } - }); - - } finally { - // set our migrating version back to zero - try { - if (ctx.invoke(new UpdateMigratingVersion(0, _schemaVersion)) == 0) { - log.warning("Failed to restore migrating version to zero!", "record", _pClass); - } - } catch (Exception e) { - log.warning("Failure restoring migrating version! Bad bad!", "record", _pClass, e); - } - } - } - - protected void createTable (PersistenceContext ctx, final SQLBuilder builder, - final ColumnDefinition[] declarations) - throws DatabaseException - { - log.info("Creating initial table '" + getTableName() + "'."); - - final String[][] uniqueConCols = new String[_uniqueConstraints.size()][]; - int kk = 0; - for (Set colSet : _uniqueConstraints) { - uniqueConCols[kk++] = colSet.toArray(new String[colSet.size()]); - } - final Iterable indexen = _indexes.values(); - ctx.invoke(new Modifier() { - @Override - public Integer invoke (Connection conn, DatabaseLiaison liaison) throws SQLException { - // create the table - String[] primaryKeyColumns = null; - if (_pkColumns != null) { - primaryKeyColumns = new String[_pkColumns.size()]; - for (int ii = 0; ii < primaryKeyColumns.length; ii ++) { - primaryKeyColumns[ii] = _pkColumns.get(ii).getColumnName(); - } - } - liaison.createTableIfMissing( - conn, getTableName(), fieldsToColumns(_columnFields), - declarations, uniqueConCols, primaryKeyColumns); - - // add its indexen - for (Index idx : indexen) { - liaison.addIndexToTable( - conn, getTableName(), fieldsToColumns(idx.fields()), - getTableName() + "_" + idx.name(), idx.unique()); - } - - // create our value generators - for (ValueGenerator vg : _valueGenerators.values()) { - vg.create(conn, liaison); - } - - // and its full text search indexes - for (FullTextIndex fti : _fullTextIndexes.values()) { - builder.addFullTextSearch(conn, DepotMarshaller.this, fti); - } - - return 0; - } - }); - } - - protected TableMetaData runMigrations (PersistenceContext ctx, TableMetaData metaData, - final SQLBuilder builder, int currentVersion) - throws DatabaseException - { - log.info("Migrating " + getTableName() + " from " + currentVersion + " to " + - _schemaVersion + "..."); - - if (_schemaMigs.size() > 0) { - // run our pre-default-migrations - for (SchemaMigration migration : _schemaMigs) { - if (migration.runBeforeDefault() && - migration.shouldRunMigration(currentVersion, _schemaVersion)) { - migration.init(getTableName(), _fields); - ctx.invoke(migration); - } - } - - // we don't know what the pre-migrations did so we have to re-read metadata - metaData = TableMetaData.load(ctx, getTableName()); - } - - // this is a little silly, but we need a copy for name disambiguation later - Set indicesCopy = new HashSet(metaData.indexColumns.keySet()); - - // figure out which columns we have in the table now, so that when all is said and done we - // can see what new columns we have in the table and run the creation code for any value - // generators that are defined on those columns (we can't just track the columns we add in - // our automatic migrations because someone might register custom migrations that add - // columns specially) - Set preMigrateColumns = new HashSet(metaData.tableColumns); - - // add any missing columns - for (String fname : _columnFields) { - final FieldMarshaller fmarsh = _fields.get(fname); - if (metaData.tableColumns.remove(fmarsh.getColumnName())) { - continue; - } - - // otherwise add the column - final ColumnDefinition coldef = fmarsh.getColumnDefinition(); - log.info("Adding column to " + getTableName() + ": " + fmarsh.getColumnName()); - ctx.invoke(new Modifier.Simple() { - @Override protected String createQuery (DatabaseLiaison liaison) { - return "alter table " + liaison.tableSQL(getTableName()) + - " add column " + liaison.columnSQL(fmarsh.getColumnName()) + " " + - liaison.expandDefinition(coldef); - } - }); - - // if the column is a TIMESTAMP or DATETIME column, we need to run a special query to - // update all existing rows to the current time because MySQL annoyingly assigns - // TIMESTAMP columns a value of "0000-00-00 00:00:00" regardless of whether we - // explicitly provide a "DEFAULT" value for the column or not, and DATETIME columns - // cannot accept CURRENT_TIME or NOW() defaults at all. - if (!coldef.isNullable() && (coldef.getType().equalsIgnoreCase("timestamp") || - coldef.getType().equalsIgnoreCase("datetime"))) { - log.info("Assigning current time to " + fmarsh.getColumnName() + "."); - ctx.invoke(new Modifier.Simple() { - @Override protected String createQuery (DatabaseLiaison liaison) { - // TODO: is NOW() standard SQL? - return "update " + liaison.tableSQL(getTableName()) + - " set " + liaison.columnSQL(fmarsh.getColumnName()) + " = NOW()"; - } - }); - } - } - - // add or remove the primary key as needed - if (hasPrimaryKey() && metaData.pkName == null) { - log.info("Adding primary key."); - ctx.invoke(new Modifier() { - @Override public Integer invoke (Connection conn, DatabaseLiaison liaison) - throws SQLException { - liaison.addPrimaryKey( - conn, getTableName(), fieldsToColumns(getPrimaryKeyFields())); - return 0; - } - }); - - } else if (!hasPrimaryKey() && metaData.pkName != null) { - final String pkName = metaData.pkName; - log.info("Dropping primary key: " + pkName); - ctx.invoke(new Modifier() { - @Override public Integer invoke (Connection conn, DatabaseLiaison liaison) - throws SQLException { - liaison.dropPrimaryKey(conn, getTableName(), pkName); - return 0; - } - }); - } - - // add any named indices that exist on the record but not yet on the table - for (final Index index : _indexes.values()) { - final String ixName = getTableName() + "_" + index.name(); - if (metaData.indexColumns.containsKey(ixName)) { - // this index already exists - metaData.indexColumns.remove(ixName); - continue; - } - // but this is a new, named index, so we create it - ctx.invoke(new Modifier() { - @Override public Integer invoke (Connection conn, DatabaseLiaison liaison) - throws SQLException { - liaison.addIndexToTable( - conn, getTableName(), fieldsToColumns(index.fields()), - ixName, index.unique()); - return 0; - } - }); - } - - // now check if there are any @Entity(uniqueConstraints) that need to be created - Set> uniqueIndices = new HashSet>(metaData.indexColumns.values()); - - // unique constraints are unordered and may be unnamed, so we view them only as column sets - for (Set colSet : _uniqueConstraints) { - if (uniqueIndices.contains(colSet)) { - // the table already contains precisely this column set - continue; - } - - // else build the new constraint; we'll name it after one of its columns, adding _N - // to resolve any possible ambiguities, because using all the column names in the - // index name may exceed the maximum length of an SQL identifier - String indexName = colSet.iterator().next(); - if (indicesCopy.contains(indexName)) { - int num = 1; - indexName += "_"; - while (indicesCopy.contains(indexName + num)) { - num ++; - } - indexName += num; - } - - final String[] colArr = colSet.toArray(new String[colSet.size()]); - final String fName = indexName; - ctx.invoke(new Modifier() { - @Override public Integer invoke (Connection conn, DatabaseLiaison liaison) - throws SQLException { - liaison.addIndexToTable(conn, getTableName(), colArr, fName, true); - return 0; - } - }); - } - - // next we create any full text search indexes that exist on the record but not in the - // table, first step being to do a dialect-sensitive enumeration of existing indexes - Set tableFts = new HashSet(); - builder.getFtsIndexes(metaData.tableColumns, metaData.indexColumns.keySet(), tableFts); - - // then iterate over what should be there - for (final FullTextIndex recordFts : _fullTextIndexes.values()) { - if (tableFts.contains(recordFts.name())) { - // the table already contains this one - continue; - } - - // but not this one, so let's create it - ctx.invoke(new Modifier() { - @Override public Integer invoke (Connection conn, DatabaseLiaison liaison) - throws SQLException { - builder.addFullTextSearch(conn, DepotMarshaller.this, recordFts); - return 0; - } - }); - } - - // we do not auto-remove columns but rather require that SchemaMigration.Drop records be - // registered by hand to avoid accidentally causing the loss of data - - // we don't auto-remove indices either because we'd have to sort out the potentially - // complex origins of an index (which might be because of a @Unique column or maybe the - // index was hand defined in a @Column clause) - - // run our post-default-migrations - for (SchemaMigration migration : _schemaMigs) { - if (!migration.runBeforeDefault() && - migration.shouldRunMigration(currentVersion, _schemaVersion)) { - migration.init(getTableName(), _fields); - ctx.invoke(migration); - } - } - - // now reload our table metadata so that we can see what columns we have now - metaData = TableMetaData.load(ctx, getTableName()); - - // initialize value generators for any columns that have been newly added - for (String column : metaData.tableColumns) { - if (preMigrateColumns.contains(column)) { - continue; - } - - // see if we have a value generator for this new column - final ValueGenerator valgen = _valueGenerators.get(column); - if (valgen == null) { - continue; - } - - // note: if someone renames a column that has an identity value generator, things will - // break because Postgres automatically creates a table_column_seq sequence that is - // used to generate values for that column and god knows what happens when that is - // renamed; plus we're potentially going to try to reinitialize it if it has a non-zero - // initialValue which will use the new column name to obtain the sequence name which - // ain't going to work either; we punt! - ctx.invoke(new Modifier() { - @Override public Integer invoke (Connection conn, DatabaseLiaison liaison) - throws SQLException { - valgen.create(conn, liaison); - return 0; - } - }); - } - - return metaData; - } - - // translate an array of field names to an array of column names - protected String[] fieldsToColumns (String[] fields) - { - String[] columns = new String[fields.length]; - for (int ii = 0; ii < columns.length; ii ++) { - FieldMarshaller fm = _fields.get(fields[ii]); - if (fm == null) { - throw new IllegalArgumentException( - "Unknown field on record [field=" + fields[ii] + ", class=" + _pClass + "]"); - } - columns[ii] = fm.getColumnName(); - } - return columns; - } - - /** - * Checks that there are no database columns for which we no longer have Java fields. - */ - protected void checkForStaleness (TableMetaData meta, PersistenceContext ctx, SQLBuilder builder) - throws DatabaseException - { - for (String fname : _columnFields) { - FieldMarshaller fmarsh = _fields.get(fname); - meta.tableColumns.remove(fmarsh.getColumnName()); - } - for (String column : meta.tableColumns) { - if (builder.isPrivateColumn(column)) { - continue; - } - log.warning(getTableName() + " contains stale column '" + column + "'."); - } - } - - protected abstract class SimpleModifier extends Modifier { - @Override - public Integer invoke (Connection conn, DatabaseLiaison liaison) throws SQLException { - Statement stmt = conn.createStatement(); - try { - return invoke(liaison, stmt); - } finally { - stmt.close(); - } - } - - protected abstract int invoke (DatabaseLiaison liaison, Statement stmt) throws SQLException; - } - - // this is a Modifier not a Query because we want to be sure we're talking to the database - // server to whom we would talk if we were doing a modification (ie. the master, not a - // read-only slave) - protected class ReadVersion extends SimpleModifier { - protected int invoke (DatabaseLiaison liaison, Statement stmt) throws SQLException { - ResultSet rs = stmt.executeQuery( - " select " + liaison.columnSQL(V_COLUMN) + - " from " + liaison.tableSQL(SCHEMA_VERSION_TABLE) + - " where " + liaison.columnSQL(P_COLUMN) + " = '" + getTableName() + "'"); - return (rs.next()) ? rs.getInt(1) : -1; - } - } - - protected class UpdateMigratingVersion extends SimpleModifier { - public UpdateMigratingVersion (int newMigratingVersion, int guardVersion) { - _newMigratingVersion = newMigratingVersion; - _guardVersion = guardVersion; - } - protected int invoke (DatabaseLiaison liaison, Statement stmt) throws SQLException { - return stmt.executeUpdate( - "update " + liaison.tableSQL(SCHEMA_VERSION_TABLE) + - " set " + liaison.columnSQL(MV_COLUMN) + " = " + _newMigratingVersion + - " where " + liaison.columnSQL(P_COLUMN) + " = '" + getTableName() + "'" + - " and " + liaison.columnSQL(MV_COLUMN) + " = " + _guardVersion); - } - protected int _newMigratingVersion, _guardVersion; - } - - protected static class TableMetaData - { - public boolean tableExists; - public Set tableColumns = new HashSet(); - public Map> indexColumns = new HashMap>(); - public String pkName; - public Set pkColumns = new HashSet(); - - public static TableMetaData load (PersistenceContext ctx, final String tableName) - throws DatabaseException - { - return ctx.invoke(new Query.Trivial() { - @Override public TableMetaData invoke (Connection conn, DatabaseLiaison dl) - throws SQLException { - return new TableMetaData(conn.getMetaData(), tableName); - } - }); - } - - public TableMetaData (DatabaseMetaData meta, String tableName) - throws SQLException - { - tableExists = meta.getTables("", "", tableName, null).next(); - if (!tableExists) { - return; - } - - ResultSet rs = meta.getColumns(null, null, tableName, "%"); - while (rs.next()) { - tableColumns.add(rs.getString("COLUMN_NAME")); - } - - rs = meta.getIndexInfo(null, null, tableName, false, false); - while (rs.next()) { - String indexName = rs.getString("INDEX_NAME"); - Set set = indexColumns.get(indexName); - if (rs.getBoolean("NON_UNIQUE")) { - // not a unique index: just make sure there's an entry in the keyset - if (set == null) { - indexColumns.put(indexName, null); - } - - } else { - // for unique indices we collect the column names - if (set == null) { - set = new HashSet(); - indexColumns.put(indexName, set); - } - set.add(rs.getString("COLUMN_NAME")); - } - } - - rs = meta.getPrimaryKeys(null, null, tableName); - while (rs.next()) { - pkName = rs.getString("PK_NAME"); - pkColumns.add(rs.getString("COLUMN_NAME")); - } - } - } - - /** The persistent object class that we manage. */ - protected Class _pClass; - - /** The name of our persistent object table. */ - protected String _tableName; - - /** The @Computed annotation of this entity, or null. */ - protected Computed _computed; - - /** A mapping of field names to value generators for that field. */ - protected Map _valueGenerators = new HashMap(); - - /** A field marshaller for each persistent field in our object. */ - protected Map> _fields = new HashMap>(); - - /** The field marshallers for our persistent object's primary key columns or null if it did not - * define a primary key. */ - protected ArrayList> _pkColumns; - - /** The persisent fields of our object, in definition order. */ - protected String[] _allFields; - - /** The fields of our object with directly corresponding table columns. */ - protected String[] _columnFields; - - /** The indexes defined in @Entity annotations for this record. */ - protected Map _indexes = new HashMap(); - - /** The unique constraints defined in @Entity annotations for this record. */ - protected Set> _uniqueConstraints = new HashSet>(); - - protected Map _fullTextIndexes = new HashMap(); - - /** The version of our persistent object schema as specified in the class definition. */ - protected int _schemaVersion = -1; - - /** Indicates that we have been initialized (created or migrated our tables). */ - protected boolean _initialized; - - /** A list of hand registered schema migrations to run prior to doing the default migration. */ - protected ArrayList _schemaMigs = new ArrayList(); - - /** The name of the table we use to track schema versions. */ - protected static final String SCHEMA_VERSION_TABLE = "DepotSchemaVersion"; - - /** The name of the 'persistentClass' column in the {@link #SCHEMA_VERSION_TABLE}. */ - protected static final String P_COLUMN = "persistentClass"; - - /** The name of the 'version' column in the {@link #SCHEMA_VERSION_TABLE}. */ - protected static final String V_COLUMN = "version"; - - /** The name of the 'migratingVersion' column in the {@link #SCHEMA_VERSION_TABLE}. */ - protected static final String MV_COLUMN = "migratingVersion"; -} diff --git a/src/java/com/samskivert/jdbc/depot/DepotMigrationHistoryRecord.java b/src/java/com/samskivert/jdbc/depot/DepotMigrationHistoryRecord.java deleted file mode 100644 index f3d5a634..00000000 --- a/src/java/com/samskivert/jdbc/depot/DepotMigrationHistoryRecord.java +++ /dev/null @@ -1,73 +0,0 @@ -// -// $Id$ -// -// samskivert library - useful routines for java programs -// Copyright (C) 2001-2008 Michael Bayne -// -// This library is free software; you can redistribute it and/or modify it -// under the terms of the GNU Lesser General Public License as published -// by the Free Software Foundation; either version 2.1 of the License, or -// (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -package com.samskivert.jdbc.depot; - -import java.sql.Timestamp; - -import com.samskivert.jdbc.depot.annotation.Column; -import com.samskivert.jdbc.depot.annotation.Id; -import com.samskivert.jdbc.depot.expression.ColumnExp; - -/** - * Maintains a record of all successfully invoked data migrations. - */ -public class DepotMigrationHistoryRecord extends PersistentRecord -{ - // AUTO-GENERATED: FIELDS START - /** The column identifier for the {@link #ident} field. */ - public static final String IDENT = "ident"; - - /** The qualified column identifier for the {@link #ident} field. */ - public static final ColumnExp IDENT_C = - new ColumnExp(DepotMigrationHistoryRecord.class, IDENT); - - /** The column identifier for the {@link #whenCompleted} field. */ - public static final String WHEN_COMPLETED = "whenCompleted"; - - /** The qualified column identifier for the {@link #whenCompleted} field. */ - public static final ColumnExp WHEN_COMPLETED_C = - new ColumnExp(DepotMigrationHistoryRecord.class, WHEN_COMPLETED); - // AUTO-GENERATED: FIELDS END - - /** Our schema version. Probably not likely to change. */ - public static final int SCHEMA_VERSION = 1; - - /** The unique identifier for this migration. */ - @Id public String ident; - - /** The time at which the migration was completed. */ - @Column(nullable=true) - public Timestamp whenCompleted; - - // AUTO-GENERATED: METHODS START - /** - * Create and return a primary {@link Key} to identify a {@link DepotMigrationHistoryRecord} - * with the supplied key values. - */ - public static Key getKey (String ident) - { - return new Key( - DepotMigrationHistoryRecord.class, - new String[] { IDENT }, - new Comparable[] { ident }); - } - // AUTO-GENERATED: METHODS END -} diff --git a/src/java/com/samskivert/jdbc/depot/DepotRepository.java b/src/java/com/samskivert/jdbc/depot/DepotRepository.java deleted file mode 100644 index 86fa652f..00000000 --- a/src/java/com/samskivert/jdbc/depot/DepotRepository.java +++ /dev/null @@ -1,988 +0,0 @@ -// -// $Id$ -// -// samskivert library - useful routines for java programs -// Copyright (C) 2006-2007 Michael Bayne, Pär Winzell -// -// This library is free software; you can redistribute it and/or modify it -// under the terms of the GNU Lesser General Public License as published -// by the Free Software Foundation; either version 2.1 of the License, or -// (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -package com.samskivert.jdbc.depot; - -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Timestamp; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import com.samskivert.util.ArrayUtil; - -import com.samskivert.jdbc.ConnectionProvider; -import com.samskivert.jdbc.DatabaseLiaison; -import com.samskivert.jdbc.JDBCUtil; - -import com.samskivert.jdbc.depot.Modifier.*; -import com.samskivert.jdbc.depot.clause.DeleteClause; -import com.samskivert.jdbc.depot.clause.FieldOverride; -import com.samskivert.jdbc.depot.clause.InsertClause; -import com.samskivert.jdbc.depot.clause.QueryClause; -import com.samskivert.jdbc.depot.clause.SelectClause; -import com.samskivert.jdbc.depot.clause.UpdateClause; -import com.samskivert.jdbc.depot.expression.SQLExpression; -import com.samskivert.jdbc.depot.expression.ValueExp; - -import static com.samskivert.jdbc.depot.Log.log; - -/** - * Provides a base for classes that provide access to persistent objects. Also defines the - * mechanism by which all persistent queries and updates are routed through the distributed cache. - */ -public abstract class DepotRepository -{ - /** - * Creates a repository with the supplied persistence context. Any schema migrations needed by - * this repository should be registered in its constructor. A repository should not - * perform any actual database operations in its constructor, only register schema - * migrations. Initialization related database operations should be performed in {@link #init}. - */ - protected DepotRepository (PersistenceContext context) - { - _ctx = context; - _ctx.repositoryCreated(this); - } - - /** - * Creates a repository with the supplied connection provider and its own private persistence - * context. This should generally not be used for new systems, and is only included to - * facilitate the integration of small numbers of Depot-based repositories into systems using - * the older samskivert SimpleRepository system. - */ - protected DepotRepository (ConnectionProvider conprov) - { - _ctx = new PersistenceContext(); - _ctx.init(getClass().getName(), conprov, null); - _ctx.repositoryCreated(this); - } - - /** - * Resolves all persistent records registered to this repository (via {@link - * #getManagedRecords}. This will be done before the repository is initialized via {@link - * #init}. - */ - protected void resolveRecords () - throws DatabaseException - { - Set> classes = - new HashSet>(); - getManagedRecords(classes); - for (Class rclass : classes) { - _ctx.getMarshaller(rclass); - } - } - - /** - * Provides a place where a repository can perform any initialization that requires database - * operations. - */ - protected void init () - throws DatabaseException - { - // run any registered data migrations - for (DataMigration migration : _dataMigs) { - runMigration(migration); - } - _dataMigs = null; // note that we've been initialized - } - - /** - * Registers a data migration for this repository. This migration will only be run once and its - * unique identifier will be stored persistently to ensure that it is never run again on the - * same database. Nonetheless, migrations should strive to be idempotent because someone might - * come along and create a brand new system installation and all registered migrations will be - * run once on the freshly created database. As with all database migrations, understand - * clearly how the process works and think about edge cases when creating a migration. - * - *

See {@link PersistenceContext#registerMigration} for details on how schema migrations - * operate and how they might interact with data migrations. - */ - protected void registerMigration (DataMigration migration) - { - if (_dataMigs == null) { - // we've already been initialized, so we have to run this migration immediately - runMigration(migration); - } else { - _dataMigs.add(migration); - } - } - - /** - * Adds the persistent classes used by this repository to the supplied set. - */ - protected abstract void getManagedRecords (Set> classes); - - /** - * Loads the persistent object that matches the specified primary key. - */ - protected T load (Class type, Comparable primaryKey, - QueryClause... clauses) - throws DatabaseException - { - clauses = ArrayUtil.append(clauses, _ctx.getMarshaller(type).makePrimaryKey(primaryKey)); - return load(type, clauses); - } - - /** - * Loads the persistent object that matches the specified primary key. - */ - protected T load (Class type, String ix, Comparable val, - QueryClause... clauses) - throws DatabaseException - { - clauses = ArrayUtil.append(clauses, new Key(type, ix, val)); - return load(type, clauses); - } - - /** - * Loads the persistent object that matches the specified two-column primary key. - */ - protected T load (Class type, String ix1, Comparable val1, - String ix2, Comparable val2, - QueryClause... clauses) - throws DatabaseException - { - clauses = ArrayUtil.append(clauses, new Key(type, ix1, val1, ix2, val2)); - return load(type, clauses); - } - - /** - * Loads the persistent object that matches the specified three-column primary key. - */ - protected T load (Class type, String ix1, Comparable val1, - String ix2, Comparable val2, String ix3, - Comparable val3, QueryClause... clauses) - throws DatabaseException - { - clauses = ArrayUtil.append(clauses, new Key(type, ix1, val1, ix2, val2, ix3, val3)); - return load(type, clauses); - } - - /** - * Loads the first persistent object that matches the supplied query clauses. - */ - protected T load ( - Class type, Collection clauses) - throws DatabaseException - { - return load(type, clauses.toArray(new QueryClause[clauses.size()])); - } - - /** - * Loads the first persistent object that matches the supplied query clauses. - */ - protected T load (Class type, QueryClause... clauses) - throws DatabaseException - { - return _ctx.invoke(new FindOneQuery(_ctx, type, clauses)); - } - - /** - * Loads up all persistent records that match the supplied set of raw primary keys. - */ - protected List loadAll ( - Class type, Collection> primaryKeys) - throws DatabaseException - { - // convert the raw keys into real key records - DepotMarshaller marsh = _ctx.getMarshaller(type); - List> keys = new ArrayList>(); - for (Comparable key : primaryKeys) { - keys.add(marsh.makePrimaryKey(key)); - } - return loadAll(keys); - } - - /** - * Loads up all persistent records that match the supplied set of primary keys. - */ - protected List loadAll (Collection> keys) - throws DatabaseException - { - return (keys.size() == 0) ? Collections.emptyList() : - _ctx.invoke(new FindAllQuery.WithKeys(_ctx, keys)); - } - - /** - * A varargs version of {@link #findAll(Class,Collection)}. - */ - protected List findAll (Class type, QueryClause... clauses) - throws DatabaseException - { - return findAll(type, Arrays.asList(clauses)); - } - - /** - * Loads all persistent objects that match the specified clauses. - * - * We have two strategies for doing this: one performs the query as-is, the second executes two - * passes: first fetching only key columns and consulting the cache for each such key; then, in - * the second pass, fetching the full entity only for keys that were not found in the cache. - * - * The more complex strategy could save a lot of data shuffling. On the other hand, its - * complexity is an inherent drawback, and it does execute two separate database queries for - * what the simple method does in one. - */ - protected List findAll ( - Class type, Collection clauses) - throws DatabaseException - { - return findAll(type, false, clauses); - } - - /** - * Loads all persistent objects that match the specified clauses. - * - * @param skipCache if true, our normal mixed select strategy that allows cached records to be - * loaded from the cache will not be used even if it otherwise could. See {@link - * #findAll(Class,Collection)} for details on the mixed strategy. - */ - protected List findAll ( - Class type, boolean skipCache, Collection clauses) - throws DatabaseException - { - DepotMarshaller marsh = _ctx.getMarshaller(type); - boolean useExplicit = skipCache || (marsh.getTableName() == null) || - !marsh.hasPrimaryKey() || !_ctx.isUsingCache(); - - // queries on @Computed records or the presence of FieldOverrides use the simple algorithm - for (QueryClause clause : clauses) { - useExplicit |= (clause instanceof FieldOverride); - } - - return _ctx.invoke(useExplicit ? new FindAllQuery.Explicitly(_ctx, type, clauses) : - new FindAllQuery.WithCache(_ctx, type, clauses)); - } - - /** - * Looks up and returns {@link Key} records for all rows that match the supplied query clauses. - * - * @param forUpdate if true, the query will be run using a read-write connection to ensure that - * it talks to the master database, if false, the query will be run on a read-only connection - * and may load keys from a slave. For performance reasons, you should always pass false unless - * you know you will be modifying the database as a result of this query and absolutely need - * the latest data. - */ - protected List> findAllKeys ( - Class type, boolean forUpdate, QueryClause... clause) - throws DatabaseException - { - return findAllKeys(type, forUpdate, Arrays.asList(clause)); - } - - /** - * Looks up and returns {@link Key} records for all rows that match the supplied query clauses. - * - * @param forUpdate if true, the query will be run using a read-write connection to ensure that - * it talks to the master database, if false, the query will be run on a read-only connection - * and may load keys from a slave. For performance reasons, you should always pass false unless - * you know you will be modifying the database as a result of this query and absolutely need - * the latest data. - */ - protected List> findAllKeys ( - Class type, boolean forUpdate, Collection clauses) - throws DatabaseException - { - final List> keys = new ArrayList>(); - final DepotMarshaller marsh = _ctx.getMarshaller(type); - SelectClause select = new SelectClause(type, marsh.getPrimaryKeyFields(), clauses); - final SQLBuilder builder = _ctx.getSQLBuilder(DepotTypes.getDepotTypes(_ctx, select)); - builder.newQuery(select); - - if (forUpdate) { - _ctx.invoke(new Modifier(null) { - @Override public Integer invoke (Connection conn, DatabaseLiaison liaison) - throws SQLException { - PreparedStatement stmt = builder.prepare(conn); - try { - ResultSet rs = stmt.executeQuery(); - while (rs.next()) { - keys.add(marsh.makePrimaryKey(rs)); - } - return 0; - } finally { - JDBCUtil.close(stmt); - } - } - }); - - } else { - _ctx.invoke(new Query.Trivial() { - @Override - public Void invoke (Connection conn, DatabaseLiaison liaison) throws SQLException { - PreparedStatement stmt = builder.prepare(conn); - try { - ResultSet rs = stmt.executeQuery(); - while (rs.next()) { - keys.add(marsh.makePrimaryKey(rs)); - } - return null; - } finally { - JDBCUtil.close(stmt); - } - } - }); - } - - return keys; - } - - /** - * Inserts the supplied persistent object into the database, assigning its primary key (if it - * has one) in the process. - * - * @return the number of rows modified by this action, this should always be one. - */ - protected int insert (T record) - throws DatabaseException - { - @SuppressWarnings("unchecked") final Class pClass = (Class) record.getClass(); - final DepotMarshaller marsh = _ctx.getMarshaller(pClass); - Key key = marsh.getPrimaryKey(record, false); - - DepotTypes types = DepotTypes.getDepotTypes(_ctx); - types.addClass(_ctx, pClass); - final SQLBuilder builder = _ctx.getSQLBuilder(types); - - // key will be null if record was supplied without a primary key - return _ctx.invoke(new CachingModifier(record, key, key) { - @Override - public Integer invoke (Connection conn, DatabaseLiaison liaison) throws SQLException { - // if needed, update our modifier's key so that it can cache our results - Set identityFields = Collections.emptySet(); - if (_key == null) { - // set any auto-generated column values - identityFields = marsh.generateFieldValues(conn, liaison, _result, false); - updateKey(marsh.getPrimaryKey(_result, false)); - } - - builder.newQuery(new InsertClause(pClass, _result, identityFields)); - - PreparedStatement stmt = builder.prepare(conn); - try { - int mods = stmt.executeUpdate(); - // run any post-factum value generators and potentially generate our key - if (_key == null) { - marsh.generateFieldValues(conn, liaison, _result, true); - updateKey(marsh.getPrimaryKey(_result, false)); - } - return mods; - - } finally { - JDBCUtil.close(stmt); - } - } - }); - } - - /** - * Updates all fields of the supplied persistent object, using its primary key to identify the - * row to be updated. - * - * @return the number of rows modified by this action. - */ - protected int update (T record) - throws DatabaseException - { - @SuppressWarnings("unchecked") Class pClass = (Class) record.getClass(); - requireNotComputed(pClass, "update"); - - DepotMarshaller marsh = _ctx.getMarshaller(pClass); - Key key = marsh.getPrimaryKey(record); - if (key == null) { - throw new IllegalArgumentException("Can't update record with null primary key."); - } - - UpdateClause update = new UpdateClause(pClass, key, marsh._columnFields, record); - final SQLBuilder builder = _ctx.getSQLBuilder(DepotTypes.getDepotTypes(_ctx, update)); - builder.newQuery(update); - - return _ctx.invoke(new CachingModifier(record, key, key) { - @Override - public Integer invoke (Connection conn, DatabaseLiaison liaison) throws SQLException { - PreparedStatement stmt = builder.prepare(conn); - try { - return stmt.executeUpdate(); - } finally { - JDBCUtil.close(stmt); - } - } - }); - } - - /** - * Updates just the specified fields of the supplied persistent object, using its primary key - * to identify the row to be updated. This method currently flushes the associated record from - * the cache, but in the future it should be modified to update the modified fields in the - * cached value iff the record exists in the cache. - * - * @return the number of rows modified by this action. - */ - protected int update (T record, final String... modifiedFields) - throws DatabaseException - { - @SuppressWarnings("unchecked") Class pClass = (Class) record.getClass(); - requireNotComputed(pClass, "updatePartial"); - - DepotMarshaller marsh = _ctx.getMarshaller(pClass); - Key key = marsh.getPrimaryKey(record); - if (key == null) { - throw new IllegalArgumentException("Can't update record with null primary key."); - } - - UpdateClause update = new UpdateClause(pClass, key, modifiedFields, record); - final SQLBuilder builder = _ctx.getSQLBuilder(DepotTypes.getDepotTypes(_ctx, update)); - builder.newQuery(update); - - return _ctx.invoke(new CachingModifier(record, key, key) { - @Override - public Integer invoke (Connection conn, DatabaseLiaison liaison) throws SQLException { - PreparedStatement stmt = builder.prepare(conn); - // clear out _result so that we don't rewrite this partial record to the cache - _result = null; - try { - return stmt.executeUpdate(); - } finally { - JDBCUtil.close(stmt); - } - } - }); - } - - /** - * Updates the specified columns for all persistent objects matching the supplied primary key. - * - * @param type the type of the persistent object to be modified. - * @param primaryKey the primary key to match in the update. - * @param updates an mapping from the names of the fields/columns ti the values to be assigned. - * - * @return the number of rows modified by this action. - */ - protected int updatePartial ( - Class type, Comparable primaryKey, Map updates) - throws DatabaseException - { - Object[] fieldsValues = new Object[updates.size()*2]; - int idx = 0; - for (Map.Entry entry : updates.entrySet()) { - fieldsValues[idx++] = entry.getKey(); - fieldsValues[idx++] = entry.getValue(); - } - return updatePartial(type, primaryKey, fieldsValues); - } - - /** - * Updates the specified columns for all persistent objects matching the supplied primary key. - * - * @param type the type of the persistent object to be modified. - * @param primaryKey the primary key to match in the update. - * @param fieldsValues an array containing the names of the fields/columns and the values to be - * assigned, in key, value, key, value, etc. order. - * - * @return the number of rows modified by this action. - */ - protected int updatePartial ( - Class type, Comparable primaryKey, Object... fieldsValues) - throws DatabaseException - { - return updatePartial(_ctx.getMarshaller(type).makePrimaryKey(primaryKey), fieldsValues); - } - - /** - * Updates the specified columns for all persistent objects matching the supplied two-column - * primary key. - * - * @param type the type of the persistent object to be modified. - * @param fieldsValues an array containing the names of the fields/columns and the values to be - * assigned, in key, value, key, value, etc. order. - * - * @return the number of rows modified by this action. - */ - protected int updatePartial ( - Class type, String ix1, Comparable val1, String ix2, Comparable val2, - Object... fieldsValues) - throws DatabaseException - { - return updatePartial(new Key(type, ix1, val1, ix2, val2), fieldsValues); - } - - /** - * Updates the specified columns for all persistent objects matching the supplied three-column - * primary key. - * - * @param type the type of the persistent object to be modified. - * @param fieldsValues an array containing the names of the fields/columns and the values to be - * assigned, in key, value, key, value, etc. order. - * - * @return the number of rows modified by this action. - */ - protected int updatePartial ( - Class type, String ix1, Comparable val1, String ix2, Comparable val2, - String ix3, Comparable val3, Object... fieldsValues) - throws DatabaseException - { - return updatePartial(new Key(type, ix1, val1, ix2, val2, ix3, val3), fieldsValues); - } - - /** - * Updates the specified columns for all persistent objects matching the supplied key. - * - * @param key the key for the persistent objects to be modified. - * @param fieldsValues an array containing the names of the fields/columns and the values to be - * assigned, in key, value, key, value, etc. order. - * - * @return the number of rows modified by this action. - */ - protected int updatePartial (Key key, Object... fieldsValues) - throws DatabaseException - { - return updatePartial(key.getPersistentClass(), key, key, fieldsValues); - } - - /** - * Updates the specified columns for all persistent objects matching the supplied key. This - * method currently flushes the associated record from the cache, but in the future it should - * be modified to update the modified fields in the cached value iff the record exists in the - * cache. - * - * @param type the type of the persistent object to be modified. - * @param key the key to match in the update. - * @param invalidator a cache invalidator that will be run prior to the update to flush the - * relevant persistent objects from the cache, or null if no invalidation is needed. - * @param fieldsValues an array containing the names of the fields/columns and the values to be - * assigned, in key, value, key, value, etc. order. - * - * @return the number of rows modified by this action. - */ - protected int updatePartial ( - Class type, final WhereClause key, CacheInvalidator invalidator, Object... fieldsValues) - throws DatabaseException - { - if (invalidator instanceof ValidatingCacheInvalidator) { - ((ValidatingCacheInvalidator)invalidator).validateFlushType(type); // sanity check - } - key.validateQueryType(type); // and another - - // separate the arguments into keys and values - final String[] fields = new String[fieldsValues.length/2]; - final SQLExpression[] values = new SQLExpression[fields.length]; - for (int ii = 0, idx = 0; ii < fields.length; ii++) { - fields[ii] = (String)fieldsValues[idx++]; - values[ii] = new ValueExp(fieldsValues[idx++]); - } - UpdateClause update = new UpdateClause(type, key, fields, values); - final SQLBuilder builder = _ctx.getSQLBuilder(DepotTypes.getDepotTypes(_ctx, update)); - builder.newQuery(update); - - return _ctx.invoke(new Modifier(invalidator) { - @Override - public Integer invoke (Connection conn, DatabaseLiaison liaison) throws SQLException { - PreparedStatement stmt = builder.prepare(conn); - try { - return stmt.executeUpdate(); - } finally { - JDBCUtil.close(stmt); - } - } - }); - } - - /** - * Updates the specified columns for all persistent objects matching the supplied primary - * key. The values in this case must be literal SQL to be inserted into the update statement. - * In general this is used when you want to do something like the following: - * - *

-     * update FOO set BAR = BAR + 1;
-     * update BAZ set BIF = NOW();
-     * 
- * - * @param type the type of the persistent object to be modified. - * @param primaryKey the key to match in the update. - * @param fieldsValues an array containing the names of the fields/columns and the values to be - * assigned, in key, literal value, key, literal value, etc. order. - * - * @return the number of rows modified by this action. - */ - protected int updateLiteral ( - Class type, Comparable primaryKey, Map fieldsValues) - throws DatabaseException - { - Key key = _ctx.getMarshaller(type).makePrimaryKey(primaryKey); - return updateLiteral(type, key, key, fieldsValues); - } - - /** - * Updates the specified columns for all persistent objects matching the supplied two-column - * primary key. The values in this case must be literal SQL to be inserted into the update - * statement. In general this is used when you want to do something like the following: - * - *
-     * update FOO set BAR = BAR + 1;
-     * update BAZ set BIF = NOW();
-     * 
- * - * @param type the type of the persistent object to be modified. - * @param fieldsValues an array containing the names of the fields/columns and the values to be - * assigned, in key, literal value, key, literal value, etc. order. - * - * @return the number of rows modified by this action. - */ - protected int updateLiteral ( - Class type, String ix1, Comparable val1, String ix2, Comparable val2, - Map fieldsValues) - throws DatabaseException - { - Key key = new Key(type, ix1, val1, ix2, val2); - return updateLiteral(type, key, key, fieldsValues); - } - - /** - * Updates the specified columns for all persistent objects matching the supplied three-column - * primary key. The values in this case must be literal SQL to be inserted into the update - * statement. In general this is used when you want to do something like the following: - * - *
-     * update FOO set BAR = BAR + 1;
-     * update BAZ set BIF = NOW();
-     * 
- * - * @param type the type of the persistent object to be modified. - * @param fieldsValues an array containing the names of the fields/columns and the values to be - * assigned, in key, literal value, key, literal value, etc. order. - * - * @return the number of rows modified by this action. - */ - protected int updateLiteral ( - Class type, String ix1, Comparable val1, String ix2, Comparable val2, - String ix3, Comparable val3, Map fieldsValues) - throws DatabaseException - { - Key key = new Key(type, ix1, val1, ix2, val2, ix3, val3); - return updateLiteral(type, key, key, fieldsValues); - } - - /** - * Updates the specified columns for all persistent objects matching the supplied primary - * key. The values in this case must be literal SQL to be inserted into the update statement. - * In general this is used when you want to do something like the following: - * - *
-     * update FOO set BAR = BAR + 1;
-     * update BAZ set BIF = NOW();
-     * 
- * - * @param type the type of the persistent object to be modified. - * @param key the key to match in the update. - * @param fieldsValues an array containing the names of the fields/columns and the values to be - * assigned, in key, literal value, key, literal value, etc. order. - * - * @return the number of rows modified by this action. - */ - protected int updateLiteral ( - Class type, final WhereClause key, CacheInvalidator invalidator, - Map fieldsValues) - throws DatabaseException - { - requireNotComputed(type, "updateLiteral"); - - if (invalidator instanceof ValidatingCacheInvalidator) { - ((ValidatingCacheInvalidator)invalidator).validateFlushType(type); // sanity check - } - key.validateQueryType(type); // and another - - // separate the arguments into keys and values - final String[] fields = new String[fieldsValues.size()]; - final SQLExpression[] values = new SQLExpression[fields.length]; - int ii = 0; - for (Map.Entry entry : fieldsValues.entrySet()) { - fields[ii] = entry.getKey(); - values[ii] = entry.getValue(); - ii ++; - } - - UpdateClause update = new UpdateClause(type, key, fields, values); - final SQLBuilder builder = _ctx.getSQLBuilder(DepotTypes.getDepotTypes(_ctx, update)); - builder.newQuery(update); - - return _ctx.invoke(new Modifier(invalidator) { - @Override - public Integer invoke (Connection conn, DatabaseLiaison liaison) throws SQLException { - PreparedStatement stmt = builder.prepare(conn); - try { - return stmt.executeUpdate(); - } finally { - JDBCUtil.close(stmt); - } - } - }); - } - - /** - * Stores the supplied persisent object in the database. If it has no primary key assigned (it - * is null or zero), it will be inserted directly. Otherwise an update will first be attempted - * and if that matches zero rows, the object will be inserted. - * - * @return true if the record was created, false if it was updated. - */ - protected boolean store (T record) - throws DatabaseException - { - @SuppressWarnings("unchecked") final Class pClass = (Class) record.getClass(); - requireNotComputed(pClass, "store"); - - final DepotMarshaller marsh = _ctx.getMarshaller(pClass); - Key key = marsh.hasPrimaryKey() ? marsh.getPrimaryKey(record) : null; - final UpdateClause update = - new UpdateClause(pClass, key, marsh._columnFields, record); - final SQLBuilder builder = _ctx.getSQLBuilder(DepotTypes.getDepotTypes(_ctx, update)); - - // if our primary key isn't null, we start by trying to update rather than insert - if (key != null) { - builder.newQuery(update); - } - - final boolean[] created = new boolean[1]; - _ctx.invoke(new CachingModifier(record, key, key) { - @Override - public Integer invoke (Connection conn, DatabaseLiaison liaison) throws SQLException { - PreparedStatement stmt = null; - try { - if (_key != null) { - // run the update - stmt = builder.prepare(conn); - int mods = stmt.executeUpdate(); - if (mods > 0) { - // if it succeeded, we're done - return mods; - } - JDBCUtil.close(stmt); - } - - // if the update modified zero rows or the primary key was unset, insert - Set identityFields = Collections.emptySet(); - if (_key == null) { - // first, set any auto-generated column values - identityFields = marsh.generateFieldValues(conn, liaison, _result, false); - // update our modifier's key so that it can cache our results - updateKey(marsh.getPrimaryKey(_result, false)); - } - - builder.newQuery(new InsertClause(pClass, _result, identityFields)); - - stmt = builder.prepare(conn); - int mods = stmt.executeUpdate(); - - // run any post-factum value generators and potentially generate our key - if (_key == null) { - marsh.generateFieldValues(conn, liaison, _result, true); - updateKey(marsh.getPrimaryKey(_result, false)); - } - created[0] = true; - return mods; - - } finally { - JDBCUtil.close(stmt); - } - } - }); - return created[0]; - } - - /** - * Deletes all persistent objects from the database with a primary key matching the primary key - * of the supplied object. - * - * @return the number of rows deleted by this action. - */ - protected int delete (T record) - throws DatabaseException - { - @SuppressWarnings("unchecked") Class type = (Class)record.getClass(); - Key primaryKey = _ctx.getMarshaller(type).getPrimaryKey(record); - if (primaryKey == null) { - throw new IllegalArgumentException("Can't delete record with null primary key."); - } - return delete(type, primaryKey); - } - - /** - * Deletes all persistent objects from the database with a primary key matching the supplied - * primary key. - * - * @return the number of rows deleted by this action. - */ - protected int delete (Class type, Comparable primaryKeyValue) - throws DatabaseException - { - return delete(type, _ctx.getMarshaller(type).makePrimaryKey(primaryKeyValue)); - } - - /** - * Deletes all persistent objects from the database with a primary key matching the supplied - * primary key. - * - * @return the number of rows deleted by this action. - */ - protected int delete (Class type, Key primaryKey) - throws DatabaseException - { - return deleteAll(type, primaryKey, primaryKey); - } - - /** - * Deletes all persistent objects from the database that match the supplied where clause. - * - * @return the number of rows deleted by this action. - */ - protected int deleteAll (Class type, final WhereClause where) - throws DatabaseException - { - if (_ctx.getMarshaller(type).hasPrimaryKey()) { - // look up the primary keys for all rows matching our where clause and delete using those - KeySet pwhere = new KeySet(type, findAllKeys(type, true, where)); - return deleteAll(type, pwhere, pwhere); - } else { - // otherwise just do the delete directly as we can't have cached a record that has no - // primary key in the first place - return deleteAll(type, where, null); - } - } - - /** - * Deletes all persistent objects from the database that match the supplied key. - * - * @return the number of rows deleted by this action. - */ - protected int deleteAll ( - Class type, final WhereClause where, CacheInvalidator invalidator) - throws DatabaseException - { - if (invalidator instanceof ValidatingCacheInvalidator) { - ((ValidatingCacheInvalidator)invalidator).validateFlushType(type); // sanity check - } - where.validateQueryType(type); // and another - - DeleteClause delete = new DeleteClause(type, where); - final SQLBuilder builder = _ctx.getSQLBuilder(DepotTypes.getDepotTypes(_ctx, delete)); - builder.newQuery(delete); - - return _ctx.invoke(new Modifier(invalidator) { - @Override - public Integer invoke (Connection conn, DatabaseLiaison liaison) throws SQLException { - PreparedStatement stmt = builder.prepare(conn); - try { - return stmt.executeUpdate(); - } finally { - JDBCUtil.close(stmt); - } - } - }); - } - - // make sure the given type corresponds to a concrete class - protected void requireNotComputed (Class type, String action) - throws DatabaseException - { - DepotMarshaller marsh = _ctx.getMarshaller(type); - if (marsh == null) { - throw new DatabaseException("Unknown persistent type [class=" + type + "]"); - } - if (marsh.getTableName() == null) { - throw new DatabaseException( - "Can't " + action + " computed entities [class=" + type + "]"); - } - } - - /** - * If the supplied migration has not already been run, it will be run and if it completes, we - * will note in the DepotMigrationHistory table that it has been run. - */ - protected void runMigration (DataMigration migration) - throws DatabaseException - { - // attempt to get a lock to run this migration (or detect that it has already been run) - DepotMigrationHistoryRecord record; - while (true) { - // check to see if the migration has already been completed - record = load(DepotMigrationHistoryRecord.class, migration.getIdent()); - if (record != null && record.whenCompleted != null) { - return; // great, no need to do anything - } - - // if no record exists at all, try to insert one and thereby obtain the migration lock - if (record == null) { - try { - record = new DepotMigrationHistoryRecord(); - record.ident = migration.getIdent(); - insert(record); - break; // we got the lock, break out of this loop and run the migration - } catch (DuplicateKeyException dke) { - // someone beat us to the punch, so we have to wait for them to finish - } - } - - // we didn't get the lock, so wait 5 seconds and then check to see if the other process - // finished the update or failed in which case we'll try to grab the lock ourselves - try { - log.info("Waiting on migration lock for " + migration.getIdent() + "."); - Thread.sleep(5000); - } catch (InterruptedException ie) { - throw new DatabaseException("Interrupted while waiting on migration lock."); - } - } - - log.info("Running data migration", "ident", migration.getIdent()); - try { - // run the migration - migration.invoke(); - - // report to the world that we've done so - record.whenCompleted = new Timestamp(System.currentTimeMillis()); - update(record); - - } finally { - // clear out our migration history record if we failed to get the job done - if (record.whenCompleted == null) { - try { - delete(record); - } catch (Throwable dt) { - log.warning("Oh noez! Failed to delete history record for failed migration. " + - "All clients will loop forever waiting for the lock.", - "ident", migration.getIdent(), dt); - } - } - } - } - - protected PersistenceContext _ctx; - protected List _dataMigs = new ArrayList(); -} diff --git a/src/java/com/samskivert/jdbc/depot/DepotTypes.java b/src/java/com/samskivert/jdbc/depot/DepotTypes.java deleted file mode 100644 index c0ff4e9f..00000000 --- a/src/java/com/samskivert/jdbc/depot/DepotTypes.java +++ /dev/null @@ -1,221 +0,0 @@ -// -// $Id$ -// -// samskivert library - useful routines for java programs -// Copyright (C) 2006-2007 Michael Bayne, Pär Winzell -// -// This library is free software; you can redistribute it and/or modify it -// under the terms of the GNU Lesser General Public License as published -// by the Free Software Foundation; either version 2.1 of the License, or -// (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -package com.samskivert.jdbc.depot; - -import java.sql.SQLException; - -import java.util.Arrays; -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Map; -import java.util.Set; - -import com.samskivert.jdbc.depot.clause.QueryClause; -import com.samskivert.jdbc.depot.expression.SQLExpression; - -/** - * Maintains a record of the persistent classes brought into the context of the associated SQL, - * i.e. any class associated with a concrete table that would appear in FROM or JOIN clauses or as - * the target of an UPDATE or an INSERT or any other place where a table abbreviation could be - * constructed. - * - * The main motivation for breaking this functionality out into its own class is to encapsulate the - * operation that throws {@link DatabaseException} as separate from the operations that throw - * {@link SQLException}. Once this class has been constructed, it may be used to create {@link - * SQLBuilder} instances without any {@link DatabaseException} worries. - */ -public class DepotTypes -{ - /** A trivial instance that is accessible in places where we want the dialectal benefits of the - * SQLBuilder without really requiring per-persistent-class context. */ - public static DepotTypes TRIVIAL = new DepotTypes(); - - /** - * Conveniently constructs a {@link DepotTypes} object given {@link QueryClause} objects, which - * are interrogated for their class definition sets through {@link SQLExpression#addClasses}. - */ - public static DepotTypes getDepotTypes ( - PersistenceContext ctx, Collection clauses) - throws DatabaseException - { - Set> classSet = - new HashSet>(); - for (QueryClause clause : clauses) { - if (clause != null) { - clause.addClasses(classSet); - } - } - return new DepotTypes(ctx, classSet); - } - - /** - * A varargs version of {@link #getDepotTypes(PersistenceContext,Collection)}. - */ - public static DepotTypes getDepotTypes ( - PersistenceContext ctx, QueryClause... clauses) - throws DatabaseException - { - return getDepotTypes(ctx, Arrays.asList(clauses)); - } - - /** - * Create a new DepotTypes with the given {@link PersistenceContext} and a collection of - * persistent record classes. - */ - public DepotTypes (PersistenceContext ctx, Collection> others) - throws DatabaseException - { - for (Class c : others) { - addClass(ctx, c); - } - } - - /** - * Create a new DepotTypes with the given {@link PersistenceContext} and the given - * persistent record. - */ - public DepotTypes (PersistenceContext ctx, Class pClass) - throws DatabaseException - { - addClass(ctx, pClass); - } - - /** - * Return the full table name of the given persistent class, which must have been previously - * registered with this object. - */ - public String getTableName (Class cl) - { - return getMarshaller(cl).getTableName(); - } - - /** - * Return the current abbreviation by which we refer to the table associated with the given - * persistent record -- which must have been previously registered with this object. If the - * useTableAbbreviations flag is false, we return the full table name instead. - * - * @exception IllegalArgumentException thrown if the specified class is not known. - */ - public String getTableAbbreviation (Class cl) - { - if (_useTableAbbreviations) { - Integer ix = _classIx.get(cl); - if (ix == null) { - throw new IllegalArgumentException("Unknown persistence class: " + cl); - } - return "T" + (ix+1); - } - return getTableName(cl); - } - - /** - * Return the associated database column of the given field of the given persistent class, - * throwing an exception if the record has not been registered with this object, or if the - * field is unknown on the record. - * - * @exception IllegalArgumentException thrown if the specified field is not part of the - * specified persistent class. - */ - public String getColumnName (Class cl, String field) - { - FieldMarshaller fm = getMarshaller(cl).getFieldMarshaller(field); - if (fm == null) { - throw new IllegalArgumentException( - "Field not known on class [field=" + field + ", class=" + cl + "]"); - } - return fm.getColumnName(); - } - - /** - * Return the {@link DepotMarshaller} associated with the given persistent class, if it's been - * registered with this object. - * - * @exception IllegalArgumentException thrown if the specified class is not known. - */ - public DepotMarshaller getMarshaller (Class cl) - { - DepotMarshaller marsh = _classMap.get(cl); - if (marsh == null) { - throw new IllegalArgumentException("Persistent class not known: " + cl); - } - return marsh; - } - - /** - * Register a new persistent class with this object. - */ - public void addClass (PersistenceContext ctx, Class type) - throws DatabaseException - { - if (_classMap.containsKey(type)) { - return; - } - - // add the class in question - DepotMarshaller marsh = ctx.getMarshaller(type); - _classMap.put(type, marsh); - _classIx.put(type, _classIx.size()); - - // if this class is @Computed and has a shadow, add its shadow - if (marsh.getComputed() != null && - !PersistentRecord.class.equals(marsh.getComputed().shadowOf())) { - addClass(ctx, marsh.getComputed().shadowOf()); - } - } - - /** - * Return the value of the useTableAbbreviations flag, which governs the behaviour when - * referencing columns during SQL construction. Normally, this flag is on, and tables are - * referenced as e.g. T1.itemId, but there are cases of weak/broken SQL where abbreviations - * may not be brought into play. In these cases we prepend the full table name. - */ - public boolean getUseTableAbbreviations () - { - return _useTableAbbreviations; - } - - /** - * Sets the value of the useTableAbbreviations flag, which governs the behaviour when - * referencing columns during SQL construction. Normally, this flag is on, and tables are - * referenced as e.g. T1.itemId, but there are cases of weak/broken SQL where abbreviations - * may not be brought into play. In these cases we prepend the full table name. - */ - public void setUseTableAbbreviations (boolean doUse) - { - _useTableAbbreviations = doUse; - } - - // constructor used to create TRIVIAL - protected DepotTypes () - { - } - - /** Classes mapped to integers, used for table abbreviation indexing. */ - protected Map, Integer> _classIx = new HashMap, Integer>(); - - /** Classes mapped to marshallers, used for table names and field lists. */ - protected Map, DepotMarshaller> _classMap = - new HashMap, DepotMarshaller>(); - - /** When false, override the normal table abbreviations and return full table names instead. */ - protected boolean _useTableAbbreviations = true; -} diff --git a/src/java/com/samskivert/jdbc/depot/DuplicateKeyException.java b/src/java/com/samskivert/jdbc/depot/DuplicateKeyException.java deleted file mode 100644 index 90960890..00000000 --- a/src/java/com/samskivert/jdbc/depot/DuplicateKeyException.java +++ /dev/null @@ -1,33 +0,0 @@ -// -// $Id$ -// -// samskivert library - useful routines for java programs -// Copyright (C) 2001-2008 Michael Bayne -// -// This library is free software; you can redistribute it and/or modify it -// under the terms of the GNU Lesser General Public License as published -// by the Free Software Foundation; either version 2.1 of the License, or -// (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -package com.samskivert.jdbc.depot; - -/** - * Thrown when an insert or update results in a duplicate key on a column that has a uniqueness - * constraint. - */ -public class DuplicateKeyException extends DatabaseException -{ - public DuplicateKeyException (String message) - { - super(message); - } -} diff --git a/src/java/com/samskivert/jdbc/depot/EHCacheAdapter.java b/src/java/com/samskivert/jdbc/depot/EHCacheAdapter.java deleted file mode 100644 index 54c543c8..00000000 --- a/src/java/com/samskivert/jdbc/depot/EHCacheAdapter.java +++ /dev/null @@ -1,169 +0,0 @@ -// -// $Id$ -// -// samskivert library - useful routines for java programs -// Copyright (C) 2006-2007 Michael Bayne, Pär Winzell -// -// This library is free software; you can redistribute it and/or modify it -// under the terms of the GNU Lesser General Public License as published -// by the Free Software Foundation; either version 2.1 of the License, or -// (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -package com.samskivert.jdbc.depot; - -import java.io.Serializable; - -import net.sf.ehcache.Cache; -import net.sf.ehcache.CacheManager; -import net.sf.ehcache.Element; -import net.sf.ehcache.distribution.CacheManagerPeerListener; -import net.sf.ehcache.distribution.CacheManagerPeerProvider; -import net.sf.ehcache.distribution.RMIAsynchronousCacheReplicator; - -import static com.samskivert.jdbc.depot.Log.log; - -/** - * An implementation of {@link CacheAdapter} for ehcache. - */ -public class EHCacheAdapter - implements CacheAdapter -{ - /** - * Creates an adapter using the supplied cache manager. Note: this adapter does not shut down - * the supplied manager when it is shutdown. The caller is responsible for shutting down the - * cache manager when it knows that Depot and any other clients no longer need it. - */ - public EHCacheAdapter (CacheManager cachemgr) - { - _cachemgr = cachemgr; - - CacheManagerPeerListener listener = _cachemgr.getCachePeerListener(); - CacheManagerPeerProvider provider = _cachemgr.getCachePeerProvider(); - if ((provider != null) != (listener != null)) { - // we want either both listener and provider, or neither - log.warning("EHCache misconfigured, distributed mode disabled [listener =" + - listener + ", provider=" + provider); - _distributed = false; - - } else { - _distributed = (listener != null); - } - } - - public CacheBin getCache (String id) - { - return new EHCacheBin(id); - } - - /** - * The main ehcache-bridging class, a {@link CacheBin} interface against {@link Cache}. - */ - protected class EHCacheBin implements CacheBin - { - // from CacheBin - public CachedValue lookup (Serializable key) - { - Element hit = _cache.get(key); - if (hit == null) { - return null; - } - - Serializable rawValue = hit.getValue(); - @SuppressWarnings("unchecked") - final T value = (T) (rawValue instanceof NullValue ? null : rawValue); - return new CachedValue() { - public T getValue () { - return value; - } - @Override public String toString () { - return String.valueOf(value); - } - }; - } - - // from CacheBin - public void store (Serializable key, T value) - { - _cache.put(new Element(key, value != null ? value : NULL)); - } - - // from CacheBin - public void remove (Serializable key) - { - _cache.remove(key); - } - - // from CacheBin - public Iterable enumerateKeys () - { - @SuppressWarnings("unchecked") Iterable keys = _cache.getKeys(); - return keys; - } - - protected EHCacheBin (String id) - { - synchronized (_cachemgr) { - _cache = _cachemgr.getCache(id); - if (_cache == null) { - // create the cache programatically with reasonable settings - // TODO: we will eventually need this to be configurable in .properties - _cache = new Cache(id, - 1000, // keep 1000 elements in RAM - true, // overflow the rest to disk - false, // don't keep records around eternally - 300, // keep them for 5 minutes after they're created - 20); // or 20 seconds after last access - - if (_distributed) { - // a programatically created cache has to have its replicator event - // listener programatically added. - _cache.getCacheEventNotificationService().registerListener( - new RMIAsynchronousCacheReplicator(true, true, true, true, 1000)); - } - _cachemgr.addCache(_cache); - } - } - } - - protected Cache _cache; - } - - // from CacheAdapter - public void shutdown () - { - } - - protected boolean _distributed; - protected CacheManager _cachemgr; - - // this is just for convenience and memory use; we don't rely on pointer equality anywhere - protected static Serializable NULL = new NullValue() {}; - - /** A class to represent an explicitly Serializable concept of null for EHCache. */ - protected static class NullValue implements Serializable - { - @Override public String toString () - { - return ""; - } - - @Override public boolean equals (Object other) - { - return other != null && other.getClass().equals(NullValue.class); - } - - @Override public int hashCode () - { - return 1; - } - } -} diff --git a/src/java/com/samskivert/jdbc/depot/FieldMarshaller.java b/src/java/com/samskivert/jdbc/depot/FieldMarshaller.java deleted file mode 100644 index 37efe3fb..00000000 --- a/src/java/com/samskivert/jdbc/depot/FieldMarshaller.java +++ /dev/null @@ -1,477 +0,0 @@ -// -// $Id$ -// -// samskivert library - useful routines for java programs -// Copyright (C) 2006-2007 Michael Bayne, Pär Winzell -// -// This library is free software; you can redistribute it and/or modify it -// under the terms of the GNU Lesser General Public License as published -// by the Free Software Foundation; either version 2.1 of the License, or -// (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -package com.samskivert.jdbc.depot; - -import java.lang.reflect.Field; -import java.lang.reflect.Method; -import java.lang.reflect.Modifier; -import java.nio.ByteBuffer; - -import java.sql.Blob; -import java.sql.Clob; -import java.sql.Date; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Time; -import java.sql.Timestamp; - -import com.samskivert.jdbc.ColumnDefinition; -import com.samskivert.jdbc.depot.annotation.Column; -import com.samskivert.jdbc.depot.annotation.Computed; -import com.samskivert.jdbc.depot.annotation.GeneratedValue; - -import com.samskivert.util.StringUtil; - -/** - * Handles the marshalling and unmarshalling of a particular field of a persistent object. - * - * @see DepotMarshaller - */ -public abstract class FieldMarshaller -{ - /** - * Creates and returns a field marshaller for the specified field. Throws an exception if the - * field in question cannot be marshalled. - */ - public static FieldMarshaller createMarshaller (Field field) - { - Class ftype = field.getType(); - FieldMarshaller marshaller; - - // primitive types - if (ftype.equals(Boolean.TYPE)) { - marshaller = new BooleanMarshaller(); - } else if (ftype.equals(Byte.TYPE)) { - marshaller = new ByteMarshaller(); - } else if (ftype.equals(Short.TYPE)) { - marshaller = new ShortMarshaller(); - } else if (ftype.equals(Integer.TYPE)) { - marshaller = new IntMarshaller(); - } else if (ftype.equals(Long.TYPE)) { - marshaller = new LongMarshaller(); - } else if (ftype.equals(Float.TYPE)) { - marshaller = new FloatMarshaller(); - } else if (ftype.equals(Double.TYPE)) { - marshaller = new DoubleMarshaller(); - - // "natural" types - } else if (ftype.equals(Byte.class) || - ftype.equals(Short.class) || - ftype.equals(Integer.class) || - ftype.equals(Long.class) || - ftype.equals(Float.class) || - ftype.equals(Double.class) || - ftype.equals(String.class)) { - marshaller = new ObjectMarshaller(); - - // some primitive array types - } else if (ftype.equals(byte[].class)) { - marshaller = new ByteArrayMarshaller(); - - } else if (ftype.equals(int[].class)) { - marshaller = new IntArrayMarshaller(); - - // SQL types - } else if (ftype.equals(Date.class) || - ftype.equals(Time.class) || - ftype.equals(Timestamp.class) || - ftype.equals(Blob.class) || - ftype.equals(Clob.class)) { - marshaller = new ObjectMarshaller(); - - // special Enum types - } else if (ByteEnum.class.isAssignableFrom(ftype)) { - marshaller = new ByteEnumMarshaller(ftype); - - } else { - throw new IllegalArgumentException( - "Cannot marshall field of type '" + ftype.getName() + "'."); - } - - marshaller.create(field); - return marshaller; - } - - /** - * Initializes this field marshaller with a SQL builder which it uses to construct its column - * definition according to the appropriate database dialect. - */ - public void init (SQLBuilder builder) - throws DatabaseException - { - _columnDefinition = builder.buildColumnDefinition(this); - } - - /** - * Returns the {@link Field} handled by this marshaller. - */ - public Field getField () - { - return _field; - } - - /** - * Returns the Computed annotation on this field, if any. - */ - public Computed getComputed () - { - return _computed; - } - - /** - * Returns the GeneratedValue annotation on this field, if any. - */ - public GeneratedValue getGeneratedValue () - { - return _generatedValue; - } - - /** - * Returns the name of the table column used to store this field. - */ - public String getColumnName () - { - return _columnName; - } - - /** - * Returns the SQL used to define this field's column. - */ - public ColumnDefinition getColumnDefinition () - { - return _columnDefinition; - } - - /** - * Reads this field from the given persistent object. - */ - public abstract T getFromObject (Object po) - throws IllegalArgumentException, IllegalAccessException; - - /** - * Sets the specified column of the given prepared statement to the given value. - */ - public abstract void writeToStatement (PreparedStatement ps, int column, T value) - throws SQLException; - - /** - * Reads the value of our field from the supplied persistent object and sets that value into - * the specified column of the supplied prepared statement. - */ - public void getAndWriteToStatement (PreparedStatement ps, int column, Object po) - throws SQLException, IllegalAccessException - { - writeToStatement(ps, column, getFromObject(po)); - } - - /** - * Reads and returns this field from the result set. - */ - public abstract T getFromSet (ResultSet rs) - throws SQLException; - - /** - * Writes the given value to the given persistent value. - */ - public abstract void writeToObject (Object po, T value) - throws IllegalArgumentException, IllegalAccessException; - - /** - * Reads the specified column from the supplied result set and writes it to the appropriate - * field of the persistent object. - */ - public void getAndWriteToObject (ResultSet rset, Object po) - throws SQLException, IllegalAccessException - { - writeToObject(po, getFromSet(rset)); - } - - protected void create (Field field) - { - _field = field; - _columnName = field.getName(); - - Column column = _field.getAnnotation(Column.class); - if (column != null) { - if (!StringUtil.isBlank(column.name())) { - _columnName = column.name(); - } - } - - _computed = field.getAnnotation(Computed.class); - if (_computed != null) { - return; - } - - // figure out how we're going to generate our primary key values - _generatedValue = field.getAnnotation(GeneratedValue.class); - } - - protected static class BooleanMarshaller extends FieldMarshaller { - @Override public Boolean getFromObject (Object po) - throws IllegalArgumentException, IllegalAccessException { - return _field.getBoolean(po); - } - @Override public Boolean getFromSet (ResultSet rs) - throws SQLException { - return rs.getBoolean(getColumnName()); - } - @Override public void writeToObject (Object po, Boolean value) - throws IllegalArgumentException, IllegalAccessException { - _field.setBoolean(po, value); - } - @Override public void writeToStatement (PreparedStatement ps, int column, Boolean value) - throws SQLException { - ps.setBoolean(column, value); - } - } - - protected static class ByteMarshaller extends FieldMarshaller { - @Override public Byte getFromObject (Object po) - throws IllegalArgumentException, IllegalAccessException { - return _field.getByte(po); - } - @Override public Byte getFromSet (ResultSet rs) - throws SQLException { - return rs.getByte(getColumnName()); - } - @Override public void writeToObject (Object po, Byte value) - throws IllegalArgumentException, IllegalAccessException { - _field.setByte(po, value); - } - @Override public void writeToStatement (PreparedStatement ps, int column, Byte value) - throws SQLException { - ps.setByte(column, value); - } - } - - protected static class ShortMarshaller extends FieldMarshaller { - @Override public Short getFromObject (Object po) - throws IllegalArgumentException, IllegalAccessException { - return _field.getShort(po); - } - @Override public Short getFromSet (ResultSet rs) - throws SQLException { - return rs.getShort(getColumnName()); - } - @Override public void writeToObject (Object po, Short value) - throws IllegalArgumentException, IllegalAccessException { - _field.setShort(po, value); - } - @Override public void writeToStatement (PreparedStatement ps, int column, Short value) - throws SQLException { - ps.setShort(column, value); - } - } - - protected static class IntMarshaller extends FieldMarshaller { - @Override public Integer getFromObject (Object po) - throws IllegalArgumentException, IllegalAccessException { - return _field.getInt(po); - } - @Override public Integer getFromSet (ResultSet rs) - throws SQLException { - return rs.getInt(getColumnName()); - } - @Override public void writeToObject (Object po, Integer value) - throws IllegalArgumentException, IllegalAccessException { - _field.setInt(po, value); - } - @Override public void writeToStatement (PreparedStatement ps, int column, Integer value) - throws SQLException { - ps.setInt(column, value); - } - } - - protected static class LongMarshaller extends FieldMarshaller { - @Override public Long getFromObject (Object po) - throws IllegalArgumentException, IllegalAccessException { - return _field.getLong(po); - } - @Override public Long getFromSet (ResultSet rs) - throws SQLException { - return rs.getLong(getColumnName()); - } - @Override public void writeToObject (Object po, Long value) - throws IllegalArgumentException, IllegalAccessException { - _field.setLong(po, value); - } - @Override public void writeToStatement (PreparedStatement ps, int column, Long value) - throws SQLException { - ps.setLong(column, value); - } - } - - protected static class FloatMarshaller extends FieldMarshaller { - @Override public Float getFromObject (Object po) - throws IllegalArgumentException, IllegalAccessException { - return _field.getFloat(po); - } - @Override public Float getFromSet (ResultSet rs) - throws SQLException { - return rs.getFloat(getColumnName()); - } - @Override public void writeToObject (Object po, Float value) - throws IllegalArgumentException, IllegalAccessException { - _field.setFloat(po, value); - } - @Override public void writeToStatement (PreparedStatement ps, int column, Float value) - throws SQLException { - ps.setFloat(column, value); - } - } - - protected static class DoubleMarshaller extends FieldMarshaller { - @Override public Double getFromObject (Object po) - throws IllegalArgumentException, IllegalAccessException { - return _field.getDouble(po); - } - @Override public Double getFromSet (ResultSet rs) - throws SQLException { - return rs.getDouble(getColumnName()); - } - @Override public void writeToObject (Object po, Double value) - throws IllegalArgumentException, IllegalAccessException { - _field.setDouble(po, value); - } - @Override public void writeToStatement (PreparedStatement ps, int column, Double value) - throws SQLException { - ps.setDouble(column, value); - } - } - - protected static class ObjectMarshaller extends FieldMarshaller { - @Override public Object getFromObject (Object po) - throws IllegalArgumentException, IllegalAccessException { - return _field.get(po); - } - @Override public Object getFromSet (ResultSet rs) - throws SQLException { - return rs.getObject(getColumnName()); - } - @Override public void writeToObject (Object po, Object value) - throws IllegalArgumentException, IllegalAccessException { - _field.set(po, value); - } - @Override public void writeToStatement (PreparedStatement ps, int column, Object value) - throws SQLException { - ps.setObject(column, value); - } - } - - protected static class ByteArrayMarshaller extends FieldMarshaller { - @Override public byte[] getFromObject (Object po) - throws IllegalArgumentException, IllegalAccessException { - return (byte[]) _field.get(po); - } - @Override public byte[] getFromSet (ResultSet rs) - throws SQLException { - return rs.getBytes(getColumnName()); - } - @Override public void writeToObject (Object po, byte[] value) - throws IllegalArgumentException, IllegalAccessException { - _field.set(po, value); - } - @Override public void writeToStatement (PreparedStatement ps, int column, byte[] value) - throws SQLException { - ps.setBytes(column, value); - } - } - - protected static class IntArrayMarshaller extends FieldMarshaller { - @Override public byte[] getFromObject (Object po) - throws IllegalArgumentException, IllegalAccessException { - int[] values = (int[]) _field.get(po); - if (values == null) { - return null; - } - ByteBuffer bbuf = ByteBuffer.allocate(values.length * 4); - bbuf.asIntBuffer().put(values); - return bbuf.array(); - - } - @Override public byte[] getFromSet (ResultSet rs) - throws SQLException { - return (byte[]) rs.getObject(getColumnName()); - } - @Override public void writeToObject (Object po, byte[] data) - throws IllegalArgumentException, IllegalAccessException { - int[] value = null; - if (data != null) { - value = new int[data.length/4]; - ByteBuffer.wrap(data).asIntBuffer().get(value); - } - _field.set(po, value); - } - @Override public void writeToStatement (PreparedStatement ps, int column, byte[] value) - throws SQLException { - ps.setObject(column, value); - } - } - - protected static class ByteEnumMarshaller extends FieldMarshaller { - public ByteEnumMarshaller (Class clazz) { - try { - _factmeth = clazz.getMethod("fromByte", new Class[] { Byte.TYPE }); - } catch (Exception e) { - throw new IllegalArgumentException( - "Could not locate fromByte() method on enum field " + _field.getType() + "."); - } - if (!Modifier.isPublic(_factmeth.getModifiers()) || - !Modifier.isStatic(_factmeth.getModifiers())) { - throw new IllegalArgumentException( - _field.getType() + ".fromByte() must be public and static."); - } - } - - @Override public ByteEnum getFromObject (Object po) - throws IllegalArgumentException, IllegalAccessException { - return (ByteEnum) _field.get(po); - } - @Override public ByteEnum getFromSet (ResultSet rs) - throws SQLException { - try { - return (ByteEnum) _factmeth.invoke(null, rs.getByte(getColumnName())); - } catch (SQLException se) { - throw se; - } catch (Exception e) { - throw new RuntimeException(e); - } - } - @Override public void writeToObject (Object po, ByteEnum value) - throws IllegalArgumentException, IllegalAccessException { - _field.set(po, value); - } - @Override public void writeToStatement (PreparedStatement ps, int column, ByteEnum value) - throws SQLException { - ps.setByte(column, value.toByte()); - } - - protected Method _factmeth; - } - - protected Field _field; - protected String _columnName; - protected ColumnDefinition _columnDefinition; - protected Computed _computed; - protected GeneratedValue _generatedValue; -} diff --git a/src/java/com/samskivert/jdbc/depot/FindAllQuery.java b/src/java/com/samskivert/jdbc/depot/FindAllQuery.java deleted file mode 100644 index 8d559d07..00000000 --- a/src/java/com/samskivert/jdbc/depot/FindAllQuery.java +++ /dev/null @@ -1,303 +0,0 @@ -// -// $Id$ -// -// samskivert library - useful routines for java programs -// Copyright (C) 2006-2007 Michael Bayne, Pär Winzell -// -// This library is free software; you can redistribute it and/or modify it -// under the terms of the GNU Lesser General Public License as published -// by the Free Software Foundation; either version 2.1 of the License, or -// (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -package com.samskivert.jdbc.depot; - -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.HashSet; -import java.util.Iterator; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import com.samskivert.jdbc.DatabaseLiaison; -import com.samskivert.jdbc.JDBCUtil; - -import com.samskivert.jdbc.depot.clause.FieldOverride; -import com.samskivert.jdbc.depot.clause.QueryClause; -import com.samskivert.jdbc.depot.clause.SelectClause; -import com.samskivert.jdbc.depot.operator.Conditionals.*; - -import static com.samskivert.jdbc.depot.Log.log; - -/** - * This class implements the functionality required by {@link DepotRepository#findAll}: fetch - * a collection of persistent objects using one of two included strategies. - */ -public abstract class FindAllQuery - implements Query> -{ - /** - * The two-pass collection query implementation. See {@link DepotRepository#findAll} for - * details. - */ - public static class WithCache extends FindAllQuery - { - public WithCache (PersistenceContext ctx, Class type, - Collection clauses) - throws DatabaseException - { - super(ctx, type); - - if (_marsh.getComputed() != null) { - throw new IllegalArgumentException( - "This algorithm doesn't work on @Computed records."); - } - for (QueryClause clause : clauses) { - if (clause instanceof FieldOverride) { - throw new IllegalArgumentException( - "This algorithm doesn't work with FieldOverrides."); - } - } - - SelectClause select = - new SelectClause(_type, _marsh.getPrimaryKeyFields(), clauses); - _builder = _ctx.getSQLBuilder(DepotTypes.getDepotTypes(ctx, select)); - _builder.newQuery(select); - } - - public List invoke (Connection conn, DatabaseLiaison liaison) - throws SQLException - { - Map, T> entities = new HashMap, T>(); - List> allKeys = new ArrayList>(); - Set> fetchKeys = new HashSet>(); - - PreparedStatement stmt = _builder.prepare(conn); - String stmtString = stmt.toString(); // for debugging - try { - ResultSet rs = stmt.executeQuery(); - while (rs.next()) { - Key key = _marsh.makePrimaryKey(rs); - allKeys.add(key); - - // TODO: All this cache fiddling needs to move to PersistenceContext? - CacheAdapter.CachedValue hit = _ctx.cacheLookup(key); - if (hit != null) { - T value = hit.getValue(); - if (value != null) { - @SuppressWarnings("unchecked") T newValue = (T) value.clone(); - entities.put(key, newValue); - continue; - } - } - - fetchKeys.add(key); - } - - } finally { - JDBCUtil.close(stmt); - } - - return loadAndResolve(conn, allKeys, fetchKeys, entities, stmtString); - } - } - - /** - * The two-pass collection query implementation. See {@link DepotRepository#findAll} for - * details. - */ - public static class WithKeys extends FindAllQuery - { - public WithKeys (PersistenceContext ctx, Collection> keys) - throws DatabaseException - { - super(ctx, keys.iterator().next().getPersistentClass()); - _keys = keys; - _builder = ctx.getSQLBuilder(new DepotTypes(ctx, _type)); - } - - public List invoke (Connection conn, DatabaseLiaison liaison) - throws SQLException - { - Map, T> entities = new HashMap, T>(); - Set> fetchKeys = new HashSet>(); - for (Key key : _keys) { - // TODO: All this cache fiddling needs to move to PersistenceContext? - CacheAdapter.CachedValue hit = _ctx.cacheLookup(key); - if (hit != null) { - T value = hit.getValue(); - if (value != null) { - @SuppressWarnings("unchecked") T newValue = (T) value.clone(); - entities.put(key, newValue); - continue; - } - } - fetchKeys.add(key); - } - - return loadAndResolve(conn, _keys, fetchKeys, entities, null); - } - - protected Collection> _keys; - } - - /** - * The single-pass collection query implementation. See {@link DepotRepository#findAll} for - * details. - */ - public static class Explicitly extends FindAllQuery - { - public Explicitly (PersistenceContext ctx, Class type, - Collection clauses) - throws DatabaseException - { - super(ctx, type); - SelectClause select = new SelectClause(type, _marsh.getFieldNames(), clauses); - _builder = ctx.getSQLBuilder(DepotTypes.getDepotTypes(ctx, select)); - _builder.newQuery(select); - } - - public List invoke (Connection conn, DatabaseLiaison liaison) - throws SQLException - { - List result = new ArrayList(); - PreparedStatement stmt = _builder.prepare(conn); - try { - ResultSet rs = stmt.executeQuery(); - while (rs.next()) { - result.add(_marsh.createObject(rs)); - } - } finally { - JDBCUtil.close(stmt); - } - return result; - } - } - - public FindAllQuery (PersistenceContext ctx, Class type) - throws DatabaseException - { - _ctx = ctx; - _type = type; - _marsh = _ctx.getMarshaller(type); - } - - // from Query - public CacheKey getCacheKey () - { - return null; - } - - // from Query - public void updateCache (PersistenceContext ctx, List result) { - if (_marsh.hasPrimaryKey()) { - for (T bit : result) { - ctx.cacheStore(_marsh.getPrimaryKey(bit), bit.clone()); - } - } - } - - // from Query - public List transformCacheHit (CacheKey key, List bits) - { - if (bits == null) { - return bits; - } - - List result = new ArrayList(); - for (T bit : bits) { - if (bit != null) { - @SuppressWarnings("unchecked") T cbit = (T) bit.clone(); - result.add(cbit); - } else { - result.add(null); - } - } - return result; - } - - protected List loadAndResolve (Connection conn, Collection> allKeys, - Set> fetchKeys, Map, T> entities, - String origStmt) - throws SQLException - { - // if we're fetching a huge number of records, we have to do it in multiple queries - if (fetchKeys.size() > In.MAX_KEYS) { - int keyCount = fetchKeys.size(); - do { - Set> keys = new HashSet>(); - Iterator> iter = fetchKeys.iterator(); - for (int ii = 0; ii < Math.min(keyCount, In.MAX_KEYS); ii++) { - keys.add(iter.next()); - iter.remove(); - } - keyCount -= keys.size(); - loadRecords(conn, keys, entities, origStmt); - } while (keyCount > 0); - - } else if (fetchKeys.size() > 0) { - loadRecords(conn, fetchKeys, entities, origStmt); - } - - List result = new ArrayList(); - for (Key key : allKeys) { - T value = entities.get(key); - if (value != null) { - result.add(value); - } - } - return result; - } - - protected void loadRecords (Connection conn, Set> keys, Map, T> entities, - String origStmt) - throws SQLException - { - _builder.newQuery(new SelectClause(_type, _marsh.getFieldNames(), - new KeySet(_type, keys))); - PreparedStatement stmt = _builder.prepare(conn); - try { - Set> got = new HashSet>(); - ResultSet rs = stmt.executeQuery(); - int cnt = 0, dups = 0; - while (rs.next()) { - T obj = _marsh.createObject(rs); - Key key = _marsh.getPrimaryKey(obj); - if (entities.put(key, obj) != null) { - dups++; - } - got.add(key); - cnt++; - } - // if we get more results than we planned, or if we're doing a two-phase query and got - // fewer, then complain - if (cnt > keys.size() || (origStmt != null && cnt < keys.size())) { - log.warning("Row count mismatch in second pass", "origQuery", origStmt, - "wanted", keys, "got", got, "dups", dups, new Exception()); - } - - } finally { - JDBCUtil.close(stmt); - } - } - - protected PersistenceContext _ctx; - protected SQLBuilder _builder; - protected DepotMarshaller _marsh; - protected Class _type; -} diff --git a/src/java/com/samskivert/jdbc/depot/FindOneQuery.java b/src/java/com/samskivert/jdbc/depot/FindOneQuery.java deleted file mode 100644 index 5cc449a2..00000000 --- a/src/java/com/samskivert/jdbc/depot/FindOneQuery.java +++ /dev/null @@ -1,110 +0,0 @@ -// -// $Id$ -// -// samskivert library - useful routines for java programs -// Copyright (C) 2006-2007 Michael Bayne, Pär Winzell -// -// This library is free software; you can redistribute it and/or modify it -// under the terms of the GNU Lesser General Public License as published -// by the Free Software Foundation; either version 2.1 of the License, or -// (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -package com.samskivert.jdbc.depot; - -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; - -import com.samskivert.jdbc.DatabaseLiaison; -import com.samskivert.jdbc.JDBCUtil; -import com.samskivert.jdbc.depot.clause.QueryClause; -import com.samskivert.jdbc.depot.clause.SelectClause; - -/** - * The implementation of {@link DepotRepository#load} functionality. - */ -public class FindOneQuery - implements Query -{ - public FindOneQuery (PersistenceContext ctx, Class type, QueryClause[] clauses) - throws DatabaseException - { - _marsh = ctx.getMarshaller(type); - _select = new SelectClause(type, _marsh.getFieldNames(), clauses); - WhereClause where = _select.getWhereClause(); - if (where != null) { - _select.getWhereClause().validateQueryType(type); // sanity check - } - _builder = ctx.getSQLBuilder(DepotTypes.getDepotTypes(ctx, _select)); - _builder.newQuery(_select); - } - - // from Query - public CacheKey getCacheKey () - { - WhereClause where = _select.getWhereClause(); - if (where != null && where instanceof CacheKey) { - return (CacheKey) where; - } - return null; - } - - // from Query - public T invoke (Connection conn, DatabaseLiaison liaison) throws SQLException - { - PreparedStatement stmt = _builder.prepare(conn); - try { - T result = null; - ResultSet rs = stmt.executeQuery(); - if (rs.next()) { - result = _marsh.createObject(rs); - } - // TODO: if (rs.next()) issue warning? - rs.close(); - return result; - - } finally { - JDBCUtil.close(stmt); - } - } - - // from Query - public void updateCache (PersistenceContext ctx, T result) - { - CacheKey key = getCacheKey(); - if (key == null) { - // no row-specific cache key was given - if (result == null || !_marsh.hasPrimaryKey()) { - return; - } - // if we can, create a key from what was actually returned - key = _marsh.getPrimaryKey(result); - } - ctx.cacheStore(key, (result != null) ? result.clone() : null); - } - - // from Query - public T transformCacheHit (CacheKey key, T value) - { - if (value == null) { - return null; - } - // we do not want to return a reference to the actual cached entity so we clone it - @SuppressWarnings("unchecked") T cvalue = (T) value.clone(); - return cvalue; - } - - protected DepotMarshaller _marsh; - protected SelectClause _select; - protected SQLBuilder _builder; -} diff --git a/src/java/com/samskivert/jdbc/depot/IdentityValueGenerator.java b/src/java/com/samskivert/jdbc/depot/IdentityValueGenerator.java deleted file mode 100644 index 84d7f458..00000000 --- a/src/java/com/samskivert/jdbc/depot/IdentityValueGenerator.java +++ /dev/null @@ -1,65 +0,0 @@ -// -// $Id$ -// -// samskivert library - useful routines for java programs -// Copyright (C) 2006-2007 Michael Bayne, Pär Winzell -// -// This library is free software; you can redistribute it and/or modify it -// under the terms of the GNU Lesser General Public License as published -// by the Free Software Foundation; either version 2.1 of the License, or -// (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -package com.samskivert.jdbc.depot; - -import java.sql.Connection; -import java.sql.SQLException; - -import com.samskivert.jdbc.DatabaseLiaison; -import com.samskivert.jdbc.depot.annotation.GeneratedValue; - -/** - * Generates primary keys using an identity column. - */ -public class IdentityValueGenerator extends ValueGenerator -{ - public IdentityValueGenerator (GeneratedValue gv, DepotMarshaller dm, FieldMarshaller fm) - { - super(gv, dm, fm); - } - - @Override // from ValueGenerator - public boolean isPostFactum () - { - return true; - } - - @Override // from ValueGenerator - public void create (Connection conn, DatabaseLiaison liaison) - throws SQLException - { - liaison.createGenerator(conn, _dm.getTableName(), _fm.getColumnName(), _initialValue); - } - - @Override // from ValueGenerator - public int nextGeneratedValue (Connection conn, DatabaseLiaison liaison) - throws SQLException - { - return liaison.lastInsertedId(conn, _dm.getTableName(), _fm.getColumnName()); - } - - @Override // from ValueGenerator - public void delete (Connection conn, DatabaseLiaison liaison) - throws SQLException - { - liaison.deleteGenerator(conn, _dm.getTableName(), _fm.getColumnName()); - } -} diff --git a/src/java/com/samskivert/jdbc/depot/Key.java b/src/java/com/samskivert/jdbc/depot/Key.java deleted file mode 100644 index eb21415b..00000000 --- a/src/java/com/samskivert/jdbc/depot/Key.java +++ /dev/null @@ -1,246 +0,0 @@ -// -// $Id$ -// -// samskivert library - useful routines for java programs -// Copyright (C) 2006-2007 Michael Bayne, Pär Winzell -// -// This library is free software; you can redistribute it and/or modify it -// under the terms of the GNU Lesser General Public License as published -// by the Free Software Foundation; either version 2.1 of the License, or -// (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -package com.samskivert.jdbc.depot; - -import java.io.Serializable; -import java.util.ArrayList; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import com.samskivert.jdbc.depot.expression.ExpressionVisitor; -import com.samskivert.jdbc.depot.expression.SQLExpression; -import com.samskivert.util.StringUtil; - -/** - * A special form of {@link WhereClause} that uniquely specifies a single database row and - * thus also a single persistent object. Because it implements both {@link CacheKey} and - * {@link CacheInvalidator} it also uniquely indexes into the cache and knows how to invalidate - * itself upon modification. This class is created by many {@link DepotMarshaller} methods as - * a convenience, and may also be instantiated explicitly. - */ -public class Key extends WhereClause - implements SQLExpression, CacheKey, ValidatingCacheInvalidator, Serializable -{ - /** Handles the matching of the key columns to its bound values. This is needed so that we can - * combine a buncy of keys into a {@link KeySet}. */ - public static class Expression implements SQLExpression - { - public Expression (Class pClass, List> values) { - _pClass = pClass; - _values = values; - } - public Class getPersistentClass () { - return _pClass; - } - public List> getValues () { - return _values; - } - public void accept (ExpressionVisitor builder) { - builder.visit(this); - } - public void addClasses (Collection> classSet) { - classSet.add(getPersistentClass()); - } - protected Class _pClass; - protected List> _values; - } - - /** - * Constructs a new single-column {@code Key} with the given value. - */ - public Key (Class pClass, String ix, Comparable val) - { - this(pClass, new String[] { ix }, new Comparable[] { val }); - } - - /** - * Constructs a new two-column {@code Key} with the given values. - */ - public Key (Class pClass, String ix1, Comparable val1, - String ix2, Comparable val2) - { - this(pClass, new String[] { ix1, ix2 }, new Comparable[] { val1, val2 }); - } - - /** - * Constructs a new three-column {@code Key} with the given values. - */ - public Key (Class pClass, String ix1, Comparable val1, - String ix2, Comparable val2, String ix3, Comparable val3) - { - this(pClass, new String[] { ix1, ix2, ix3 }, new Comparable[] { val1, val2, val3 }); - } - - /** - * Constructs a new multi-column {@code Key} with the given values. - */ - public Key (Class pClass, String[] fields, Comparable[] values) - { - if (fields.length != values.length) { - throw new IllegalArgumentException("Field and Value arrays must be of equal length."); - } - - // keep this for posterity - _pClass = pClass; - - // build a local map of field name -> field value - Map> map = new HashMap>(); - for (int i = 0; i < fields.length; i ++) { - map.put(fields[i], values[i]); - } - - // look up the cached primary key fields for this object - String[] keyFields = KeyUtil.getKeyFields(pClass); - - // now extract the values in field order and ensure none are extra or missing - _values = new ArrayList>(); - for (int ii = 0; ii < keyFields.length; ii++) { - Comparable nugget = map.remove(keyFields[ii]); - if (nugget == null) { - // make sure we were provided with a value for this primary key field - throw new IllegalArgumentException("Missing value for key field: " + keyFields[ii]); - } - if (nugget instanceof Serializable) { - _values.add(nugget); - continue; - } - throw new IllegalArgumentException( - "Non-serializable argument [key=" + keyFields[ii] + ", arg=" + nugget + "]"); - } - - // finally make sure we were not given any fields that are not in fact primary key fields - if (map.size() > 0) { - throw new IllegalArgumentException( - "Non-key columns given: " + StringUtil.join(map.keySet().toArray(), ", ")); - } - } - - /** - * Returns the persistent class for which we represent a key. - */ - public Class getPersistentClass () - { - return _pClass; - } - - /** - * Returns the values bound to this key. - */ - public List> getValues () - { - return _values; - } - - // from WhereClause - public SQLExpression getWhereExpression () - { - return new Expression(_pClass, _values); - } - - // from SQLExpression - public void addClasses (Collection> classSet) - { - classSet.add(_pClass); - } - - // from SQLExpression - public void accept (ExpressionVisitor builder) - { - builder.visit(this); - } - - // from CacheKey - public String getCacheId () - { - return _pClass.getName(); - } - - // from CacheKey - public Serializable getCacheKey () - { - return _values; - } - - // from ValidatingCacheInvalidator - public void validateFlushType (Class pClass) - { - if (!pClass.equals(_pClass)) { - throw new IllegalArgumentException( - "Class mismatch between persistent record and cache invalidator " + - "[record=" + pClass.getSimpleName() + ", invtype=" + _pClass.getSimpleName() + "]."); - } - } - - // from CacheInvalidator - public void invalidate (PersistenceContext ctx) - { - ctx.cacheInvalidate(this); - } - - @Override // from WhereClause - public void validateQueryType (Class pClass) - { - super.validateQueryType(pClass); - validateTypesMatch(pClass, _pClass); - } - - @Override - public boolean equals (Object obj) - { - if (this == obj) { - return true; - } - if (obj == null || getClass() != obj.getClass()) { - return false; - } - return _values.equals(((Key) obj)._values); - } - - @Override - public int hashCode () - { - return _values.hashCode(); - } - - @Override - public String toString () - { - StringBuilder builder = new StringBuilder(_pClass.getSimpleName()); - builder.append("("); - String[] keyFields = KeyUtil.getKeyFields(_pClass); - for (int ii = 0; ii < keyFields.length; ii ++) { - if (ii > 0) { - builder.append(", "); - } - builder.append(keyFields[ii]).append("=").append(_values.get(ii)); - } - builder.append(")"); - return builder.toString(); - } - - /** The persistent record type for which we are a key. */ - protected final Class _pClass; - - /** The expression that identifies our row. */ - protected final ArrayList> _values; // must declare as ArrayList for Serializable -} diff --git a/src/java/com/samskivert/jdbc/depot/KeySet.java b/src/java/com/samskivert/jdbc/depot/KeySet.java deleted file mode 100644 index e5bb8517..00000000 --- a/src/java/com/samskivert/jdbc/depot/KeySet.java +++ /dev/null @@ -1,160 +0,0 @@ -// -// $Id$ -// -// samskivert library - useful routines for java programs -// Copyright (C) 2001-2008 Michael Bayne -// -// This library is free software; you can redistribute it and/or modify it -// under the terms of the GNU Lesser General Public License as published -// by the Free Software Foundation; either version 2.1 of the License, or -// (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -package com.samskivert.jdbc.depot; - -import java.util.Collection; - -import com.samskivert.jdbc.depot.expression.ExpressionVisitor; -import com.samskivert.jdbc.depot.expression.LiteralExp; -import com.samskivert.jdbc.depot.expression.SQLExpression; -import com.samskivert.jdbc.depot.operator.Conditionals; -import com.samskivert.jdbc.depot.operator.Logic; - -/** - * Contains a set of primary keys that match a set of persistent records. This is used internally - * in Depot when decomposing queries into two parts: first a query for the primary keys that - * identify the records that match a free-form query and then another query that operates on the - * previously identified keys. The keys obtained in the first query are used to create a KeySet and - * modifications and deletons using this set will automatically flush the appropriate records from - * the cache. - */ -public class KeySet extends WhereClause - implements SQLExpression, ValidatingCacheInvalidator -{ - /** - * Creates a set from the supplied primary keys. - */ - public KeySet (Class pClass, Collection> keys) - { - _pClass = pClass; - _keys = keys; - - String[] keyFields = KeyUtil.getKeyFields(pClass); - if (keys.size() == 0) { - _condition = new LiteralExp("false"); - - } else if (keyFields.length == 1) { - // TODO: remove when we update to 1.6 and change Postgres In handling - if (keys.size() > Conditionals.In.MAX_KEYS) { - throw new IllegalArgumentException("Cannot create where clause for more than " + - Conditionals.In.MAX_KEYS + " at a time."); - } - - // Single-column keys result in the compact IN(keyVal1, keyVal2, ...) - Comparable first = keys.iterator().next().getValues().get(0); - Comparable[] keyFieldValues; - if (first instanceof Integer) { - keyFieldValues = new Integer[keys.size()]; - } else if (first instanceof Integer) { - keyFieldValues = new String[keys.size()]; - } else { - keyFieldValues = new Comparable[keys.size()]; - } - int ii = 0; - for (Key key : keys) { - keyFieldValues[ii++] = key.getValues().get(0); - } - _condition = new Conditionals.In(pClass, keyFields[0], keyFieldValues); - - } else { - // TODO: is there a maximum size of an or query? 32768? - - // Multi-column keys result in OR'd AND's, of unknown efficiency (TODO check). - SQLExpression[] keyArray = new SQLExpression[keys.size()]; - int ii = 0; - for (Key key : keys) { - keyArray[ii++] = key.getWhereExpression(); - } - _condition = new Logic.Or(keyArray); - } - } - - // from WhereClause - public SQLExpression getWhereExpression () - { - return _condition; - } - - // from SQLExpression - public void addClasses (Collection> classSet) - { - classSet.add(_pClass); - } - - // from SQLExpression - public void accept (ExpressionVisitor builder) - { - builder.visit(this); - } - - // from ValidatingCacheInvalidator - public void validateFlushType (Class pClass) - { - if (!pClass.equals(_pClass)) { - throw new IllegalArgumentException( - "Class mismatch between persistent record and cache invalidator " + - "[record=" + pClass.getSimpleName() + ", invtype=" + _pClass.getSimpleName() + "]."); - } - } - - // from CacheInvalidator - public void invalidate (PersistenceContext ctx) - { - for (Key key : _keys) { - ctx.cacheInvalidate(key); - } - } - - @Override // from WhereClause - public void validateQueryType (Class pClass) - { - super.validateQueryType(pClass); - validateTypesMatch(pClass, _pClass); - } - - @Override - public boolean equals (Object obj) - { - if (this == obj) { - return true; - } - if (obj == null || getClass() != obj.getClass()) { - return false; - } - return _condition.equals(((KeySet) obj)._condition); - } - - @Override - public int hashCode () - { - return _condition.hashCode(); - } - - @Override - public String toString () - { - return _keys.toString(); - } - - protected Class _pClass; - protected Collection> _keys; - protected SQLExpression _condition; -} diff --git a/src/java/com/samskivert/jdbc/depot/KeyUtil.java b/src/java/com/samskivert/jdbc/depot/KeyUtil.java deleted file mode 100644 index 61b0ac16..00000000 --- a/src/java/com/samskivert/jdbc/depot/KeyUtil.java +++ /dev/null @@ -1,59 +0,0 @@ -// -// $Id$ -// -// samskivert library - useful routines for java programs -// Copyright (C) 2001-2008 Michael Bayne -// -// This library is free software; you can redistribute it and/or modify it -// under the terms of the GNU Lesser General Public License as published -// by the Free Software Foundation; either version 2.1 of the License, or -// (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -package com.samskivert.jdbc.depot; - -import java.lang.reflect.Field; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import com.samskivert.jdbc.depot.annotation.Id; - -/** - * Simple utility methods used by {@link Key} and {@link KeySet}. - */ -public class KeyUtil -{ - /** - * Returns an array containing the names of the primary key fields for the supplied persistent - * class. The values are introspected and cached for the lifetime of the VM. - */ - public static String[] getKeyFields (Class pClass) - { - String[] fields = _keyFields.get(pClass); - if (fields == null) { - List kflist = new ArrayList(); - for (Field field : pClass.getFields()) { - // look for @Id fields - if (field.getAnnotation(Id.class) != null) { - kflist.add(field.getName()); - } - } - _keyFields.put(pClass, fields = kflist.toArray(new String[kflist.size()])); - } - return fields; - } - - /** A (never expiring) cache of primary key field names for all persistent classes (of which - * there are merely dozens, so we don't need to worry about expiring). */ - protected static Map,String[]> _keyFields = new HashMap,String[]>(); -} diff --git a/src/java/com/samskivert/jdbc/depot/Log.java b/src/java/com/samskivert/jdbc/depot/Log.java deleted file mode 100644 index 4721b803..00000000 --- a/src/java/com/samskivert/jdbc/depot/Log.java +++ /dev/null @@ -1,32 +0,0 @@ -// -// $Id$ -// -// samskivert library - useful routines for java programs -// Copyright (C) 2006-2007 Michael Bayne, Pär Winzell -// -// This library is free software; you can redistribute it and/or modify it -// under the terms of the GNU Lesser General Public License as published -// by the Free Software Foundation; either version 2.1 of the License, or -// (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -package com.samskivert.jdbc.depot; - -import com.samskivert.util.Logger; - -/** - * Contains a reference to the log object used by this package. - */ -public class Log -{ - /** We dispatch our log messages through this logger. */ - public static Logger log = Logger.getLogger("com.samskivert.jdbc.depot"); -} diff --git a/src/java/com/samskivert/jdbc/depot/Modifier.java b/src/java/com/samskivert/jdbc/depot/Modifier.java deleted file mode 100644 index aed61d44..00000000 --- a/src/java/com/samskivert/jdbc/depot/Modifier.java +++ /dev/null @@ -1,144 +0,0 @@ -// -// $Id$ -// -// samskivert library - useful routines for java programs -// Copyright (C) 2006-2007 Michael Bayne, Pär Winzell -// -// This library is free software; you can redistribute it and/or modify it -// under the terms of the GNU Lesser General Public License as published -// by the Free Software Foundation; either version 2.1 of the License, or -// (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -package com.samskivert.jdbc.depot; - -import java.sql.Connection; -import java.sql.SQLException; -import java.sql.Statement; - -import com.samskivert.jdbc.DatabaseLiaison; - -/** - * Encapsulates a modification of persistent objects. - */ -public abstract class Modifier implements Operation -{ - /** - * A simple modifier that executes a single SQL statement. No cache flushing is done as a - * result of this operation. - */ - public abstract static class Simple extends Modifier - { - public Simple () { - super(null); - } - - @Override - public Integer invoke (Connection conn, DatabaseLiaison liaison) throws SQLException { - Statement stmt = conn.createStatement(); - try { - return stmt.executeUpdate(createQuery(liaison)); - } finally { - stmt.close(); - } - } - - protected abstract String createQuery (DatabaseLiaison liaison); - } - - /** - * A convenience modifier that can perform cache updates in addition to invalidation: - * - Before {@link #invoke}, the {@link CacheInvalidator} is run, if given. - * - After {@link #invoke}, the cache is updated with the modified object, - * presuming both _key and _result are non-null. These variables may be set or modified - * during execution in addition to being supplied to the constructor. - */ - public static abstract class CachingModifier extends Modifier - { - /** - * Construct a new CachingModifier with the given result, cache key, and invalidator, - * all of which are optional, and may also be set during execution. - */ - protected CachingModifier (T result, CacheKey key, CacheInvalidator invalidator) - { - super(invalidator); - _result = result; - _key = key; - } - - /** - * Update this {@link CachingModifier}'s cache key, e.g. during insertion when a - * persistent object first receives a generated key. - */ - protected void updateKey (CacheKey key) - { - if (key != null) { - _key = key; - } - } - - @Override // from Modifier - public void cacheUpdate (PersistenceContext ctx) - { - super.cacheUpdate(ctx); - // if we have both a key and a record, cache - if (_key != null && _result != null) { - ctx.cacheStore(_key, _result.clone()); - } - } - - protected CacheKey _key; - protected T _result; - } - - /** - * Overriden to perform the actual database modifications represented by this object; should - * return the number of modified rows. - */ - public abstract Integer invoke (Connection conn, DatabaseLiaison liaison) throws SQLException; - - /** - * Constructs a {@link Modifier} without a cache invalidator. - */ - public Modifier () - { - this(null); - } - - /** - * Constructs a {@link Modifier} with the given cache invalidator. - */ - public Modifier (CacheInvalidator invalidator) - { - _invalidator = invalidator; - } - - /** - * Do any cache invalidation needed for this modification. This method is called just - * before the database statement is executed. - */ - public void cacheInvalidation (PersistenceContext ctx) - { - if (_invalidator != null) { - _invalidator.invalidate(ctx); - } - } - - /** - * Do any cache updates needed for this modification. This method is called just after - * the successful execution of the database statement. - */ - public void cacheUpdate (PersistenceContext ctx) - { - } - - protected CacheInvalidator _invalidator; -} diff --git a/src/java/com/samskivert/jdbc/depot/MultiKey.java b/src/java/com/samskivert/jdbc/depot/MultiKey.java deleted file mode 100644 index d1fe8aa2..00000000 --- a/src/java/com/samskivert/jdbc/depot/MultiKey.java +++ /dev/null @@ -1,155 +0,0 @@ -// -// $Id$ -// -// samskivert library - useful routines for java programs -// Copyright (C) 2006-2007 Michael Bayne, Pär Winzell -// -// This library is free software; you can redistribute it and/or modify it -// under the terms of the GNU Lesser General Public License as published -// by the Free Software Foundation; either version 2.1 of the License, or -// (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -package com.samskivert.jdbc.depot; - -import java.util.Collection; -import java.util.HashMap; -import java.util.Map; - -import com.samskivert.jdbc.depot.clause.Where; -import com.samskivert.jdbc.depot.expression.ExpressionVisitor; -import com.samskivert.jdbc.depot.expression.SQLExpression; - -/** - * A special form of {@link Where} clause that specifies an explicit range of database rows. It - * does not implement {@link CacheKey} but it does implement {@link CacheInvalidator} which means - * it can be sent into e.g. {@link DepotRepository#deleteAll} and have it clean up after itself. - */ -public class MultiKey extends WhereClause - implements ValidatingCacheInvalidator -{ - /** - * Constructs a new single-column {@code MultiKey} with the given value range. - */ - public MultiKey (Class pClass, String ix, Comparable... val) - { - this(pClass, new String[0], new Comparable[0], ix, val); - } - - /** - * Constructs a new two-column {@code MultiKey} with the given value range. - */ - public MultiKey (Class pClass, String ix1, Comparable val1, String ix2, - Comparable... val2) - { - this(pClass, new String[] { ix1 }, new Comparable[] { val1 }, ix2, val2); - } - - /** - * Constructs a new three-column {@code MultiKey} with the given value range. - */ - public MultiKey (Class pClass, String ix1, Comparable val1, - String ix2, Comparable val2, String ix3, Comparable... val3) - { - this(pClass, new String[] { ix1, ix2 }, new Comparable[] { val1, val2 }, ix3, val3); - } - - /** - * Constructs a new multi-column {@code MultiKey} with the given value range. - * See {@link Key#Key(Class,String[],Comparable[])} for somewhat relevant comments. - */ - public MultiKey (Class pClass, String[] sFields, Comparable[] sValues, - String mField, Comparable[] mValues) - { - if (sFields.length != sValues.length) { - throw new IllegalArgumentException( - "Key field and values arrays must be of equal length."); - } - _pClass = pClass; - _mField = mField; - _mValues = mValues; - _map = new HashMap>(); - for (int i = 0; i < sFields.length; i ++) { - _map.put(sFields[i], sValues[i]); - } - } - - public Class getPersistentClass () - { - return _pClass; - } - - public Map> getSingleFieldsMap () - { - return _map; - } - - public String getMultiField () - { - return _mField; - } - - public Comparable[] getMultiValues () - { - return _mValues; - } - - // from WhereClause - public SQLExpression getWhereExpression () - { - throw new RuntimeException("Not used"); - } - - // from SQLExpression - public void accept (ExpressionVisitor builder) - { - builder.visit(this); - } - - // from SQLExpression - public void addClasses (Collection> classSet) - { - // nothing to add - } - - // from ValidatingCacheInvalidator - public void validateFlushType (Class pClass) - { - if (!pClass.equals(_pClass)) { - throw new IllegalArgumentException( - "Class mismatch between persistent record and cache invalidator " + - "[record=" + pClass.getSimpleName() + - ", invtype=" + _pClass.getSimpleName() + "]."); - } - } - - // from CacheInvalidator - public void invalidate (PersistenceContext ctx) - { - HashMap> newMap = new HashMap>(_map); - for (int i = 0; i < _mValues.length; i ++) { - newMap.put(_mField, _mValues[i]); - ctx.cacheInvalidate(new SimpleCacheKey(_pClass, newMap)); - } - } - - @Override // from WhereClause - public void validateQueryType (Class pClass) - { - super.validateQueryType(pClass); - validateTypesMatch(pClass, _pClass); - } - - protected String _mField; - protected Comparable[] _mValues; - protected Class _pClass; - protected HashMap> _map; -} diff --git a/src/java/com/samskivert/jdbc/depot/MySQLBuilder.java b/src/java/com/samskivert/jdbc/depot/MySQLBuilder.java deleted file mode 100644 index 21df1883..00000000 --- a/src/java/com/samskivert/jdbc/depot/MySQLBuilder.java +++ /dev/null @@ -1,276 +0,0 @@ -// -// $Id$ -// -// samskivert library - useful routines for java programs -// Copyright (C) 2006 Michael Bayne, Pär Winzell -// -// This library is free software; you can redistribute it and/or modify it -// under the terms of the GNU Lesser General Public License as published -// by the Free Software Foundation; either version 2.1 of the License, or -// (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -package com.samskivert.jdbc.depot; - -import java.sql.Blob; -import java.sql.Clob; -import java.sql.Connection; -import java.sql.Date; -import java.sql.PreparedStatement; -import java.sql.SQLException; -import java.sql.Statement; -import java.sql.Time; -import java.sql.Timestamp; -import java.util.Set; - -import com.samskivert.jdbc.JDBCUtil; -import com.samskivert.jdbc.depot.FieldMarshaller.BooleanMarshaller; -import com.samskivert.jdbc.depot.FieldMarshaller.ByteArrayMarshaller; -import com.samskivert.jdbc.depot.FieldMarshaller.ByteEnumMarshaller; -import com.samskivert.jdbc.depot.FieldMarshaller.ByteMarshaller; -import com.samskivert.jdbc.depot.FieldMarshaller.DoubleMarshaller; -import com.samskivert.jdbc.depot.FieldMarshaller.FloatMarshaller; -import com.samskivert.jdbc.depot.FieldMarshaller.IntArrayMarshaller; -import com.samskivert.jdbc.depot.FieldMarshaller.IntMarshaller; -import com.samskivert.jdbc.depot.FieldMarshaller.LongMarshaller; -import com.samskivert.jdbc.depot.FieldMarshaller.ObjectMarshaller; -import com.samskivert.jdbc.depot.FieldMarshaller.ShortMarshaller; -import com.samskivert.jdbc.depot.annotation.FullTextIndex; -import com.samskivert.jdbc.depot.clause.DeleteClause; -import com.samskivert.jdbc.depot.expression.ColumnExp; -import com.samskivert.jdbc.depot.expression.EpochSeconds; -import com.samskivert.jdbc.depot.operator.Conditionals.FullTextMatch; - -import static com.samskivert.Log.log; - -public class MySQLBuilder - extends SQLBuilder -{ - public class MSBuildVisitor extends BuildVisitor - { - @Override public void visit (FullTextMatch match) - { - _builder.append("match("); - Class pClass = match.getPersistentRecord(); - String[] fields = - _types.getMarshaller(pClass).getFullTextIndex(match.getName()).fields(); - for (int ii = 0; ii < fields.length; ii ++) { - if (ii > 0) { - _builder.append(", "); - } - new ColumnExp(pClass, fields[ii]).accept(this); - } - _builder.append(") against (? in boolean mode)"); - } - - @Override public void visit (DeleteClause deleteClause) - { - _builder.append("delete from "); - appendTableName(deleteClause.getPersistentClass()); - _builder.append(" "); - - // MySQL can't do DELETE FROM SomeTable AS T1, so we turn off abbreviations briefly. - boolean savedFlag = _types.getUseTableAbbreviations(); - _types.setUseTableAbbreviations(false); - try { - deleteClause.getWhereClause().accept(this); - } finally { - _types.setUseTableAbbreviations(savedFlag); - } - } - - public void visit (EpochSeconds epochSeconds) - { - _builder.append("unix_timestamp("); - epochSeconds.getArgument().accept(this); - _builder.append(")"); - } - - protected MSBuildVisitor (DepotTypes types) - { - super(types); - } - - @Override protected void appendTableName (Class type) - { - _builder.append(_types.getTableName(type)); - } - - @Override protected void appendTableAbbreviation (Class type) - { - _builder.append(_types.getTableAbbreviation(type)); - } - - @Override protected void appendIdentifier (String field) - { - _builder.append(field); - } - } - - public class MSBindVisitor extends BindVisitor - { - protected MSBindVisitor (DepotTypes types, Connection conn, PreparedStatement stmt) { - super(types, conn, stmt); - } - - @Override public void visit (FullTextMatch match) { - try { - _stmt.setString(_argIdx++, match.getQuery()); - } catch (SQLException sqe) { - throw new DatabaseException("Failed to configure full-text match column " + - "[idx=" + (_argIdx-1) + ", match=" + match + "]", sqe); - } - } - } - - public MySQLBuilder (DepotTypes types) - { - super(types); - } - - @Override - public void getFtsIndexes ( - Iterable columns, Iterable indexes, Set target) - { - for (String index : indexes) { - if (index.startsWith("ftsIx_")) { - target.add(index.substring("ftsIx_".length())); - } - } - } - - @Override - public boolean addFullTextSearch ( - Connection conn, DepotMarshaller marshaller, FullTextIndex fts) - throws SQLException - { - Class pClass = marshaller.getPersistentClass(); - StringBuilder update = new StringBuilder("ALTER TABLE "). - append(marshaller.getTableName()).append(" ADD FULLTEXT INDEX ftsIx_"). - append(fts.name()).append(" ("); - String[] fields = fts.fields(); - for (int ii = 0; ii < fields.length; ii ++) { - if (ii > 0) { - update.append(", "); - } - update.append(_types.getColumnName(pClass, fields[ii])); - } - update.append(")"); - - Statement stmt = conn.createStatement(); - try { - log.info("Adding full-text search index: ftsIx_" + fts.name()); - stmt.executeUpdate(update.toString()); - } finally { - JDBCUtil.close(stmt); - } - return true; - } - - @Override - public boolean isPrivateColumn (String column) - { - // The MySQL builder does not yet have any private columns. - return false; - } - - @Override - protected String getBooleanDefault () - { - return "0"; - } - - @Override - protected BuildVisitor getBuildVisitor () - { - return new MSBuildVisitor(_types); - } - - @Override - protected BindVisitor getBindVisitor (Connection conn, PreparedStatement stmt) - { - return new MSBindVisitor(_types, conn, stmt); - } - - @Override - protected String getColumnType (FieldMarshaller fm, int length) - { - if (fm instanceof ByteMarshaller) { - return "TINYINT"; - } else if (fm instanceof ShortMarshaller) { - return "SMALLINT"; - } else if (fm instanceof IntMarshaller) { - return "INTEGER"; - } else if (fm instanceof LongMarshaller) { - return "BIGINT"; - } else if (fm instanceof FloatMarshaller) { - return "FLOAT"; - } else if (fm instanceof DoubleMarshaller) { - return "DOUBLE"; - } else if (fm instanceof ObjectMarshaller) { - Class ftype = fm.getField().getType(); - if (ftype.equals(Byte.class)) { - return "SMALLINT"; - } else if (ftype.equals(Short.class)) { - return "SMALLINT"; - } else if (ftype.equals(Integer.class)) { - return "INTEGER"; - } else if (ftype.equals(Long.class)) { - return "BIGINT"; - } else if (ftype.equals(Float.class)) { - return "FLOAT"; - } else if (ftype.equals(Double.class)) { - return "DOUBLE"; - } else if (ftype.equals(String.class)) { - if (length < (1 << 15)) { - return "VARCHAR(" + length + ")"; - } - return "TEXT"; - } else if (ftype.equals(Date.class)) { - return "DATE"; - } else if (ftype.equals(Time.class)) { - return "DATETIME"; - } else if (ftype.equals(Timestamp.class)) { - return "DATETIME"; - } else if (ftype.equals(Blob.class)) { - return "BYTEA"; - } else if (ftype.equals(Clob.class)) { - return "TEXT"; - } else { - throw new IllegalArgumentException( - "Don't know how to create SQL for " + ftype + "."); - } - } else if (fm instanceof ByteArrayMarshaller || - fm instanceof IntArrayMarshaller) { - if (fm instanceof IntArrayMarshaller) { - length *= 4; - } - // semi-arbitrarily use VARBINARY() up to 32767 - if (length < (1 << 15)) { - return "VARBINARY(" + length + ")"; - } - // use BLOB to 65535 - if (length < (1 << 16)) { - return "BLOB"; - } - if (length < (1 << 24)) { - return "MEDIUMBLOB"; - } - return "LONGBLOB"; - } else if (fm instanceof ByteEnumMarshaller) { - return "TINYINT"; - } else if (fm instanceof BooleanMarshaller) { - return "TINYINT"; - } else { - throw new IllegalArgumentException("Unknown field marshaller type: " + fm.getClass()); - } - } -} diff --git a/src/java/com/samskivert/jdbc/depot/Operation.java b/src/java/com/samskivert/jdbc/depot/Operation.java deleted file mode 100644 index bb07cab8..00000000 --- a/src/java/com/samskivert/jdbc/depot/Operation.java +++ /dev/null @@ -1,38 +0,0 @@ -// -// $Id$ -// -// samskivert library - useful routines for java programs -// Copyright (C) 2001-2008 Michael Bayne -// -// This library is free software; you can redistribute it and/or modify it -// under the terms of the GNU Lesser General Public License as published -// by the Free Software Foundation; either version 2.1 of the License, or -// (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -package com.samskivert.jdbc.depot; - -import java.sql.Connection; -import java.sql.SQLException; - -import com.samskivert.jdbc.DatabaseLiaison; - -/** - * An abstraction that encompasses both {@link Query} and {@link Modifier} operations. - */ -public interface Operation -{ - /** - * Performs the actual JDBC interactions associated with this operation. - */ - public T invoke (Connection conn, DatabaseLiaison liaison) - throws SQLException; -} diff --git a/src/java/com/samskivert/jdbc/depot/PersistenceContext.java b/src/java/com/samskivert/jdbc/depot/PersistenceContext.java deleted file mode 100644 index b0c93b3f..00000000 --- a/src/java/com/samskivert/jdbc/depot/PersistenceContext.java +++ /dev/null @@ -1,607 +0,0 @@ -// -// $Id$ -// -// samskivert library - useful routines for java programs -// Copyright (C) 2006-2007 Michael Bayne, Pär Winzell -// -// This library is free software; you can redistribute it and/or modify it -// under the terms of the GNU Lesser General Public License as published -// by the Free Software Foundation; either version 2.1 of the License, or -// (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -package com.samskivert.jdbc.depot; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; - -import java.io.Serializable; -import java.sql.Connection; -import java.sql.SQLException; - -import com.samskivert.io.PersistenceException; -import com.samskivert.util.StringUtil; - -import com.samskivert.jdbc.ConnectionProvider; -import com.samskivert.jdbc.DatabaseLiaison; -import com.samskivert.jdbc.LiaisonRegistry; -import com.samskivert.jdbc.MySQLLiaison; -import com.samskivert.jdbc.PostgreSQLLiaison; - -import com.samskivert.jdbc.depot.annotation.TableGenerator; - -import static com.samskivert.jdbc.depot.Log.log; - -/** - * Defines a scope in which global annotations are shared. - */ -public class PersistenceContext -{ - /** Allow toggling of query logging and other debug output via a system property. */ - public static final boolean DEBUG = Boolean.getBoolean("com.samskivert.jdbc.depot.debug"); - - /** Map {@link TableGenerator} instances by name. */ - public HashMap tableGenerators = new HashMap(); - - /** - * A cache listener is notified when cache entries change. Its purpose is typically to do - * further invalidation of dependent entries in other caches. - */ - public static interface CacheListener - { - /** - * The given entry (which is never null) has just been evicted from the cache slot - * indicated by the given key. - * - * This method is most commonly used to trigger custom cache invalidation of records that - * depend on the one that was just invalidated. - */ - public void entryInvalidated (CacheKey key, T oldEntry); - - /** - * The given entry, which may be an explicit null, has just been placed into the cache - * under the given key. The previous cache entry, if any, is also supplied. - * - * This method is most likely used by repositories to index entries by attribute for quick - * cache invalidation when brute force is unrealistically time consuming. - */ - public void entryCached (CacheKey key, T newEntry, T oldEntry); - } - - /** - * The callback for {@link #cacheTraverse}; this is called for each entry in a given cache. - */ - public static interface CacheTraverser - { - /** - * Performs whatever cache-related tasks need doing for this cache entry. This method - * is called for each cache entry in a full-cache enumeration. - */ - public void visitCacheEntry ( - PersistenceContext ctx, String cacheId, Serializable key, T record); - } - - /** - * A simple implementation of {@link CacheTraverser} that selectively deletes entries in - * a cache depending on the return value of {@link #testForEviction}. - */ - public static abstract class CacheEvictionFilter - implements CacheTraverser - { - // from CacheTraverser - public void visitCacheEntry ( - PersistenceContext ctx, String cacheId, Serializable key, T record) - { - if (testForEviction(key, record)) { - ctx.cacheInvalidate(cacheId, key); - } - } - - /** - * Decides whether or not this entry should be evicted and returns true if yes, false if - * no. - */ - protected abstract boolean testForEviction (Serializable key, T record); - } - - /** - * Returns the cache adapter used by this context or null if caching is disabled. - */ - public CacheAdapter getCacheAdapter () - { - return _cache; - } - - /** - * Creates an uninitialized persistence context. {@link #init} must later be called on this - * context to prepare it for operation. - */ - public PersistenceContext () - { - } - - /** - * Creates and initializes a persistence context. See {@link #init}. - */ - public PersistenceContext (String ident, ConnectionProvider conprov, CacheAdapter adapter) - { - init(ident, conprov, adapter); - } - - /** - * Initializes this context with its connection provider and cache adapter. - * - * @param ident the identifier to provide to the connection provider when requesting a - * connection. - * @param conprov provides JDBC {@link Connection} instances. - * @param adapter an optional adapter to a cache management system. - */ - public void init (String ident, ConnectionProvider conprov, CacheAdapter adapter) - { - _ident = ident; - _conprov = conprov; - _liaison = LiaisonRegistry.getLiaison(conprov.getURL(ident)); - _cache = adapter; - } - - /** - * Shuts this persistence context down, shutting down any caching system in use and shutting - * down the JDBC connection pool. - */ - public void shutdown () - { - try { - if (_cache != null) { - _cache.shutdown(); - } - } catch (Throwable t) { - log.warning("Failure shutting down Depot cache.", t); - } - _conprov.shutdown(); - } - - /** - * Create and return a new {@link SQLBuilder} for the appropriate dialect. - * - * TODO: At some point perhaps use a more elegant way of discerning our dialect. - */ - public SQLBuilder getSQLBuilder (DepotTypes types) - { - if (_liaison instanceof PostgreSQLLiaison) { - return new PostgreSQLBuilder(types); - } - if (_liaison instanceof MySQLLiaison) { - return new MySQLBuilder(types); - } - throw new IllegalArgumentException("Unknown liaison type: " + _liaison.getClass()); - } - - /** - * Registers a schema migration for the specified entity class. - * - *

This method must be called before an Entity is used by any repository. Thus you - * should register all migrations in the constructor of the repository that declares them in - * its {@link DepotRepository#getManagedRecords} method. - * - *

Note that the migration process is as follows: - * - *

  • Note the difference between the entity's declared version and the version recorded - * in the database. - *
  • Run all registered pre-migrations - *
  • Perform all default migrations (column and index additions, index removals) - *
  • Run all registered post-migrations
- * - * Thus you must either be prepared for the entity to be at any version prior to your - * migration target version because we may start up, find the schema at version 1 and the - * Entity class at version 8 and do all "standard" migrations in one fell swoop. So if a column - * got added in version 2 and renamed in version 6 and your migration was registered for - * version 6 to do that migration, it must be prepared for the column not to exist at all. - * - *

If you want a completely predictable migration process, never use the default migrations - * and register a pre-migration for every single schema migration and they will then be - * guaranteed to be run in registration order and with predictable pre- and post-conditions. - * - *

Note that if {@link PersistenceContext#initializeRepositories} is used, then all schema - * migrations for all known repositories will be run and then all data migrations for all known - * repositories will be run. This is recommeneded because schema migrations may fail and it is - * generally better to have not yet done the data migration rather than having schema and data - * migrations interleaved and potentially leaving the database in a strange state. - */ - public void registerMigration ( - Class type, SchemaMigration migration) - { - getRawMarshaller(type).registerMigration(migration); - } - - /** - * Returns the marshaller for the specified persistent object class, creating and initializing - * it if necessary. - */ - public DepotMarshaller getMarshaller (Class type) - throws DatabaseException - { - checkAreInitialized(); // le check du sanity - DepotMarshaller marshaller = getRawMarshaller(type); - try { - if (!marshaller.isInitialized()) { - // initialize the marshaller which may create or migrate the table for its - // underlying persistent object - marshaller.init(this); - if (marshaller.getTableName() != null && _warnOnLazyInit) { - log.warning("Record initialized lazily", "type", type.getName(), - new Exception()); - } - } - } catch (DatabaseException pe) { - throw (DatabaseException)new DatabaseException( - "Failed to initialize marshaller [type=" + type + "].").initCause(pe); - } - return marshaller; - } - - /** - * Invokes a non-modifying query and returns its result. - */ - public T invoke (Query query) - throws DatabaseException - { - CacheKey key = query.getCacheKey(); - // if there is a cache key, check the cache - if (key != null && _cache != null) { - CacheAdapter.CachedValue cacheHit = cacheLookup(key); - if (cacheHit != null) { - log.debug("cache hit [key=" + key + ", hit=" + cacheHit + "]"); - T value = cacheHit.getValue(); - value = query.transformCacheHit(key, value); - if (value != null) { - return value; - } - log.debug("transformCacheHit returned null; rejecting cached value."); - } - log.debug("cache miss [key=" + key + "]"); - } - // otherwise, perform the query - T result = invoke(query, true); - // and let the caller figure out if it wants to cache itself somehow - query.updateCache(this, result); - return result; - } - - /** - * Invokes a modifying query and returns the number of rows modified. - */ - public int invoke (Modifier modifier) - throws DatabaseException - { - modifier.cacheInvalidation(this); - int rows = invoke(modifier, true); - if (rows > 0) { - modifier.cacheUpdate(this); - } - return rows; - } - - /** - * Returns true if there is a {@link CacheAdapter} configured, false otherwise. - */ - public boolean isUsingCache () - { - return _cache != null; - } - - /** - * Looks up an entry in the cache by the given key. - */ - public CacheAdapter.CachedValue cacheLookup (CacheKey key) - { - if (_cache == null) { - return null; - } - CacheAdapter.CacheBin bin = _cache.getCache(key.getCacheId()); - return bin.lookup(key.getCacheKey()); - } - - /** - * Stores a new entry indexed by the given key. - */ - public void cacheStore (CacheKey key, T entry) - { - if (_cache == null) { - return; - } - if (key == null) { - log.warning("Cache key must not be null [entry=" + entry + "]"); - Thread.dumpStack(); - return; - } - log.debug("storing [key=" + key + ", value=" + entry + "]"); - - CacheAdapter.CacheBin bin = _cache.getCache(key.getCacheId()); - CacheAdapter.CachedValue element = bin.lookup(key.getCacheKey()); - T oldEntry = (element != null ? element.getValue() : null); - - // update the cache - bin.store(key.getCacheKey(), entry); - - // then do cache invalidations - Set> listeners = _listenerSets.get(key.getCacheId()); - if (listeners != null && listeners.size() > 0) { - for (CacheListener listener : listeners) { - log.debug("cascading [listener=" + listener + "]"); - @SuppressWarnings("unchecked") - CacheListener casted = (CacheListener)listener; - casted.entryCached(key, entry, oldEntry); - } - } - } - - /** - * Evicts the cache entry indexed under the given key, if there is one. The eviction may - * trigger further cache invalidations. - */ - public void cacheInvalidate (CacheKey key) - { - if (key == null) { - log.warning("Cache key to invalidate must not be null."); - Thread.dumpStack(); - } else { - cacheInvalidate(key.getCacheId(), key.getCacheKey()); - } - } - - /** - * Evicts the cache entry indexed under the given class and cache key, if there is one. The - * eviction may trigger further cache invalidations. - */ - public void cacheInvalidate (Class pClass, Serializable cacheKey) - { - cacheInvalidate(pClass.getName(), cacheKey); - } - - /** - * Evicts the cache entry indexed under the given cache id and cache key, if there is one. The - * eviction may trigger further cache invalidations. - */ - public void cacheInvalidate (String cacheId, Serializable cacheKey) - { - if (_cache == null) { - return; - } - log.debug("invalidating [cacheId=" + cacheId + ", cacheKey=" + cacheKey + "]"); - - CacheAdapter.CacheBin bin = _cache.getCache(cacheId); - CacheAdapter.CachedValue element = bin.lookup(cacheKey); - if (element != null) { - // find the old entry, if any - T oldEntry = element.getValue(); - if (oldEntry != null) { - // if there was one, do (possibly cascading) cache invalidations - Set> listeners = _listenerSets.get(cacheId); - if (listeners != null && listeners.size() > 0) { - CacheKey key = new SimpleCacheKey(cacheId, cacheKey); - for (CacheListener listener : listeners) { - log.debug("cascading [listener=" + listener + "]"); - @SuppressWarnings("unchecked") CacheListener casted = - (CacheListener)listener; - casted.entryInvalidated(key, oldEntry); - } - } - } - } - - // then remove the keyed entry from the cache system - bin.remove(cacheKey); - } - - /** - * Brutally iterates over the entire contents of the cache associated with the given class, - * invoking the callback for each cache entry. - */ - public void cacheTraverse ( - Class pClass, CacheTraverser filter) - { - cacheTraverse(pClass.getName(), filter); - } - - /** - * Brutally iterates over the entire contents of the cache identified by the given cache id, - * invoking the callback for each cache entry. - */ - public void cacheTraverse (String cacheId, CacheTraverser filter) - { - if (_cache == null) { - return; - } - CacheAdapter.CacheBin bin = _cache.getCache(cacheId); - if (bin != null) { - for (Object key : bin.enumerateKeys()) { - CacheAdapter.CachedValue element = bin.lookup((Serializable) key); - T value; - if (element != null && (value = element.getValue()) != null) { - filter.visitCacheEntry(this, cacheId, (Serializable) key, value); - } - } - } - } - - /** - * Registers a new cache listener with the cache associated with the given class. - */ - public void addCacheListener ( - Class pClass, CacheListener listener) - { - addCacheListener(pClass.getName(), listener); - } - - /** - * Registers a new cache listener with the identified cache. - */ - public void addCacheListener ( - String cacheId, CacheListener listener) - { - Set> listenerSet = _listenerSets.get(cacheId); - if (listenerSet == null) { - listenerSet = new HashSet>(); - _listenerSets.put(cacheId, listenerSet); - } - listenerSet.add(listener); - } - - /** - * Initializes all repositories that have been created and registered with this persistence - * context. Any repositories that are constructed after this call will be immediately - * initialized at the time they are constructed (which is probably undesirable). When a - * repository is initialized, schema migrations for all of its managed persistent records are - * run. It is best to do all schema migrations when the system initializes which is why lazy - * initialization of repositories is undesirable. - * - * @param warnOnLazyInit if true, any repositories are constructed after this method is called - * will result in a warning so that the application developer can restructure their code to - * ensure that those repositories are properly created prior to this call. - */ - public void initializeRepositories (boolean warnOnLazyInit) - throws DatabaseException - { - // resolve all persistent records and trigger all schema migrations - for (DepotRepository repo : _repositories) { - repo.resolveRecords(); - } - // then run all repository initialization methods, triggering all data migrations - for (DepotRepository repo : _repositories) { - repo.init(); - } - // now potentially issue a warning if we lazily initialize any other persistent record - _warnOnLazyInit = warnOnLazyInit; - // finally note that we've now been initialized - _repositories = null; - } - - /** - * Called when a depot repository is created. We register all persistent record classes used by - * the repository so that systems that desire it can force the resolution of all database - * tables rather than allowing resolution to happen on demand. - */ - protected void repositoryCreated (DepotRepository repo) - { - if (_repositories == null) { - if (_warnOnLazyInit) { - log.warning("Repository created lazily: " + repo.getClass().getName()); - } - repo.resolveRecords(); - repo.init(); - } else { - _repositories.add(repo); - } - } - - /** - * Looks up and creates, but does not initialize, the marshaller for the specified Entity type. - */ - protected DepotMarshaller getRawMarshaller (Class type) - { - @SuppressWarnings("unchecked") DepotMarshaller marshaller = - (DepotMarshaller)_marshallers.get(type); - if (marshaller == null) { - _marshallers.put(type, marshaller = new DepotMarshaller(type, this)); - } - return marshaller; - } - - /** - * Internal invoke method that takes care of transient retries for both queries and modifiers. - */ - protected T invoke (Operation op, boolean retryOnTransientFailure) - throws DatabaseException - { - checkAreInitialized(); // le check du sanity - - boolean isReadOnly = !(op instanceof Modifier); - Connection conn; - try { - conn = _conprov.getConnection(_ident, isReadOnly); - } catch (PersistenceException pe) { - throw new DatabaseException(pe.getMessage(), pe.getCause()); - } - - // TEMP: we synchronize on the connection to cooperate with SimpleRepository when used in - // conjunction with a StaticConnectionProvider; at some point we'll switch to standard JDBC - // connection pooling which will block in getConnection() instead of returning a connection - // that someone else may be using - synchronized (conn) { - try { - // if this becomes more complex than this single statement, then this should turn - // into a method call that contains the complexity - return op.invoke(conn, _liaison); - - } catch (SQLException sqe) { - if (!isReadOnly) { - // convert this exception to a DuplicateKeyException if appropriate - if (_liaison.isDuplicateRowException(sqe)) { - throw new DuplicateKeyException(sqe.getMessage()); - } - } - - // let the provider know that the connection failed - _conprov.connectionFailed(_ident, isReadOnly, conn, sqe); - conn = null; - - if (retryOnTransientFailure && _liaison.isTransientException(sqe)) { - // the MySQL JDBC driver has the annoying habit of including the embedded - // exception stack trace in the message of their outer exception; if I want a - // fucking stack trace, I'll call printStackTrace() thanksverymuch - String msg = StringUtil.split(String.valueOf(sqe), "\n")[0]; - log.info("Transient failure executing op, retrying [error=" + msg + "]."); - - } else { - throw new DatabaseException("Operation failure " + op, sqe); - } - - } finally { - _conprov.releaseConnection(_ident, isReadOnly, conn); - } - } - - // if we got here, we want to retry a transient failure - return invoke(op, false); - } - - protected void checkAreInitialized () - { - if (_conprov == null) { - throw new IllegalStateException( - "This persistence context has not yet been initialized. You are probably " + - "doing something too early, like in a repository's constructor. Don't do that."); - } - } - - protected String _ident; - protected ConnectionProvider _conprov; - protected DatabaseLiaison _liaison; - protected boolean _warnOnLazyInit; - - /** The object through which all our caching is relayed, or null, for no caching. */ - protected CacheAdapter _cache; - - /** Tracks repositories during the pre-initialization phase. */ - protected List _repositories = new ArrayList(); - - /** A mapping from persistent record class to resolved marshaller. */ - protected Map, DepotMarshaller> _marshallers = - new HashMap, DepotMarshaller>(); - - /** A mapping of cache listeners by cache id. */ - protected Map>> _listenerSets = - new HashMap>>(); -} diff --git a/src/java/com/samskivert/jdbc/depot/PersistentRecord.java b/src/java/com/samskivert/jdbc/depot/PersistentRecord.java deleted file mode 100644 index 604123a0..00000000 --- a/src/java/com/samskivert/jdbc/depot/PersistentRecord.java +++ /dev/null @@ -1,41 +0,0 @@ -// -// $Id$ -// -// samskivert library - useful routines for java programs -// Copyright (C) 2006-2007 Michael Bayne, Pär Winzell -// -// This library is free software; you can redistribute it and/or modify it -// under the terms of the GNU Lesser General Public License as published -// by the Free Software Foundation; either version 2.1 of the License, or -// (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -package com.samskivert.jdbc.depot; - -import java.io.Serializable; - -/** - * The base class for all persistent records used in Depot. Persistent records must be cloneable - * and serializable; this class is used to enforce those requirements. - */ -public class PersistentRecord - implements Cloneable, Serializable -{ - @Override // from Object - public PersistentRecord clone () - { - try { - return (PersistentRecord) super.clone(); - } catch (CloneNotSupportedException cnse) { - throw new RuntimeException(cnse); // this should never happen - } - } -} diff --git a/src/java/com/samskivert/jdbc/depot/PostgreSQLBuilder.java b/src/java/com/samskivert/jdbc/depot/PostgreSQLBuilder.java deleted file mode 100644 index ced8727f..00000000 --- a/src/java/com/samskivert/jdbc/depot/PostgreSQLBuilder.java +++ /dev/null @@ -1,297 +0,0 @@ -// -// $Id$ -// -// samskivert library - useful routines for java programs -// Copyright (C) 2006 Michael Bayne, Pär Winzell -// -// This library is free software; you can redistribute it and/or modify it -// under the terms of the GNU Lesser General Public License as published -// by the Free Software Foundation; either version 2.1 of the License, or -// (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -package com.samskivert.jdbc.depot; - -import java.sql.Blob; -import java.sql.Clob; -import java.sql.Connection; -import java.sql.Date; -import java.sql.PreparedStatement; -import java.sql.SQLException; -import java.sql.Statement; -import java.sql.Time; -import java.sql.Timestamp; -import java.util.Set; - -import com.samskivert.jdbc.DatabaseLiaison; -import com.samskivert.jdbc.JDBCUtil; -import com.samskivert.jdbc.LiaisonRegistry; -import com.samskivert.jdbc.depot.FieldMarshaller.BooleanMarshaller; -import com.samskivert.jdbc.depot.FieldMarshaller.ByteArrayMarshaller; -import com.samskivert.jdbc.depot.FieldMarshaller.ByteEnumMarshaller; -import com.samskivert.jdbc.depot.FieldMarshaller.ByteMarshaller; -import com.samskivert.jdbc.depot.FieldMarshaller.DoubleMarshaller; -import com.samskivert.jdbc.depot.FieldMarshaller.FloatMarshaller; -import com.samskivert.jdbc.depot.FieldMarshaller.IntArrayMarshaller; -import com.samskivert.jdbc.depot.FieldMarshaller.IntMarshaller; -import com.samskivert.jdbc.depot.FieldMarshaller.LongMarshaller; -import com.samskivert.jdbc.depot.FieldMarshaller.ObjectMarshaller; -import com.samskivert.jdbc.depot.FieldMarshaller.ShortMarshaller; -import com.samskivert.jdbc.depot.annotation.FullTextIndex; -import com.samskivert.jdbc.depot.expression.EpochSeconds; -import com.samskivert.jdbc.depot.operator.Conditionals.FullTextMatch; -import com.samskivert.util.ArrayUtil; -import com.samskivert.util.StringUtil; - -import static com.samskivert.Log.log; - -public class PostgreSQLBuilder - extends SQLBuilder -{ - public class PGBuildVisitor extends BuildVisitor - { - @Override public void visit (FullTextMatch match) { - appendIdentifier("ftsCol_" + match.getName()); - _builder.append(" @@ TO_TSQUERY('default', ?)"); - } - - @Override public void visit (EpochSeconds epochSeconds) { - _builder.append("date_part('epoch', "); - epochSeconds.getArgument().accept(this); - _builder.append(")"); - } - -// TODO: enable when we can require 1.6 support -// @Override public void visit (In in) { -// in.getColumn().accept(this); -// _builder.append(" = any (?)"); -// } - - protected PGBuildVisitor (DepotTypes types) { - super(types); - } - - @Override protected void appendIdentifier (String field) { - _builder.append("\"").append(field).append("\""); - } - } - - public class PGBindVisitor extends BindVisitor - { - @Override public void visit (FullTextMatch match) { - // The tsearch2 engine takes queries on the form - // (foo&bar)|goop - // so in this first simple implementation, we just take the user query, chop it into - // words by space/punctuation and 'or' those together like so: - // 'ho! who goes there?' -> 'ho|who|goes|there' - String[] searchTerms = match.getQuery().toLowerCase().split("\\W+"); - if (searchTerms.length > 0 && searchTerms[0].length() == 0) { - searchTerms = ArrayUtil.splice(searchTerms, 0, 1); - } - String query = StringUtil.join(searchTerms, "|"); - try { - _stmt.setString(_argIdx++, query); - } catch (SQLException sqe) { - throw new DatabaseException("Failed to configure full-text match column " + - "[idx=" + (_argIdx-1) + ", query=" + query + "]", sqe); - } - } - -// TODO: enable when we can require 1.6 support -// @Override public void visit (In in) { -// Comparable[] values = in.getValues(); -// try { -// _stmt.setObject( -// _argIdx++, _conn.createArrayOf(getElementType(values), (Object[])values)); -// } catch (SQLException sqe) { -// throw new DatabaseException( -// "Failed to write value to statement [idx=" + (_argIdx-1) + -// ", values=" + StringUtil.safeToString(values) + "]", sqe); -// } -// } - -// protected String getElementType (Comparable[] values) { -// if (values instanceof Integer[]) { -// return "integer"; -// } else if (values instanceof String[]) { -// return "character varying"; -// } else { -// throw new DatabaseException( -// "Don't know how to make Postgres array for " + values.getClass()); -// } -// } - - protected PGBindVisitor (DepotTypes types, Connection conn, PreparedStatement stmt) { - super(types, conn, stmt); - } - } - - public PostgreSQLBuilder (DepotTypes types) - { - super(types); - } - - @Override - public void getFtsIndexes ( - Iterable columns, Iterable indexes, Set target) - { - for (String column : columns) { - if (column.startsWith("ftsCol_")) { - target.add(column.substring("ftsCol_".length())); - } - } - } - - @Override - public boolean addFullTextSearch ( - Connection conn, DepotMarshaller marshaller, FullTextIndex fts) - throws SQLException - { - Class pClass = marshaller.getPersistentClass(); - DatabaseLiaison liaison = LiaisonRegistry.getLiaison(conn); - - String[] fields = fts.fields(); - - String table = marshaller.getTableName(); - String column = "ftsCol_" + fts.name(); - String index = table + "_ftsIx_" + fts.name(); - String trigger = table + "_ftsTrig_" + fts.name(); - - // build the UPDATE - StringBuilder initColumn = new StringBuilder("UPDATE "). - append(liaison.tableSQL(table)).append(" SET ").append(liaison.columnSQL(column)). - append(" = TO_TSVECTOR('default', "); - - for (int ii = 0; ii < fields.length; ii ++) { - if (ii > 0) { - initColumn.append(" || ' ' || "); - } - initColumn.append("COALESCE("). - append(liaison.columnSQL(_types.getColumnName(pClass, fields[ii]))). - append(", '')"); - } - initColumn.append(")"); - - // build the CREATE TRIGGER - StringBuilder createTrigger = new StringBuilder("CREATE TRIGGER "). - append(liaison.columnSQL(trigger)).append(" BEFORE UPDATE OR INSERT ON "). - append(liaison.tableSQL(table)).append(" FOR EACH ROW EXECUTE PROCEDURE tsearch2("). - append(liaison.columnSQL(column)).append(", "); - - for (int ii = 0; ii < fields.length; ii ++) { - if (ii > 0) { - createTrigger.append(", "); - } - createTrigger.append(liaison.columnSQL(_types.getColumnName(pClass, fields[ii]))); - } - createTrigger.append(")"); - - // build the CREATE INDEX - StringBuilder createIndex = new StringBuilder("CREATE INDEX "). - append(liaison.columnSQL(index)).append(" ON " ).append(liaison.tableSQL(table)). - append(" USING GIST(").append(liaison.columnSQL(column)).append(")"); - - Statement stmt = conn.createStatement(); - try { - log.info( - "Adding full-text search column, index and trigger: " + column + ", " + - index + ", " + trigger); - liaison.addColumn(conn, table, column, "TSVECTOR", true); - stmt.executeUpdate(initColumn.toString()); - stmt.executeUpdate(createIndex.toString()); - stmt.executeUpdate(createTrigger.toString()); - - } finally { - JDBCUtil.close(stmt); - } - return true; - } - - @Override - public boolean isPrivateColumn (String column) - { - // filter out any column that we created as part of FTS support - return column.startsWith("ftsCol_"); - } - - @Override - protected BuildVisitor getBuildVisitor () - { - return new PGBuildVisitor(_types); - } - - @Override - protected BindVisitor getBindVisitor (Connection conn, PreparedStatement stmt) - { - return new PGBindVisitor(_types, conn, stmt); - } - - @Override - protected String getColumnType (FieldMarshaller fm, int length) - { - if (fm instanceof ByteMarshaller) { - return "SMALLINT"; - } else if (fm instanceof ShortMarshaller) { - return "SMALLINT"; - } else if (fm instanceof IntMarshaller) { - return "INTEGER"; - } else if (fm instanceof LongMarshaller) { - return "BIGINT"; - } else if (fm instanceof FloatMarshaller) { - return "REAL"; - } else if (fm instanceof DoubleMarshaller) { - return "DOUBLE PRECISION"; - } else if (fm instanceof ObjectMarshaller) { - Class ftype = fm.getField().getType(); - if (ftype.equals(Byte.class)) { - return "SMALLINT"; - } else if (ftype.equals(Short.class)) { - return "SMALLINT"; - } else if (ftype.equals(Integer.class)) { - return "INTEGER"; - } else if (ftype.equals(Long.class)) { - return "BIGINT"; - } else if (ftype.equals(Float.class)) { - return "FLOAT"; - } else if (ftype.equals(Double.class)) { - return "DOUBLE"; - } else if (ftype.equals(String.class)) { - if (length < (1 << 15)) { - return "VARCHAR(" + length + ")"; - } - return "TEXT"; - } else if (ftype.equals(Date.class)) { - return "DATE"; - } else if (ftype.equals(Time.class)) { - return "TIME"; - } else if (ftype.equals(Timestamp.class)) { - return "TIMESTAMP"; - } else if (ftype.equals(Blob.class)) { - return "BYTEA"; - } else if (ftype.equals(Clob.class)) { - return "TEXT"; - } else { - throw new IllegalArgumentException( - "Don't know how to create SQL for " + ftype + "."); - } - } else if (fm instanceof ByteArrayMarshaller) { - return "BYTEA"; - } else if (fm instanceof IntArrayMarshaller) { - return "BYTEA"; - } else if (fm instanceof ByteEnumMarshaller) { - return "SMALLINT"; - } else if (fm instanceof BooleanMarshaller) { - return "BOOLEAN"; - } else { - throw new IllegalArgumentException("Unknown field marshaller type: " + fm.getClass()); - } - } -} diff --git a/src/java/com/samskivert/jdbc/depot/Query.java b/src/java/com/samskivert/jdbc/depot/Query.java deleted file mode 100644 index 70e7d3d8..00000000 --- a/src/java/com/samskivert/jdbc/depot/Query.java +++ /dev/null @@ -1,73 +0,0 @@ -// -// $Id$ -// -// samskivert library - useful routines for java programs -// Copyright (C) 2006-2007 Michael Bayne, Pär Winzell -// -// This library is free software; you can redistribute it and/or modify it -// under the terms of the GNU Lesser General Public License as published -// by the Free Software Foundation; either version 2.1 of the License, or -// (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -package com.samskivert.jdbc.depot; - -import java.sql.Connection; -import java.sql.SQLException; - -import com.samskivert.jdbc.DatabaseLiaison; -import com.samskivert.jdbc.depot.PersistenceContext.CacheListener; - -/** - * The base of all read-only queries. - */ -public interface Query extends Operation -{ - /** A simple base class for non-complex queries. */ - public abstract class Trivial implements Query - { - public abstract T invoke (Connection conn, DatabaseLiaison liaison) throws SQLException; - - public CacheKey getCacheKey () { - return null; - } - - public T transformCacheHit (CacheKey key, T value) { - return value; - } - - public void updateCache (PersistenceContext ctx, T result) { - } - } - - /** - * Any query may elect to utilize the built-in cache by returning a non-null {@link CacheKey} - * in this method. This is done automatically by the {@link DepotRepository} when looking up - * single entities by primary key, but even entire collections can be cached under a single - * key. - * - * Great care must be taken to invalidate such cached collections when their constituent - * entities are invalidated. This is generally done using {@link CacheListener} and - * {@link CacheInvalidator}. - */ - public CacheKey getCacheKey (); - - /** - * Overriden by subclasses to perform special operations when the query would return a cache - * hit. The value may be mutated, modified, or null may be return to force a database hit. - */ - public T transformCacheHit (CacheKey key, T value); - - /** - * Overriden by subclasses to perform case-by-case cache updates. - */ - public void updateCache (PersistenceContext ctx, T result); -} diff --git a/src/java/com/samskivert/jdbc/depot/SQLBuilder.java b/src/java/com/samskivert/jdbc/depot/SQLBuilder.java deleted file mode 100644 index 2683c60c..00000000 --- a/src/java/com/samskivert/jdbc/depot/SQLBuilder.java +++ /dev/null @@ -1,230 +0,0 @@ -// -// $Id$ -// -// samskivert library - useful routines for java programs -// Copyright (C) 2006-2007 Michael Bayne, Pär Winzell -// -// This library is free software; you can redistribute it and/or modify it -// under the terms of the GNU Lesser General Public License as published -// by the Free Software Foundation; either version 2.1 of the License, or -// (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -package com.samskivert.jdbc.depot; - -import java.lang.reflect.Field; -import java.util.Set; - -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.SQLException; - -import com.samskivert.jdbc.ColumnDefinition; -import com.samskivert.jdbc.depot.annotation.Column; -import com.samskivert.jdbc.depot.annotation.FullTextIndex; -import com.samskivert.jdbc.depot.annotation.GeneratedValue; -import com.samskivert.jdbc.depot.clause.QueryClause; -import com.samskivert.jdbc.depot.expression.ExpressionVisitor; - -import static com.samskivert.jdbc.depot.Log.log; - -/** - * At the heart of Depot's SQL generation, this object constructs two {@link ExpressionVisitor} - * objects and executes them, one after another; the first one constructs SQL as it recurses, the - * other binds arguments in the {@link PreparedStatement}. This class must be subclassed by the - * database dialects we wish to support. - */ -public abstract class SQLBuilder -{ - public SQLBuilder (DepotTypes types) - { - _types = types; - } - - /** - * Construct an entirely new SQL query relative to our configured {@link DepotTypes} data. - * This method may be called multiple times, each time beginning a new query, and should be - * followed up by a call to {@link #prepare(Connection)} which creates, configures and - * returns the actual {@link PreparedStatement} to execute. - */ - public void newQuery (QueryClause clause) - { - _clause = clause; - _buildVisitor = getBuildVisitor(); - _clause.accept(_buildVisitor); - } - - /** - * After {@link #newQuery(QueryClause)} has been executed, this method is run to recurse - * through the {@link QueryClause} structure, setting the {@link PreparedStatement} arguments - * that were defined in the generated SQL. - * - * This method throws {@link SQLException} and is thus meant to be called from within - * {@link Query#invoke} and {@link Modifier#invoke}. - */ - public PreparedStatement prepare (Connection conn) - throws SQLException - { - if (_buildVisitor == null) { - throw new IllegalArgumentException("Cannot prepare query until it's been built."); - } - - PreparedStatement stmt = conn.prepareStatement(_buildVisitor.getQuery()); - _bindVisitor = getBindVisitor(conn, stmt); - _clause.accept(_bindVisitor); - - if (PersistenceContext.DEBUG) { - log.info("SQL: " + stmt.toString()); - } - - return stmt; - } - - protected String nullify (String str) { - return (str != null && str.length() > 0) ? str : null; - } - - /** - * Generates the SQL needed to construct a database column for field represented by the given - * {@link FieldMarshaller}. - * - * TODO: This method should be split into several parts that are more easily overridden on a - * case-by-case basis in the dialectal subclasses. - */ - public ColumnDefinition buildColumnDefinition (FieldMarshaller fm) - { - // if this field is @Computed, it has no SQL definition - if (fm.getComputed() != null) { - return null; - } - - Field field = fm.getField(); - - String type = null; - boolean nullable = false; - boolean unique = false; - String defaultValue = null; - int length = 255; - - Column column = field.getAnnotation(Column.class); - if (column != null) { - type = nullify(column.type()); - nullable = column.nullable(); - unique = column.unique(); - defaultValue = nullify(column.defaultValue()); - length = column.length(); - } - - // handle primary keyness - GeneratedValue genValue = fm.getGeneratedValue(); - if (genValue != null) { - switch (genValue.strategy()) { - case AUTO: - case IDENTITY: - type = "SERIAL"; - unique = true; - break; - case SEQUENCE: // TODO - throw new IllegalArgumentException( - "SEQUENCE key generation strategy not yet supported."); - case TABLE: - // nothing to do here, it'll be handled later - break; - } - } - - if (type == null) { - type = getColumnType(fm, length); - } - - // sanity check nullability - if (nullable && field.getType().isPrimitive()) { - throw new IllegalArgumentException( - "Primitive Java type cannot be nullable [field=" + field.getName() + "]"); - } - - // Java primitive types cannot be null, so we provide a default value for these columns - // that matches Java's default for primitive types; however, if the column has a generated - // value, don't provide a default because that will anger the database Gods - if (defaultValue == null && genValue == null) { - if (field.getType().equals(Byte.TYPE) || - field.getType().equals(Short.TYPE) || - field.getType().equals(Integer.TYPE) || - field.getType().equals(Long.TYPE) || - field.getType().equals(Float.TYPE) || - field.getType().equals(Double.TYPE) || - ByteEnum.class.isAssignableFrom(field.getType())) { - defaultValue = "0"; - - } else if (field.getType().equals(Boolean.TYPE)) { - defaultValue = getBooleanDefault(); - } - } - - return new ColumnDefinition(type, nullable, unique, defaultValue); - } - - /** - * Add full-text search capabilities, as defined by the provided {@link FullTextIndex}, on - * the table associated with the given {@link DepotMarshaller}. This is a highly database - * specific operation and must thus be implemented by each dialect subclass. - * - * @see FullTextIndex - */ - public abstract boolean addFullTextSearch ( - Connection conn, DepotMarshaller marshaller, FullTextIndex fts) - throws SQLException; - - /** - * Return true if the supplied column is an internal consideration of this {@link SQLBuilder}, - * e.g. PostgreSQL's full text search data is stored in a table column that should otherwise - * not be visible to Depot; this method helps mask it. - */ - public abstract boolean isPrivateColumn (String column); - - /** - * Figure out what full text search indexes already exist on this table and add the names of - * those indexes to the supplied target set. - */ - public abstract void getFtsIndexes ( - Iterable columns, Iterable indexes, Set target); - - /** - * Returns the boolean literal that corresponds to false. - */ - protected String getBooleanDefault () - { - return "false"; - } - - /** - * Overridden by subclasses to create a dialect-specific {@link BuildVisitor}. - */ - protected abstract BuildVisitor getBuildVisitor (); - - /** - * Overridden by subclasses to create a dialect-specific {@link BindVisitor}. - */ - protected abstract BindVisitor getBindVisitor (Connection conn, PreparedStatement stmt); - - /** - * Overridden by subclasses to figure the dialect-specific SQL type of the given field. - * @param length - */ - protected abstract String getColumnType (FieldMarshaller fm, int length); - - /** The class that maps persistent classes to marshallers. */ - protected DepotTypes _types; - - protected QueryClause _clause; - protected BuildVisitor _buildVisitor; - protected BindVisitor _bindVisitor; -} diff --git a/src/java/com/samskivert/jdbc/depot/SchemaMigration.java b/src/java/com/samskivert/jdbc/depot/SchemaMigration.java deleted file mode 100644 index 1f99efb2..00000000 --- a/src/java/com/samskivert/jdbc/depot/SchemaMigration.java +++ /dev/null @@ -1,246 +0,0 @@ -// -// $Id$ -// -// samskivert library - useful routines for java programs -// Copyright (C) 2006-2007 Michael Bayne, Pär Winzell -// -// This library is free software; you can redistribute it and/or modify it -// under the terms of the GNU Lesser General Public License as published -// by the Free Software Foundation; either version 2.1 of the License, or -// (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -package com.samskivert.jdbc.depot; - -import java.sql.Connection; -import java.sql.SQLException; -import java.util.Map; - -import com.samskivert.jdbc.ColumnDefinition; -import com.samskivert.jdbc.DatabaseLiaison; -import com.samskivert.jdbc.depot.annotation.Column; - -import static com.samskivert.jdbc.depot.Log.log; - -/** - * Encapsulates the migration of a persistent record's database schema. These can be registered - * with the {@link PersistenceContext} to effect hand-coded migrations between entity versions. The - * modifier should override {@link #invoke} to perform its migrations. See {@link - * PersistenceContext#registerMigration} for details on the migration process. - * - *

Note: these should only be used for actual schema changes (column additions, removals, - * renames, retypes, etc.). It should not be used for data migration, use {@link DataMigration} for - * that. - */ -public abstract class SchemaMigration extends Modifier -{ - /** - * A convenient migration for dropping a column from an entity. - */ - public static class Drop extends SchemaMigration - { - public Drop (int targetVersion, String columnName) { - super(targetVersion); - _columnName = columnName; - } - - @Override - public Integer invoke (Connection conn, DatabaseLiaison liaison) throws SQLException { - if (!liaison.tableContainsColumn(conn, _tableName, _columnName)) { - // we'll accept this inconsistency - log.warning(_tableName + "." + _columnName + " already dropped."); - return 0; - } - - log.info("Dropping '" + _columnName + "' from " + _tableName); - return liaison.dropColumn(conn, _tableName, _columnName) ? 1 : 0; - } - - protected String _columnName; - } - - /** - * A convenient migration for renaming a column in an entity. - */ - public static class Rename extends SchemaMigration - { - public Rename (int targetVersion, String oldColumnName, String newColumnName) { - super(targetVersion); - _oldColumnName = oldColumnName; - _newColumnName = newColumnName; - } - - @Override - public Integer invoke (Connection conn, DatabaseLiaison liaison) throws SQLException { - if (!liaison.tableContainsColumn(conn, _tableName, _oldColumnName)) { - if (liaison.tableContainsColumn(conn, _tableName, _newColumnName)) { - // we'll accept this inconsistency - log.warning(_tableName + "." + _oldColumnName + " already renamed to " + - _newColumnName + "."); - return 0; - } - // but this is not OK - throw new IllegalArgumentException( - _tableName + " does not contain '" + _oldColumnName + "'"); - } - - // nor is this - if (liaison.tableContainsColumn(conn, _tableName, _newColumnName)) { - throw new IllegalArgumentException( - _tableName + " already contains '" + _newColumnName + "'"); - } - - log.info("Renaming '" + _oldColumnName + "' to '" + _newColumnName + "' in: " + - _tableName); - return liaison.renameColumn( - conn, _tableName, _oldColumnName, _newColumnName, _newColumnDef) ? 1 : 0; - } - - @Override public boolean runBeforeDefault () { - return true; - } - - @Override - protected void init (String tableName, Map> marshallers) { - super.init(tableName, marshallers); - FieldMarshaller fm = marshallers.get(_newColumnName); - if (fm == null) { - throw new IllegalArgumentException( - _tableName + " does not contain '" + _newColumnName + "' field."); - } - _newColumnDef = fm.getColumnDefinition(); - } - - protected String _oldColumnName, _newColumnName; - protected ColumnDefinition _newColumnDef; - } - - /** - * A convenient migration for changing the type of an existing field. NOTE: This object is - * instantiated with the name of a persistent field, not the name of a database column. These - * can be very different things for classes that use @Column annotations. - */ - public static class Retype extends SchemaMigration - { - public Retype (int targetVersion, String fieldName) { - super(targetVersion); - _fieldName = fieldName; - } - - @Override - public Integer invoke (Connection conn, DatabaseLiaison liaison) throws SQLException { - log.info("Updating type of '" + _fieldName + "' in " + _tableName); - return liaison.changeColumn(conn, _tableName, _fieldName, _newColumnDef.getType(), - _newColumnDef.isNullable(), _newColumnDef.isUnique(), - _newColumnDef.getDefaultValue()) ? 1 : 0; - } - - @Override public boolean runBeforeDefault () { - return false; - } - - @Override - protected void init (String tableName, Map> marshallers) { - super.init(tableName, marshallers); - _columnName = marshallers.get(_fieldName).getColumnName(); - _newColumnDef = marshallers.get(_fieldName).getColumnDefinition(); - } - - protected String _fieldName, _columnName; - protected ColumnDefinition _newColumnDef; - } - - /** - * A convenient migration for adding a new column that requires a default value to be specified - * during the addition. Normally Depot will automatically handle column addition, but if you - * have a column that normally does not have a default value but needs one when it is added to - * a table with existing rows, you can use this migration. - * - * @see Column#defaultValue - */ - public static class Add extends SchemaMigration - { - public Add (int targetVersion, String fieldName, String defaultValue) { - super(targetVersion); - _fieldName = fieldName; - _defaultValue = defaultValue; - } - - @Override - public Integer invoke (Connection conn, DatabaseLiaison liaison) throws SQLException { - // override the default value in the column definition with the one provided - ColumnDefinition defColumnDef = new ColumnDefinition( - _newColumnDef.getType(), _newColumnDef.isNullable(), - _newColumnDef.isUnique(), _defaultValue); - // first add the column with the overridden default value - if (liaison.addColumn(conn, _tableName, _fieldName, defColumnDef, true)) { - // then change the column to the permanent default value - liaison.changeColumn(conn, _tableName, _fieldName, _newColumnDef.getType(), - null, null, _newColumnDef.getDefaultValue()); - return 1; - } - return 0; - } - - @Override public boolean runBeforeDefault () { - return true; - } - - @Override - protected void init (String tableName, Map> marshallers) { - super.init(tableName, marshallers); - _columnName = marshallers.get(_fieldName).getColumnName(); - _newColumnDef = marshallers.get(_fieldName).getColumnDefinition(); - } - - protected String _fieldName, _columnName, _defaultValue; - protected ColumnDefinition _newColumnDef; - } - - /** - * If this method returns true, this migration will be run before the default - * migrations, if false it will be run after. - */ - public boolean runBeforeDefault () - { - return true; - } - - /** - * When an Entity is being migrated, this method will be called to check whether this migration - * should be run. The default implementation runs as long as the currentVersion is less than - * the target version supplied to the migration at construct time. - */ - public boolean shouldRunMigration (int currentVersion, int targetVersion) - { - return (currentVersion < _targetVersion); - } - - protected SchemaMigration (int targetVersion) - { - super(); - _targetVersion = targetVersion; - } - - /** - * This is called to provide the migration with the name of the entity table and access to its - * field marshallers prior to being invoked. This will only be called after this - * migration has been determined to be runnable so one cannot rely on this method having been - * called in {@link #shouldRunMigration}. - */ - protected void init (String tableName, Map> marshallers) - { - _tableName = tableName; - } - - protected int _targetVersion; - protected String _tableName; -} diff --git a/src/java/com/samskivert/jdbc/depot/SimpleCacheKey.java b/src/java/com/samskivert/jdbc/depot/SimpleCacheKey.java deleted file mode 100644 index 1b40b3ea..00000000 --- a/src/java/com/samskivert/jdbc/depot/SimpleCacheKey.java +++ /dev/null @@ -1,113 +0,0 @@ -// -// $Id$ -// -// samskivert library - useful routines for java programs -// Copyright (C) 2006-2007 Michael Bayne, Pär Winzell -// -// This library is free software; you can redistribute it and/or modify it -// under the terms of the GNU Lesser General Public License as published -// by the Free Software Foundation; either version 2.1 of the License, or -// (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -package com.samskivert.jdbc.depot; - -import java.io.Serializable; - -/** - * Convenience class that implements {@link CacheKey} as simply as possibly. This class is - * typically used when the caller wants to cache a non-obvious query such as a collection, - * and needs to specify their own cache key and file it under a hand-picked cache id. - */ -public class SimpleCacheKey - implements CacheKey -{ - /** - * Construct a {@link SimpleCacheKey} for a query that has no parameters whatsoever. - */ - public SimpleCacheKey (String cacheId) - { - this(cacheId, Boolean.TRUE); - } - - /** - * Construct a {@link SimpleCacheKey} associated with the given persistent class with - * the given cache key. - */ - public SimpleCacheKey (Class cacheClass, Serializable cacheKey) - { - this(cacheClass.getName(), cacheKey); - } - - /** - * Construct a {@link SimpleCacheKey} for the given cache id with the given cache key. - */ - public SimpleCacheKey (String cacheId, Serializable value) - { - _cacheId = cacheId; - _cacheKey = value; - } - - // from CacheKey - public String getCacheId () - { - return _cacheId; - } - - // from CacheKey - public Serializable getCacheKey () - { - return _cacheKey; - } - - @Override - public int hashCode () - { - final int PRIME = 31; - int result = 1; - result = PRIME * result + ((_cacheId == null) ? 0 : _cacheId.hashCode()); - result = PRIME * result + ((_cacheKey == null) ? 0 : _cacheKey.hashCode()); - return result; - } - - @Override - public boolean equals (Object obj) - { - if (obj == null || obj.getClass() != getClass()) { - return false; - } - SimpleCacheKey other = (SimpleCacheKey) obj; - if (_cacheId == null) { - if (other._cacheId != null) { - return false; - } - } else if (!_cacheId.equals(other._cacheId)) { - return false; - } - if (_cacheKey == null) { - if (other._cacheKey != null) { - return false; - } - } else if (!_cacheKey.equals(other._cacheKey)) { - return false; - } - return true; - } - - @Override - public String toString () - { - return "[cacheId=" + _cacheId + ", value=" + _cacheKey + "]"; - } - - protected String _cacheId; - protected Serializable _cacheKey; -} diff --git a/src/java/com/samskivert/jdbc/depot/TableValueGenerator.java b/src/java/com/samskivert/jdbc/depot/TableValueGenerator.java deleted file mode 100644 index 602c71ac..00000000 --- a/src/java/com/samskivert/jdbc/depot/TableValueGenerator.java +++ /dev/null @@ -1,174 +0,0 @@ -// -// $Id$ -// -// samskivert library - useful routines for java programs -// Copyright (C) 2006-2007 Michael Bayne, Pär Winzell -// -// This library is free software; you can redistribute it and/or modify it -// under the terms of the GNU Lesser General Public License as published -// by the Free Software Foundation; either version 2.1 of the License, or -// (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -package com.samskivert.jdbc.depot; - -import java.sql.Connection; -import java.sql.PreparedStatement; -import java.sql.ResultSet; -import java.sql.SQLException; - -import com.samskivert.jdbc.depot.annotation.GeneratedValue; -import com.samskivert.jdbc.depot.annotation.TableGenerator; - -import com.samskivert.jdbc.ColumnDefinition; -import com.samskivert.jdbc.DatabaseLiaison; -import com.samskivert.jdbc.JDBCUtil; - -/** - * Generates primary keys using an external table . - */ -public class TableValueGenerator extends ValueGenerator -{ - public TableValueGenerator ( - TableGenerator tg, GeneratedValue gv, DepotMarshaller dm, FieldMarshaller fm) - { - super(gv, dm, fm); - _valueTable = defStr(tg.table(), "IdSequences"); - _pkColumnName = defStr(tg.pkColumnName(), "sequence"); - _pkColumnValue = defStr(tg.pkColumnValue(), "default"); - _valueColumnName = defStr(tg.valueColumnName(), "value"); - } - - @Override // from ValueGenerator - public boolean isPostFactum () - { - return false; - } - - @Override // from ValueGenerator - public void create (Connection conn, DatabaseLiaison liaison) - throws SQLException - { - // make sure our table exists - liaison.createTableIfMissing( - conn, _valueTable, - new String[] { _pkColumnName, _valueColumnName }, - new ColumnDefinition[] { - new ColumnDefinition("VARCHAR(255)", true, false, null), - new ColumnDefinition("INTEGER") - }, - null, - new String[] { _pkColumnName }); - - // and also that there's a row in it for us - PreparedStatement stmt = null; - try { - stmt = conn.prepareStatement( - " SELECT * FROM " + liaison.tableSQL(_valueTable) + - " WHERE " + liaison.columnSQL(_pkColumnName) + " = ?"); - stmt.setString(1, _pkColumnValue); - if (stmt.executeQuery().next()) { - return; - } - - JDBCUtil.close(stmt); - stmt = null; - - int initialValue = _initialValue; - if (_migrateIfExists) { - Integer max = getFieldMaximum(conn, liaison); - if (max != null) { - initialValue = 1 + max.intValue(); - } - } - - stmt = conn.prepareStatement( - " INSERT INTO " + liaison.tableSQL(_valueTable) + " (" + - liaison.columnSQL(_pkColumnName) + ", " + liaison.columnSQL(_valueColumnName) + - ") VALUES (?, ?)"); - stmt.setString(1, _pkColumnValue); - stmt.setInt(2, initialValue); - stmt.executeUpdate(); - - } finally { - JDBCUtil.close(stmt); - } - } - - @Override // from ValueGenerator - public void delete (Connection conn, DatabaseLiaison liaison) throws SQLException - { - PreparedStatement stmt = null; - try { - stmt = conn.prepareStatement( - " DELETE FROM " + liaison.tableSQL(_valueTable) + - " WHERE " + liaison.columnSQL(_pkColumnName) + " = ?"); - stmt.setString(1, _pkColumnValue); - stmt.executeUpdate(); - - } finally { - JDBCUtil.close(stmt); - } - } - - @Override // from ValueGenerator - public int nextGeneratedValue (Connection conn, DatabaseLiaison liaison) - throws SQLException - { - PreparedStatement stmt = null; - try { - // TODO: Make this lockless! - String query = - " SELECT " + liaison.columnSQL(_valueColumnName) + - " FROM " + liaison.tableSQL(_valueTable) + - " WHERE " + liaison.columnSQL(_pkColumnName) + " = ? FOR UPDATE"; - stmt = conn.prepareStatement(query); - stmt.setString(1, _pkColumnValue); - - ResultSet rs = stmt.executeQuery(); - if (!rs.next()) { - throw new SQLException("Failed to find next primary key value " + - "[table=" + _valueTable + ", column=" + _valueColumnName + - ", where=" + _pkColumnName + "=" + _pkColumnValue + "]"); - } - int val = rs.getInt(1); - JDBCUtil.close(stmt); - - stmt = conn.prepareStatement( - " UPDATE " + liaison.tableSQL(_valueTable) + - " SET " + liaison.columnSQL(_valueColumnName) + " = ? " + - " WHERE " + liaison.columnSQL(_pkColumnName) + " = ?"); - stmt.setInt(1, val + _allocationSize); - stmt.setString(2, _pkColumnValue); - stmt.executeUpdate(); - return val; - - } finally { - JDBCUtil.close(stmt); - } - } - - /** - * Convenience function to return a value or a default fallback. - */ - protected static String defStr (String value, String def) - { - if (value == null || value.trim().length() == 0) { - return def; - } - return value; - } - - protected String _valueTable; - protected String _pkColumnName; - protected String _pkColumnValue; - protected String _valueColumnName; -} diff --git a/src/java/com/samskivert/jdbc/depot/ValidatingCacheInvalidator.java b/src/java/com/samskivert/jdbc/depot/ValidatingCacheInvalidator.java deleted file mode 100644 index 96094f5f..00000000 --- a/src/java/com/samskivert/jdbc/depot/ValidatingCacheInvalidator.java +++ /dev/null @@ -1,38 +0,0 @@ -// -// $Id$ -// -// samskivert library - useful routines for java programs -// Copyright (C) 2001-2007 Michael Bayne -// -// This library is free software; you can redistribute it and/or modify it -// under the terms of the GNU Lesser General Public License as published -// by the Free Software Foundation; either version 2.1 of the License, or -// (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -package com.samskivert.jdbc.depot; - -/** - * An augmented cache invalidator interface for invalidators that can ensure that they are - * operating on the proper persistent record class. - */ -public interface ValidatingCacheInvalidator extends CacheInvalidator -{ - /** - * Validates that this invalidator operates on the supplied persistent record class. This helps - * to catch programmer errors where one record type is used for a query clause and another is - * used for the cache invalidator. - * - * @exception IllegalArgumentException thrown if the supplied persistent record class does not - * match the class that this invalidator will flush from the cache. - */ - public void validateFlushType (Class pClass); -} diff --git a/src/java/com/samskivert/jdbc/depot/ValueGenerator.java b/src/java/com/samskivert/jdbc/depot/ValueGenerator.java deleted file mode 100644 index e2e75f0e..00000000 --- a/src/java/com/samskivert/jdbc/depot/ValueGenerator.java +++ /dev/null @@ -1,124 +0,0 @@ -// -// $Id$ -// -// samskivert library - useful routines for java programs -// Copyright (C) 2006-2007 Michael Bayne, Pär Winzell -// -// This library is free software; you can redistribute it and/or modify it -// under the terms of the GNU Lesser General Public License as published -// by the Free Software Foundation; either version 2.1 of the License, or -// (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -package com.samskivert.jdbc.depot; - -import java.sql.Connection; -import java.sql.ResultSet; -import java.sql.SQLException; -import java.sql.Statement; - -import com.samskivert.jdbc.DatabaseLiaison; -import com.samskivert.jdbc.JDBCUtil; -import com.samskivert.jdbc.depot.annotation.GeneratedValue; - -import static com.samskivert.jdbc.depot.Log.log; - -/** - * Defines the interface to our value generators. - */ -public abstract class ValueGenerator -{ - public ValueGenerator (GeneratedValue gv, DepotMarshaller dm, FieldMarshaller fm) - { - _allocationSize = gv.allocationSize(); - _initialValue = gv.initialValue(); - _migrateIfExists = gv.migrateIfExists(); - _dm = dm; - _fm = fm; - } - - /** - * If true, this key generator will be run after the insert statement, if false, it will be run - * before. - */ - public abstract boolean isPostFactum (); - - /** - * Ensures the generator is prepared for operation, creating it if necessary. Care is taken to - * only run this the first time a column is created. However, if a column with a value - * generator is renamed, we can't distinguish that from a newly created column and we call this - * method again on the renamed column. If it's possible to not fail in that circumstance, try - * to avoid doing so. - */ - public abstract void create (Connection conn, DatabaseLiaison liaison) - throws SQLException; - - /** - * Fetch/generate the next primary key value. - */ - public abstract int nextGeneratedValue (Connection conn, DatabaseLiaison liaison) - throws SQLException; - - /** - * Delete all database entities associated with this value generator. - */ - public abstract void delete (Connection conn, DatabaseLiaison liaison) - throws SQLException; - - /** - * Scans the table associated with this {@link ValueGenerator} and returns either null, if - * there are no rows, or an {@link Integer} containing the largest numerical value our - * field attains. - */ - protected Integer getFieldMaximum (Connection conn, DatabaseLiaison liaison) - throws SQLException - { - String column = _fm.getColumnName(); - String table = _dm.getTableName(); - - Statement stmt = conn.createStatement(); - try { - ResultSet rs = stmt.executeQuery( - " SELECT COUNT(*), MAX(" + liaison.columnSQL(column) + ") " + - " FROM " + liaison.tableSQL(table)); - if (!rs.next()) { - log.warning("Query on count()/max() bizarrely returned no rows."); - return null; - } - - int cnt = rs.getInt(1); - if (cnt > 0) { - return Integer.valueOf(rs.getInt(2)); - } - return null; - - } finally { - JDBCUtil.close(stmt); - } - } - - public DepotMarshaller getDepotMarshaller () - { - return _dm; - } - - public FieldMarshaller getFieldMarshaller () - { - return _fm; - } - - protected int _initialValue; - protected int _allocationSize; - protected boolean _migrateIfExists; - - protected DepotMarshaller _dm; - protected FieldMarshaller _fm; -} diff --git a/src/java/com/samskivert/jdbc/depot/WhereClause.java b/src/java/com/samskivert/jdbc/depot/WhereClause.java deleted file mode 100644 index db6d8eb4..00000000 --- a/src/java/com/samskivert/jdbc/depot/WhereClause.java +++ /dev/null @@ -1,60 +0,0 @@ -// -// $Id$ -// -// samskivert library - useful routines for java programs -// Copyright (C) 2006-2007 Michael Bayne, Pär Winzell -// -// This library is free software; you can redistribute it and/or modify it -// under the terms of the GNU Lesser General Public License as published -// by the Free Software Foundation; either version 2.1 of the License, or -// (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -package com.samskivert.jdbc.depot; - -import com.samskivert.jdbc.depot.clause.QueryClause; -import com.samskivert.jdbc.depot.expression.SQLExpression; - -/** - * Currently only exists as a type without any functionality of its own. - */ -public abstract class WhereClause extends QueryClause -{ - /** - * Returns the condition associated with this where clause. - */ - public abstract SQLExpression getWhereExpression (); - - /** - * Validates that the supplied persistent record type is the type matched by this where clause. - * Not all clauses will be able to perform this validation, but those that can, should do so to - * help alleviate programmer error. - * - * @exception IllegalArgumentException thrown if the supplied class is known not to by the type - * matched by this where clause. - */ - public void validateQueryType (Class pClass) - { - // nothing by default - } - - /** - * A helper function for implementing {@link #validateQueryType}. - */ - protected void validateTypesMatch (Class qClass, Class kClass) - { - if (!qClass.equals(kClass)) { - throw new IllegalArgumentException( - "Class mismatch between persistent record and key in query " + - "[qtype=" + qClass.getSimpleName() + ", ktype=" + kClass.getSimpleName() + "]."); - } - } -} diff --git a/src/java/com/samskivert/jdbc/depot/annotation/Column.java b/src/java/com/samskivert/jdbc/depot/annotation/Column.java deleted file mode 100644 index 193cbfe9..00000000 --- a/src/java/com/samskivert/jdbc/depot/annotation/Column.java +++ /dev/null @@ -1,71 +0,0 @@ -// -// $Id$ -// -// samskivert library - useful routines for java programs -// Copyright (C) 2006-2007 Michael Bayne, Pär Winzell -// -// This library is free software; you can redistribute it and/or modify it -// under the terms of the GNU Lesser General Public License as published -// by the Free Software Foundation; either version 2.1 of the License, or -// (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -package com.samskivert.jdbc.depot.annotation; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Is used to specify a mapped column for a persistent property or field. If no Column annotation - * is specified, the default values are applied. - */ -@Target(value=ElementType.FIELD) -@Retention(value=RetentionPolicy.RUNTIME) -public @interface Column -{ - /** - * The name of the column. Defaults to the field name. - */ - String name () default ""; - - /** - * Whether the property is a unique key. This is a shortcut for the UniqueConstraint annotation - * at the table level and is useful for when the unique key constraint is only a single - * field. This constraint applies in addition to any constraint entailed by primary key mapping - * and to constraints specified at the table level. - */ - boolean unique () default false; - - /** - * Whether the database column is nullable. Note: this default differs from the value - * used by the EJB3 persistence framework. - */ - boolean nullable () default false; - - /** - * The SQL type that is used when generating the DDL for the column. - */ - String type() default ""; - - /** - * The column length. (Applies to String and byte[] columns.) - */ - int length () default 255; - - /** - * The SQL literal value to be used when defining this column's default value. The value must - * be quoted and escaped if it is not a SQL primitive datatype. For example: - * '2006-01-01' or 25 or NULL. - */ - String defaultValue () default ""; -} diff --git a/src/java/com/samskivert/jdbc/depot/annotation/Computed.java b/src/java/com/samskivert/jdbc/depot/annotation/Computed.java deleted file mode 100644 index f7fe38cb..00000000 --- a/src/java/com/samskivert/jdbc/depot/annotation/Computed.java +++ /dev/null @@ -1,64 +0,0 @@ -// -// $Id$ -// -// samskivert library - useful routines for java programs -// Copyright (C) 2006-2007 Michael Bayne, Pär Winzell -// -// This library is free software; you can redistribute it and/or modify it -// under the terms of the GNU Lesser General Public License as published -// by the Free Software Foundation; either version 2.1 of the License, or -// (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -package com.samskivert.jdbc.depot.annotation; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -import com.samskivert.jdbc.depot.PersistentRecord; -import com.samskivert.jdbc.depot.clause.FieldOverride; -import com.samskivert.jdbc.depot.clause.FromOverride; -import com.samskivert.jdbc.depot.clause.Join; - -/** - * Marks a field as computed, meaning it is ignored for schema purposes and it does not directly - * correspond to a column in a table. - */ -@Retention(value=RetentionPolicy.RUNTIME) -@Target({ ElementType.FIELD, ElementType.TYPE }) -public @interface Computed -{ - /** If this value is false, the field is not populated at all. */ - boolean required () default true; - - /** A non-empty value here is taken as literal SQL and used to populate the computed field. */ - String fieldDefinition () default ""; - - /** - * A computed record can shadow a concrete record, which causes any field the former has in - * common with the latter and which is not otherwise overriden to inherit its definition. The - * shadowed class may also be given at the field level. - * - * The purpose of shadowing is largely to avoid having to supply a {@link FieldOverride} when - * querying for objects that that contain large subsets of some other persistent object's - * fields -- in other words, when you use a computed entity to query only some of the columns - * from a table. - * - * The shadowed class must have been brought into the query using e.g. {@link FromOverride} - * or {@link Join} clauses. The referenced fields must be simple concrete columns in a table; - * they must themselves be computed or overridden or shadowing. - * - * TODO: Do in fact let the shadowed field be computed, overriden or shadowing. - */ - Class shadowOf () default PersistentRecord.class; -} diff --git a/src/java/com/samskivert/jdbc/depot/annotation/Entity.java b/src/java/com/samskivert/jdbc/depot/annotation/Entity.java deleted file mode 100644 index 5cdf2040..00000000 --- a/src/java/com/samskivert/jdbc/depot/annotation/Entity.java +++ /dev/null @@ -1,48 +0,0 @@ -// -// $Id$ -// -// samskivert library - useful routines for java programs -// Copyright (C) 2006-2007 Michael Bayne, Pär Winzell -// -// This library is free software; you can redistribute it and/or modify it -// under the terms of the GNU Lesser General Public License as published -// by the Free Software Foundation; either version 2.1 of the License, or -// (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -package com.samskivert.jdbc.depot.annotation; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Specifies the primary field(s) of an entity. - */ -@Target(value=ElementType.TYPE) -@Retention(value=RetentionPolicy.RUNTIME) -public @interface Entity -{ - /** The name of an entity. Defaults to the unqualified name of the entity class. */ - String name () default ""; - - /** Unique constraints that are to be placed on this entity's table. These constraints apply in - * addition to any constraints specified by the Column annotation and constraints entailed by - * primary key mappings. Defaults to no additional constraints. */ - UniqueConstraint[] uniqueConstraints () default {}; - - /** Indices to add to this entity's table. */ - Index[] indices () default {}; - - /** Full-text search indexes defined on this entity, if any. Defaults to none. */ - FullTextIndex[] fullTextIndices () default {}; -} diff --git a/src/java/com/samskivert/jdbc/depot/annotation/FullTextIndex.java b/src/java/com/samskivert/jdbc/depot/annotation/FullTextIndex.java deleted file mode 100644 index 98c5341d..00000000 --- a/src/java/com/samskivert/jdbc/depot/annotation/FullTextIndex.java +++ /dev/null @@ -1,44 +0,0 @@ -// -// $Id$ -// -// samskivert library - useful routines for java programs -// Copyright (C) 2007 Michael Bayne, Pär Winzell -// -// This library is free software; you can redistribute it and/or modify it -// under the terms of the GNU Lesser General Public License as published -// by the Free Software Foundation; either version 2.1 of the License, or -// (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -package com.samskivert.jdbc.depot.annotation; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * This annotation is used to specify that a full text index is to be included in the generated DDL - * for a table. - */ -@Target(value={}) -@Retention(value=RetentionPolicy.RUNTIME) -public @interface FullTextIndex -{ - /** - * An identifier for this index, unique with the scope of the record. - */ - public String name (); - - /** - * An array of the field names that should be indexed. - */ - public String[] fields (); -} diff --git a/src/java/com/samskivert/jdbc/depot/annotation/GeneratedValue.java b/src/java/com/samskivert/jdbc/depot/annotation/GeneratedValue.java deleted file mode 100644 index c771d440..00000000 --- a/src/java/com/samskivert/jdbc/depot/annotation/GeneratedValue.java +++ /dev/null @@ -1,64 +0,0 @@ -// -// $Id$ -// -// samskivert library - useful routines for java programs -// Copyright (C) 2006-2007 Michael Bayne, Pär Winzell -// -// This library is free software; you can redistribute it and/or modify it -// under the terms of the GNU Lesser General Public License as published -// by the Free Software Foundation; either version 2.1 of the License, or -// (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -package com.samskivert.jdbc.depot.annotation; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Provides for the specification of generation strategies for the values of primary keys. The - * GeneratedValue annotation may be applied to a primary field in conjunction with the {@link Id} - * annotation. - */ -@Target(value=ElementType.FIELD) -@Retention(value=RetentionPolicy.RUNTIME) -public @interface GeneratedValue -{ - /** Identifies which generator should be used to generate this value when using a table or - * sequence generator. */ - String generator () default ""; - - /** Identifies the strategy to be used to generate this value. */ - GenerationType strategy () default GenerationType.AUTO; - - /** - * The initial value to be used when allocating id numbers from the generator. The default - * initial value is 1. Note: this default differs from the value used by the EJB3 - * persistence framework. - */ - int initialValue () default 1; - - /** - * If there are rows in our corresponding table, this boolean determines whether or not to - * attempt to initialize the generator to the maximum value of our associated field over - * those rows. This attribute does not exist in the EJB3 framework. - */ - boolean migrateIfExists () default true; - - /** - * The amount to increment by when allocating id numbers from the generator. The default - * allocation size is 1. Note: this default differs from the value used by the EJB3 - * persistence framework. - */ - int allocationSize () default 1; -} diff --git a/src/java/com/samskivert/jdbc/depot/annotation/GenerationType.java b/src/java/com/samskivert/jdbc/depot/annotation/GenerationType.java deleted file mode 100644 index 789030eb..00000000 --- a/src/java/com/samskivert/jdbc/depot/annotation/GenerationType.java +++ /dev/null @@ -1,51 +0,0 @@ -// -// $Id$ -// -// samskivert library - useful routines for java programs -// Copyright (C) 2006-2007 Michael Bayne, Pär Winzell -// -// This library is free software; you can redistribute it and/or modify it -// under the terms of the GNU Lesser General Public License as published -// by the Free Software Foundation; either version 2.1 of the License, or -// (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -package com.samskivert.jdbc.depot.annotation; - -/** - * Defines the types of primary key generation. - */ -public enum GenerationType -{ - /** - * Indicates that the persistence provider must assign primary keys for the entity using an - * underlying database table to ensure uniqueness. - */ - TABLE, - - /** - * Indicates that the persistence provider must assign primary keys for the entity using - * database sequences. - */ - SEQUENCE, - - /** - * Indicates that the persistence provider must assign primary keys for the entity using - * database identity column. - */ - IDENTITY, - - /** - * Indicates that the persistence provider should pick an appropriate strategy for the - * particular database. - */ - AUTO; -} diff --git a/src/java/com/samskivert/jdbc/depot/annotation/Id.java b/src/java/com/samskivert/jdbc/depot/annotation/Id.java deleted file mode 100644 index 754130cd..00000000 --- a/src/java/com/samskivert/jdbc/depot/annotation/Id.java +++ /dev/null @@ -1,35 +0,0 @@ -// -// $Id$ -// -// samskivert library - useful routines for java programs -// Copyright (C) 2006-2007 Michael Bayne, Pär Winzell -// -// This library is free software; you can redistribute it and/or modify it -// under the terms of the GNU Lesser General Public License as published -// by the Free Software Foundation; either version 2.1 of the License, or -// (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -package com.samskivert.jdbc.depot.annotation; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Specifies the primary key property or field of an entity. - */ -@Target(value=ElementType.FIELD) -@Retention(value=RetentionPolicy.RUNTIME) -public @interface Id -{ -} diff --git a/src/java/com/samskivert/jdbc/depot/annotation/Index.java b/src/java/com/samskivert/jdbc/depot/annotation/Index.java deleted file mode 100644 index fae91b8f..00000000 --- a/src/java/com/samskivert/jdbc/depot/annotation/Index.java +++ /dev/null @@ -1,42 +0,0 @@ -// -// $Id$ -// -// samskivert library - useful routines for java programs -// Copyright (C) 2006-2007 Michael Bayne, Pär Winzell -// -// This library is free software; you can redistribute it and/or modify it -// under the terms of the GNU Lesser General Public License as published -// by the Free Software Foundation; either version 2.1 of the License, or -// (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -package com.samskivert.jdbc.depot.annotation; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * Defines an index on an entity table. - */ -@Target(value={}) -@Retention(value=RetentionPolicy.RUNTIME) -public @interface Index -{ - /** Defines the name of the index. */ - String name (); - - /** Does this index enforce a uniqueness constraint? */ - boolean unique () default false; - - /** Defines the fields on which the index operates. */ - String[] fields () default {}; -} diff --git a/src/java/com/samskivert/jdbc/depot/annotation/TableGenerator.java b/src/java/com/samskivert/jdbc/depot/annotation/TableGenerator.java deleted file mode 100644 index 82bfca62..00000000 --- a/src/java/com/samskivert/jdbc/depot/annotation/TableGenerator.java +++ /dev/null @@ -1,66 +0,0 @@ -// -// $Id$ -// -// samskivert library - useful routines for java programs -// Copyright (C) 2006-2007 Michael Bayne, Pär Winzell -// -// This library is free software; you can redistribute it and/or modify it -// under the terms of the GNU Lesser General Public License as published -// by the Free Software Foundation; either version 2.1 of the License, or -// (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -package com.samskivert.jdbc.depot.annotation; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * This annotation defines a primary key generator that may be referenced by name when a generator - * element is specified for the GeneratedValue annotation. A table generator may be specified on - * the entity class or on the primary key field. The scope of the generator name is global to the - * persistence unit (across all generator types). - */ -@Target(value={ElementType.TYPE, ElementType.FIELD}) -@Retention(value=RetentionPolicy.RUNTIME) -public @interface TableGenerator -{ - /** - * A unique generator name that can be referenced by one or more classes to be the - * generator for id values. - */ - String name (); - - /** - * Name of table that stores the generated id values. Defaults to a name chosen by persistence - * provider. - */ - String table () default ""; - - /** - * Name of the primary key column in the table Defaults to a provider-chosen name. - */ - String pkColumnName () default ""; - - /** - * Name of the column that stores the last value generated Defaults to a provider-chosen name. - */ - String valueColumnName () default ""; - - /** - * The primary key value in the generator table that distinguishes this set of generated values - * from others that may be stored in the table Defaults to a provider-chosen value to store in - * the primary key column of the generator table - */ - String pkColumnValue () default ""; -} diff --git a/src/java/com/samskivert/jdbc/depot/annotation/Transient.java b/src/java/com/samskivert/jdbc/depot/annotation/Transient.java deleted file mode 100644 index 26a37dab..00000000 --- a/src/java/com/samskivert/jdbc/depot/annotation/Transient.java +++ /dev/null @@ -1,36 +0,0 @@ -// -// $Id$ -// -// samskivert library - useful routines for java programs -// Copyright (C) 2006-2007 Michael Bayne, Pär Winzell -// -// This library is free software; you can redistribute it and/or modify it -// under the terms of the GNU Lesser General Public License as published -// by the Free Software Foundation; either version 2.1 of the License, or -// (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -package com.samskivert.jdbc.depot.annotation; - -import java.lang.annotation.ElementType; -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * This annotation specifies that the property or field is not persistent. It is used to annotate - * a property or field of an entity class, mapped superclass, or embeddable class. - */ -@Target(value=ElementType.FIELD) -@Retention(value=RetentionPolicy.RUNTIME) -public @interface Transient -{ -} diff --git a/src/java/com/samskivert/jdbc/depot/annotation/UniqueConstraint.java b/src/java/com/samskivert/jdbc/depot/annotation/UniqueConstraint.java deleted file mode 100644 index f6d6a666..00000000 --- a/src/java/com/samskivert/jdbc/depot/annotation/UniqueConstraint.java +++ /dev/null @@ -1,39 +0,0 @@ -// -// $Id$ -// -// samskivert library - useful routines for java programs -// Copyright (C) 2006-2007 Michael Bayne, Pär Winzell -// -// This library is free software; you can redistribute it and/or modify it -// under the terms of the GNU Lesser General Public License as published -// by the Free Software Foundation; either version 2.1 of the License, or -// (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -package com.samskivert.jdbc.depot.annotation; - -import java.lang.annotation.Retention; -import java.lang.annotation.RetentionPolicy; -import java.lang.annotation.Target; - -/** - * This annotation is used to specify that a unique constraint is to be included in the - * generated DDL for a table. - */ -@Target(value={}) -@Retention(value=RetentionPolicy.RUNTIME) -public @interface UniqueConstraint -{ - /** - * An array of the field names that make up the constraint - */ - public String[] fieldNames () default {}; -} diff --git a/src/java/com/samskivert/jdbc/depot/clause/DeleteClause.java b/src/java/com/samskivert/jdbc/depot/clause/DeleteClause.java deleted file mode 100644 index a35df284..00000000 --- a/src/java/com/samskivert/jdbc/depot/clause/DeleteClause.java +++ /dev/null @@ -1,67 +0,0 @@ -// -// $Id$ -// -// samskivert library - useful routines for java programs -// Copyright (C) 2006 Michael Bayne -// -// This library is free software; you can redistribute it and/or modify it -// under the terms of the GNU Lesser General Public License as published -// by the Free Software Foundation; either version 2.1 of the License, or -// (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -package com.samskivert.jdbc.depot.clause; - -import java.util.Collection; - -import com.samskivert.jdbc.depot.PersistentRecord; -import com.samskivert.jdbc.depot.WhereClause; -import com.samskivert.jdbc.depot.expression.ExpressionVisitor; - -/** - * Builds actual SQL given a main persistent type and some {@link QueryClause} objects. - */ -public class DeleteClause extends QueryClause -{ - public DeleteClause (Class pClass, WhereClause where) - { - _pClass = pClass; - _where = where; - } - - public Class getPersistentClass () - { - return _pClass; - } - - public WhereClause getWhereClause () - { - return _where; - } - - // from SQLExpression - public void addClasses (Collection> classSet) - { - classSet.add(_pClass); - } - - // from SQLExpression - public void accept (ExpressionVisitor builder) - { - builder.visit(this); - } - - /** The type of persistent record on which we operate. */ - protected Class _pClass; - - /** The where clause. */ - protected WhereClause _where; -} diff --git a/src/java/com/samskivert/jdbc/depot/clause/FieldDefinition.java b/src/java/com/samskivert/jdbc/depot/clause/FieldDefinition.java deleted file mode 100644 index a5b7f6fb..00000000 --- a/src/java/com/samskivert/jdbc/depot/clause/FieldDefinition.java +++ /dev/null @@ -1,89 +0,0 @@ -// -// $Id$ -// -// samskivert library - useful routines for java programs -// Copyright (C) 2006-2007 Michael Bayne, Pär Winzell -// -// This library is free software; you can redistribute it and/or modify it -// under the terms of the GNU Lesser General Public License as published -// by the Free Software Foundation; either version 2.1 of the License, or -// (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -package com.samskivert.jdbc.depot.clause; - -import java.util.Collection; - -import com.samskivert.jdbc.depot.PersistentRecord; -import com.samskivert.jdbc.depot.expression.ColumnExp; -import com.samskivert.jdbc.depot.expression.ExpressionVisitor; -import com.samskivert.jdbc.depot.expression.LiteralExp; -import com.samskivert.jdbc.depot.expression.SQLExpression; - -/** - * Supplies a definition for a computed field of the persistent object we're creating. - * - * Thus the select portion of a query can include a reference to a different column in a different - * table through a {@link ColumnExp}, or a literal expression such as COUNT(*) through a - * {@link LiteralExp}. - * - * @see FieldOverride - */ -public class FieldDefinition extends QueryClause -{ - public FieldDefinition (String field, String str) - { - this(field, new LiteralExp(str)); - } - - public FieldDefinition (String field, Class pClass, String pCol) - { - this(field, new ColumnExp(pClass, pCol)); - } - - public FieldDefinition (String field, SQLExpression override) - { - _field = field; - _definition = override; - } - - /** - * The field we're defining. The Query object uses this for indexing. - */ - public String getField () - { - return _field; - } - - public SQLExpression getDefinition () - { - return _definition; - } - - // from SQLExpression - public void addClasses (Collection> classSet) - { - _definition.addClasses(classSet); - } - - // from SQLExpression - public void accept (ExpressionVisitor visitor) - { - visitor.visit(this); - } - - /** The name of the field on the persistent object to override. */ - protected String _field; - - /** The defining expression. */ - protected SQLExpression _definition; - -} diff --git a/src/java/com/samskivert/jdbc/depot/clause/FieldOverride.java b/src/java/com/samskivert/jdbc/depot/clause/FieldOverride.java deleted file mode 100644 index cf59a99e..00000000 --- a/src/java/com/samskivert/jdbc/depot/clause/FieldOverride.java +++ /dev/null @@ -1,52 +0,0 @@ -// -// $Id$ -// -// samskivert library - useful routines for java programs -// Copyright (C) 2006-2007 Michael Bayne, Pär Winzell -// -// This library is free software; you can redistribute it and/or modify it -// under the terms of the GNU Lesser General Public License as published -// by the Free Software Foundation; either version 2.1 of the License, or -// (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -package com.samskivert.jdbc.depot.clause; - -import com.samskivert.jdbc.depot.PersistentRecord; -import com.samskivert.jdbc.depot.expression.ColumnExp; -import com.samskivert.jdbc.depot.expression.LiteralExp; -import com.samskivert.jdbc.depot.expression.SQLExpression; - -/** - * Redirects one field of the persistent object we're creating from its default associated column - * to a general {@link SQLExpression}. - * - * Thus the select portion of a query can include a reference to a different column in a different - * table through a {@link ColumnExp}, or a literal expression such as COUNT(*) through a - * {@link LiteralExp}. - */ -public class FieldOverride extends FieldDefinition -{ - public FieldOverride (String field, String str) - { - super(field, str); - } - - public FieldOverride (String field, Class pClass, String pCol) - { - super(field, pClass, pCol); - } - - public FieldOverride (String field, SQLExpression override) - { - super(field, override); - } -} diff --git a/src/java/com/samskivert/jdbc/depot/clause/ForUpdate.java b/src/java/com/samskivert/jdbc/depot/clause/ForUpdate.java deleted file mode 100644 index 2adb39ec..00000000 --- a/src/java/com/samskivert/jdbc/depot/clause/ForUpdate.java +++ /dev/null @@ -1,43 +0,0 @@ -// -// $Id$ -// -// samskivert library - useful routines for java programs -// Copyright (C) 2006-2007 Michael Bayne, Pär Winzell -// -// This library is free software; you can redistribute it and/or modify it -// under the terms of the GNU Lesser General Public License as published -// by the Free Software Foundation; either version 2.1 of the License, or -// (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -package com.samskivert.jdbc.depot.clause; - -import java.util.Collection; - -import com.samskivert.jdbc.depot.PersistentRecord; -import com.samskivert.jdbc.depot.expression.ExpressionVisitor; - -/** - * Represents a FOR UPDATE clause. - */ -public class ForUpdate extends QueryClause -{ - // from SQLExpression - public void accept (ExpressionVisitor builder) - { - builder.visit(this); - } - - // from SQLExpression - public void addClasses (Collection> classSet) - { - } -} diff --git a/src/java/com/samskivert/jdbc/depot/clause/FromOverride.java b/src/java/com/samskivert/jdbc/depot/clause/FromOverride.java deleted file mode 100644 index 22160d6d..00000000 --- a/src/java/com/samskivert/jdbc/depot/clause/FromOverride.java +++ /dev/null @@ -1,72 +0,0 @@ -// -// $Id$ -// -// samskivert library - useful routines for java programs -// Copyright (C) 2006-2007 Michael Bayne, Pär Winzell -// -// This library is free software; you can redistribute it and/or modify it -// under the terms of the GNU Lesser General Public License as published -// by the Free Software Foundation; either version 2.1 of the License, or -// (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -package com.samskivert.jdbc.depot.clause; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; - -import com.samskivert.jdbc.depot.PersistentRecord; -import com.samskivert.jdbc.depot.expression.ExpressionVisitor; - -/** - * Completely overrides the FROM clause, if it exists. - */ -public class FromOverride extends QueryClause -{ - public FromOverride (Class fromClass) - { - _fromClasses.add(fromClass); - } - - public FromOverride (Class fromClass1, - Class fromClass2) - { - _fromClasses.add(fromClass1); - _fromClasses.add(fromClass2); - } - - public FromOverride (Collection> fromClasses) - { - _fromClasses.addAll(fromClasses); - } - - public List> getFromClasses () - { - return _fromClasses; - } - - // from SQLExpression - public void addClasses (Collection> classSet) - { - classSet.addAll(getFromClasses()); - } - - // from SQLExpression - public void accept (ExpressionVisitor builder) - { - builder.visit(this); - } - - /** The classes of the tables we're selecting from. */ - protected List> _fromClasses = - new ArrayList>(); -} diff --git a/src/java/com/samskivert/jdbc/depot/clause/GroupBy.java b/src/java/com/samskivert/jdbc/depot/clause/GroupBy.java deleted file mode 100644 index 497da3b9..00000000 --- a/src/java/com/samskivert/jdbc/depot/clause/GroupBy.java +++ /dev/null @@ -1,59 +0,0 @@ -// -// $Id$ -// -// samskivert library - useful routines for java programs -// Copyright (C) 2006-2007 Michael Bayne, Pär Winzell -// -// This library is free software; you can redistribute it and/or modify it -// under the terms of the GNU Lesser General Public License as published -// by the Free Software Foundation; either version 2.1 of the License, or -// (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -package com.samskivert.jdbc.depot.clause; - -import java.util.Collection; - -import com.samskivert.jdbc.depot.PersistentRecord; -import com.samskivert.jdbc.depot.expression.ExpressionVisitor; -import com.samskivert.jdbc.depot.expression.SQLExpression; - -/** - * Represents a GROUP BY clause. - */ -public class GroupBy extends QueryClause -{ - public GroupBy (SQLExpression... values) - { - _values = values; - } - - public SQLExpression[] getValues () - { - return _values; - } - - // from SQLExpression - public void accept (ExpressionVisitor builder) - { - builder.visit(this); - } - - // from SQLExpression - public void addClasses (Collection> classSet) - { - // I can't imagine a GROUP BY clause bringing in new tables... ? - } - - /** The expressions that are generated for the clause. */ - protected SQLExpression[] _values; - -} diff --git a/src/java/com/samskivert/jdbc/depot/clause/InsertClause.java b/src/java/com/samskivert/jdbc/depot/clause/InsertClause.java deleted file mode 100644 index 5024b019..00000000 --- a/src/java/com/samskivert/jdbc/depot/clause/InsertClause.java +++ /dev/null @@ -1,76 +0,0 @@ -// -// $Id$ -// -// samskivert library - useful routines for java programs -// Copyright (C) 2006 Michael Bayne -// -// This library is free software; you can redistribute it and/or modify it -// under the terms of the GNU Lesser General Public License as published -// by the Free Software Foundation; either version 2.1 of the License, or -// (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -package com.samskivert.jdbc.depot.clause; - -import java.util.Collection; -import java.util.Set; - -import com.samskivert.jdbc.depot.PersistentRecord; -import com.samskivert.jdbc.depot.expression.ExpressionVisitor; - -/** - * Builds actual SQL given a main persistent type and some {@link QueryClause} objects. - */ -public class InsertClause extends QueryClause -{ - public InsertClause ( - Class pClass, Object pojo, Set identityFields) - { - _pClass = pClass; - _pojo = pojo; - _idFields = identityFields; - } - - public Class getPersistentClass () - { - return _pClass; - } - - public Object getPojo () - { - return _pojo; - } - - public Set getIdentityFields () - { - return _idFields; - } - - // from SQLExpression - public void addClasses (Collection> classSet) - { - classSet.add(_pClass); - // If we add SQLExpression[] values INSERT, remember to recurse into them here. - } - - // from SQLExpression - public void accept (ExpressionVisitor builder) - { - builder.visit(this); - } - - protected Class _pClass; - - /** The object from which to fetch values, or null. */ - protected Object _pojo; - - protected Set _idFields; -} diff --git a/src/java/com/samskivert/jdbc/depot/clause/Join.java b/src/java/com/samskivert/jdbc/depot/clause/Join.java deleted file mode 100644 index 42616586..00000000 --- a/src/java/com/samskivert/jdbc/depot/clause/Join.java +++ /dev/null @@ -1,103 +0,0 @@ -// -// $Id$ -// -// samskivert library - useful routines for java programs -// Copyright (C) 2006-2007 Michael Bayne, Pär Winzell -// -// This library is free software; you can redistribute it and/or modify it -// under the terms of the GNU Lesser General Public License as published -// by the Free Software Foundation; either version 2.1 of the License, or -// (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -package com.samskivert.jdbc.depot.clause; - -import java.util.Collection; - -import com.samskivert.jdbc.depot.PersistentRecord; -import com.samskivert.jdbc.depot.expression.ColumnExp; -import com.samskivert.jdbc.depot.expression.ExpressionVisitor; -import com.samskivert.jdbc.depot.expression.SQLExpression; -import com.samskivert.jdbc.depot.operator.Conditionals.Equals; - -/** - * Represents a JOIN. - */ -public class Join extends QueryClause -{ - /** Indicates the join type to be used. The default is INNER. */ - public static enum Type { INNER, LEFT_OUTER, RIGHT_OUTER }; - - public Join (Class pClass, String pCol, - Class joinClass, String jCol) - { - _joinClass = joinClass; - _joinCondition = new Equals(new ColumnExp(joinClass, jCol), new ColumnExp(pClass, pCol)); - } - - public Join (ColumnExp primary, ColumnExp join) - { - _joinClass = join.getPersistentClass(); - _joinCondition = new Equals(primary, join); - } - - public Join (Class joinClass, SQLExpression joinCondition) - { - _joinClass = joinClass; - _joinCondition = joinCondition; - } - - /** - * Configures the type of join to be performed. - */ - public Join setType (Type type) - { - _type = type; - return this; - } - - public Type getType () - { - return _type; - } - - public Class getJoinClass () - { - return _joinClass; - } - - public SQLExpression getJoinCondition () - { - return _joinCondition; - } - - // from SQLExpression - public void accept (ExpressionVisitor builder) - { - builder.visit(this); - } - - // from SQLExpression - public void addClasses (Collection> classSet) - { - classSet.add(_joinClass); - _joinCondition.addClasses(classSet); - } - - /** Indicates the type of join to be performed. */ - protected Type _type = Type.INNER; - - /** The class of the table we're to join against. */ - protected Class _joinClass; - - /** The condition used to join in the new table. */ - protected SQLExpression _joinCondition; -} diff --git a/src/java/com/samskivert/jdbc/depot/clause/Limit.java b/src/java/com/samskivert/jdbc/depot/clause/Limit.java deleted file mode 100644 index 375558a8..00000000 --- a/src/java/com/samskivert/jdbc/depot/clause/Limit.java +++ /dev/null @@ -1,65 +0,0 @@ -// -// $Id$ -// -// samskivert library - useful routines for java programs -// Copyright (C) 2006-2007 Michael Bayne, Pär Winzell -// -// This library is free software; you can redistribute it and/or modify it -// under the terms of the GNU Lesser General Public License as published -// by the Free Software Foundation; either version 2.1 of the License, or -// (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -package com.samskivert.jdbc.depot.clause; - -import java.util.Collection; - -import com.samskivert.jdbc.depot.PersistentRecord; -import com.samskivert.jdbc.depot.expression.ExpressionVisitor; - -/** - * Represents a LIMIT/OFFSET clause, for pagination. - */ -public class Limit extends QueryClause -{ - public Limit (int offset, int count) - { - _offset = offset; - _count = count; - } - - public int getOffset () - { - return _offset; - } - - public int getCount () - { - return _count; - } - - // from SQLExpression - public void accept (ExpressionVisitor builder) - { - builder.visit(this); - } - - // from SQLExpression - public void addClasses (Collection> classSet) - { - } - - /** The first row of the result set to return. */ - protected int _offset; - - /** The number of rows, at most, to return. */ - protected int _count; -} diff --git a/src/java/com/samskivert/jdbc/depot/clause/OrderBy.java b/src/java/com/samskivert/jdbc/depot/clause/OrderBy.java deleted file mode 100644 index 0459c120..00000000 --- a/src/java/com/samskivert/jdbc/depot/clause/OrderBy.java +++ /dev/null @@ -1,98 +0,0 @@ -// -// $Id$ -// -// samskivert library - useful routines for java programs -// Copyright (C) 2006-2007 Michael Bayne, Pär Winzell -// -// This library is free software; you can redistribute it and/or modify it -// under the terms of the GNU Lesser General Public License as published -// by the Free Software Foundation; either version 2.1 of the License, or -// (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -package com.samskivert.jdbc.depot.clause; - -import java.util.Collection; - -import com.samskivert.jdbc.depot.PersistentRecord; -import com.samskivert.jdbc.depot.expression.ExpressionVisitor; -import com.samskivert.jdbc.depot.expression.LiteralExp; -import com.samskivert.jdbc.depot.expression.SQLExpression; - -/** - * Represents an ORDER BY clause. - */ -public class OrderBy extends QueryClause -{ - /** Indicates the order of the clause. */ - public enum Order { ASC, DESC }; - - /** - * Creates and returns a random order by clause. - */ - public static OrderBy random () - { - return ascending(new LiteralExp("rand()")); - } - - /** - * Creates and returns an ascending order by clause on the supplied expression. - */ - public static OrderBy ascending (SQLExpression value) - { - return new OrderBy(new SQLExpression[] { value } , new Order[] { Order.ASC }); - } - - /** - * Creates and returns a descending order by clause on the supplied expression. - */ - public static OrderBy descending (SQLExpression value) - { - return new OrderBy(new SQLExpression[] { value }, new Order[] { Order.DESC }); - } - - public OrderBy (SQLExpression[] values, Order[] orders) - { - _values = values; - _orders = orders; - } - - public SQLExpression[] getValues () - { - return _values; - } - - public Order[] getOrders () - { - return _orders; - } - - // from SQLExpression - public void accept (ExpressionVisitor builder) - { - builder.visit(this); - } - - // from SQLExpression - public void addClasses (Collection> classSet) - { - for (SQLExpression expression : _values) { - expression.addClasses(classSet); - } - } - - /** The expressions that are generated for the clause. */ - protected SQLExpression[] _values; - - /** Whether the ordering is to be ascending or descending. */ - protected Order[] _orders; - -} diff --git a/src/java/com/samskivert/jdbc/depot/clause/QueryClause.java b/src/java/com/samskivert/jdbc/depot/clause/QueryClause.java deleted file mode 100644 index 89f229e3..00000000 --- a/src/java/com/samskivert/jdbc/depot/clause/QueryClause.java +++ /dev/null @@ -1,30 +0,0 @@ -// -// $Id$ -// -// samskivert library - useful routines for java programs -// Copyright (C) 2006-2007 Michael Bayne, Pär Winzell -// -// This library is free software; you can redistribute it and/or modify it -// under the terms of the GNU Lesser General Public License as published -// by the Free Software Foundation; either version 2.1 of the License, or -// (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -package com.samskivert.jdbc.depot.clause; - -import com.samskivert.jdbc.depot.expression.SQLExpression; - -/** - * Represents a piece or modifier of an SQL query. - */ -public abstract class QueryClause implements SQLExpression -{ -} diff --git a/src/java/com/samskivert/jdbc/depot/clause/SelectClause.java b/src/java/com/samskivert/jdbc/depot/clause/SelectClause.java deleted file mode 100644 index e5bda4dd..00000000 --- a/src/java/com/samskivert/jdbc/depot/clause/SelectClause.java +++ /dev/null @@ -1,226 +0,0 @@ -// -// $Id$ -// -// samskivert library - useful routines for java programs -// Copyright (C) 2006 Michael Bayne -// -// This library is free software; you can redistribute it and/or modify it -// under the terms of the GNU Lesser General Public License as published -// by the Free Software Foundation; either version 2.1 of the License, or -// (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -package com.samskivert.jdbc.depot.clause; - -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import com.samskivert.jdbc.depot.PersistentRecord; -import com.samskivert.jdbc.depot.WhereClause; -import com.samskivert.jdbc.depot.expression.ExpressionVisitor; - -/** - * Builds actual SQL given a main persistent type and some {@link QueryClause} objects. - */ -public class SelectClause extends QueryClause -{ - /** - * Creates a new Query object to generate one or more instances of the specified persistent - * class, as dictated by the key and query clauses. A persistence context is supplied for - * instantiation of marshallers, which may trigger table creations and schema migrations. - */ - public SelectClause (Class pClass, String[] fields, Collection clauses) - { - _pClass = pClass; - _fields = fields; - - // iterate over the clauses and sort them into the different types we understand - for (QueryClause clause : clauses) { - if (clause == null) { - continue; - } - if (clause instanceof WhereClause) { - if (_where != null) { - throw new IllegalArgumentException( - "Query can't contain multiple Where clauses."); - } - _where = (WhereClause) clause; - - } else if (clause instanceof FromOverride) { - if (_fromOverride != null) { - throw new IllegalArgumentException( - "Query can't contain multiple FromOverride clauses."); - } - _fromOverride = (FromOverride) clause; - - } else if (clause instanceof Join) { - _joinClauses.add((Join) clause); - - } else if (clause instanceof FieldDefinition) { - _disMap.put(((FieldDefinition) clause).getField(), ((FieldDefinition) clause)); - - } else if (clause instanceof OrderBy) { - if (_orderBy != null) { - throw new IllegalArgumentException( - "Query can't contain multiple OrderBy clauses."); - } - _orderBy = (OrderBy) clause; - - } else if (clause instanceof GroupBy) { - if (_groupBy != null) { - throw new IllegalArgumentException( - "Query can't contain multiple GroupBy clauses."); - } - _groupBy = (GroupBy) clause; - - } else if (clause instanceof Limit) { - if (_limit != null) { - throw new IllegalArgumentException( - "Query can't contain multiple Limit clauses."); - } - _limit = (Limit) clause; - - } else if (clause instanceof ForUpdate) { - if (_forUpdate != null) { - throw new IllegalArgumentException( - "Query can't contain multiple For Update clauses."); - } - _forUpdate = (ForUpdate) clause; - - } else { - throw new IllegalArgumentException( - "Unknown clause provided in select " + clause + "."); - } - } - } - - /** - * A varargs version of the constructor. - */ - public SelectClause (Class pClass, String[] fields, QueryClause... clauses) - { - this(pClass, fields, Arrays.asList(clauses)); - } - - public FieldDefinition lookupDefinition (String field) - { - return _disMap.get(field); - } - - public Collection getFieldDefinitions () - { - return _disMap.values(); - } - - public Class getPersistentClass () - { - return _pClass; - } - - public String[] getFields () - { - return _fields; - } - - public FromOverride getFromOverride () - { - return _fromOverride; - } - - public WhereClause getWhereClause () - { - return _where; - } - - public List getJoinClauses () - { - return _joinClauses; - } - - public OrderBy getOrderBy () - { - return _orderBy; - } - - public GroupBy getGroupBy () - { - return _groupBy; - } - - public Limit getLimit () - { - return _limit; - } - - public ForUpdate getForUpdate () - { - return _forUpdate; - } - - // from SQLExpression - public void addClasses (Collection> classSet) - { - classSet.add(_pClass); - - if (_fromOverride != null) { - _fromOverride.addClasses(classSet); - } - if (_where != null) { - _where.addClasses(classSet); - } - for (Join join : _joinClauses) { - join.addClasses(classSet); - } - for (FieldDefinition override : _disMap.values()) { - override.addClasses(classSet); - } - } - - // from SQLExpression - public void accept (ExpressionVisitor builder) - { - builder.visit(this); - } - - /** Persistent class fields mapped to field override clauses. */ - protected Map _disMap = new HashMap(); - - /** The persistent class this select defines. */ - protected Class _pClass; - - /** The persistent fields to select. */ - protected String[] _fields; - - /** The from override clause, if any. */ - protected FromOverride _fromOverride; - - /** The where clause. */ - protected WhereClause _where; - - /** A list of join clauses, each potentially referencing a new class. */ - protected List _joinClauses = new ArrayList(); - - /** The order by clause, if any. */ - protected OrderBy _orderBy; - - /** The group by clause, if any. */ - protected GroupBy _groupBy; - - /** The limit clause, if any. */ - protected Limit _limit; - - /** The For Update clause, if any. */ - protected ForUpdate _forUpdate; -} diff --git a/src/java/com/samskivert/jdbc/depot/clause/UpdateClause.java b/src/java/com/samskivert/jdbc/depot/clause/UpdateClause.java deleted file mode 100644 index 8d4766ae..00000000 --- a/src/java/com/samskivert/jdbc/depot/clause/UpdateClause.java +++ /dev/null @@ -1,114 +0,0 @@ -// -// $Id$ -// -// samskivert library - useful routines for java programs -// Copyright (C) 2006 Michael Bayne -// -// This library is free software; you can redistribute it and/or modify it -// under the terms of the GNU Lesser General Public License as published -// by the Free Software Foundation; either version 2.1 of the License, or -// (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -package com.samskivert.jdbc.depot.clause; - -import java.util.Collection; - -import com.samskivert.jdbc.depot.PersistentRecord; -import com.samskivert.jdbc.depot.WhereClause; -import com.samskivert.jdbc.depot.expression.ExpressionVisitor; -import com.samskivert.jdbc.depot.expression.SQLExpression; - -/** - * Builds actual SQL given a main persistent type and some {@link QueryClause} objects. - */ -public class UpdateClause extends QueryClause -{ - public UpdateClause (Class pClass, WhereClause where, - String[] fields, T pojo) - { - _pClass = pClass; - _where = where; - _fields = fields; - _values = null; - _pojo = pojo; - } - - public UpdateClause (Class pClass, WhereClause where, - String[] fields, SQLExpression[] values) - { - _pClass = pClass; - _fields = fields; - _where = where; - _values = values; - _pojo = null; - } - - public WhereClause getWhereClause () - { - return _where; - } - - public String[] getFields () - { - return _fields; - } - - public SQLExpression[] getValues () - { - return _values; - } - - public Object getPojo () - { - return _pojo; - } - - public Class getPersistentClass () - { - return _pClass; - } - - // from SQLExpression - public void addClasses (Collection> classSet) - { - classSet.add(_pClass); - if (_where != null) { - _where.addClasses(classSet); - } - if (_values != null) { - for (int ii = 0; ii < _values.length; ii ++) { - _values[ii].addClasses(classSet); - } - } - } - - // from SQLExpression - public void accept (ExpressionVisitor builder) - { - builder.visit(this); - } - - /** The class we're updating. */ - protected Class _pClass; - - /** The where clause. */ - protected WhereClause _where; - - /** The persistent fields to update. */ - protected String[] _fields; - - /** The field values, or null. */ - protected SQLExpression[] _values; - - /** The object from which to fetch values, or null. */ - protected Object _pojo; -} diff --git a/src/java/com/samskivert/jdbc/depot/clause/Where.java b/src/java/com/samskivert/jdbc/depot/clause/Where.java deleted file mode 100644 index 2392d7c1..00000000 --- a/src/java/com/samskivert/jdbc/depot/clause/Where.java +++ /dev/null @@ -1,99 +0,0 @@ -// -// $Id$ -// -// samskivert library - useful routines for java programs -// Copyright (C) 2006-2007 Michael Bayne, Pär Winzell -// -// This library is free software; you can redistribute it and/or modify it -// under the terms of the GNU Lesser General Public License as published -// by the Free Software Foundation; either version 2.1 of the License, or -// (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -package com.samskivert.jdbc.depot.clause; - -import java.util.Collection; - -import com.samskivert.jdbc.depot.PersistentRecord; -import com.samskivert.jdbc.depot.WhereClause; -import com.samskivert.jdbc.depot.expression.ColumnExp; -import com.samskivert.jdbc.depot.expression.ExpressionVisitor; -import com.samskivert.jdbc.depot.expression.SQLExpression; -import com.samskivert.jdbc.depot.expression.ValueExp; -import com.samskivert.jdbc.depot.operator.Conditionals.Equals; -import com.samskivert.jdbc.depot.operator.Conditionals.IsNull; -import com.samskivert.jdbc.depot.operator.Logic.And; - -/** - * Represents a where clause: the condition can be any comparison operator or logical combination - * thereof. - */ -public class Where extends WhereClause -{ - public Where (ColumnExp column, Comparable value) - { - this(new ColumnExp[] { column }, new Comparable[] { value }); - } - - public Where (ColumnExp index1, Comparable value1, - ColumnExp index2, Comparable value2) - { - this(new ColumnExp[] { index1, index2 }, new Comparable[] { value1, value2 }); - } - - public Where (ColumnExp index1, Comparable value1, - ColumnExp index2, Comparable value2, - ColumnExp index3, Comparable value3) - { - this(new ColumnExp[] { index1, index2, index3 }, - new Comparable[] { value1, value2, value3 }); - } - - public Where (ColumnExp[] columns, Comparable[] values) - { - this(toCondition(columns, values)); - } - - public Where (SQLExpression condition) - { - _condition = condition; - } - - // from WhereClause - public SQLExpression getWhereExpression () - { - return _condition; - } - - // from SQLExpression - public void accept (ExpressionVisitor builder) - { - builder.visit(this); - } - - // from SQLExpression - public void addClasses (Collection> classSet) - { - _condition.addClasses(classSet); - } - - protected static SQLExpression toCondition (ColumnExp[] columns, Comparable[] values) - { - SQLExpression[] comparisons = new SQLExpression[columns.length]; - for (int ii = 0; ii < columns.length; ii ++) { - comparisons[ii] = (values[ii] == null) ? new IsNull(columns[ii]) : - new Equals(columns[ii], new ValueExp(values[ii])); - } - return new And(comparisons); - } - - protected SQLExpression _condition; -} diff --git a/src/java/com/samskivert/jdbc/depot/expression/ColumnExp.java b/src/java/com/samskivert/jdbc/depot/expression/ColumnExp.java deleted file mode 100644 index d10f8fab..00000000 --- a/src/java/com/samskivert/jdbc/depot/expression/ColumnExp.java +++ /dev/null @@ -1,67 +0,0 @@ -// -// $Id$ -// -// samskivert library - useful routines for java programs -// Copyright (C) 2006-2007 Michael Bayne, Pär Winzell -// -// This library is free software; you can redistribute it and/or modify it -// under the terms of the GNU Lesser General Public License as published -// by the Free Software Foundation; either version 2.1 of the License, or -// (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -package com.samskivert.jdbc.depot.expression; - -import java.util.Collection; - -import com.samskivert.jdbc.depot.PersistentRecord; - -/** - * An expression that unambiguously identifies a field of a class, e.g. GameRecord.itemId. - */ -public class ColumnExp - implements SQLExpression -{ - public ColumnExp (Class pClass, String field) - { - super(); - _pClass = pClass; - _pField = field; - } - - // from SQLExpression - public void accept (ExpressionVisitor builder) - { - builder.visit(this); - } - - // from SQLExpression - public void addClasses (Collection> classSet) - { - classSet.add(_pClass); - } - - public Class getPersistentClass () - { - return _pClass; - } - - public String getField () - { - return _pField; - } - - /** The table that hosts the column we reference, or null. */ - protected final Class _pClass; - - /** The name of the column we reference. */ - protected final String _pField; -} diff --git a/src/java/com/samskivert/jdbc/depot/expression/EpochSeconds.java b/src/java/com/samskivert/jdbc/depot/expression/EpochSeconds.java deleted file mode 100644 index 94118df8..00000000 --- a/src/java/com/samskivert/jdbc/depot/expression/EpochSeconds.java +++ /dev/null @@ -1,59 +0,0 @@ -// -// $Id$ -// -// samskivert library - useful routines for java programs -// Copyright (C) 2006-2007 Michael Bayne, Pär Winzell -// -// This library is free software; you can redistribute it and/or modify it -// under the terms of the GNU Lesser General Public License as published -// by the Free Software Foundation; either version 2.1 of the License, or -// (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -package com.samskivert.jdbc.depot.expression; - -import java.util.Collection; - -import com.samskivert.jdbc.depot.PersistentRecord; - -/** - * An expression for extracting the seconds since the epoch from a date expression. - */ -public class EpochSeconds implements SQLExpression -{ - /** - * Create a new EpochSeconds with the given argument. - */ - public EpochSeconds (SQLExpression arg) - { - _arg = arg; - } - - // from SQLExpression - public void accept (ExpressionVisitor builder) - { - builder.visit(this); - } - - // from SQLExpression - public void addClasses (Collection> classSet) - { - _arg.addClasses(classSet); - } - - public SQLExpression getArgument () - { - return _arg; - } - - /** The argument. */ - protected SQLExpression _arg; -} diff --git a/src/java/com/samskivert/jdbc/depot/expression/ExpressionVisitor.java b/src/java/com/samskivert/jdbc/depot/expression/ExpressionVisitor.java deleted file mode 100644 index a629b71c..00000000 --- a/src/java/com/samskivert/jdbc/depot/expression/ExpressionVisitor.java +++ /dev/null @@ -1,79 +0,0 @@ -// -// $Id$ -// -// samskivert library - useful routines for java programs -// Copyright (C) 2006 Michael Bayne, Pär Winzell -// -// This library is free software; you can redistribute it and/or modify it -// under the terms of the GNU Lesser General Public License as published -// by the Free Software Foundation; either version 2.1 of the License, or -// (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -package com.samskivert.jdbc.depot.expression; - -import com.samskivert.jdbc.depot.Key; -import com.samskivert.jdbc.depot.MultiKey; -import com.samskivert.jdbc.depot.PersistentRecord; -import com.samskivert.jdbc.depot.WhereClause; - -import com.samskivert.jdbc.depot.clause.DeleteClause; -import com.samskivert.jdbc.depot.clause.FieldDefinition; -import com.samskivert.jdbc.depot.clause.ForUpdate; -import com.samskivert.jdbc.depot.clause.FromOverride; -import com.samskivert.jdbc.depot.clause.GroupBy; -import com.samskivert.jdbc.depot.clause.InsertClause; -import com.samskivert.jdbc.depot.clause.Join; -import com.samskivert.jdbc.depot.clause.Limit; -import com.samskivert.jdbc.depot.clause.OrderBy; -import com.samskivert.jdbc.depot.clause.SelectClause; -import com.samskivert.jdbc.depot.clause.UpdateClause; - -import com.samskivert.jdbc.depot.operator.Conditionals.Exists; -import com.samskivert.jdbc.depot.operator.Conditionals.In; -import com.samskivert.jdbc.depot.operator.Conditionals.IsNull; -import com.samskivert.jdbc.depot.operator.Conditionals.FullTextMatch; -import com.samskivert.jdbc.depot.operator.Logic.Not; -import com.samskivert.jdbc.depot.operator.SQLOperator.BinaryOperator; -import com.samskivert.jdbc.depot.operator.SQLOperator.MultiOperator; - -/** - * Enumerates visitation methods for every possible SQL expression type. - */ -public interface ExpressionVisitor -{ - public void visit (FieldDefinition fieldOverride); - public void visit (FunctionExp functionExp); - public void visit (EpochSeconds epochSeconds); - public void visit (FromOverride fromOverride); - public void visit (MultiOperator multiOperator); - public void visit (BinaryOperator binaryOperator); - public void visit (IsNull isNull); - public void visit (In in); - public void visit (FullTextMatch match); - public void visit (ColumnExp columnExp); - public void visit (Not not); - public void visit (GroupBy groupBy); - public void visit (ForUpdate forUpdate); - public void visit (OrderBy orderBy); - public void visit (Join join); - public void visit (Limit limit); - public void visit (LiteralExp literalExp); - public void visit (ValueExp valueExp); - public void visit (WhereClause where); - public void visit (Key.Expression key); - public void visit (MultiKey key); - public void visit (Exists exists); - public void visit (SelectClause selectClause); - public void visit (UpdateClause updateClause); - public void visit (DeleteClause deleteClause); - public void visit (InsertClause insertClause); -} diff --git a/src/java/com/samskivert/jdbc/depot/expression/FunctionExp.java b/src/java/com/samskivert/jdbc/depot/expression/FunctionExp.java deleted file mode 100644 index f17864c1..00000000 --- a/src/java/com/samskivert/jdbc/depot/expression/FunctionExp.java +++ /dev/null @@ -1,70 +0,0 @@ -// -// $Id$ -// -// samskivert library - useful routines for java programs -// Copyright (C) 2006-2007 Michael Bayne, Pär Winzell -// -// This library is free software; you can redistribute it and/or modify it -// under the terms of the GNU Lesser General Public License as published -// by the Free Software Foundation; either version 2.1 of the License, or -// (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -package com.samskivert.jdbc.depot.expression; - -import java.util.Collection; - -import com.samskivert.jdbc.depot.PersistentRecord; - -/** - * An expression for a function, e.g. FLOOR(blah). - */ -public class FunctionExp implements SQLExpression -{ - /** - * Create a new FunctionExp with the given function and arguments. - */ - public FunctionExp (String function, SQLExpression... arguments) - { - _function = function; - _arguments = arguments; - } - - // from SQLExpression - public void accept (ExpressionVisitor builder) - { - builder.visit(this); - } - - // from SQLExpression - public void addClasses (Collection> classSet) - { - for (int ii = 0; ii < _arguments.length; ii ++) { - _arguments[ii].addClasses(classSet); - } - } - - public String getFunction () - { - return _function; - } - - public SQLExpression[] getArguments () - { - return _arguments; - } - - /** The literal name of this function, e.g. FLOOR */ - protected String _function; - - /** The arguments to this function */ - protected SQLExpression[] _arguments; -} diff --git a/src/java/com/samskivert/jdbc/depot/expression/LiteralExp.java b/src/java/com/samskivert/jdbc/depot/expression/LiteralExp.java deleted file mode 100644 index 2092f400..00000000 --- a/src/java/com/samskivert/jdbc/depot/expression/LiteralExp.java +++ /dev/null @@ -1,57 +0,0 @@ -// -// $Id$ -// -// samskivert library - useful routines for java programs -// Copyright (C) 2006-2007 Michael Bayne, Pär Winzell -// -// This library is free software; you can redistribute it and/or modify it -// under the terms of the GNU Lesser General Public License as published -// by the Free Software Foundation; either version 2.1 of the License, or -// (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -package com.samskivert.jdbc.depot.expression; - -import java.util.Collection; - -import com.samskivert.jdbc.depot.PersistentRecord; - -/** - * An expression for things we don't support natively, e.g. COUNT(*). - */ -public class LiteralExp - implements SQLExpression -{ - public LiteralExp (String text) - { - super(); - _text = text; - } - - // from SQLExpression - public void accept (ExpressionVisitor builder) - { - builder.visit(this); - } - - // from SQLExpression - public void addClasses (Collection> classSet) - { - } - - public String getText () - { - return _text; - } - - /** The literal text of this expression, e.g. COUNT(*) */ - protected String _text; -} diff --git a/src/java/com/samskivert/jdbc/depot/expression/SQLExpression.java b/src/java/com/samskivert/jdbc/depot/expression/SQLExpression.java deleted file mode 100644 index d70ad22e..00000000 --- a/src/java/com/samskivert/jdbc/depot/expression/SQLExpression.java +++ /dev/null @@ -1,48 +0,0 @@ -// -// $Id$ -// -// samskivert library - useful routines for java programs -// Copyright (C) 2006-2007 Michael Bayne, Pär Winzell -// -// This library is free software; you can redistribute it and/or modify it -// under the terms of the GNU Lesser General Public License as published -// by the Free Software Foundation; either version 2.1 of the License, or -// (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -package com.samskivert.jdbc.depot.expression; - -import java.util.Collection; - -import com.samskivert.jdbc.depot.PersistentRecord; -import com.samskivert.jdbc.depot.SQLBuilder; - -/** - * Represents an SQL expression, e.g. column name, function, or constant. - */ -public interface SQLExpression -{ - /** - * Most uses of this class have been implemented with a visitor pattern. Create your own - * {@link ExpressionVisitor} and call this method with it. - * - * @see SQLBuilder - */ - public void accept (ExpressionVisitor builder); - - /** - * Adds all persistent classes that are brought into the SQL context by this clause: FROM - * clauses, JOINs, UPDATEs, anything that could create a new table abbreviation. This method - * should recurse into any subordinate state that may in turn bring in new classes so that - * sub-queries work correctly. - */ - public void addClasses (Collection> classSet); -} diff --git a/src/java/com/samskivert/jdbc/depot/expression/ValueExp.java b/src/java/com/samskivert/jdbc/depot/expression/ValueExp.java deleted file mode 100644 index 080c7b46..00000000 --- a/src/java/com/samskivert/jdbc/depot/expression/ValueExp.java +++ /dev/null @@ -1,56 +0,0 @@ -// -// $Id$ -// -// samskivert library - useful routines for java programs -// Copyright (C) 2006-2007 Michael Bayne, Pär Winzell -// -// This library is free software; you can redistribute it and/or modify it -// under the terms of the GNU Lesser General Public License as published -// by the Free Software Foundation; either version 2.1 of the License, or -// (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -package com.samskivert.jdbc.depot.expression; - -import java.util.Collection; - -import com.samskivert.jdbc.depot.PersistentRecord; - -/** - * A Java value that is bound as a parameter to the query, e.g. 1 or 'abc'. - */ -public class ValueExp - implements SQLExpression -{ - public ValueExp (Object _value) - { - this._value = _value; - } - - // from SQLExpression - public void accept (ExpressionVisitor builder) - { - builder.visit(this); - } - - // from SQLExpression - public void addClasses (Collection> classSet) - { - } - - public Object getValue () - { - return _value; - } - - /** The value to be bound to the SQL parameters. */ - protected Object _value; -} diff --git a/src/java/com/samskivert/jdbc/depot/operator/Arithmetic.java b/src/java/com/samskivert/jdbc/depot/operator/Arithmetic.java deleted file mode 100644 index 8519ad68..00000000 --- a/src/java/com/samskivert/jdbc/depot/operator/Arithmetic.java +++ /dev/null @@ -1,145 +0,0 @@ -// -// $Id$ -// -// samskivert library - useful routines for java programs -// Copyright (C) 2006-2007 Michael Bayne, Pär Winzell -// -// This library is free software; you can redistribute it and/or modify it -// under the terms of the GNU Lesser General Public License as published -// by the Free Software Foundation; either version 2.1 of the License, or -// (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -package com.samskivert.jdbc.depot.operator; - -import com.samskivert.jdbc.depot.expression.SQLExpression; -import com.samskivert.jdbc.depot.operator.SQLOperator.BinaryOperator; - -/** - * A convenient container for implementations of arithmetic operators. Classes that value brevity - * that feel otherwise will use Arithmetic.Add() and Arithmetic.Sub(). - */ -public abstract class Arithmetic -{ - /** The SQL '+' operator. */ - public static class Add extends BinaryOperator - { - public Add (SQLExpression column, Comparable value) - { - super(column, value); - } - - public Add (SQLExpression column, SQLExpression value) - { - super(column, value); - } - - @Override public String operator() - { - return "+"; - } - } - - /** The SQL '-' operator. */ - public static class Sub extends BinaryOperator - { - public Sub (SQLExpression column, Comparable value) - { - super(column, value); - } - - public Sub (SQLExpression column, SQLExpression value) - { - super(column, value); - } - - @Override public String operator() - { - return "-"; - } - } - - /** The SQL '*' operator. */ - public static class Mul extends BinaryOperator - { - public Mul (SQLExpression column, Comparable value) - { - super(column, value); - } - - public Mul (SQLExpression column, SQLExpression value) - { - super(column, value); - } - - @Override public String operator() - { - return "*"; - } - } - - /** The SQL '/' operator. */ - public static class Div extends BinaryOperator - { - public Div (SQLExpression column, Comparable value) - { - super(column, value); - } - - public Div (SQLExpression column, SQLExpression value) - { - super(column, value); - } - - @Override public String operator() - { - return " / "; // Pad with spaces to work-around a MySQL bug. - } - } - - /** The SQL '&' operator. */ - public static class BitAnd extends BinaryOperator - { - public BitAnd (SQLExpression column, Comparable value) - { - super(column, value); - } - - public BitAnd (SQLExpression column, SQLExpression value) - { - super(column, value); - } - - @Override public String operator() - { - return "&"; - } - } - - /** The SQL '|' operator. */ - public static class BitOr extends BinaryOperator - { - public BitOr (SQLExpression column, Comparable value) - { - super(column, value); - } - - public BitOr (SQLExpression column, SQLExpression value) - { - super(column, value); - } - - @Override public String operator() - { - return "|"; - } - } -} diff --git a/src/java/com/samskivert/jdbc/depot/operator/Conditionals.java b/src/java/com/samskivert/jdbc/depot/operator/Conditionals.java deleted file mode 100644 index 1e083bce..00000000 --- a/src/java/com/samskivert/jdbc/depot/operator/Conditionals.java +++ /dev/null @@ -1,336 +0,0 @@ -// -// $Id$ -// -// samskivert library - useful routines for java programs -// Copyright (C) 2006-2007 Michael Bayne, Pär Winzell -// -// This library is free software; you can redistribute it and/or modify it -// under the terms of the GNU Lesser General Public License as published -// by the Free Software Foundation; either version 2.1 of the License, or -// (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -package com.samskivert.jdbc.depot.operator; - -import java.util.Collection; - -import com.samskivert.jdbc.depot.PersistentRecord; -import com.samskivert.jdbc.depot.clause.SelectClause; -import com.samskivert.jdbc.depot.expression.ColumnExp; -import com.samskivert.jdbc.depot.expression.ExpressionVisitor; -import com.samskivert.jdbc.depot.expression.SQLExpression; - -/** - * A convenient container for implementations of conditional operators. Classes that value brevity - * classes that feel otherwise will use Conditionals.Equals() and Conditionals.In(). - */ -public abstract class Conditionals -{ - /** The SQL 'is null' operator. */ - public static class IsNull - implements SQLOperator - { - public IsNull (String pColumn) - { - this(new ColumnExp(null, pColumn)); - } - - public IsNull (Class pClass, String pColumn) - { - this(new ColumnExp(pClass, pColumn)); - } - - public IsNull (ColumnExp column) - { - _column = column; - } - - public ColumnExp getColumn() - { - return _column; - } - - // from SQLExpression - public void accept (ExpressionVisitor builder) - { - builder.visit(this); - } - - // from SQLExpression - public void addClasses (Collection> classSet) - { - } - - protected ColumnExp _column; - } - - /** The SQL '=' operator. */ - public static class Equals extends SQLOperator.BinaryOperator - { - public Equals (SQLExpression column, Comparable value) - { - super(column, value); - } - - public Equals (SQLExpression column, SQLExpression value) - { - super(column, value); - } - - @Override public String operator() - { - return "="; - } - } - - /** The SQL '!=' operator. */ - public static class NotEquals extends SQLOperator.BinaryOperator - { - public NotEquals (SQLExpression column, Comparable value) - { - super(column, value); - } - - public NotEquals (SQLExpression column, SQLExpression value) - { - super(column, value); - } - - @Override public String operator() - { - return "!="; - } - } - - /** The SQL '<' operator. */ - public static class LessThan extends SQLOperator.BinaryOperator - { - public LessThan (SQLExpression column, Comparable value) - { - super(column, value); - } - - public LessThan (SQLExpression column, SQLExpression value) - { - super(column, value); - } - - @Override public String operator() - { - return "<"; - } - } - - /** The SQL '<=' operator. */ - public static class LessThanEquals extends SQLOperator.BinaryOperator - { - public LessThanEquals (SQLExpression column, Comparable value) - { - super(column, value); - } - - public LessThanEquals (SQLExpression column, SQLExpression value) - { - super(column, value); - } - - @Override public String operator() - { - return "<="; - } - } - - /** The SQL '>' operator. */ - public static class GreaterThan extends SQLOperator.BinaryOperator - { - public GreaterThan (SQLExpression column, Comparable value) - { - super(column, value); - } - - public GreaterThan (SQLExpression column, SQLExpression value) - { - super(column, value); - } - - @Override public String operator() - { - return ">"; - } - } - - /** The SQL '>=' operator. */ - public static class GreaterThanEquals extends SQLOperator.BinaryOperator - { - public GreaterThanEquals (SQLExpression column, Comparable value) - { - super(column, value); - } - - public GreaterThanEquals (SQLExpression column, SQLExpression value) - { - super(column, value); - } - - @Override public String operator() - { - return ">="; - } - } - - /** The SQL 'in (...)' operator. */ - public static class In - implements SQLOperator - { - /** The maximum number of keys allowed in an IN() clause. */ - public static final int MAX_KEYS = Short.MAX_VALUE; - - public In (Class pClass, String pColumn, Comparable... values) - { - this(new ColumnExp(pClass, pColumn), values); - } - - public In (Class pClass, String pColumn, - Collection> values) - { - this(new ColumnExp(pClass, pColumn), values.toArray(new Comparable[values.size()])); - } - - public In (ColumnExp column, Comparable... values) - { - if (values.length == 0) { - throw new IllegalArgumentException("In() condition needs at least one value."); - } - _column = column; - _values = values; - } - - public In (ColumnExp pColumn, Collection> values) - { - this(pColumn, values.toArray(new Comparable[values.size()])); - } - - public ColumnExp getColumn () - { - return _column; - } - - public Comparable[] getValues () - { - return _values; - } - - // from SQLExpression - public void accept (ExpressionVisitor builder) - { - builder.visit(this); - } - - // from SQLExpression - public void addClasses (Collection> classSet) - { - _column.addClasses(classSet); - } - - protected ColumnExp _column; - protected Comparable[] _values; - } - - /** The SQL ' like ' operator. */ - public static class Like extends SQLOperator.BinaryOperator - { - public Like (SQLExpression column, Comparable value) - { - super(column, value); - } - - public Like (SQLExpression column, SQLExpression value) - { - super(column, value); - } - - @Override public String operator() - { - return " like "; - } - } - - /** The SQL ' exists' operator. */ - public static class Exists implements SQLOperator - { - public Exists (SelectClause clause) - { - _clause = clause; - } - - public void accept (ExpressionVisitor builder) - { - builder.visit(this); - } - - public void addClasses (Collection> classSet) - { - _clause.addClasses(classSet); - } - - public SelectClause getSubClause () - { - return _clause; - } - - protected SelectClause _clause; - } - - /** - * An attempt at a dialect-agnostic full-text search condition, such as MySQL's MATCH() and - * PostgreSQL's @@ TO_TSQUERY(...) abilities. - */ - public static class FullTextMatch - implements SQLOperator - { - public FullTextMatch (Class pClass, String name, String query) - { - _pClass = pClass; - _name = name; - _query = query; - } - - public Class getPersistentRecord () - { - return _pClass; - } - - public String getQuery () - { - return _query; - } - - public String getName () - { - return _name; - } - - // from SQLExpression - public void accept (ExpressionVisitor builder) - { - builder.visit(this); - } - - // from SQLExpression - public void addClasses (Collection> classSet) - { - } - - protected Class _pClass; - protected String _name; - protected String _query; - } -} diff --git a/src/java/com/samskivert/jdbc/depot/operator/Logic.java b/src/java/com/samskivert/jdbc/depot/operator/Logic.java deleted file mode 100644 index ee08788f..00000000 --- a/src/java/com/samskivert/jdbc/depot/operator/Logic.java +++ /dev/null @@ -1,107 +0,0 @@ -// -// $Id$ -// -// samskivert library - useful routines for java programs -// Copyright (C) 2006-2007 Michael Bayne, Pär Winzell -// -// This library is free software; you can redistribute it and/or modify it -// under the terms of the GNU Lesser General Public License as published -// by the Free Software Foundation; either version 2.1 of the License, or -// (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -package com.samskivert.jdbc.depot.operator; - -import java.util.Collection; - -import com.samskivert.jdbc.depot.PersistentRecord; -import com.samskivert.jdbc.depot.expression.ExpressionVisitor; -import com.samskivert.jdbc.depot.expression.SQLExpression; - -/** - * A convenient container for implementations of logical operators. Classes that value brevity - * feel otherwise will use Logic.And() and Logic.Not(). - */ -public abstract class Logic -{ - /** - * Represents a condition that is false iff all its subconditions are false. - */ - public static class Or extends SQLOperator.MultiOperator - { - public Or (Collection conditions) - { - super(conditions.toArray(new SQLExpression[conditions.size()])); - } - - public Or (SQLExpression... conditions) - { - super(conditions); - } - - @Override public String operator() - { - return "or"; - } - } - - /** - * Represents a condition that is true iff all its subconditions are true. - */ - public static class And extends SQLOperator.MultiOperator - { - public And (Collection conditions) - { - super(conditions.toArray(new SQLExpression[conditions.size()])); - } - - public And (SQLExpression... conditions) - { - super(conditions); - } - - @Override public String operator() - { - return "and"; - } - } - - /** - * Represents the truth negation of another conditon. - */ - public static class Not - implements SQLOperator - { - public Not (SQLExpression condition) - { - _condition = condition; - } - - public SQLExpression getCondition () - { - return _condition; - } - - // from SQLExpression - public void accept (ExpressionVisitor builder) - { - builder.visit(this); - } - - // from SQLExpression - public void addClasses (Collection> classSet) - { - _condition.addClasses(classSet); - } - - protected SQLExpression _condition; - } -} diff --git a/src/java/com/samskivert/jdbc/depot/operator/SQLOperator.java b/src/java/com/samskivert/jdbc/depot/operator/SQLOperator.java deleted file mode 100644 index 86022bf8..00000000 --- a/src/java/com/samskivert/jdbc/depot/operator/SQLOperator.java +++ /dev/null @@ -1,122 +0,0 @@ -// -// $Id$ -// -// samskivert library - useful routines for java programs -// Copyright (C) 2006-2007 Michael Bayne, Pär Winzell -// -// This library is free software; you can redistribute it and/or modify it -// under the terms of the GNU Lesser General Public License as published -// by the Free Software Foundation; either version 2.1 of the License, or -// (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -package com.samskivert.jdbc.depot.operator; - -import java.util.Collection; - -import com.samskivert.jdbc.depot.PersistentRecord; -import com.samskivert.jdbc.depot.expression.ExpressionVisitor; -import com.samskivert.jdbc.depot.expression.SQLExpression; -import com.samskivert.jdbc.depot.expression.ValueExp; - -/** - * A common interface for operator hierarchies in SQL. The main purpose of breaking this out from - * SQLExpression is to capture the recursive nature of e.g. the logical operators, which work on - * other SQLOperators but not general SQLExpressions. - */ -public interface SQLOperator extends SQLExpression -{ - /** - * Represents an operator with any number of operands. - */ - public abstract static class MultiOperator - implements SQLOperator - { - public MultiOperator (SQLExpression ... conditions) - { - _conditions = conditions; - } - - // from SQLExpression - public void accept (ExpressionVisitor builder) - { - builder.visit(this); - } - - // from SQLExpression - public void addClasses (Collection> classSet) - { - for (int ii = 0; ii < _conditions.length; ii ++) { - _conditions[ii].addClasses(classSet); - } - } - - public SQLExpression[] getConditions () - { - return _conditions; - } - - /** - * Returns the text infix to be used to join expressions together. - */ - public abstract String operator (); - - protected SQLExpression[] _conditions; - } - - /** - * Does the real work for simple binary operators such as Equals. - */ - public abstract static class BinaryOperator implements SQLOperator - { - public BinaryOperator (SQLExpression lhs, SQLExpression rhs) - { - _lhs = lhs; - _rhs = rhs; - } - - public BinaryOperator (SQLExpression lhs, Comparable rhs) - { - this(lhs, new ValueExp(rhs)); - } - - // from SQLExpression - public void accept (ExpressionVisitor builder) - { - builder.visit(this); - } - - // from SQLExpression - public void addClasses (Collection> classSet) - { - _lhs.addClasses(classSet); - _rhs.addClasses(classSet); - } - - /** - * Returns the string representation of the operator. - */ - public abstract String operator(); - - public SQLExpression getLeftHandSide () - { - return _lhs; - } - - public SQLExpression getRightHandSide () - { - return _rhs; - } - - protected SQLExpression _lhs; - protected SQLExpression _rhs; - } -} diff --git a/src/java/com/samskivert/jdbc/depot/tests/TestRecord.java b/src/java/com/samskivert/jdbc/depot/tests/TestRecord.java deleted file mode 100644 index ed2abbc4..00000000 --- a/src/java/com/samskivert/jdbc/depot/tests/TestRecord.java +++ /dev/null @@ -1,128 +0,0 @@ -// -// $Id$ -// -// samskivert library - useful routines for java programs -// Copyright (C) 2006-2007 Michael Bayne, Pär Winzell -// -// This library is free software; you can redistribute it and/or modify it -// under the terms of the GNU Lesser General Public License as published -// by the Free Software Foundation; either version 2.1 of the License, or -// (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -package com.samskivert.jdbc.depot.tests; - -import java.sql.Date; -import java.sql.Timestamp; - -import com.samskivert.jdbc.depot.Key; -import com.samskivert.jdbc.depot.PersistentRecord; -import com.samskivert.jdbc.depot.annotation.Entity; -import com.samskivert.jdbc.depot.annotation.Id; -import com.samskivert.jdbc.depot.annotation.Index; -import com.samskivert.jdbc.depot.expression.ColumnExp; - -import com.samskivert.util.StringUtil; - -/** - * A test persistent object. - */ -@Entity(indices={ @Index(name="createdIndex", fields={"created"}) }) -public class TestRecord extends PersistentRecord -{ - // AUTO-GENERATED: FIELDS START - /** The column identifier for the {@link #recordId} field. */ - public static final String RECORD_ID = "recordId"; - - /** The qualified column identifier for the {@link #recordId} field. */ - public static final ColumnExp RECORD_ID_C = - new ColumnExp(TestRecord.class, RECORD_ID); - - /** The column identifier for the {@link #name} field. */ - public static final String NAME = "name"; - - /** The qualified column identifier for the {@link #name} field. */ - public static final ColumnExp NAME_C = - new ColumnExp(TestRecord.class, NAME); - - /** The column identifier for the {@link #age} field. */ - public static final String AGE = "age"; - - /** The qualified column identifier for the {@link #age} field. */ - public static final ColumnExp AGE_C = - new ColumnExp(TestRecord.class, AGE); - - /** The column identifier for the {@link #homeTown} field. */ - public static final String HOME_TOWN = "homeTown"; - - /** The qualified column identifier for the {@link #homeTown} field. */ - public static final ColumnExp HOME_TOWN_C = - new ColumnExp(TestRecord.class, HOME_TOWN); - - /** The column identifier for the {@link #created} field. */ - public static final String CREATED = "created"; - - /** The qualified column identifier for the {@link #created} field. */ - public static final ColumnExp CREATED_C = - new ColumnExp(TestRecord.class, CREATED); - - /** The column identifier for the {@link #lastModified} field. */ - public static final String LAST_MODIFIED = "lastModified"; - - /** The qualified column identifier for the {@link #lastModified} field. */ - public static final ColumnExp LAST_MODIFIED_C = - new ColumnExp(TestRecord.class, LAST_MODIFIED); - - /** The column identifier for the {@link #numbers} field. */ - public static final String NUMBERS = "numbers"; - - /** The qualified column identifier for the {@link #numbers} field. */ - public static final ColumnExp NUMBERS_C = - new ColumnExp(TestRecord.class, NUMBERS); - // AUTO-GENERATED: FIELDS END - - public static final int SCHEMA_VERSION = 3; - - @Id - public int recordId; - - public String name; - - public int age; - - public String homeTown; - - public Date created; - - public Timestamp lastModified; - - public int[] numbers; - - @Override - public String toString () - { - return StringUtil.fieldsToString(this); - } - - // AUTO-GENERATED: METHODS START - /** - * Create and return a primary {@link Key} to identify a {@link TestRecord} - * with the supplied key values. - */ - public static Key getKey (int recordId) - { - return new Key( - TestRecord.class, - new String[] { RECORD_ID }, - new Comparable[] { recordId }); - } - // AUTO-GENERATED: METHODS END -} diff --git a/src/java/com/samskivert/jdbc/depot/tests/TestRepository.java b/src/java/com/samskivert/jdbc/depot/tests/TestRepository.java deleted file mode 100644 index 482b953f..00000000 --- a/src/java/com/samskivert/jdbc/depot/tests/TestRepository.java +++ /dev/null @@ -1,126 +0,0 @@ -// -// $Id$ -// -// samskivert library - useful routines for java programs -// Copyright (C) 2006-2007 Michael Bayne, Pär Winzell -// -// This library is free software; you can redistribute it and/or modify it -// under the terms of the GNU Lesser General Public License as published -// by the Free Software Foundation; either version 2.1 of the License, or -// (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -package com.samskivert.jdbc.depot.tests; - -import java.sql.Date; -import java.sql.Timestamp; -// import java.util.HashSet; -import java.util.Set; - -import com.samskivert.util.RandomUtil; - -import com.samskivert.jdbc.StaticConnectionProvider; -import com.samskivert.jdbc.depot.DepotRepository; -// import com.samskivert.jdbc.depot.Key; -// import com.samskivert.jdbc.depot.KeySet; -import com.samskivert.jdbc.depot.PersistenceContext; -import com.samskivert.jdbc.depot.PersistentRecord; -import com.samskivert.jdbc.depot.SchemaMigration; -import com.samskivert.jdbc.depot.clause.Where; -import com.samskivert.jdbc.depot.expression.LiteralExp; -import com.samskivert.jdbc.depot.operator.Conditionals; - -/** - * A test tool for the Depot repository services. - */ -public class TestRepository extends DepotRepository -{ - public static void main (String[] args) - throws Exception - { - PersistenceContext perCtx = new PersistenceContext(); - perCtx.init("test", new StaticConnectionProvider("depot.properties"), null); - - // tests a bogus rename migration - // perCtx.registerMigration(TestRecord.class, new SchemaMigration.Rename(1, "foo", "bar")); - - // tests a custom add column migration - perCtx.registerMigration(TestRecord.class, - new SchemaMigration.Add(2, TestRecord.HOME_TOWN, "'Anytown USA'")); - - TestRepository repo = new TestRepository(perCtx); - - repo.delete(TestRecord.class, 1); - - Date now = new Date(System.currentTimeMillis()); - Timestamp tnow = new Timestamp(System.currentTimeMillis()); - - TestRecord record = new TestRecord(); - record.recordId = 1; - record.name = "Elvis"; - record.age = 99; - record.created = now; - record.homeTown = "Right here"; - record.lastModified = tnow; - record.numbers = new int[] { 9, 0, 2, 1, 0 }; - - repo.insert(record); - System.out.println(repo.load(TestRecord.class, record.recordId)); - -// record.age = 25; -// record.name = "Bob"; -// record.numbers = new int[] { 1, 2, 3, 4, 5 }; -// repo.update(record, TestRecord.AGE, TestRecord.NAME, TestRecord.NUMBERS); - - repo.updatePartial(TestRecord.class, record.recordId, - TestRecord.AGE, 25, TestRecord.NAME, "Bob", - TestRecord.NUMBERS, new int[] { 1, 2, 3, 4, 5 }); - System.out.println(repo.load(TestRecord.class, record.recordId)); - - for (int ii = 2; ii < CREATE_RECORDS; ii++) { - record = new TestRecord(); - record.recordId = ii; - record.name = "Spam!"; - record.age = RandomUtil.getInt(150); - record.homeTown = "Over there"; - record.numbers = new int[] { 5, 4, 3, 2, 1 }; - record.created = now; - record.lastModified = tnow; - repo.insert(record); - } - - System.out.println("Have " + repo.findAll(TestRecord.class).size() + " records."); - repo.deleteAll(TestRecord.class, new Where(new Conditionals.LessThan( - TestRecord.RECORD_ID_C, CREATE_RECORDS/2))); - System.out.println("Now have " + repo.findAll(TestRecord.class).size() + " records."); - repo.deleteAll(TestRecord.class, new Where(new LiteralExp("true"))); -// // TODO: try to break our In() clause -// Set> ids = new HashSet>(); -// for (int ii = 1; ii <= Conditionals.In.MAX_KEYS*2+3; ii++) { -// ids.add(TestRecord.getKey(ii)); -// } -// repo.deleteAll(TestRecord.class, new KeySet(TestRecord.class, ids)); - System.out.println("Now have " + repo.findAll(TestRecord.class).size() + " records."); - } - - public TestRepository (PersistenceContext perCtx) - { - super(perCtx); - } - - @Override // from DepotRepository - protected void getManagedRecords (Set> classes) - { - classes.add(TestRecord.class); - } - - protected static final int CREATE_RECORDS = 150; -} diff --git a/src/java/com/samskivert/jdbc/depot/tools/GenRecordTask.java b/src/java/com/samskivert/jdbc/depot/tools/GenRecordTask.java deleted file mode 100644 index f046b633..00000000 --- a/src/java/com/samskivert/jdbc/depot/tools/GenRecordTask.java +++ /dev/null @@ -1,493 +0,0 @@ -// -// $Id$ -// -// samskivert library - useful routines for java programs -// Copyright (C) 2006-2007 Michael Bayne, Pär Winzell -// -// This library is free software; you can redistribute it and/or modify it -// under the terms of the GNU Lesser General Public License as published -// by the Free Software Foundation; either version 2.1 of the License, or -// (at your option) any later version. -// -// This library is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -// Lesser General Public License for more details. -// -// You should have received a copy of the GNU Lesser General Public -// License along with this library; if not, write to the Free Software -// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA - -package com.samskivert.jdbc.depot.tools; - -import java.io.BufferedReader; -import java.io.BufferedWriter; -import java.io.File; -import java.io.FileReader; -import java.io.FileWriter; -import java.io.IOException; -import java.io.StringWriter; - -import java.lang.annotation.Annotation; -import java.lang.reflect.Field; -import java.lang.reflect.Modifier; - -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Set; -import java.util.regex.Matcher; -import java.util.regex.Pattern; - -import org.apache.tools.ant.BuildException; -import org.apache.tools.ant.DirectoryScanner; -import org.apache.tools.ant.Task; -import org.apache.tools.ant.types.FileSet; -import org.apache.tools.ant.types.Reference; -import org.apache.tools.ant.util.ClasspathUtils; - -import org.apache.velocity.VelocityContext; -import org.apache.velocity.app.VelocityEngine; - -import com.samskivert.jdbc.depot.PersistentRecord; -import com.samskivert.jdbc.depot.annotation.Id; -import com.samskivert.jdbc.depot.annotation.Transient; -import com.samskivert.util.ClassUtil; -import com.samskivert.util.GenUtil; -import com.samskivert.util.StringUtil; -import com.samskivert.velocity.VelocityUtil; - -/** - * An ant task that updates the column constants for a persistent record. - */ -public class GenRecordTask extends Task -{ - /** - * Adds a nested fileset element which enumerates record source files. - */ - public void addFileset (FileSet set) - { - _filesets.add(set); - } - - /** - * Configures that classpath that we'll use to load record classes. - */ - public void setClasspathref (Reference pathref) - { - _cloader = ClasspathUtils.getClassLoaderForPath(getProject(), pathref); - } - - @Override - public void execute () throws BuildException - { - if (_cloader == null) { - String errmsg = "This task requires a 'classpathref' attribute " + - "to be set to the project's classpath."; - throw new BuildException(errmsg); - } - - try { - _velocity = VelocityUtil.createEngine(); - } catch (Exception e) { - throw new BuildException("Failure initializing Velocity", e); - } - - // resolve the PersistentRecord class using our classloader - try { - _prclass = _cloader.loadClass(PersistentRecord.class.getName()); - } catch (Exception e) { - throw new BuildException("Can't resolve InvocationListener", e); - } - - for (FileSet fs : _filesets) { - DirectoryScanner ds = fs.getDirectoryScanner(getProject()); - File fromDir = fs.getDir(getProject()); - String[] srcFiles = ds.getIncludedFiles(); - for (int f = 0; f < srcFiles.length; f++) { - processRecord(new File(fromDir, srcFiles[f])); - } - } - } - - /** - * Processes a distributed object source file. - */ - protected void processRecord (File source) - { - // System.err.println("Processing " + source + "..."); - - // load up the file and determine it's package and classname - String name = null; - try { - name = readClassName(source); - } catch (Exception e) { - System.err.println("Failed to parse " + source + ": " + e.getMessage()); - } - - try { - processRecord(source, _cloader.loadClass(name)); - } catch (ClassNotFoundException cnfe) { - System.err.println("Failed to load " + name + ".\n" + - "Missing class: " + cnfe.getMessage()); - System.err.println("Be sure to set the 'classpathref' attribute to a classpath\n" + - "that contains your projects invocation service classes."); - } catch (Exception e) { - e.printStackTrace(System.err); - } - } - - /** Processes a resolved persistent record class instance. */ - protected void processRecord (File source, Class rclass) - { - // make sure we extend persistent record - if (!_prclass.isAssignableFrom(rclass)) { - // System.err.println("Skipping " + rclass.getName() + "..."); - return; - } - boolean isAbstract = Modifier.isAbstract(rclass.getModifiers()); - - // determine our primary key fields for getKey() generation (if we're not an abstract) - List kflist = new ArrayList(); - if (!isAbstract) { - // determine which fields make up our primary key; we'd just use Class.getFields() but - // that returns things in a random order whereas ClassUtil returns fields in - // declaration order starting from the top-most class and going down the line - for (Field field : ClassUtil.getFields(rclass)) { - if (hasAnnotation(field, Id.class)) { - kflist.add(field); - continue; - } - } - } - - // determine which fields we need to generate constants for - List flist = new ArrayList(); - for (Field field : rclass.getFields()) { - if (isPersistentField(field)) { - flist.add(field); - } - } - Set declared = new HashSet(); - for (Field field : rclass.getDeclaredFields()) { - if (isPersistentField(field)) { - declared.add(field); - } - } - - // slurp our source file into newline separated strings - String[] lines = null; - try { - BufferedReader bin = new BufferedReader(new FileReader(source)); - ArrayList llist = new ArrayList(); - String line = null; - while ((line = bin.readLine()) != null) { - llist.add(line); - } - lines = llist.toArray(new String[llist.size()]); - bin.close(); - } catch (IOException ioe) { - System.err.println("Error reading '" + source + "': " + ioe); - return; - } - - // now determine where to insert our static field declarations - int bstart = -1, bend = -1; - int nstart = -1, nend = -1; - int mstart = -1, mend = -1; - for (int ii = 0; ii < lines.length; ii++) { - String line = lines[ii].trim(); - - // look for the start of the class body - if (NAME_PATTERN.matcher(line).find()) { - if (line.endsWith("{")) { - bstart = ii+1; - } else { - // search down a few lines for the open brace - for (int oo = 1; oo < 10; oo++) { - if (get(lines, ii+oo).trim().endsWith("{")) { - bstart = ii+oo+1; - break; - } - } - } - - // track the last } on a line by itself and we'll call that the end of the class body - } else if (line.equals("}")) { - bend = ii; - - // look for our field and method markers - } else if (line.equals(FIELDS_START)) { - nstart = ii; - } else if (line.equals(FIELDS_END)) { - nend = ii+1; - } else if (line.equals(METHODS_START)) { - mstart = ii; - } else if (line.equals(METHODS_END)) { - mend = ii+1; - } - } - - // sanity check the markers - if (check(source, "fields start", nstart, "fields end", nend) || - check(source, "fields end", nend, "fields start", nstart) || - check(source, "methods start", mstart, "methods end", mend) || - check(source, "methods end", mend, "methods start", mstart)) { - return; - } - - // we have no previous markers then stuff the fields at the top of the class body and the - // methods at the bottom - if (nstart == -1) { - nstart = bstart; - nend = bstart; - } - if (mstart == -1) { - mstart = bend; - mend = bend; - } - - // get the unqualified class name - String rname = rclass.getName(); - rname = rname.substring(rname.lastIndexOf(".")+1); - - // generate our fields section - StringBuilder fsection = new StringBuilder(); - for (int ii = 0; ii < flist.size(); ii++) { - Field f = flist.get(ii); - String fname = f.getName(); - - // create our velocity context - VelocityContext ctx = new VelocityContext(); - ctx.put("record", rname); - ctx.put("field", fname); - ctx.put("capfield", StringUtil.unStudlyName(fname).toUpperCase()); - - // now generate our bits - if (declared.contains(f)) { - if (fsection.length() > 0) { - fsection.append("\n"); - } - fsection.append(mergeTemplate(NAME_TMPL, ctx)); - } - if (!isAbstract) { - if (fsection.length() > 0) { - fsection.append("\n"); - } - fsection.append(mergeTemplate(COL_TMPL, ctx)); - } - } - - // generate our methods section - StringBuilder msection = new StringBuilder(); - - // add a getKey() method, if applicable - if (kflist.size() > 0) { - // create our velocity context - VelocityContext ctx = new VelocityContext(); - ctx.put("record", rname); - - StringBuilder argList = new StringBuilder(); - StringBuilder argNameList = new StringBuilder(); - StringBuilder fieldNameList = new StringBuilder(); - for (Field keyField : kflist) { - if (argList.length() > 0) { - argList.append(", "); - argNameList.append(", "); - fieldNameList.append(", "); - } - String name = keyField.getName(); - argList.append(GenUtil.simpleName(keyField)).append(" ").append(name); - argNameList.append(name); - fieldNameList.append(StringUtil.unStudlyName(name)); - } - - ctx.put("argList", argList.toString()); - ctx.put("argNameList", argNameList.toString()); - ctx.put("fieldNameList", fieldNameList.toString()); - - // generate our bits and append them as appropriate to the string buffers - msection.append(mergeTemplate(KEY_TMPL, ctx)); - } - - // now bolt everything back together into a class declaration - try { - BufferedWriter bout = new BufferedWriter(new FileWriter(source)); - for (int ii = 0; ii < nstart; ii++) { - writeln(bout, lines[ii]); - } - - if (fsection.length() > 0) { - String prev = get(lines, nstart-1); - if (!StringUtil.isBlank(prev) && !prev.equals("{")) { - bout.newLine(); - } - writeln(bout, " " + FIELDS_START); - bout.write(fsection.toString()); - writeln(bout, " " + FIELDS_END); - if (!StringUtil.isBlank(get(lines, nend))) { - bout.newLine(); - } - } - for (int ii = nend; ii < mstart; ii++) { - writeln(bout, lines[ii]); - } - - if (msection.length() > 0) { - if (!StringUtil.isBlank(get(lines, mstart-1))) { - bout.newLine(); - } - writeln(bout, " " + METHODS_START); - bout.write(msection.toString()); - writeln(bout, " " + METHODS_END); - String next = get(lines, mend); - if (!StringUtil.isBlank(next) && !next.equals("}")) { - bout.newLine(); - } - } - for (int ii = mend; ii < lines.length; ii++) { - writeln(bout, lines[ii]); - } - - bout.close(); - } catch (IOException ioe) { - System.err.println("Error writing to '" + source + "': " + ioe); - } - } - - /** - * Returns true if the supplied field is part of a persistent record (is a public, non-static, - * non-transient field). - */ - protected boolean isPersistentField (Field field) - { - int mods = field.getModifiers(); - return Modifier.isPublic(mods) && !Modifier.isStatic(mods) && - !Modifier.isTransient(mods) && !hasAnnotation(field, Transient.class); - } - - /** - * Safely gets the indexth line, returning the empty string if we exceed the - * length of the array. - */ - protected String get (String[] lines, int index) - { - return (index < lines.length) ? lines[index] : ""; - } - - /** Helper function for sanity checking marker existence. */ - protected boolean check (File source, String mname, int mline, String fname, int fline) - { - if (mline == -1 && fline != -1) { - System.err.println("Found " + fname + " marker (at line " + (fline+1) + ") but no " + - mname + " marker in '" + source + "'."); - return true; - } - return false; - } - - /** Helper function for writing a string and a newline to a writer. */ - protected void writeln (BufferedWriter bout, String line) - throws IOException - { - bout.write(line); - bout.newLine(); - } - - /** Helper function for generating our boilerplate code. */ - protected String mergeTemplate (String tmpl, VelocityContext ctx) - { - StringWriter writer = new StringWriter(); - try { - _velocity.mergeTemplate(tmpl, "UTF-8", ctx, writer); - } catch (Exception e) { - System.err.println("Failed processing template [tmpl=" + tmpl + "]"); - e.printStackTrace(System.err); - } - return writer.toString(); - } - - protected static boolean hasAnnotation (Field field, Class annotation) - { - // iterate becase getAnnotation() fails if we're dealing with multiple classloaders - for (Annotation a : field.getAnnotations()) { - if (annotation.getName().equals(a.annotationType().getName())) { - return true; - } - } - return false; - } - - /** - * Reads in the supplied source file and locates the package and class or interface name and - * returns a fully qualified class name. - */ - protected static String readClassName (File source) - throws IOException - { - // load up the file and determine it's package and classname - String pkgname = null, name = null; - BufferedReader bin = new BufferedReader(new FileReader(source)); - String line; - while ((line = bin.readLine()) != null) { - Matcher pm = PACKAGE_PATTERN.matcher(line); - if (pm.find()) { - pkgname = pm.group(1); - } - Matcher nm = NAME_PATTERN.matcher(line); - if (nm.find()) { - name = nm.group(2); - break; - } - } - bin.close(); - - // make sure we found something - if (name == null) { - throw new IOException("Unable to locate class or interface name in " + source + "."); - } - - // prepend the package name to get a name we can Class.forName() - if (pkgname != null) { - name = pkgname + "." + name; - } - - return name; - } - - /** A list of filesets that contain tile images. */ - protected ArrayList _filesets = new ArrayList(); - - /** Used to do our own classpath business. */ - protected ClassLoader _cloader; - - /** Used to generate source files from templates. */ - protected VelocityEngine _velocity; - - /** {@link PersistentRecord} resolved with the proper classloader so that we can compare it to - * loaded derived classes. */ - protected Class _prclass; - - /** Specifies the path to the name code template. */ - protected static final String NAME_TMPL = "com/samskivert/jdbc/depot/tools/record_name.tmpl"; - - /** Specifies the path to the column code template. */ - protected static final String COL_TMPL = "com/samskivert/jdbc/depot/tools/record_column.tmpl"; - - /** Specifies the path to the key code template. */ - protected static final String KEY_TMPL = "com/samskivert/jdbc/depot/tools/record_key.tmpl"; - - // markers - protected static final String MARKER = "// AUTO-GENERATED: "; - protected static final String FIELDS_START = MARKER + "FIELDS START"; - protected static final String FIELDS_END = MARKER + "FIELDS END"; - protected static final String METHODS_START = MARKER + "METHODS START"; - protected static final String METHODS_END = MARKER + "METHODS END"; - - /** A regular expression for matching the package declaration. */ - protected static final Pattern PACKAGE_PATTERN = Pattern.compile("^\\s*package\\s+(\\S+)\\W"); - - /** A regular expression for matching the class or interface declaration. */ - protected static final Pattern NAME_PATTERN = Pattern.compile( - "^\\s*public\\s+(?:abstract\\s+)?(interface|class)\\s+(\\w+)(\\W|$)"); -} diff --git a/src/java/com/samskivert/jdbc/depot/tools/record_column.tmpl b/src/java/com/samskivert/jdbc/depot/tools/record_column.tmpl deleted file mode 100644 index 82e236fd..00000000 --- a/src/java/com/samskivert/jdbc/depot/tools/record_column.tmpl +++ /dev/null @@ -1,3 +0,0 @@ - /** The qualified column identifier for the {@link #$field} field. */ - public static final ColumnExp ${capfield}_C = - new ColumnExp(${record}.class, $capfield); diff --git a/src/java/com/samskivert/jdbc/depot/tools/record_key.tmpl b/src/java/com/samskivert/jdbc/depot/tools/record_key.tmpl deleted file mode 100644 index c185b7d7..00000000 --- a/src/java/com/samskivert/jdbc/depot/tools/record_key.tmpl +++ /dev/null @@ -1,11 +0,0 @@ - /** - * Create and return a primary {@link Key} to identify a {@link $record} - * with the supplied key values. - */ - public static Key<${record}> getKey (${argList}) - { - return new Key<${record}>( - ${record}.class, - new String[] { $fieldNameList }, - new Comparable[] { $argNameList }); - } diff --git a/src/java/com/samskivert/jdbc/depot/tools/record_name.tmpl b/src/java/com/samskivert/jdbc/depot/tools/record_name.tmpl deleted file mode 100644 index e212ce62..00000000 --- a/src/java/com/samskivert/jdbc/depot/tools/record_name.tmpl +++ /dev/null @@ -1,2 +0,0 @@ - /** The column identifier for the {@link #$field} field. */ - public static final String $capfield = "$field";