Author: [log in to unmask] Date: Mon Apr 20 15:47:54 2015 New Revision: 2756 Log: implement conditions object conversion Added: java/branches/conditions-HPSJAVA-488/src/main/java/org/hps/conditions/apinew/AbstractConditionsObjectConverter.java java/branches/conditions-HPSJAVA-488/src/main/java/org/hps/conditions/apinew/ConditionsObjectUtilities.java java/branches/conditions-HPSJAVA-488/src/main/java/org/hps/conditions/apinew/TableRegistry.java java/branches/conditions-HPSJAVA-488/src/main/java/org/hps/conditions/dummy/ java/branches/conditions-HPSJAVA-488/src/main/java/org/hps/conditions/dummy/DummyConditionsObject.java java/branches/conditions-HPSJAVA-488/src/main/java/org/hps/conditions/dummy/DummyConditionsObjectConverter.java java/branches/conditions-HPSJAVA-488/src/main/resources/org/hps/conditions/config/jeremym_dev_connection.prop java/branches/conditions-HPSJAVA-488/src/test/java/org/hps/conditions/apinew/DummyConditionsObjectConverterTest.java Modified: 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 Added: java/branches/conditions-HPSJAVA-488/src/main/java/org/hps/conditions/apinew/AbstractConditionsObjectConverter.java ============================================================================= --- java/branches/conditions-HPSJAVA-488/src/main/java/org/hps/conditions/apinew/AbstractConditionsObjectConverter.java (added) +++ java/branches/conditions-HPSJAVA-488/src/main/java/org/hps/conditions/apinew/AbstractConditionsObjectConverter.java Mon Apr 20 15:47:54 2015 @@ -0,0 +1,178 @@ +package org.hps.conditions.apinew; + +import java.sql.SQLException; + +import org.hps.conditions.api.ConditionsObjectException; +import org.hps.conditions.api.ConditionsRecord; +import org.hps.conditions.api.ConditionsRecord.ConditionsRecordCollection; +import org.hps.conditions.database.DatabaseConditionsManager; +import org.hps.conditions.database.MultipleCollectionsAction; +import org.lcsim.conditions.ConditionsConverter; +import org.lcsim.conditions.ConditionsManager; + +/** + * <p> + * Implementation of default conversion from database tables to a {@link ConditionsObject} class. + * <p> + * This class actually returns collections and not individual objects. + * + * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a> + * @param <T> The type of the returned data which should be a class extending {@link BaseConditionsObjectCollection}. + */ +public abstract class AbstractConditionsObjectConverter<T> implements ConditionsConverter<T> { + + /** + * Create a conditions object collection. + * + * @param conditionsRecord the conditions record + * @param tableMetaData the table data + * @return the conditions object collection + * @throws ConditionsObjectException if there is a problem creating the collection + */ + static final BaseConditionsObjectCollection<?> createCollection(final DatabaseConditionsManager manager, + final ConditionsRecord conditionsRecord, final TableMetaData tableMetaData) + throws ConditionsObjectException { + BaseConditionsObjectCollection<?> collection; + try { + collection = tableMetaData.getCollectionClass().newInstance(); + if (conditionsRecord != null) { + collection.setConnection(manager.getConnection()); + collection.setTableMetaData(tableMetaData); + collection.setCollectionId(conditionsRecord.getCollectionId()); + } + } catch (InstantiationException | IllegalAccessException e) { + throw new ConditionsObjectException("Error creating conditions object collection.", e); + } + return collection; + } + + /** + * The action to take if multiple overlapping conditions sets are found. The default is using the most recently + * updated one. + */ + private MultipleCollectionsAction multipleCollections = MultipleCollectionsAction.LAST_UPDATED; + + /** + * Class constructor. + */ + public AbstractConditionsObjectConverter() { + } + + /** + * Get the conditions data based on the name, e.g. "ecal_channels". The table information is found using the type + * handled by the Converter. + * + * @param conditionsManager the current conditions manager + * @param name the name of the conditions set (maps to table name) + * @return the conditions data + */ + @Override + @SuppressWarnings({"unchecked", "rawtypes"}) + public T getData(final ConditionsManager conditionsManager, final String name) { + + // Get the DatabaseConditionsManager which is required for using this converter. + final DatabaseConditionsManager databaseConditionsManager = (DatabaseConditionsManager) conditionsManager; + + // Setup connection if necessary. + final boolean openedConnection = databaseConditionsManager.openConnection(); + + // Get the TableMetaData from the table name. + final TableMetaData tableMetaData = TableRegistry.getTableRegistry().findByTableName(name); + + // Throw an exception if the table name does not map to a known type. + if (tableMetaData == null) { + throw new RuntimeException(new ConditionsObjectException("No table information found for name: " + name)); + } + + // Get the ConditionsRecordCollection with the run number assignments. + final ConditionsRecordCollection conditionsRecords = databaseConditionsManager.findConditionsRecords(name); + + // The record with the collection information. + ConditionsRecord conditionsRecord = null; + + // Now we need to determine which ConditionsRecord object to use. + if (conditionsRecords.size() == 0) { + // No conditions records were found for the key. + throw new RuntimeException("No conditions were found with key: " + name); + } else if (conditionsRecords.size() == 1) { + // Use the single conditions set that was found. + conditionsRecord = conditionsRecords.get(0); + } else if (conditionsRecords.size() > 1) { + if (this.multipleCollections.equals(MultipleCollectionsAction.LAST_UPDATED)) { + // Use the conditions set with the latest updated date. + conditionsRecord = conditionsRecords.sortedByUpdated().get(conditionsRecords.size() - 1); + } else if (this.multipleCollections.equals(MultipleCollectionsAction.LAST_CREATED)) { + // Use the conditions set with the latest created date. + conditionsRecord = conditionsRecords.sortedByCreated().get(conditionsRecords.size() - 1); + } else if (this.multipleCollections.equals(MultipleCollectionsAction.LATEST_RUN_START)) { + // Use the conditions set with the greatest run start value. + conditionsRecord = conditionsRecords.sortedByRunStart().get(conditionsRecords.size() - 1); + } else if (this.multipleCollections.equals(MultipleCollectionsAction.ERROR)) { + // The converter has been configured to throw an error. + throw new RuntimeException("Multiple ConditionsRecord object found for conditions key " + name); + } + } + + // Create a collection of objects to return. + ConditionsObjectCollection collection = null; + try { + collection = createCollection(databaseConditionsManager, conditionsRecord, tableMetaData); + } catch (final ConditionsObjectException e) { + throw new RuntimeException(e); + } + + DatabaseConditionsManager.getLogger().info("loading conditions set..." + '\n' + conditionsRecord); + + // Select the objects into the collection by the collection ID. + try { + collection.select(conditionsRecord.getCollectionId()); + } catch (ConditionsObjectException | SQLException e) { + throw new RuntimeException("Error creating conditions collection from table " + name + + " with collection ID " + conditionsRecord.getCollectionId(), e); + } + + if (openedConnection) { + // Close connection if one was opened. + databaseConditionsManager.closeConnection(); + } + + return (T) collection; + } + + /** + * Get the multiple collections action. + * + * @return the multiple collections action + */ + public final MultipleCollectionsAction getMultipleCollectionsAction() { + return this.multipleCollections; + } + + /** + * Get the specific type converted by this class. + * + * @return the class that this converter handles + */ + @Override + public abstract Class<T> getType(); + + /** + * Set the action that the converter will use to disambiguate when multiple conditions sets are found. + * + * @param multipleCollections the multiple collections action + */ + final void setMultipleCollectionsAction(final MultipleCollectionsAction multipleCollections) { + this.multipleCollections = multipleCollections; + } + + /** + * Convert object to string. + * + * @return the object converted to string + */ + @Override + public String toString() { + return "ConditionsObjectConverter: type = " + this.getType() + ", multipleCollectionsAction = " + + this.getMultipleCollectionsAction().toString(); + } +} Modified: 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 (original) +++ java/branches/conditions-HPSJAVA-488/src/main/java/org/hps/conditions/apinew/BaseConditionsObject.java Mon Apr 20 15:47:54 2015 @@ -8,6 +8,7 @@ import java.util.Date; import org.hps.conditions.api.ConditionsObjectException; +import org.hps.conditions.database.Field; /** * This is a basic ORM class for performing CRUD (create, read, update, delete) operations on objects in the conditions @@ -50,7 +51,7 @@ /** * The field values. */ - private final FieldValues fields; + private FieldValues fieldValues; /** * The row ID of the object in its table. This will be -1 for new objects that are not in the database. @@ -68,7 +69,7 @@ private TableMetaData tableMetaData; protected BaseConditionsObject() { - this.fields = new FieldValuesMap(); + this.fieldValues = new FieldValuesMap(); } /** @@ -83,7 +84,7 @@ public BaseConditionsObject(final Connection connection, final TableMetaData tableMetaData) { this.connection = connection; this.tableMetaData = tableMetaData; - this.fields = new FieldValuesMap(tableMetaData); + this.fieldValues = new FieldValuesMap(tableMetaData); } /** @@ -98,7 +99,7 @@ public BaseConditionsObject(final Connection connection, final TableMetaData tableMetaData, final FieldValues fields) { this.connection = connection; this.tableMetaData = tableMetaData; - this.fields = fields; + this.fieldValues = fields; } /** @@ -117,7 +118,7 @@ throws ConditionsObjectException, SQLException { this.connection = connection; this.tableMetaData = tableMetaData; - this.fields = new FieldValuesMap(tableMetaData); + this.fieldValues = new FieldValuesMap(tableMetaData); final boolean selected = select(rowId); if (!selected) { throw new ConditionsObjectException("Failed to select data into object using row ID " + rowId); @@ -147,8 +148,9 @@ } @Override - public final int getCollectionId() { - if (this.fields.isNonNull(COLLECTION_ID_FIELD)) { + @Field(names = {"collection_id"}) + public final Integer getCollectionId() { + if (this.fieldValues.isNonNull(COLLECTION_ID_FIELD)) { return getValue(Integer.class, COLLECTION_ID_FIELD); } else { return UNSET_COLLECTION_ID; @@ -157,7 +159,7 @@ @Override public FieldValues getFieldValues() { - return this.fields; + return this.fieldValues; } @Override @@ -172,7 +174,7 @@ @Override public final <T> T getValue(final Class<T> type, final String name) { - return type.cast(this.fields.getValue(type, name)); + return type.cast(this.fieldValues.getValue(type, name)); } @Override @@ -182,12 +184,12 @@ } final StringBuffer sb = new StringBuffer(); sb.append("INSERT INTO " + this.tableMetaData.getTableName() + " ("); - for (final String fieldName : this.fields.getFieldNames()) { + for (final String fieldName : this.fieldValues.getFieldNames()) { sb.append(fieldName + ", "); } sb.setLength(sb.length() - 2); sb.append(") VALUES ("); - for (final Object value : this.fields.getValues()) { + for (final Object value : this.fieldValues.getValues()) { if (value instanceof Date) { sb.append("STR_TO_DATE( '" + DATE_FORMAT.format((Date) value) + "', '%Y-%m-%d %H:%i:%S' ), "); } else { @@ -291,6 +293,11 @@ } @Override + public void setFieldValues(final FieldValues fieldValues) { + this.fieldValues = fieldValues; + } + + @Override public void setId(final int id) { this.id = id; } @@ -302,7 +309,7 @@ @Override public final void setValue(final String name, final Object value) { - this.fields.setValue(name, value); + this.fieldValues.setValue(name, value); this.isDirty = true; } @@ -319,9 +326,9 @@ } final StringBuffer sb = new StringBuffer(); sb.append("UPDATE " + this.tableMetaData.getTableName() + " SET "); - for (final String fieldName : this.fields.getFieldNames()) { + for (final String fieldName : this.fieldValues.getFieldNames()) { sb.append(fieldName + "="); - final Object value = this.fields.getValue(fieldName); + final Object value = this.fieldValues.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' ), "); Modified: 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 (original) +++ java/branches/conditions-HPSJAVA-488/src/main/java/org/hps/conditions/apinew/BaseConditionsObjectCollection.java Mon Apr 20 15:47:54 2015 @@ -6,6 +6,7 @@ import java.sql.SQLException; import java.sql.Statement; import java.util.Collection; +import java.util.Collections; import java.util.Iterator; import java.util.LinkedHashSet; import java.util.Set; @@ -18,7 +19,7 @@ public class BaseConditionsObjectCollection<ObjectType extends ConditionsObject> implements ConditionsObjectCollection<ObjectType> { - private int collectionId; + private int collectionId = BaseConditionsObject.UNSET_COLLECTION_ID; private Connection connection; private final Set<ObjectType> objects = new LinkedHashSet<ObjectType>(); private TableMetaData tableMetaData; @@ -98,7 +99,7 @@ @Override public Collection<ObjectType> getObjects() { - return this.objects; + return Collections.unmodifiableCollection(this.objects); } @Override @@ -137,16 +138,13 @@ this.connection.setAutoCommit(false); insertObjects = this.connection.prepareStatement(updateStatement, Statement.RETURN_GENERATED_KEYS); for (final ObjectType object : this.getObjects()) { + object.setCollectionId(this.collectionId); 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)); - } + final Object value = object.getValue(getTableMetaData().getFieldType(fieldName), fieldName); + System.out.println(fieldName + "=" + value); + insertObjects.setObject(fieldIndex + 1, + object.getValue(getTableMetaData().getFieldType(fieldName), fieldName)); } insertObjects.executeUpdate(); this.connection.commit(); @@ -225,6 +223,20 @@ } @Override + public void setCollectionId(final int collectionId) { + this.collectionId = collectionId; + } + + public void setConnection(final Connection connection) { + this.connection = connection; + } + + @Override + public void setTableMetaData(final TableMetaData tableMetaData) { + this.tableMetaData = tableMetaData; + } + + @Override public int size() { return this.objects.size(); } Modified: 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 (original) +++ java/branches/conditions-HPSJAVA-488/src/main/java/org/hps/conditions/apinew/ConditionsObject.java Mon Apr 20 15:47:54 2015 @@ -17,7 +17,7 @@ /** * @return */ - int getCollectionId(); + Integer getCollectionId(); FieldValues getFieldValues(); @@ -68,6 +68,8 @@ */ void setConnection(Connection connection); + void setFieldValues(FieldValues fieldValues); + void setId(int id); void setTableMetaData(TableMetaData tableMetaData); Modified: 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 (original) +++ java/branches/conditions-HPSJAVA-488/src/main/java/org/hps/conditions/apinew/ConditionsObjectCollection.java Mon Apr 20 15:47:54 2015 @@ -25,6 +25,10 @@ void select(final int collectionId) throws ConditionsObjectException, SQLException; + void setCollectionId(int collectionId); + + void setTableMetaData(TableMetaData tableMetaData); + int size(); void updateAll() throws ConditionsObjectException, SQLException; Added: java/branches/conditions-HPSJAVA-488/src/main/java/org/hps/conditions/apinew/ConditionsObjectUtilities.java ============================================================================= --- java/branches/conditions-HPSJAVA-488/src/main/java/org/hps/conditions/apinew/ConditionsObjectUtilities.java (added) +++ java/branches/conditions-HPSJAVA-488/src/main/java/org/hps/conditions/apinew/ConditionsObjectUtilities.java Mon Apr 20 15:47:54 2015 @@ -0,0 +1,115 @@ +package org.hps.conditions.apinew; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; +import java.util.HashSet; +import java.util.Set; + +import javassist.Modifier; + +import org.hps.conditions.database.Field; +import org.hps.conditions.database.Table; +import org.reflections.Reflections; + +/** + * This is a collection of utility methods for {@link ConditionsObject}. + * + * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a> + */ +public final class ConditionsObjectUtilities { + + /** + * Find all available classes that extend ConditionsObject. + * + * @return The set of all available classes that extend ConditionsObject. + */ + public static Set<Class<? extends ConditionsObject>> findConditionsObjectTypes() { + final Reflections reflections = new Reflections("org.hps.conditions"); + final Set<Class<? extends ConditionsObject>> objectTypes = new HashSet<Class<? extends ConditionsObject>>(); + for (final Class<? extends ConditionsObject> objectType : reflections.getSubTypesOf(ConditionsObject.class)) { + if (Modifier.isAbstract(objectType.getModifiers())) { + continue; + } + if (objectType.getAnnotation(Table.class) == null) { + continue; + } + objectTypes.add(objectType); + } + return objectTypes; + } + + /** + * Get the class for the collection of the ConditionsObject type. + * + * @param type the class of the ConditionsObject + * @return the class of the collection + */ + @SuppressWarnings("unchecked") + public static Class<? extends BaseConditionsObjectCollection<? extends ConditionsObject>> getCollectionType( + final Class<? extends ConditionsObject> type) { + final String collectionClassName = type.getCanonicalName() + "$" + type.getSimpleName() + "Collection"; + Class<?> rawCollectionClass; + try { + rawCollectionClass = Class.forName(collectionClassName); + } catch (final ClassNotFoundException e) { + throw new RuntimeException("The type does not define a nested collection class.", e); + } + if (!BaseConditionsObjectCollection.class.isAssignableFrom(rawCollectionClass)) { + throw new RuntimeException("The class " + rawCollectionClass.getSimpleName() + + " does not extend ConditionsObjectCollection."); + } + return (Class<? extends BaseConditionsObjectCollection<? extends ConditionsObject>>) rawCollectionClass; + } + + /** + * Get the list of database field names for the class. + * + * @param type the class + * @return the list of field names + */ + public static Set<String> getFieldNames(final Class<? extends ConditionsObject> type) { + final Set<String> fieldNames = new HashSet<String>(); + for (final Method method : type.getMethods()) { + System.out.println(method.getName()); + if (!method.getReturnType().equals(Void.TYPE)) { + for (final Annotation annotation : method.getAnnotations()) { + if (annotation.annotationType().equals(Field.class)) { + if (!Modifier.isPublic(method.getModifiers())) { + throw new RuntimeException("The method " + type.getName() + "." + method.getName() + + " has a Field annotation but is not public."); + } + final Field field = (Field) annotation; + for (final String fieldName : field.names()) { + if (fieldName != null && !"".equals(fieldName)) { + System.out.println(" " + fieldName); + fieldNames.add(fieldName); + } + } + } + } + } + } + return fieldNames; + } + + /** + * Get the list of table names for the class. + * + * @param type the class + * @return the list of table names + */ + public static String[] getTableNames(final Class<? extends ConditionsObject> type) { + final Table tableAnnotation = type.getAnnotation(Table.class); + if (tableAnnotation != null) { + return tableAnnotation.names(); + } else { + return new String[] {}; + } + } + + /** + * Do not allow class to be instantiated. + */ + private ConditionsObjectUtilities() { + } +} Modified: 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 (original) +++ java/branches/conditions-HPSJAVA-488/src/main/java/org/hps/conditions/apinew/FieldValues.java Mon Apr 20 15:47:54 2015 @@ -20,6 +20,8 @@ boolean isNonNull(String name); + boolean isNull(String name); + void setValue(String name, Object value); int size(); Modified: 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 (original) +++ java/branches/conditions-HPSJAVA-488/src/main/java/org/hps/conditions/apinew/FieldValuesMap.java Mon Apr 20 15:47:54 2015 @@ -52,6 +52,11 @@ } @Override + public boolean isNull(final String name) { + return this.data.get(name) == null; + } + + @Override public void setValue(final String name, final Object value) { this.data.put(name, value); } Added: java/branches/conditions-HPSJAVA-488/src/main/java/org/hps/conditions/apinew/TableRegistry.java ============================================================================= --- java/branches/conditions-HPSJAVA-488/src/main/java/org/hps/conditions/apinew/TableRegistry.java (added) +++ java/branches/conditions-HPSJAVA-488/src/main/java/org/hps/conditions/apinew/TableRegistry.java Mon Apr 20 15:47:54 2015 @@ -0,0 +1,172 @@ +package org.hps.conditions.apinew; + +import java.lang.annotation.Annotation; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.hps.conditions.database.Field; + +/** + * This is a registry providing a map between tables and their meta-data. + * + * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a> + */ +@SuppressWarnings("serial") +public final class TableRegistry extends HashMap<String, TableMetaData> { + + /** + * Maps collection types to table meta data. + */ + static class CollectionTypeMap extends + HashMap<Class<? extends BaseConditionsObjectCollection<?>>, List<TableMetaData>> { + + /** + * Add a mapping between a collection type and table meta data. + * + * @param type the collection type + * @param metaData the table meta data + */ + void add(final Class<? extends BaseConditionsObjectCollection<?>> type, final TableMetaData metaData) { + if (this.get(type) == null) { + this.put(type, new ArrayList<TableMetaData>()); + } + this.get(type).add(metaData); + } + } + + /** + * Maps types to table meta data. + */ + static class ObjectTypeMap extends HashMap<Class<? extends ConditionsObject>, List<TableMetaData>> { + /** + * Add a connection between an object type and table meta data. + * + * @param type the object type + * @param metaData the table meta data + */ + void add(final Class<? extends ConditionsObject> type, final TableMetaData metaData) { + if (this.get(type) == null) { + this.put(type, new ArrayList<TableMetaData>()); + } + this.get(type).add(metaData); + } + } + + static TableRegistry instance = null; + + /** + * Create a new table meta data registry. + * + * @return the meta data registry + */ + static TableRegistry create() { + final TableRegistry registry = new TableRegistry(); + for (final Class<? extends ConditionsObject> objectType : ConditionsObjectUtilities.findConditionsObjectTypes()) { + + // Get the collection type. + final Class<? extends BaseConditionsObjectCollection<?>> collectionType = ConditionsObjectUtilities + .getCollectionType(objectType); + + // Get the list of field names. + final Set<String> fieldNames = ConditionsObjectUtilities.getFieldNames(objectType); + + // Create map of fields to their types. + final Map<String, Class<?>> fieldTypes = new HashMap<String, Class<?>>(); + for (final Method method : objectType.getMethods()) { + if (!method.getReturnType().equals(Void.TYPE)) { + for (final Annotation annotation : method.getAnnotations()) { + if (annotation.annotationType().equals(Field.class)) { + final Field field = (Field) annotation; + for (final String fieldName : field.names()) { + fieldTypes.put(fieldName, method.getReturnType()); + } + } + } + } + } + + for (final String name : ConditionsObjectUtilities.getTableNames(objectType)) { + // Create a meta data mapping for each table name in the class description. + final TableMetaData data = new TableMetaData(name, name, objectType, collectionType, fieldNames, + fieldTypes); + registry.put(name, data); + registry.objectTypeMap.add(objectType, data); + registry.collectionTypeMap.add(collectionType, data); + } + } + return registry; + } + + public synchronized static TableRegistry getTableRegistry() { + if (instance == null) { + instance = TableRegistry.create(); + } + return instance; + } + + /** + * Map between collection types and meta data. + */ + private final CollectionTypeMap collectionTypeMap = new CollectionTypeMap(); + + /** + * Map between object types and meta data. + */ + private final ObjectTypeMap objectTypeMap = new ObjectTypeMap(); + + /** + * Class should not be directly instantiated. + * <p> + * Use the {@link #create()} method instead. + */ + private TableRegistry() { + } + + /** + * Find meta data by collection type. + * + * @param collectionType the collection type + * @return the meta data or <code>null</code> if none exists. + */ + List<TableMetaData> findByCollectionType(final Class<?> collectionType) { + return this.collectionTypeMap.get(collectionType); + } + + /** + * Find meta data by object type. + * + * @param objectType the object type + * @return the meta data or <code>null</code> if none exists. + */ + List<TableMetaData> findByObjectType(final Class<? extends ConditionsObject> objectType) { + return this.objectTypeMap.get(objectType); + } + + /** + * Find meta data by table name. + * + * @param name the table name + * @return the meta data or <code>null</code> if none exists + */ + TableMetaData findByTableName(final String name) { + return this.get(name); + } + + /** + * Convert this object to a string. + * + * @return this object converted to a string + */ + @Override + public String toString() { + final StringBuffer buff = new StringBuffer(); + for (final TableMetaData tableMetaData : this.values()) { + buff.append(tableMetaData.toString()); + } + return buff.toString(); + } +} Added: java/branches/conditions-HPSJAVA-488/src/main/java/org/hps/conditions/dummy/DummyConditionsObject.java ============================================================================= --- java/branches/conditions-HPSJAVA-488/src/main/java/org/hps/conditions/dummy/DummyConditionsObject.java (added) +++ java/branches/conditions-HPSJAVA-488/src/main/java/org/hps/conditions/dummy/DummyConditionsObject.java Mon Apr 20 15:47:54 2015 @@ -0,0 +1,40 @@ +package org.hps.conditions.dummy; + +import java.sql.Connection; +import java.sql.SQLException; + +import org.hps.conditions.api.ConditionsObjectException; +import org.hps.conditions.apinew.BaseConditionsObject; +import org.hps.conditions.apinew.BaseConditionsObjectCollection; +import org.hps.conditions.apinew.TableMetaData; +import org.hps.conditions.database.Field; +import org.hps.conditions.database.Table; + +/** + * A dummy conditions object type. + */ +@Table(names = {"dummy"}) +public final class DummyConditionsObject extends BaseConditionsObject { + + public static class DummyConditionsObjectCollection extends BaseConditionsObjectCollection<DummyConditionsObject> { + public DummyConditionsObjectCollection() { + } + + DummyConditionsObjectCollection(final Connection connection, final TableMetaData tableMetaData) + throws SQLException, ConditionsObjectException { + super(connection, tableMetaData, -1); + } + } + + public DummyConditionsObject() { + } + + public DummyConditionsObject(final Connection connection, final TableMetaData tableMetaData) { + super(connection, tableMetaData); + } + + @Field(names = {"dummy"}) + public Double getDummy() { + return this.getValue(Double.class, "dummy"); + } +} Added: java/branches/conditions-HPSJAVA-488/src/main/java/org/hps/conditions/dummy/DummyConditionsObjectConverter.java ============================================================================= --- java/branches/conditions-HPSJAVA-488/src/main/java/org/hps/conditions/dummy/DummyConditionsObjectConverter.java (added) +++ java/branches/conditions-HPSJAVA-488/src/main/java/org/hps/conditions/dummy/DummyConditionsObjectConverter.java Mon Apr 20 15:47:54 2015 @@ -0,0 +1,12 @@ +package org.hps.conditions.dummy; + +import org.hps.conditions.apinew.AbstractConditionsObjectConverter; +import org.hps.conditions.dummy.DummyConditionsObject.DummyConditionsObjectCollection; + +public final class DummyConditionsObjectConverter extends + AbstractConditionsObjectConverter<DummyConditionsObjectCollection> { + @Override + public Class<DummyConditionsObjectCollection> getType() { + return DummyConditionsObjectCollection.class; + } +} Added: java/branches/conditions-HPSJAVA-488/src/main/resources/org/hps/conditions/config/jeremym_dev_connection.prop ============================================================================= --- java/branches/conditions-HPSJAVA-488/src/main/resources/org/hps/conditions/config/jeremym_dev_connection.prop (added) +++ java/branches/conditions-HPSJAVA-488/src/main/resources/org/hps/conditions/config/jeremym_dev_connection.prop Mon Apr 20 15:47:54 2015 @@ -0,0 +1,4 @@ +hostname = localhost +user = root +password = derp +database = hps_conditions_dev Added: java/branches/conditions-HPSJAVA-488/src/test/java/org/hps/conditions/apinew/DummyConditionsObjectConverterTest.java ============================================================================= --- java/branches/conditions-HPSJAVA-488/src/test/java/org/hps/conditions/apinew/DummyConditionsObjectConverterTest.java (added) +++ java/branches/conditions-HPSJAVA-488/src/test/java/org/hps/conditions/apinew/DummyConditionsObjectConverterTest.java Mon Apr 20 15:47:54 2015 @@ -0,0 +1,47 @@ +package org.hps.conditions.apinew; + +import junit.framework.TestCase; + +import org.hps.conditions.database.DatabaseConditionsManager; +import org.hps.conditions.dummy.DummyConditionsObject; +import org.hps.conditions.dummy.DummyConditionsObject.DummyConditionsObjectCollection; +import org.hps.conditions.dummy.DummyConditionsObjectConverter; + +/** + * @author <a href="mailto:[log in to unmask]">Jeremy McCormick</a> + */ +public class DummyConditionsObjectConverterTest extends TestCase { + + public void testConditionsObjectConverter() throws Exception { + + 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"); + manager.registerConditionsConverter(new DummyConditionsObjectConverter()); + manager.setDetector("HPS-dummy-detector", 1); + manager.openConnection(); + + final TableMetaData tableMetaData = TableRegistry.getTableRegistry().findByTableName("dummy"); + + final DummyConditionsObjectCollection newCollection = new DummyConditionsObjectCollection(); + newCollection.setTableMetaData(tableMetaData); + newCollection.setConnection(manager.getConnection()); + + final DummyConditionsObject object = new DummyConditionsObject(manager.getConnection(), tableMetaData); + object.setValue("dummy", 1.2345); + newCollection.add(object); + + try { + newCollection.insertAll(1002); + + final DummyConditionsObjectCollection readCollection = manager.getCachedConditions( + DummyConditionsObjectCollection.class, "dummy").getCachedData(); + + System.out.println("got dummy collection " + readCollection.getCollectionId() + " with " + + readCollection.size() + " objects"); + } finally { + System.out.println("deleting collection " + newCollection.getCollectionId()); + newCollection.deleteAll(); + } + } +}