Author: [log in to unmask]
Date: Fri Apr 17 17:20:40 2015
New Revision: 2744
Log:
Add refactored API classes to conditions branch.
Added:
java/branches/conditions-HPSJAVA-488/src/main/java/org/hps/conditions/apinew/
java/branches/conditions-HPSJAVA-488/src/main/java/org/hps/conditions/apinew/BaseConditionsObject.java
java/branches/conditions-HPSJAVA-488/src/main/java/org/hps/conditions/apinew/BaseConditionsObjectCollection.java
java/branches/conditions-HPSJAVA-488/src/main/java/org/hps/conditions/apinew/ConditionsObject.java
java/branches/conditions-HPSJAVA-488/src/main/java/org/hps/conditions/apinew/ConditionsObjectCollection.java
java/branches/conditions-HPSJAVA-488/src/main/java/org/hps/conditions/apinew/FieldValues.java
java/branches/conditions-HPSJAVA-488/src/main/java/org/hps/conditions/apinew/FieldValuesMap.java
java/branches/conditions-HPSJAVA-488/src/main/java/org/hps/conditions/apinew/TableMetaData.java
java/branches/conditions-HPSJAVA-488/src/test/java/org/hps/conditions/apinew/
java/branches/conditions-HPSJAVA-488/src/test/java/org/hps/conditions/apinew/BaseConditionsObjectCollectionTest.java
java/branches/conditions-HPSJAVA-488/src/test/java/org/hps/conditions/apinew/BaseConditionsObjectTest.java
Added: java/branches/conditions-HPSJAVA-488/src/main/java/org/hps/conditions/apinew/BaseConditionsObject.java
=============================================================================
--- java/branches/conditions-HPSJAVA-488/src/main/java/org/hps/conditions/apinew/BaseConditionsObject.java (added)
+++ java/branches/conditions-HPSJAVA-488/src/main/java/org/hps/conditions/apinew/BaseConditionsObject.java Fri Apr 17 17:20:40 2015
@@ -0,0 +1,356 @@
+package org.hps.conditions.apinew;
+
+import java.sql.Connection;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.text.SimpleDateFormat;
+import java.util.Date;
+
+import org.hps.conditions.api.ConditionsObjectException;
+
+/**
+ * This is a basic ORM class for performing CRUD (create, read, update, delete) operations on objects in the conditions
+ * system. Each object is mapped to a single row in a database table.
+ *
+ * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a>
+ */
+public class BaseConditionsObject implements ConditionsObject {
+
+ /**
+ * Field name for collection ID.
+ */
+ static final String COLLECTION_ID_FIELD = "collection_id";
+
+ /**
+ * Date formatting for insert statement.
+ */
+ static final SimpleDateFormat DATE_FORMAT = new SimpleDateFormat("yyyy-MM-dd kk:mm:ss");
+
+ static final int UNSET_COLLECTION_ID = -1;
+
+ static final int UNSET_ID = -1;
+
+ protected static String defaultToString(final BaseConditionsObject object) {
+ final StringBuffer sb = new StringBuffer();
+ sb.append("id: " + object.getId() + ", ");
+ for (final String field : object.getFieldValues().getFieldNames()) {
+ sb.append(field + "=" + object.getValue(Object.class, field) + ", ");
+ }
+ sb.setLength(sb.length() - 2);
+ sb.append('\n');
+ return sb.toString();
+ }
+
+ /**
+ * The JDBC database connection.
+ */
+ private Connection connection;
+
+ /**
+ * The field values.
+ */
+ private final FieldValues fields;
+
+ /**
+ * The row ID of the object in its table. This will be -1 for new objects that are not in the database.
+ */
+ private int id = UNSET_ID;
+
+ /**
+ * Flag to indicate object is locally changed and database update has not been executed.
+ */
+ private boolean isDirty;
+
+ /**
+ * The information about the associated table such as the table and column names.
+ */
+ private TableMetaData tableMetaData;
+
+ protected BaseConditionsObject() {
+ this.fields = new FieldValuesMap();
+ }
+
+ /**
+ * Class constructor.
+ * <p>
+ * This should be used when creating new objects without a list of field values. A new <code>FieldValues</code>
+ * object will be automatically created from the table information.
+ *
+ * @param connection
+ * @param tableMetaData
+ */
+ public BaseConditionsObject(final Connection connection, final TableMetaData tableMetaData) {
+ this.connection = connection;
+ this.tableMetaData = tableMetaData;
+ this.fields = new FieldValuesMap(tableMetaData);
+ }
+
+ /**
+ * Class constructor.
+ * <p>
+ * This should be used when creating new objects with a list of field values.
+ *
+ * @param connection
+ * @param tableMetaData
+ * @param fields
+ */
+ public BaseConditionsObject(final Connection connection, final TableMetaData tableMetaData, final FieldValues fields) {
+ this.connection = connection;
+ this.tableMetaData = tableMetaData;
+ this.fields = fields;
+ }
+
+ /**
+ * Class constructor.
+ * <p>
+ * This should be used when the object is already in the database and the row ID is known. A SQL SELECT operation
+ * will be performed to get data into this object from the database.
+ *
+ * @param connection
+ * @param rowId
+ * @param tableMetaData
+ * @throw ConditionsObjectException if getting data into this object fails
+ * @throw SQLException if there is an SQL error when executing the SELECT operation
+ */
+ public BaseConditionsObject(final Connection connection, final TableMetaData tableMetaData, final int rowId)
+ throws ConditionsObjectException, SQLException {
+ this.connection = connection;
+ this.tableMetaData = tableMetaData;
+ this.fields = new FieldValuesMap(tableMetaData);
+ final boolean selected = select(rowId);
+ if (!selected) {
+ throw new ConditionsObjectException("Failed to select data into object using row ID " + rowId);
+ }
+ }
+
+ @Override
+ public final boolean delete() throws ConditionsObjectException, SQLException {
+ if (isNew()) {
+ throw new ConditionsObjectException("Object is not in database and so cannot be deleted.");
+ }
+ final String sql = "DELETE FROM " + this.tableMetaData.getTableName() + " WHERE id=" + this.getId();
+ // if (this.verbose) {
+ // System.out.println(sql);
+ // }
+ Statement statement = null;
+ int rowsUpdated;
+ try {
+ statement = this.connection.createStatement();
+ rowsUpdated = statement.executeUpdate(sql);
+ } finally {
+ if (statement != null) {
+ statement.close();
+ }
+ }
+ return rowsUpdated != 0;
+ }
+
+ @Override
+ public final int getCollectionId() {
+ if (this.fields.isNonNull(COLLECTION_ID_FIELD)) {
+ return getValue(Integer.class, COLLECTION_ID_FIELD);
+ } else {
+ return UNSET_COLLECTION_ID;
+ }
+ }
+
+ @Override
+ public FieldValues getFieldValues() {
+ return this.fields;
+ }
+
+ @Override
+ public final int getId() {
+ return this.id;
+ }
+
+ @Override
+ public final TableMetaData getTableMetaData() {
+ return this.tableMetaData;
+ }
+
+ @Override
+ public final <T> T getValue(final Class<T> type, final String name) {
+ return type.cast(this.fields.getValue(type, name));
+ }
+
+ @Override
+ public final boolean insert() throws ConditionsObjectException, SQLException {
+ if (!isNew()) {
+ throw new ConditionsObjectException("Cannot insert an existing record.");
+ }
+ final StringBuffer sb = new StringBuffer();
+ sb.append("INSERT INTO " + this.tableMetaData.getTableName() + " (");
+ for (final String fieldName : this.fields.getFieldNames()) {
+ sb.append(fieldName + ", ");
+ }
+ sb.setLength(sb.length() - 2);
+ sb.append(") VALUES (");
+ for (final Object value : this.fields.getValues()) {
+ if (value instanceof Date) {
+ sb.append("STR_TO_DATE( '" + DATE_FORMAT.format((Date) value) + "', '%Y-%m-%d %H:%i:%S' ), ");
+ } else {
+ sb.append("'" + value + "', ");
+ }
+ }
+ sb.setLength(sb.length() - 2);
+ sb.append(")");
+ final String sql = sb.toString();
+ // if (this.verbose) {
+ // System.out.println(sql);
+ // }
+ Statement statement = null;
+ ResultSet resultSet = null;
+ int rowsUpdated = 0;
+ try {
+ statement = this.connection.createStatement();
+ rowsUpdated = statement.executeUpdate(sql, Statement.RETURN_GENERATED_KEYS);
+ resultSet = statement.getGeneratedKeys();
+ while (resultSet.next()) {
+ final int key = resultSet.getInt(1);
+ this.id = key;
+ break;
+ }
+ } finally {
+ if (resultSet != null) {
+ resultSet.close();
+ }
+ if (statement != null) {
+ statement.close();
+ }
+ }
+ return rowsUpdated != 0;
+ }
+
+ @Override
+ public final boolean isDirty() {
+ return this.isDirty;
+ }
+
+ @Override
+ public final boolean isNew() {
+ return getId() == UNSET_ID;
+ }
+
+ @Override
+ public final boolean select(final int id) throws ConditionsObjectException, SQLException {
+ this.id = id;
+ if (id < 1) {
+ throw new IllegalArgumentException("bad row ID value: " + id);
+ }
+ final StringBuffer sb = new StringBuffer();
+ sb.append("SELECT");
+ for (final String fieldName : this.tableMetaData.getFieldNames()) {
+ sb.append(" " + fieldName + ",");
+ }
+ sb.setLength(sb.length() - 1);
+ sb.append(" FROM " + this.tableMetaData.getTableName());
+ sb.append(" WHERE id = " + this.getId());
+ final String sql = sb.toString();
+ // if (this.verbose) {
+ // System.out.println(sql);
+ // }
+ Statement statement = null;
+ ResultSet resultSet = null;
+ boolean selected = false;
+ try {
+ statement = this.connection.createStatement();
+ resultSet = statement.executeQuery(sql);
+ while (resultSet.next()) {
+ for (int columnIndex = 1; columnIndex <= this.tableMetaData.getFieldNames().length; columnIndex++) {
+ this.setValue(this.tableMetaData.getFieldNames()[columnIndex - 1], resultSet.getObject(columnIndex));
+ }
+ selected = true;
+ }
+ } finally {
+ if (resultSet != null) {
+ resultSet.close();
+ }
+ if (statement != null) {
+ statement.close();
+ }
+ }
+ return selected;
+ }
+
+ @Override
+ public void setCollectionId(final int collectionId) throws ConditionsObjectException {
+ if (this.getCollectionId() != UNSET_COLLECTION_ID) {
+ throw new ConditionsObjectException("The collection ID is already set on this object.");
+ }
+ if (collectionId <= UNSET_COLLECTION_ID) {
+ throw new ConditionsObjectException("Invalid collection ID value: " + collectionId);
+ }
+ this.setValue(COLLECTION_ID_FIELD, collectionId);
+ }
+
+ @Override
+ public final void setConnection(final Connection connection) {
+ this.connection = connection;
+ }
+
+ @Override
+ public void setId(final int id) {
+ this.id = id;
+ }
+
+ @Override
+ public final void setTableMetaData(final TableMetaData tableMetaData) {
+ this.tableMetaData = tableMetaData;
+ }
+
+ @Override
+ public final void setValue(final String name, final Object value) {
+ this.fields.setValue(name, value);
+ this.isDirty = true;
+ }
+
+ @Override
+ public String toString() {
+ return defaultToString(this);
+ }
+
+ @Override
+ public final boolean update() throws ConditionsObjectException, SQLException {
+ if (isDirty()) {
+ if (isNew()) {
+ throw new ConditionsObjectException("Cannot update a new object.");
+ }
+ final StringBuffer sb = new StringBuffer();
+ sb.append("UPDATE " + this.tableMetaData.getTableName() + " SET ");
+ for (final String fieldName : this.fields.getFieldNames()) {
+ sb.append(fieldName + "=");
+ final Object value = this.fields.getValue(fieldName);
+ if (value instanceof Date) {
+ // FIXME: Is there a more generic way to handle this?
+ sb.append("STR_TO_DATE( '" + DATE_FORMAT.format((Date) value) + "', '%Y-%m-%d %H:%i:%S' ), ");
+ } else {
+ sb.append("'" + value + "', ");
+ }
+ }
+ sb.setLength(sb.length() - 2);
+ sb.append(" WHERE id=" + this.getId());
+ final String sql = sb.toString();
+ // if (this.verbose) {
+ // System.out.println(sql);
+ // }
+ Statement statement = null;
+ int rowsUpdated = 0;
+ try {
+ statement = this.connection.createStatement();
+ rowsUpdated = statement.executeUpdate(sql);
+ if (rowsUpdated > 0) {
+ this.isDirty = false;
+ }
+ } finally {
+ if (statement != null) {
+ statement.close();
+ }
+ }
+ return rowsUpdated != 0;
+ } else {
+ return false;
+ }
+ }
+}
Added: java/branches/conditions-HPSJAVA-488/src/main/java/org/hps/conditions/apinew/BaseConditionsObjectCollection.java
=============================================================================
--- java/branches/conditions-HPSJAVA-488/src/main/java/org/hps/conditions/apinew/BaseConditionsObjectCollection.java (added)
+++ java/branches/conditions-HPSJAVA-488/src/main/java/org/hps/conditions/apinew/BaseConditionsObjectCollection.java Fri Apr 17 17:20:40 2015
@@ -0,0 +1,241 @@
+package org.hps.conditions.apinew;
+
+import java.sql.Connection;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.Statement;
+import java.util.Collection;
+import java.util.Iterator;
+import java.util.LinkedHashSet;
+import java.util.Set;
+
+import org.hps.conditions.api.ConditionsObjectException;
+
+/**
+ *
+ */
+public class BaseConditionsObjectCollection<ObjectType extends ConditionsObject> implements
+ ConditionsObjectCollection<ObjectType> {
+
+ private int collectionId;
+ private Connection connection;
+ private final Set<ObjectType> objects = new LinkedHashSet<ObjectType>();
+ private TableMetaData tableMetaData;
+
+ protected BaseConditionsObjectCollection() {
+ }
+
+ public BaseConditionsObjectCollection(final Connection connection, final TableMetaData tableMetaData,
+ final int collectionId) throws SQLException, ConditionsObjectException {
+ this.connection = connection;
+ this.tableMetaData = tableMetaData;
+ this.collectionId = collectionId;
+ if (collectionId != -1) {
+ select(collectionId);
+ }
+ }
+
+ @Override
+ public void add(final ObjectType object) throws ConditionsObjectException {
+ // System.out.println("adding object " + object + " to collection " + getCollectionId());
+ if (getCollectionId() != BaseConditionsObject.UNSET_COLLECTION_ID) {
+ if (object.getCollectionId() != BaseConditionsObject.UNSET_ID) {
+ if (object.getCollectionId() != this.collectionId) {
+ throw new ConditionsObjectException("Cannot add object with different collection ID: "
+ + object.getCollectionId());
+ }
+ } else {
+ // System.out.println("object.setCollectionId - " + this.collectionId);
+ object.setCollectionId(this.collectionId);
+ }
+ }
+ this.objects.add(object);
+ }
+
+ /**
+ * @throws ConditionsObjectException
+ * @throws SQLException
+ */
+ @Override
+ public void deleteAll() throws ConditionsObjectException, SQLException {
+ Statement statement = null;
+ try {
+ final String sql = "DELETE FROM `" + this.tableMetaData.getTableName() + "` WHERE collection_id = '"
+ + getCollectionId() + "'";
+ statement = this.connection.createStatement();
+ statement.executeUpdate(sql);
+ // System.out.println("result from delete: " + result);
+ this.connection.commit();
+ } catch (final SQLException e) {
+ e.printStackTrace();
+ } finally {
+ if (statement != null) {
+ statement.close();
+ }
+ }
+ }
+
+ @Override
+ public ObjectType get(final int index) {
+ if (index + 1 > this.size() || index < 0) {
+ throw new IndexOutOfBoundsException("index out of bounds: " + index);
+ }
+ int current = 0;
+ final Iterator<ObjectType> iterator = this.objects.iterator();
+ ObjectType object = iterator.next();
+ while (current != index && iterator.hasNext()) {
+ object = iterator.next();
+ current++;
+ }
+ return object;
+ }
+
+ @Override
+ public int getCollectionId() {
+ return this.collectionId;
+ }
+
+ @Override
+ public Collection<ObjectType> getObjects() {
+ return this.objects;
+ }
+
+ @Override
+ public TableMetaData getTableMetaData() {
+ return this.tableMetaData;
+ }
+
+ /**
+ * @param collectionId
+ * @throws ConditionsObjectException
+ * @throws SQLException
+ */
+ @Override
+ public void insertAll(final int collectionId) throws ConditionsObjectException, SQLException {
+ if (this.collectionId != -1) {
+ throw new RuntimeException("collection already exists");
+ }
+ this.collectionId = collectionId;
+
+ PreparedStatement insertObjects = null;
+ final StringBuffer sb = new StringBuffer();
+ sb.append("INSERT INTO " + this.getTableMetaData().getTableName() + " (");
+ for (final String field : this.getTableMetaData().getFieldNames()) {
+ sb.append(field + ", ");
+ }
+ sb.setLength(sb.length() - 2);
+ sb.append(") VALUES (");
+ for (int fieldIndex = 0; fieldIndex < this.getTableMetaData().getFieldNames().length; fieldIndex++) {
+ sb.append("?, ");
+ }
+ sb.setLength(sb.length() - 2);
+ sb.append(")");
+ final String updateStatement = sb.toString();
+ // System.out.println(updateStatement);
+ try {
+ this.connection.setAutoCommit(false);
+ insertObjects = this.connection.prepareStatement(updateStatement, Statement.RETURN_GENERATED_KEYS);
+ for (final ObjectType object : this.getObjects()) {
+ for (int fieldIndex = 0; fieldIndex < this.getTableMetaData().getFieldNames().length; fieldIndex++) {
+ final String fieldName = this.getTableMetaData().getFieldNames()[fieldIndex];
+ object.getValue(getTableMetaData().getFieldType(fieldName), fieldName);
+ // System.out.println(fieldName + "=" + value);
+ if (fieldName.equals(BaseConditionsObject.COLLECTION_ID_FIELD)) {
+ insertObjects.setObject(fieldIndex + 1, getCollectionId());
+ } else {
+ insertObjects.setObject(fieldIndex + 1,
+ object.getValue(getTableMetaData().getFieldType(fieldName), fieldName));
+ }
+ }
+ insertObjects.executeUpdate();
+ this.connection.commit();
+ final ResultSet resultSet = insertObjects.getGeneratedKeys();
+ resultSet.next();
+ object.setId(resultSet.getInt(1));
+ // System.out.println("set id to " + resultSet.getInt(1) + " from generated keys");
+ resultSet.close();
+ }
+ } catch (final SQLException e1) {
+ e1.printStackTrace();
+ if (this.connection != null) {
+ try {
+ System.err.println("Transaction is being rolled back ...");
+ this.connection.rollback();
+ System.err.println("Done rolling back transaction!");
+ } catch (final SQLException e2) {
+ e2.printStackTrace();
+ }
+ }
+ } finally {
+ if (insertObjects != null) {
+ insertObjects.close();
+ }
+ }
+ }
+
+ @Override
+ public boolean remove(final int index) {
+ final ObjectType object = get(index);
+ if (object != null) {
+ return this.objects.remove(object);
+ } else {
+ return false;
+ }
+ }
+
+ @Override
+ public void select(final int collectionId) throws SQLException, ConditionsObjectException {
+ // System.out.println("BaseConditionsObjectCollection.select - " + collectionId);
+ this.collectionId = collectionId;
+ Statement statement = null;
+ try {
+ statement = this.connection.createStatement();
+ final StringBuffer sb = new StringBuffer();
+ sb.append("SELECT id, ");
+ for (final String fieldName : this.tableMetaData.getFieldNames()) {
+ sb.append(fieldName + ", ");
+ }
+ sb.setLength(sb.length() - 2);
+ sb.append(" FROM " + this.tableMetaData.getTableName() + " WHERE collection_id=" + collectionId);
+ final String sql = sb.toString();
+ // System.out.println(sql);
+ final ResultSet resultSet = statement.executeQuery(sql);
+ while (resultSet.next()) {
+ try {
+ final ObjectType newObject = (ObjectType) this.tableMetaData.getObjectClass().newInstance();
+ newObject.setConnection(this.connection);
+ newObject.setTableMetaData(this.tableMetaData);
+ final int id = resultSet.getInt(1);
+ newObject.setId(id);
+ for (int fieldIndex = 0; fieldIndex < this.tableMetaData.getFieldNames().length; fieldIndex++) {
+ final String fieldName = this.tableMetaData.getFieldNames()[fieldIndex];
+ newObject.setValue(fieldName, resultSet.getObject(fieldIndex + 2));
+ }
+ add(newObject);
+ } catch (InstantiationException | IllegalAccessException e) {
+ throw new RuntimeException(e);
+ }
+ }
+ } finally {
+ if (statement != null) {
+ statement.close();
+ }
+ }
+ }
+
+ @Override
+ public int size() {
+ return this.objects.size();
+ }
+
+ @Override
+ // FIXME: Should execute prepared statement in transaction.
+ public void updateAll() throws ConditionsObjectException, SQLException {
+ for (final ObjectType object : this.objects) {
+ if (object.isDirty()) {
+ object.update();
+ }
+ }
+ }
+}
Added: java/branches/conditions-HPSJAVA-488/src/main/java/org/hps/conditions/apinew/ConditionsObject.java
=============================================================================
--- java/branches/conditions-HPSJAVA-488/src/main/java/org/hps/conditions/apinew/ConditionsObject.java (added)
+++ java/branches/conditions-HPSJAVA-488/src/main/java/org/hps/conditions/apinew/ConditionsObject.java Fri Apr 17 17:20:40 2015
@@ -0,0 +1,86 @@
+package org.hps.conditions.apinew;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+
+import org.hps.conditions.api.ConditionsObjectException;
+
+public interface ConditionsObject {
+
+ /**
+ * @return
+ * @throws ConditionsObjectException
+ * @throws SQLException
+ */
+ boolean delete() throws ConditionsObjectException, SQLException;
+
+ /**
+ * @return
+ */
+ int getCollectionId();
+
+ FieldValues getFieldValues();
+
+ /**
+ * @return
+ */
+ int getId();
+
+ /**
+ * @return
+ */
+ TableMetaData getTableMetaData();
+
+ /**
+ * @param type
+ * @param name
+ * @return
+ */
+ <T> T getValue(final Class<T> type, final String name);
+
+ /**
+ * @return
+ * @throws ConditionsObjectException
+ * @throws SQLException
+ */
+ boolean insert() throws ConditionsObjectException, SQLException;
+
+ /**
+ * @return
+ */
+ boolean isDirty();
+
+ /**
+ * @return
+ */
+ boolean isNew();
+
+ boolean select(final int rowId) throws ConditionsObjectException, SQLException;
+
+ /**
+ * @param collectionId
+ * @throws ConditionsObjectException
+ */
+ void setCollectionId(int collectionId) throws ConditionsObjectException;
+
+ /**
+ * @param connection
+ */
+ void setConnection(Connection connection);
+
+ void setId(int id);
+
+ void setTableMetaData(TableMetaData tableMetaData);
+
+ /**
+ * @param name
+ * @param value
+ */
+ void setValue(String name, Object value);
+
+ /**
+ * @return
+ * @throws ConditionsObjectException
+ */
+ boolean update() throws ConditionsObjectException, SQLException;
+}
Added: java/branches/conditions-HPSJAVA-488/src/main/java/org/hps/conditions/apinew/ConditionsObjectCollection.java
=============================================================================
--- java/branches/conditions-HPSJAVA-488/src/main/java/org/hps/conditions/apinew/ConditionsObjectCollection.java (added)
+++ java/branches/conditions-HPSJAVA-488/src/main/java/org/hps/conditions/apinew/ConditionsObjectCollection.java Fri Apr 17 17:20:40 2015
@@ -0,0 +1,31 @@
+package org.hps.conditions.apinew;
+
+import java.sql.SQLException;
+import java.util.Collection;
+
+import org.hps.conditions.api.ConditionsObjectException;
+
+public interface ConditionsObjectCollection<ObjectType extends ConditionsObject> {
+
+ void add(final ObjectType object) throws ConditionsObjectException;
+
+ void deleteAll() throws ConditionsObjectException, SQLException;
+
+ ObjectType get(final int index);
+
+ int getCollectionId();
+
+ Collection<ObjectType> getObjects();
+
+ TableMetaData getTableMetaData();
+
+ void insertAll(final int collectionId) throws ConditionsObjectException, SQLException;
+
+ boolean remove(final int index);
+
+ void select(final int collectionId) throws ConditionsObjectException, SQLException;
+
+ int size();
+
+ void updateAll() throws ConditionsObjectException, SQLException;
+}
Added: java/branches/conditions-HPSJAVA-488/src/main/java/org/hps/conditions/apinew/FieldValues.java
=============================================================================
--- java/branches/conditions-HPSJAVA-488/src/main/java/org/hps/conditions/apinew/FieldValues.java (added)
+++ java/branches/conditions-HPSJAVA-488/src/main/java/org/hps/conditions/apinew/FieldValues.java Fri Apr 17 17:20:40 2015
@@ -0,0 +1,26 @@
+package org.hps.conditions.apinew;
+
+import java.util.Collection;
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a>
+ */
+public interface FieldValues {
+
+ Set<String> getFieldNames();
+
+ <T> T getValue(Class<T> type, String name);
+
+ Object getValue(String name);
+
+ Collection<Object> getValues();
+
+ boolean hasField(String name);
+
+ boolean isNonNull(String name);
+
+ void setValue(String name, Object value);
+
+ int size();
+}
Added: java/branches/conditions-HPSJAVA-488/src/main/java/org/hps/conditions/apinew/FieldValuesMap.java
=============================================================================
--- java/branches/conditions-HPSJAVA-488/src/main/java/org/hps/conditions/apinew/FieldValuesMap.java (added)
+++ java/branches/conditions-HPSJAVA-488/src/main/java/org/hps/conditions/apinew/FieldValuesMap.java Fri Apr 17 17:20:40 2015
@@ -0,0 +1,63 @@
+package org.hps.conditions.apinew;
+
+import java.util.Collection;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a>
+ */
+public class FieldValuesMap implements FieldValues {
+
+ Map<String, Object> data = new HashMap<String, Object>();
+
+ FieldValuesMap() {
+ }
+
+ FieldValuesMap(final TableMetaData tableMetaData) {
+ for (final String fieldName : tableMetaData.getFieldNames()) {
+ this.data.put(fieldName, null);
+ }
+ }
+
+ @Override
+ public Set<String> getFieldNames() {
+ return this.data.keySet();
+ }
+
+ @Override
+ public <T> T getValue(final Class<T> type, final String name) {
+ return type.cast(this.data.get(name));
+ }
+
+ @Override
+ public Object getValue(final String name) {
+ return this.data.get(name);
+ }
+
+ @Override
+ public Collection<Object> getValues() {
+ return this.data.values();
+ }
+
+ @Override
+ public boolean hasField(final String name) {
+ return this.data.containsKey(name);
+ }
+
+ @Override
+ public boolean isNonNull(final String name) {
+ return this.data.get(name) != null;
+ }
+
+ @Override
+ public void setValue(final String name, final Object value) {
+ this.data.put(name, value);
+ }
+
+ @Override
+ public int size() {
+ return this.data.size();
+ }
+}
Added: java/branches/conditions-HPSJAVA-488/src/main/java/org/hps/conditions/apinew/TableMetaData.java
=============================================================================
--- java/branches/conditions-HPSJAVA-488/src/main/java/org/hps/conditions/apinew/TableMetaData.java (added)
+++ java/branches/conditions-HPSJAVA-488/src/main/java/org/hps/conditions/apinew/TableMetaData.java Fri Apr 17 17:20:40 2015
@@ -0,0 +1,208 @@
+package org.hps.conditions.apinew;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.LinkedHashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+
+/**
+ * <p>
+ * This class provides meta data about a conditions table, including a list of conditions data fields. The list of
+ * fields does not include the collection ID or row ID, which are implicitly assumed to exist.
+ * <p>
+ * It also has references to the implementation classes which are used for the ORM onto {@link ConditionsObject} and
+ * {@link ConditionsObjectCollection}.
+ *
+ * @see org.hps.conditions.api.ConditionsObject
+ * @see org.hps.conditions.api.BaseConditionsObjectCollection
+ * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a>
+ */
+public final class TableMetaData {
+
+ /**
+ * Find table meta data by object type.
+ *
+ * @param tableMetaDataList the list of table meta data e.g. from the registry
+ * @param objectType the type of the object
+ * @return the list of table meta data that have that object type
+ */
+ public static List<TableMetaData> findByObjectType(final List<TableMetaData> tableMetaDataList,
+ final Class<? extends ConditionsObject> objectType) {
+ final List<TableMetaData> list = new ArrayList<TableMetaData>();
+ for (final TableMetaData tableMetaData : tableMetaDataList) {
+ if (tableMetaData.getObjectClass().equals(objectType)) {
+
+ list.add(tableMetaData);
+ }
+ }
+ return list;
+ }
+
+ /**
+ * The collection class.
+ */
+ private Class<? extends BaseConditionsObjectCollection<?>> collectionClass;
+
+ /**
+ * The set of field names.
+ */
+ private Set<String> fieldNames = new LinkedHashSet<String>();
+
+ /**
+ * The map of field names to their types.
+ */
+ private Map<String, Class<?>> fieldTypes = new HashMap<String, Class<?>>();
+
+ /**
+ * The conditions key named (unused???).
+ */
+ private String key;
+
+ /**
+ * The object class.
+ */
+ private Class<? extends ConditionsObject> objectClass;
+
+ /**
+ * The table name.
+ */
+ private String tableName;
+
+ public TableMetaData() {
+ }
+
+ /**
+ * Fully qualified constructor.
+ *
+ * @param key the conditions key
+ * @param tableName the table name
+ * @param objectClass the object class
+ * @param collectionClass the collection class
+ * @param fieldNames the field names
+ * @param fieldTypes the field types
+ */
+ public TableMetaData(final String key, final String tableName, final Class<? extends ConditionsObject> objectClass,
+ final Class<? extends BaseConditionsObjectCollection<?>> collectionClass, final Set<String> fieldNames,
+ final Map<String, Class<?>> fieldTypes) {
+ if (key == null) {
+ throw new IllegalArgumentException("key is null");
+ }
+ if (tableName == null) {
+ throw new IllegalArgumentException("tableName is null");
+ }
+ if (objectClass == null) {
+ throw new IllegalArgumentException("objectClass is null");
+ }
+ if (fieldNames == null) {
+ throw new IllegalArgumentException("fieldNames is null");
+ }
+ if (collectionClass == null) {
+ throw new IllegalArgumentException("collectionClass is null");
+ }
+ if (fieldTypes == null) {
+ throw new IllegalArgumentException("fieldTypes is null");
+ }
+ this.key = key;
+ this.tableName = tableName;
+ this.objectClass = objectClass;
+ this.collectionClass = collectionClass;
+ this.fieldNames = fieldNames;
+ this.fieldTypes = fieldTypes;
+ }
+
+ /**
+ * Get the type of collection this table maps onto.
+ *
+ * @return the collection class
+ */
+ public Class<? extends BaseConditionsObjectCollection<?>> getCollectionClass() {
+ return this.collectionClass;
+ }
+
+ /**
+ * Get the names of the fields. Types are implied from the database tables.
+ *
+ * @return the names of the fields
+ */
+ public String[] getFieldNames() {
+ return this.fieldNames.toArray(new String[] {});
+ }
+
+ /**
+ * Get the type of the field called <code>fieldName</code>.
+ *
+ * @return the type of the field
+ */
+ public Class<?> getFieldType(final String fieldName) {
+ return this.fieldTypes.get(fieldName);
+ }
+
+ /**
+ * Get the key of this conditions type. May be different from table name but is usually the same.
+ *
+ * @return the key name of the conditions type
+ */
+ public String getKey() {
+ return this.key;
+ }
+
+ /**
+ * Get the type of object this table maps onto.
+ *
+ * @return the type of object
+ */
+ public Class<? extends ConditionsObject> getObjectClass() {
+ return this.objectClass;
+ }
+
+ /**
+ * Get the name of the table.
+ *
+ * @return the name of the table
+ */
+ public String getTableName() {
+ return this.tableName;
+ }
+
+ void setFieldNames(final String[] fieldNames) {
+ this.fieldNames = new HashSet<String>();
+ for (final String fieldName : fieldNames) {
+ this.fieldNames.add(fieldName);
+ }
+ }
+
+ void setFieldType(final String fieldName, final Class<?> fieldType) {
+ this.fieldTypes.put(fieldName, fieldType);
+ }
+
+ void setObjectClass(final Class<? extends ConditionsObject> objectClass) {
+ this.objectClass = objectClass;
+ }
+
+ void setTableName(final String tableName) {
+ this.tableName = tableName;
+ }
+
+ /**
+ * Convert to a string.
+ *
+ * @return This object converted to a string.
+ */
+ @Override
+ public String toString() {
+ final StringBuffer buff = new StringBuffer();
+ buff.append("tableMetaData: tableName = " + this.getTableName());
+ buff.append(", objectClass = " + this.getObjectClass().getCanonicalName());
+ buff.append(", collectionClass = " + this.getCollectionClass().getCanonicalName());
+ buff.append(", fieldNames = ");
+ for (final String field : this.getFieldNames()) {
+ buff.append(field + " ");
+ }
+ buff.setLength(buff.length() - 1);
+ buff.append('\n');
+ return buff.toString();
+ }
+}
Added: java/branches/conditions-HPSJAVA-488/src/test/java/org/hps/conditions/apinew/BaseConditionsObjectCollectionTest.java
=============================================================================
--- java/branches/conditions-HPSJAVA-488/src/test/java/org/hps/conditions/apinew/BaseConditionsObjectCollectionTest.java (added)
+++ java/branches/conditions-HPSJAVA-488/src/test/java/org/hps/conditions/apinew/BaseConditionsObjectCollectionTest.java Fri Apr 17 17:20:40 2015
@@ -0,0 +1,97 @@
+package org.hps.conditions.apinew;
+
+import java.sql.Connection;
+import java.sql.SQLException;
+
+import junit.framework.TestCase;
+
+import org.hps.conditions.api.ConditionsObjectException;
+import org.hps.conditions.database.DatabaseConditionsManager;
+
+public class BaseConditionsObjectCollectionTest extends TestCase {
+
+ /**
+ * A dummy conditions object type.
+ */
+ static class DummyConditionsObject extends BaseConditionsObject {
+
+ public DummyConditionsObject() {
+ }
+
+ DummyConditionsObject(final Connection connection, final TableMetaData tableMetaData) {
+ super(connection, tableMetaData);
+ }
+ }
+
+ /**
+ * A dummy conditions object collection type.
+ */
+ static class DummyConditionsObjectCollection extends BaseConditionsObjectCollection<DummyConditionsObject> {
+ public DummyConditionsObjectCollection() {
+ }
+
+ DummyConditionsObjectCollection(final Connection connection, final TableMetaData tableMetaData)
+ throws SQLException, ConditionsObjectException {
+ super(connection, tableMetaData, -1);
+ }
+ }
+
+ public void testBaseConditionsObjectCollection() throws Exception {
+
+ // Configure the conditions system.
+ final DatabaseConditionsManager manager = DatabaseConditionsManager.getInstance();
+ manager.setConnectionResource("/org/hps/conditions/config/jeremym_dev_connection.prop");
+ manager.setXmlConfig("/org/hps/conditions/config/conditions_database_no_svt.xml");
+ final Connection connection = manager.getConnection();
+
+ // Setup basic table meta data.
+ final TableMetaData tableMetaData = new TableMetaData();
+ tableMetaData.setTableName("dummy");
+ tableMetaData.setFieldNames(new String[] {"collection_id", "dummy"});
+ tableMetaData.setFieldType("collection_id", Integer.class);
+ tableMetaData.setFieldType("dummy", Double.class);
+ tableMetaData.setObjectClass(DummyConditionsObject.class);
+
+ // Create a new collection.
+ final DummyConditionsObjectCollection collection = new DummyConditionsObjectCollection(connection,
+ tableMetaData);
+
+ // Add object to collection.
+ final DummyConditionsObject object1 = new DummyConditionsObject(connection, tableMetaData);
+ object1.setValue("dummy", 1.0);
+ collection.add(object1);
+
+ // Add object to collection.
+ final DummyConditionsObject object2 = new DummyConditionsObject(connection, tableMetaData);
+ object2.setValue("dummy", 2.0);
+ collection.add(object2);
+
+ final int collectionId = 1001;
+
+ // Insert all objects into the database.
+ System.out.println("inserting objects from new collection ID " + collectionId);
+ collection.insertAll(collectionId);
+
+ System.out.println("inserted " + collection.size() + " objects");
+
+ // Create another collection.
+ final DummyConditionsObjectCollection anotherCollection = new DummyConditionsObjectCollection(connection,
+ tableMetaData);
+
+ // Select the previously created objects into this collection by using the collection_id value.
+ anotherCollection.select(collectionId);
+ System.out.println("selected " + anotherCollection.size() + " objects into collection");
+
+ // TODO: change objects in collection and then call updateAll
+ anotherCollection.get(0).setValue("dummy", 3.0);
+ anotherCollection.get(1).setValue("dummy", 4.0);
+
+ // Update all objects.
+ System.out.println("updating objects from collection " + collection.getCollectionId());
+ anotherCollection.updateAll();
+
+ // Delete all objects.
+ System.out.println("deleting objects from collection " + collection.getCollectionId());
+ collection.deleteAll();
+ }
+}
Added: java/branches/conditions-HPSJAVA-488/src/test/java/org/hps/conditions/apinew/BaseConditionsObjectTest.java
=============================================================================
--- java/branches/conditions-HPSJAVA-488/src/test/java/org/hps/conditions/apinew/BaseConditionsObjectTest.java (added)
+++ java/branches/conditions-HPSJAVA-488/src/test/java/org/hps/conditions/apinew/BaseConditionsObjectTest.java Fri Apr 17 17:20:40 2015
@@ -0,0 +1,75 @@
+package org.hps.conditions.apinew;
+
+import java.sql.Connection;
+
+import junit.framework.TestCase;
+
+import org.hps.conditions.database.DatabaseConditionsManager;
+
+public class BaseConditionsObjectTest extends TestCase {
+
+ /**
+ * A dummy conditions object type.
+ */
+ static class DummyConditionsObject extends BaseConditionsObject {
+ DummyConditionsObject(final Connection connection, final TableMetaData tableMetaData) {
+ super(connection, tableMetaData);
+ }
+ }
+
+ /**
+ * Perform basic CRUD operations on the <code>BaseConditionsObject</code> class.
+ *
+ * @throws Exception if some test error occurs
+ */
+ public void testBaseConditionsObject() throws Exception {
+
+ // Configure the conditions system.
+ final DatabaseConditionsManager manager = DatabaseConditionsManager.getInstance();
+ manager.setConnectionResource("/org/hps/conditions/config/jeremym_dev_connection.prop");
+ manager.setXmlConfig("/org/hps/conditions/config/conditions_database_no_svt.xml");
+
+ // Open the database connection.
+ final Connection connection = manager.getConnection();
+
+ // Setup basic table meta data.
+ final TableMetaData tableMetaData = new TableMetaData();
+ tableMetaData.setTableName("dummy");
+ tableMetaData.setFieldNames(new String[] {"collection_id", "dummy"});
+
+ // Insert a new object.
+ final DummyConditionsObject newObject = new DummyConditionsObject(connection, tableMetaData);
+ newObject.setValue("collection_id", 1);
+ newObject.setValue("dummy", 1.0);
+ final boolean inserted = newObject.insert();
+ assertTrue("Insert failed.", inserted);
+ System.out.println("Inserted new object with id " + newObject.getId());
+
+ // Update the same object.
+ newObject.setValue("dummy", 2.0);
+ boolean updated = newObject.update();
+ assertTrue("Update failed.", updated);
+
+ // Update which should be ignored on non-dirty record.
+ updated = newObject.update();
+ assertTrue("Update should not have been executed.", !updated);
+ System.out.println("Update ignored on non-dirty record.");
+
+ // Select into another object using the row ID.
+ final DummyConditionsObject anotherObject = new DummyConditionsObject(connection, tableMetaData);
+ final boolean selected = anotherObject.select(newObject.getId());
+ assertTrue("Select failed.", selected);
+ assertEquals("Select object has wrong row ID.", newObject.getId(), anotherObject.getId());
+ assertEquals("Select object has wrong collcetion ID.", newObject.getValue(Integer.class, "collection_id"),
+ anotherObject.getValue(Integer.class, "collection_id"));
+ assertEquals("Select object has wrong value.", newObject.getValue(Double.class, "dummy"),
+ anotherObject.getValue(Double.class, "dummy"));
+
+ // Delete the object.
+ final boolean deleted = newObject.delete();
+ assertTrue("Delete failed.", deleted);
+
+ // Close the database connection.
+ connection.close();
+ }
+}
|