Java tutorial
/* * Copyright 2003 Draagon Software LLC. All Rights Reserved. * * This software is the proprietary information of Draagon Software LLC. * Use is subject to license terms. */ package com.draagon.meta.manager; //import com.draagon.meta.manager.db.ObjectMapping; //import com.draagon.meta.manager.db.MappingHandler; import com.draagon.meta.field.MetaField; import com.draagon.meta.loader.MetaDataLoader; import com.draagon.meta.object.MetaObjectNotFoundException; import com.draagon.meta.object.MetaObject; import com.draagon.meta.attr.MetaAttributeNotFoundException; import com.draagon.meta.*; import com.draagon.meta.manager.exp.Expression; import com.draagon.meta.manager.exp.ExpressionGroup; import com.draagon.meta.manager.exp.ExpressionOperator; import com.draagon.meta.manager.exp.Range; import com.draagon.meta.manager.exp.SortOrder; import org.apache.commons.logging.Log; import org.apache.commons.logging.LogFactory; import java.util.*; //import javax.servlet.*; /** * The Object Manager Base is able to add, update, delete, * and retrieve objects of those types from a datastore. */ public abstract class ObjectManager { private static Log log = LogFactory.getLog(ObjectManager.class); public final static String IS_KEY = "isKey"; public final static String IS_READONLY = "isReadOnly"; public final static String AUTO = "auto"; public final static String AUTO_CREATE = "create"; public final static String AUTO_UPDATE = "update"; public final static int CREATE = 1; public final static int UPDATE = 2; public final static int DELETE = 3; public static final int AUTO_NONE = 0; public static final int AUTO_PRIOR = 1; public static final int AUTO_DURING = 2; public static final int AUTO_POST = 3; //private MappingHandler mMappingHandler = null; public ObjectManager() { } /////////////////////////////////////////////////////// // MANAGEMENT METHODS // /** * Initializes the ObjectManager */ public void init() throws Exception { log.info("Object Manager " + toString() + " initialized"); } /** * Destroys the Object Manager */ public void destroy() { log.info("Object Manager " + toString() + " destroyed"); } /////////////////////////////////////////////////////// // CONNECTION HANDLING METHODS // /** * Retrieves a connection object representing the datastore */ public abstract ObjectConnection getConnection() throws MetaException; public abstract void releaseConnection(ObjectConnection oc) throws MetaException; /////////////////////////////////////////////////////// // ABSTRACT PERSISTENCE METHODS // /** Is this a createable class */ public abstract boolean isCreateableClass(MetaObject mc); /** Is this a readable class */ public abstract boolean isReadableClass(MetaObject mc); /** Gets the update mapping to the DB */ public abstract boolean isUpdateableClass(MetaObject mc); /** Gets the delete mapping to the DB */ public abstract boolean isDeleteableClass(MetaObject mc); protected String getPersistenceAttribute(MetaData md, String name) { try { if (md.hasAttribute(name)) return (String) md.getAttribute(name); } catch (MetaAttributeNotFoundException e) { throw new RuntimeException("[" + md + "] had attribute [" + name + "], but threw exception reading it", e); } return null; } protected boolean isReadOnly(MetaData md) { try { if ("true".equals(md.getAttribute(IS_READONLY))) return true; } catch (MetaAttributeNotFoundException e) { } return false; } /** * Gets an objects reference which can be used to later load the object */ public ObjectRef getObjectRef(Object obj) { MetaObject mc = MetaDataLoader.findMetaObject(obj); Collection<MetaField> keys = getPrimaryKeys(mc); if (keys.size() == 0) throw new IllegalArgumentException( "MetaClass [" + mc + "] has no primary keys, so no object reference is available"); String[] ids = new String[keys.size()]; int j = 0; for (Iterator<MetaField> i = keys.iterator(); i.hasNext(); j++) { MetaField f = i.next(); ids[j] = f.getString(obj); } return new ObjectRef(mc, ids); } /** * Gets an object reference which can be used to later load the object, based on the string reference */ public ObjectRef getObjectRef(String refStr) { return new ObjectRef(refStr); } /** * Gets the object by the id; throws exception if it did not exist */ public abstract Object getObjectByRef(ObjectConnection c, String refStr) throws MetaException; /** * Load the specified object from the datastore */ public abstract void loadObject(ObjectConnection c, Object obj) throws MetaException; /** * Add the specified object to the datastore */ public abstract void createObject(ObjectConnection c, Object obj) throws MetaException; /** * Update the specified object in the datastore */ public abstract void updateObject(ObjectConnection c, Object obj) throws MetaException; /** * Delete the specified object from the datastore */ public abstract void deleteObject(ObjectConnection c, Object obj) throws MetaException; /////////////////////////////////////////////////////// // DEFAULT IMPEMENTATIONS // May be overridden for enhanced performance @SuppressWarnings("unchecked") protected List<MetaField> getAutoFields(MetaObject mc) { final String KEY = "getAutoFields()"; ArrayList<MetaField> auto = (ArrayList<MetaField>) mc.getCacheValue(KEY); if (auto == null) { auto = new ArrayList<MetaField>(); for (MetaField f : mc.getMetaFields()) { if (f.hasAttribute(AUTO)) auto.add(f); } mc.setCacheValue(KEY, auto); } return auto; } protected void handleAutoFields(ObjectConnection c, MetaObject mc, Object obj, int state, int action) throws MetaException { for (MetaField f : getAutoFields(mc)) { Object auto = f.getAttribute(AUTO); handleAutoField(c, mc, f, obj, auto, state, action); } } public void handleAutoField(ObjectConnection c, MetaObject mc, MetaField mf, Object obj, Object auto, int state, int action) throws MetaException { if (state == AUTO_PRIOR) { if (AUTO_CREATE.equals(auto) && action == CREATE) { mf.setLong(obj, new Long(System.currentTimeMillis())); } else if (AUTO_UPDATE.equals(auto)) { mf.setLong(obj, new Long(System.currentTimeMillis())); } } } public void prePersistence(ObjectConnection c, MetaObject mc, Object obj, int action) throws MetaException { handleAutoFields(c, mc, obj, AUTO_PRIOR, action); } public void postPersistence(ObjectConnection c, MetaObject mc, Object obj, int action) throws MetaException { handleAutoFields(c, mc, obj, AUTO_POST, action); if (action == CREATE) { if (mc instanceof StateAwareMetaObject) { // Update the state of the Object ((StateAwareMetaObject) mc).setNew(obj, false); ((StateAwareMetaObject) mc).setModified(obj, false); ((StateAwareMetaObject) mc).setDeleted(obj, false); } } else if (action == UPDATE) { // Update the state of the Object if (mc instanceof StateAwareMetaObject) { ((StateAwareMetaObject) mc).setNew(obj, false); ((StateAwareMetaObject) mc).setModified(obj, false); ((StateAwareMetaObject) mc).setDeleted(obj, false); } } else if (action == DELETE) { if (mc instanceof StateAwareMetaObject) { ((StateAwareMetaObject) mc).setDeleted(obj, true); } } } /** * Determines whether the MetaField is a key */ public boolean isPrimaryKey(MetaField mf) { try { if ("true".equals(mf.getAttribute(IS_KEY))) return true; } catch (MetaAttributeNotFoundException e) { } return false; } /** * Retrieves a new object of the specified class */ public Object getNewObject(MetaObject mc) throws PersistenceException { Object o = mc.newInstance(); attachManager(o); return o; } /** * Attaches the object to the specified meta manager */ public void attachManager(Object obj) { MetaObject mc = getMetaObjectFor(obj); if (mc instanceof ManagerAwareMetaObject) { ((ManagerAwareMetaObject) mc).attachManager(this, obj); } } /** * Verifies the object belongs to this ObjectManager */ protected void verifyObjectManager(Object obj) throws PersistenceException { if (obj == null) throw new IllegalArgumentException("Cannot persist a null object"); MetaObject mc = getMetaObjectFor(obj); if (!(mc instanceof ManagerAwareMetaObject)) return; ManagerAwareMetaObject mmc = (ManagerAwareMetaObject) mc; ObjectManager mm = mmc.getManager(obj); // WARNING: Do we care?! // Verify that it is the same object manager if (mm != null && !mm.equals(this)) throw new PersistenceException("This object is attached to a different Object Manager [" + mm + "]"); // If not attached, then attach it if (mm == null) mmc.attachManager(this, obj); } /** * Retrieves the fields of a MetaClass which are keys */ @SuppressWarnings("unchecked") public Collection<MetaField> getPrimaryKeys(MetaObject mc) //throws MetaException { final String KEY = "getPrimaryKeys()"; ArrayList<MetaField> fields = (ArrayList<MetaField>) mc.getCacheValue(KEY); if (fields == null) { fields = new ArrayList<MetaField>(); for (Iterator i = mc.getMetaFields().iterator(); i.hasNext();) { MetaField f = (MetaField) i.next(); if (isPrimaryKey(f)) fields.add(f); } mc.setCacheValue(KEY, fields); } //if ( fields.size() == 0 ) // throw new RuntimeException( "No keys found for MetaClass [" + mc + "]" ); return fields; } /** * Get all objects of the specified kind from the datastore */ /*public Collection getObjects( ObjectConnection c, MetaClass mc, Collection fields ) throws MetaException { return getObjects( c, mc, fields, new QueryOptions() ); }*/ /** * Stores the specified object by adding, updating, or deleting */ public void storeObject(ObjectConnection c, Object obj) throws PersistenceException { StateAwareMetaObject pmc = getStatefulMetaClass(obj); if (pmc.isNew(obj)) createObject(c, obj); else if (pmc.isModified(obj)) updateObject(c, obj); else if (pmc.isDeleted(obj)) deleteObject(c, obj); } /** * Retrieves a persistable metaclass from the given object */ protected StateAwareMetaObject getStatefulMetaClass(Object obj) { MetaObject mc = getMetaObjectFor(obj); if (!(mc instanceof StateAwareMetaObject)) return null; return (StateAwareMetaObject) mc; } /** * Gets the object by the reference; throws exception if it did not exist */ /*public Object getObjectByRef( ObjectConnection c, String refStr ) throws MetaException { ObjectRef ref = getObjectRef( refStr ); Collection fields = getReadableFields( ref.getMetaClass() ); return getObjectByRef( c, fields, refStr ); }*/ /** Gets the total count of objects */ public long getObjectsCount(ObjectConnection c, MetaObject mc) throws MetaException { return getObjectsCount(c, mc, null); } /** Gets the total count of objects with the specified options */ public long getObjectsCount(ObjectConnection c, MetaObject mc, Expression exp) throws MetaException { Collection<MetaField> fields = new ArrayList<MetaField>(); fields.add(getPrimaryKeys(mc).iterator().next()); QueryOptions options = new QueryOptions(exp); options.setFields(fields); return getObjects(c, mc, new QueryOptions(exp)).size(); } /** * Get all objects of the specified kind from the datastore */ public Collection<?> getObjects(ObjectConnection c, MetaObject mc) throws MetaException { // Collection fields = getReadableFields( mc ); return getObjects(c, mc, new QueryOptions()); } /** * Get all objects of the specified kind from the datastore */ public abstract Collection<?> getObjects(ObjectConnection c, MetaObject mc, QueryOptions options) throws MetaException; /* { Collection fields = null; if ( options.getWriteableOnly() ) fields = getWriteableFields( mc ); else fields = getReadableFields( mc ); return getObjects( c, mc, fields, options ); }*/ /** * Get all objects of the specified kind from the datastore */ /*public Collection getObjects( ObjectConnection c, MetaClass mc, QueryOptions options ) throws MetaException { Collection results = getObjects( c, mc, fields ); Expression exp = options.getExpression(); SortOrder sort = options.getSortOrder(); Range range = options.getRange(); if ( exp != null ) results = filterObjects( results, exp ); if ( sort != null ) results = sortObjects( results, sort ); if ( range != null ) results = clipObjects( results, range ); if( options.isDistinct() ) results = distinctObjects( results ); return results; }*/ /** * Loads the specified object from the datastore */ /*public void loadObject( ObjectConnection c, Object obj ) throws MetaException { Collection fields = getReadableFields( getClassForObject( obj )); loadObject( c, fields, obj ); }*/ /** * Loads the specified fields for the objects from the datastore */ /*public void loadObjects( ObjectConnection c, Collection fields, Collection objs ) throws MetaException { for( Iterator i = objs.iterator(); i.hasNext(); ) loadObject( c, fields, i.next() ); }*/ /** * Loads the specified objects from the datastore */ public void loadObjects(ObjectConnection c, Collection<?> objs) throws MetaException { for (Iterator<?> i = objs.iterator(); i.hasNext();) { Object obj = i.next(); //Collection fields = getReadableFields( getClassForObject( obj )); loadObject(c, obj); } } /** * Add the specified objects to the datastore */ public void createObjects(ObjectConnection c, Collection<?> objs) throws MetaException { for (Iterator<?> i = objs.iterator(); i.hasNext();) createObject(c, i.next()); } /** * Update the specified objects in the datastore */ public void updateObjects(ObjectConnection c, Collection<?> objs) throws MetaException { for (Iterator<?> i = objs.iterator(); i.hasNext();) updateObject(c, i.next()); } /** * Delete the specified object from the datastore */ public void deleteObjectByRef(ObjectConnection c, String ref) throws MetaException { deleteObject(c, getObjectByRef(c, ref)); } /** * Delete the specified objects from the datastore */ public int deleteObjects(ObjectConnection c, Collection<?> objs) throws MetaException { int j = 0; for (Iterator<?> i = objs.iterator(); i.hasNext();) { deleteObject(c, i.next()); j++; } return j; } /** * Delete the objects from the datastore where the field has the specified value */ public int deleteObjects(ObjectConnection c, MetaObject mc, Expression exp) throws MetaException { return deleteObjects(c, getObjects(c, mc, new QueryOptions(exp))); } /** * Stores all objecs in the Collection by adding or updating */ public void storeObjects(ObjectConnection c, Collection<?> objs) throws MetaException { for (Iterator<?> i = objs.iterator(); i.hasNext();) storeObject(c, i.next()); } /////////////////////////////////////////////////////// // HELPER METHODS // May be overridden for enhanced performance /** * Sorts the specified objects by the provided sort order */ @SuppressWarnings("unchecked") public static Collection<Object> sortObjects(Collection<Object> objs, SortOrder sort) throws MetaException { if (objs.size() == 0 || sort.getOrder() == SortOrder.NONE) return objs; ArrayList<Object> a = new ArrayList<Object>(); a.addAll(0, objs); ObjectComparator comp = new ObjectComparator(sort); Collections.sort(a, comp); return a; } /** * Retrieves the fields of a MetaClass which are persistable * and have been modified. */ protected Collection<MetaField> getModifiedPersistableFields(StateAwareMetaObject smc, Collection<MetaField> fields, Object o) { List<MetaField> dirtyFields = new ArrayList<MetaField>(); // Iterate each field on the object that is updateable and see if anything has changed for (MetaField f : fields) { if (smc.isFieldModified(f, o)) { dirtyFields.add(f); } } return dirtyFields; } /** * Gets the SQL WHERE clause for the fields of a class */ private static boolean getExpressionResult(MetaObject mc, Expression exp, Object obj) throws MetaException { if (exp instanceof ExpressionGroup) { return getExpressionResult(mc, ((ExpressionGroup) exp).getGroup(), obj); } else if (exp instanceof ExpressionOperator) { ExpressionOperator oper = (ExpressionOperator) exp; boolean a = getExpressionResult(mc, oper.getExpressionA(), obj); boolean b = getExpressionResult(mc, oper.getExpressionB(), obj); boolean rc = false; if (oper.getOperator() == ExpressionOperator.AND) rc = a & b; else rc = a | b; //ystem.out.println( "[" + oper.getExpressionA() + "](" + a + ") {" + oper.getOperator() + "} [" + oper.getExpressionB() + "](" + b + ") = " + rc ); return rc; } else if (exp.isSpecial()) { throw new MetaException("Unsupported Special Expression [" + exp + "]"); } else { MetaField f = mc.getMetaField(exp.getField()); Object val = f.getObject(obj); Object val2 = exp.getValue(); int condition = exp.getCondition(); if (condition == Expression.EQUAL || condition == Expression.NOT_EQUAL || condition == Expression.GREATER || condition == Expression.LESSER || condition == Expression.EQUAL_GREATER || condition == Expression.EQUAL_LESSER) { return compareValue(val, val2, condition); } else if (condition == Expression.CONTAIN || condition == Expression.NOT_CONTAIN || condition == Expression.START_WITH || condition == Expression.NOT_START_WITH || condition == Expression.END_WITH || condition == Expression.NOT_END_WITH || condition == Expression.EQUALS_IGNORE_CASE) { String s1 = (val == null) ? null : val.toString(); String s2 = (val2 == null) ? null : val2.toString(); if (s1 == null || s2 == null) return false; boolean rc = compareString(s1.toLowerCase(), s2.toLowerCase(), condition); //ystem.out.println( "[" + s1 + "] (" + condition + ") [" + s2 + "] = " + rc ); return rc; } else throw new MetaException("Unsupported Expression Condition (" + Expression.condStr(condition) + ") on Expression [" + exp + "]"); } } protected static boolean compareString(String s1, String s2, int condition) { switch (condition) { case Expression.CONTAIN: if (s1.indexOf(s2) >= 0) return true; return false; case Expression.NOT_CONTAIN: if (s1.indexOf(s2) < 0) return true; return false; case Expression.START_WITH: return s1.startsWith(s2); case Expression.NOT_START_WITH: return !s1.startsWith(s2); case Expression.END_WITH: return s1.endsWith(s2); case Expression.NOT_END_WITH: return !s1.endsWith(s2); case Expression.EQUALS_IGNORE_CASE: return s1.equalsIgnoreCase(s2); default: throw new IllegalStateException( "compareString with unsupported condition type (" + Expression.condStr(condition) + ")"); } } protected static boolean compareValue(Object val, Object val2, int condition) { // If it's a collection, then iterate the whole array if (val2 instanceof Collection) { // Has to be EQUAL or NOT EQUAL if (condition != Expression.EQUAL && condition != Expression.NOT_EQUAL) { throw new IllegalArgumentException( "Can only compare with EQUAL or NOT EQUAL against a collection!"); } // Iterate each value in the collection for (Object v : ((Collection<?>) val2)) { // Get the resulting condition boolean ret = compareValue(val, v, condition); // return true if there are any matches if (condition == Expression.EQUAL && ret) return true; // if looking for not equal, return false when finding the first one else if (condition == Expression.NOT_EQUAL && !ret) return false; } // Return true or false based on the condition if (condition == Expression.EQUAL) return false; else if (condition == Expression.NOT_EQUAL) return true; else throw new IllegalStateException("This has to be EQUAL or NOT EQUAL"); } int result = 0; if (val == null || val2 == null) { if (val == null && val2 == null) result = 0; else if (val == null) result = -1; else result = 1; } else if (val instanceof Boolean) { if (((Boolean) val).equals(val2)) result = 0; else result = 1; } else if (val instanceof Byte) { Byte v = (val2 instanceof Byte) ? (Byte) val2 : new Byte(val2.toString()); result = ((Byte) val).compareTo(v); } else if (val instanceof Short) { Short v = (val2 instanceof Short) ? (Short) val2 : new Short(val2.toString()); result = ((Short) val).compareTo(v); } else if (val instanceof Integer) { Integer v = (val2 instanceof Integer) ? (Integer) val2 : new Integer(val2.toString()); result = ((Integer) val).compareTo(v); } else if (val instanceof Long) { Long v = (val2 instanceof Long) ? (Long) val2 : new Long(val2.toString()); result = ((Long) val).compareTo(v); } else if (val instanceof Float) { Float v = (val2 instanceof Float) ? (Float) val2 : new Float(val2.toString()); result = ((Float) val).compareTo(v); } else if (val instanceof Double) { Double v = (val2 instanceof Double) ? (Double) val2 : new Double(val2.toString()); result = ((Double) val).compareTo(v); } else if (val instanceof Date) { Date v = (val2 instanceof Date) ? (Date) val2 : new Date(Long.parseLong(val2.toString())); result = ((Date) val).compareTo(v); } else { result = val.toString().toLowerCase().compareTo(val2.toString().toLowerCase()); } switch (condition) { case Expression.EQUAL: if (result == 0) return true; else return false; case Expression.GREATER: if (result > 0) return true; else return false; case Expression.LESSER: if (result < 0) return true; else return false; case Expression.EQUAL_GREATER: if (result >= 0) return true; else return false; case Expression.EQUAL_LESSER: if (result <= 0) return true; else return false; case Expression.NOT_EQUAL: if (result != 0) return true; else return false; default: throw new IllegalArgumentException( "Invalid expression condition [" + Expression.condStr(condition) + "]"); } } /** * Filters the specified objects by the provided expression */ public static Collection<Object> filterObjects(Collection<Object> objs, Expression exp) throws MetaException { ArrayList<Object> a = new ArrayList<Object>(); // Check each object for validity for (Object o : objs) { MetaObject mc = MetaDataLoader.findMetaObject(o); if (getExpressionResult(mc, exp, o)) { //ystem.out.println( "ADDING: " + o ); a.add(o); } } return a; } /** * Clips the specified objects by the provided range */ public static Collection<Object> clipObjects(Collection<Object> objs, Range range) throws MetaException { ArrayList<Object> a = new ArrayList<Object>(); int j = 1; for (Object o : objs) { if (j >= range.getStart() && j <= range.getEnd()) a.add(o); } return a; } /** * Clips the specified objects by the provided range */ public static Collection<Object> distinctObjects(Collection<?> objs) throws MetaException { // TODO: Check this, as I don't think it works! ArrayList<Object> a = new ArrayList<Object>(objs); for (Iterator<Object> i = a.iterator(); i.hasNext();) { Object o = i.next(); // Find the first index of the object int fi = a.indexOf(o); // Remove all objects of the same value int li = 0; while ((li = a.lastIndexOf(o)) != fi) a.remove(li); } return a; } /** * Attempts to retrieve the MetaClass for a specified object, * and throws an exception if one does not exist */ public MetaObject getMetaObjectFor(Object o) throws MetaObjectNotFoundException { MetaObject mc = MetaDataLoader.findMetaObject(o); if (mc == null) throw new MetaObjectNotFoundException("No MetaClass exists for object [" + o + "]", o); return mc; } /////////////////////////////////////////////////////// // OBJECT QUERY LANGUAGE METHODS // public abstract int execute(ObjectConnection c, String query, Collection<?> arguments) throws MetaException; public abstract Collection<?> executeQuery(ObjectConnection c, String query, Collection<?> arguments) throws MetaException; /////////////////////////////////////////////////////// // TO STRING METHOD public String toString() { return "Unknown"; } }