From aedc34d55462a75e329bbf342251ff6504cd117e Mon Sep 17 00:00:00 2001 From: Benjamin Culkin Date: Sun, 19 May 2024 17:56:33 -0400 Subject: Initial import from SVN --- .../main/java/net/wotonomy/access/EOEntity.java | 637 +++++++++++++++++++++ 1 file changed, 637 insertions(+) create mode 100644 projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOEntity.java (limited to 'projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOEntity.java') diff --git a/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOEntity.java b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOEntity.java new file mode 100644 index 0000000..4adc4a1 --- /dev/null +++ b/projects/net.wotonomy.persistence/src/main/java/net/wotonomy/access/EOEntity.java @@ -0,0 +1,637 @@ +/* + Wotonomy: OpenStep design patterns for pure Java applications. + Copyright (C) 2001 Michael Powers + + This library is free software; you can redistribute it and/or + modify it under the terms of the GNU Lesser General Public + License as published by the Free Software Foundation; either + version 2.1 of the License, or (at your option) any later version. + + This library is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + Lesser General Public License for more details. + + You should have received a copy of the GNU Lesser General Public + License along with this library; if not, see http://www.gnu.org + */ +package net.wotonomy.access; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.util.Map; + +import net.wotonomy.control.EOAndQualifier; +import net.wotonomy.control.EOClassDescription; +import net.wotonomy.control.EOFetchSpecification; +import net.wotonomy.control.EOGenericRecord; +import net.wotonomy.control.EOGlobalID; +import net.wotonomy.control.EOIntegralKeyGlobalID; +import net.wotonomy.control.EOKeyGlobalID; +import net.wotonomy.control.EOKeyValueArchiver; +import net.wotonomy.control.EOKeyValueQualifier; +import net.wotonomy.control.EOKeyValueUnarchiver; +import net.wotonomy.control.EOQualifier; +import net.wotonomy.control.EOVectorKeyGlobalID; +import net.wotonomy.foundation.NSArray; +import net.wotonomy.foundation.NSDictionary; +import net.wotonomy.foundation.NSKeyValueCoding; +import net.wotonomy.foundation.NSMutableArray; +import net.wotonomy.foundation.NSMutableDictionary; +import net.wotonomy.foundation.NSPropertyListSerialization; + +/** +* An EOEntity is a mapping between a Java class and a database table or view. +* It indicates which attributes should be fetched from the table/view, what +* attributes are part of the primary key, what class the entity should map to. +* +* @author ezamudio@nasoft.com +* @author $Author: cgruber $ +* @version $Revision: 894 $ +*/ +public class EOEntity implements EOPropertyListEncoding { + + protected NSMutableDictionary _attributes = new NSMutableDictionary(); + protected NSMutableDictionary _relations = new NSMutableDictionary(); + private NSMutableArray _classPropertyNames = new NSMutableArray(); + private NSMutableArray _classProperties = new NSMutableArray(); + private NSMutableArray _classPropertyAttributes = new NSMutableArray(); + private NSMutableArray _classPropertyManyRelationships = new NSMutableArray(); + private NSMutableArray _classPropertyOneRelationships = new NSMutableArray(); + protected NSArray _pkAttributes = NSArray.EmptyArray; + protected NSArray _pkAttributeNames = NSArray.EmptyArray; + protected NSMutableDictionary _fetchSpecs = new NSMutableDictionary(); + protected NSMutableArray _lockingAttributes = new NSMutableArray(); + + protected String _className; + protected String _name; + protected String _externalName; + protected boolean _isAbstract; + protected boolean _isReadOnly; + protected EOModel _model; + protected NSDictionary _userInfo; + protected NSDictionary _internalInfo; + private boolean _loadedFetchSpecs; + + public EOEntity() { + super(); + } + + public EOEntity(NSDictionary dict, Object obj) { + super(); + _model = (EOModel)obj; + setName((String)dict.objectForKey("name")); + setExternalName((String)dict.objectForKey("externalName")); + setClassName((String)dict.objectForKey("className")); + if (dict.objectForKey("internalInfo") != null) + _internalInfo = (NSDictionary)dict.objectForKey("internalInfo"); + if (dict.objectForKey("userInfo") != null) + _userInfo = (NSDictionary)dict.objectForKey("userInfo"); + + //Read the attributes + NSArray atr = (NSArray)dict.objectForKey("attributes"); + for (int i = 0; i < atr.count(); i++) { + NSDictionary d = (NSDictionary)atr.objectAtIndex(i); + EOAttribute atrib = new EOAttribute(d, this); + addAttribute(atrib); + } + + //Set the primary key + atr = (NSArray)dict.objectForKey("primaryKeyAttributes"); + NSMutableArray pka = new NSMutableArray(); + for (int i = 0; i < atr.count(); i++) { + EOAttribute a = attributeNamed((String)atr.objectAtIndex(i)); + pka.addObject(a); + } + _pkAttributes = new NSArray(pka); + _pkAttributeNames = atr; + + //attributes used for locking + _lockingAttributes.removeAllObjects(); + atr = (NSArray)dict.objectForKey("attributesUsedForLocking"); + for (int i = 0; i < atr.count(); i++) { + String x = (String)atr.objectAtIndex(i); + EOAttribute a = attributeNamed(x); + _lockingAttributes.addObject(a); + } + + //class properties + atr = (NSArray)dict.objectForKey("classProperties"); + if (atr != null) { + for (int i = 0; i < atr.count(); i++) + if (!_classPropertyNames.containsObject((atr.objectAtIndex(i)))) + _classPropertyNames.addObject(atr.objectAtIndex(i)); + } + + //Read the relationships + atr = (NSArray)dict.objectForKey("relationships"); + if (atr != null) { + for (int i = 0; i < atr.count(); i++) { + NSDictionary d = (NSDictionary)atr.objectAtIndex(i); + EORelationship rel = new EORelationship(d, this); + addRelationship(rel); + } + } + } + + public void addAttribute(EOAttribute atr) { + if (atr.name() == null) + throw new IllegalArgumentException("Cannot add an unnamed attribute to an entity."); + if (_attributes.objectForKey(atr.name()) != null) + throw new IllegalArgumentException("Entity " + name() + " already has an attribute named " + atr.name()); + _attributes.setObjectForKey(atr, atr.name()); + atr.setEntity(this); + _lockingAttributes.addObject(atr); + _classProperties.addObject(atr); + _classPropertyNames.addObject(atr.name()); + _classPropertyAttributes.addObject(atr); + } + + public void removeAttribute(EOAttribute atr) { + _attributes.removeObjectForKey(atr.name()); + atr.setEntity(null); + _classProperties.removeObject(atr); + _classPropertyNames.removeObject(atr.name()); + _classPropertyAttributes.removeObject(atr); + } + + public void addFetchSpecification(EOFetchSpecification fspec, String name) { + loadFetchSpecifications(); + if (_fetchSpecs.objectForKey(name) != null) + throw new IllegalArgumentException("Entity " + name() + " already has a fetch specification named " + name); + _fetchSpecs.setObjectForKey(fspec, name); + } + + public void removeFetchSpecificationNamed(String name) { + _fetchSpecs.removeObjectForKey(name); + } + + public EOFetchSpecification fetchSpecificationNamed(String name) { + loadFetchSpecifications(); + return (EOFetchSpecification)_fetchSpecs.objectForKey(name); + } + + public NSArray fetchSpecificationNames() { + loadFetchSpecifications(); + return _fetchSpecs.allKeys(); + } + + /** Loads fetch specifications from the .fspec file, + * if one exists. + */ + private void loadFetchSpecifications() { + if (_loadedFetchSpecs) + return; + _loadedFetchSpecs = true; + if (model().path() == null) + return; + File f = new File(model().path()); + //Read the fetch specification file, if it exists + f = new File(f, name() + ".fspec"); + if (!f.exists()) + return; + NSDictionary fdict = null; + String x = null; + try { + FileInputStream fin = new FileInputStream(f); + byte[] b = new byte[fin.available()]; + fin.read(b); + fin.close(); + x = new String(b); + } catch (IOException ex) { + throw new IllegalArgumentException("Cannot read file " + f); + } + fdict = NSPropertyListSerialization.dictionaryForString(x); + if (fdict == null) + throw new IllegalArgumentException("Cannot read dictionary from " + f); + NSArray keys = fdict.allKeys(); + + //Unarchive the fetch specification + EOKeyValueUnarchiver unarch = new EOKeyValueUnarchiver(fdict); + for (int i = 0; i < keys.count(); i++) { + String k = (String)keys.objectAtIndex(i); + EOFetchSpecification fs = (EOFetchSpecification)unarch.decodeObjectForKey(k); + if (fs != null) + _fetchSpecs.setObjectForKey(fs, k); + } + } + + public NSArray attributes() { + return _attributes.allValues(); + } + + public EOAttribute attributeNamed(String name) { + return (EOAttribute)_attributes.objectForKey(name); + } + + public NSArray flattenedAttributes() { + return null; + } + + public void setClassName(String name) { + _className = name; + } + public String className() { + return _className; + } + + public void setName(String name) { + _name = name; + } + public String name() { + return _name; + } + + public void setExternalName(String name) { + _externalName = name; + } + public String externalName() { + return _externalName; + } + + public void addRelationship(EORelationship rel) { + if (rel.name() == null) + throw new IllegalArgumentException("Cannot add an unnamed relationship to an entity."); + if (_relations.objectForKey(rel.name()) != null) + throw new IllegalArgumentException("Entity " + name() + " already has a relationship named " + rel.name()); + if (_attributes.objectForKey(rel.name()) != null) + throw new IllegalArgumentException("Entity " + name() + " has an attribute named " + rel.name()); + _relations.setObjectForKey(rel, rel.name()); + _classProperties.addObject(rel); + _classPropertyNames.addObject(rel.name()); + if (rel.isToMany()) + _classPropertyManyRelationships.addObject(rel); + else + _classPropertyOneRelationships.addObject(rel); + } + + public void removeRelationship(EORelationship rel) { + _relations.removeObjectForKey(rel.name()); + _classProperties.removeObject(rel); + _classPropertyNames.removeObject(rel.name()); + _classPropertyManyRelationships.removeObject(rel); + _classPropertyOneRelationships.removeObject(rel); + } + + /** Returns the relationships from this entity to other entities. + * @return An array of the relationships of this entity. + */ + public NSArray relationships() { + return _relations.allValues(); + } + + public EORelationship relationshipNamed(String name) { + return (EORelationship)_relations.objectForKey(name); + } + public EOModel model() { + return _model; + } + + public void setPrimaryKeyAtributes(NSArray pk) { + _pkAttributes = pk; + } + public NSArray primaryKeyAttributes() { + return _pkAttributes; + } + + public NSArray primaryKeyAttributeNames() { + if (_pkAttributeNames.count() != _pkAttributes.count()) { + NSMutableArray arr = new NSMutableArray(); + for (int i = 0; i < _pkAttributes.count(); i++) { + EOAttribute a = (EOAttribute)_pkAttributes.objectAtIndex(i); + arr.addObject(a.name()); + } + _pkAttributeNames = new NSArray(arr); + } + return _pkAttributeNames; + } + + public boolean hasSimplePrimaryKey() { + return _pkAttributes.count() == 1; + } + + public boolean isValidPrimaryKeyAttribute(EOAttribute attr) { + return !attr.allowsNull(); + } + + public void setAttributesUsedForLocking(NSArray value) { + _lockingAttributes.removeAllObjects(); + _lockingAttributes.addObjectsFromArray(value); + } + public NSArray attributesUsedForLocking() { + return new NSArray(_lockingAttributes); + } + + public void setClassProperties(NSArray value) { + _classProperties.removeAllObjects(); + _classProperties.addObjectsFromArray(value); + _classPropertyNames.removeAllObjects(); + _classPropertyAttributes.removeAllObjects(); + _classPropertyOneRelationships.removeAllObjects(); + _classPropertyManyRelationships.removeAllObjects(); + for (int i = 0; i < value.count(); i++) { + EOProperty o = (EOProperty)value.objectAtIndex(i); + _classPropertyNames.addObject(o.name()); + if (o instanceof EOAttribute) { + _classPropertyAttributes.addObject(o); + } else if (o instanceof EORelationship) { + if (((EORelationship)o).isToMany()) + _classPropertyManyRelationships.addObject(o); + else + _classPropertyOneRelationships.addObject(o); + } + } + } + public NSArray classProperties() { + if (_classProperties == null) { + if (_classPropertyNames == null) + return NSArray.EmptyArray; + else { + NSMutableArray props = new NSMutableArray(); + NSMutableArray atribs = new NSMutableArray(); + NSMutableArray ones = new NSMutableArray(); + NSMutableArray manies = new NSMutableArray(); + for (int i = 0; i < _classPropertyNames.count(); i++) { + String name = (String)_classPropertyNames.objectAtIndex(i); + EOAttribute a = attributeNamed(name); + EORelationship r = relationshipNamed(name); + if (a != null) { + props.addObject(a); + atribs.addObject(a); + } else if (r != null) { + props.addObject(r); + if (r.isToMany()) + manies.addObject(r); + else + ones.addObject(r); + } else + throw new IllegalArgumentException("Cannot find attribute or relationship named " + name); + } + _classProperties = props; + _classPropertyAttributes = atribs; + _classPropertyOneRelationships = ones; + _classPropertyManyRelationships = manies; + } + } + return _classProperties; + } + + public NSArray classPropertyNames() { + return _classPropertyNames; + } + + public NSArray classPropertyAttributeNames() { + if (_classPropertyAttributes == null) + return NSArray.EmptyArray; + NSMutableArray arr = new NSMutableArray(_classPropertyAttributes.count()); + for (int i = 0 ; i < _classPropertyAttributes.count(); i++) { + EOAttribute a = (EOAttribute)_classPropertyAttributes.objectAtIndex(i); + arr.addObject(a.name()); + } + return arr; + } + + public NSArray classPropertyToManyRelationshipNames() { + if (_classPropertyManyRelationships == null) + return NSArray.EmptyArray; + NSMutableArray arr = new NSMutableArray(_classPropertyManyRelationships.count()); + for (int i = 0 ; i < _classPropertyManyRelationships.count(); i++) { + EOAttribute a = (EOAttribute)_classPropertyManyRelationships.objectAtIndex(i); + arr.addObject(a.name()); + } + return arr; + } + + public NSArray classPropertyToOneRelationshipNames() { + if (_classPropertyOneRelationships == null) + return NSArray.EmptyArray; + NSMutableArray arr = new NSMutableArray(_classPropertyOneRelationships.count()); + for (int i = 0 ; i < _classPropertyOneRelationships.count(); i++) { + EOAttribute a = (EOAttribute)_classPropertyOneRelationships.objectAtIndex(i); + arr.addObject(a.name()); + } + return arr; + } + + public void setIsAbstractEntity(boolean flag) { + _isAbstract = flag; + } + public boolean isAbstractEntity() { + return _isAbstract; + } + + public void setReadOnly(boolean flag) { + _isReadOnly = flag; + } + public boolean isReadOnly() { + return _isReadOnly; + } + + public void setStoredProcedure(EOStoredProcedure proc, String operation) { + } + public EOStoredProcedure storedProcedureForOperation(String operation) { + return null; + } + + public NSArray subEntities() { + return null; + } + + public NSArray attributesToFetch() { + return attributes(); + } + + public NSArray externalModelsReferenced() { + return null; + } + + public EOClassDescription classDescriptionForInstances() { + EOClassDescription cd = EOClassDescription.classDescriptionForEntityName(name()); + if (cd == null) { + cd = new EOEntityClassDescription(this); + Class cl = null; + try { + cl = Class.forName(className()); + } catch (ClassNotFoundException ex) { + cl = EOGenericRecord.class; + } + EOClassDescription.registerClassDescription(cd, cl); + } + return cd; + } + + /** + * Creates a global ID for a row. The row must have values + * for all the primary key attributes. + * @param row A raw row for this entity. + * @return A key global ID to identify this row. + */ + public EOGlobalID globalIDForRow(Map row) { + NSArray pknames = primaryKeyAttributeNames(); + EOKeyGlobalID gid = null; + if (pknames.count() == 1 && row.get(pknames.objectAtIndex(0)) instanceof Number) { + Number n = (Number)row.get(pknames.objectAtIndex(0)); + gid = new EOIntegralKeyGlobalID(name(), n); + } else { + Object[] vals = new Object[pknames.count()]; + for (int i = 0; i < pknames.count(); i++) { + Object v = row.get(pknames.objectAtIndex(i)); + vals[i] = v; + } + gid = new EOVectorKeyGlobalID(name(), vals); + } + return gid; + } + + /** + * Returns a dictionary with the primary key values contained in + * the global id. + * @param gid A Key global ID. + * @return A dictionary with the primary key values for gid. + */ + public NSDictionary primaryKeyForGlobalID(EOGlobalID gid) { + if (!(gid instanceof EOKeyGlobalID)) + return null; + Object[] vals = ((EOKeyGlobalID)gid).keyValues(); + NSArray pknames = primaryKeyAttributeNames(); + return new NSDictionary(vals, pknames.toArray()); + } + + public EOQualifier qualifierForPrimaryKey(Map pkey) { + NSArray pknames = primaryKeyAttributeNames(); + EOQualifier q = null; + NSMutableArray subq = new NSMutableArray(pknames.count()); + for (int i = 0; i < pknames.count(); i++) { + String key = (String)pknames.objectAtIndex(i); + Object v = pkey.get(key); + if (v == null || v == NSKeyValueCoding.NullValue) + throw new IllegalArgumentException("Primary key with null values."); + subq.addObject(new EOKeyValueQualifier(key, EOQualifier.QualifierOperatorEqual, v)); + } + if (subq.count() == 1) + q = (EOQualifier)subq.objectAtIndex(0); + else + q = new EOAndQualifier(subq); + return q; + } + + public void setUserInfo(NSDictionary value) { + _userInfo = value; + } + public NSDictionary userInfo() { + return _userInfo; + } + + public void awakeWithPropertyList(NSDictionary plist) { + } + + public void encodeIntoPropertyList(NSMutableDictionary dict) { + dict.setObjectForKey(name(), "name"); + dict.setObjectForKey(externalName(), "externalName"); + dict.setObjectForKey(className(), "className"); + + //Encode attributes + NSMutableArray arr = new NSMutableArray(_attributes.allValues()); + for (int i = 0; i < _attributes.count(); i++) { + EOAttribute a = (EOAttribute)arr.objectAtIndex(i); + NSMutableDictionary d = new NSMutableDictionary(); + a.encodeIntoPropertyList(d); + arr.replaceObjectAtIndex(i, d); + } + dict.setObjectForKey(arr, "attributes"); + //Encode relationships + if (_relations.count() > 0) { + arr = new NSMutableArray(_relations.allValues()); + for (int i = 0; i < _relations.count(); i++) { + EORelationship r = (EORelationship)arr.objectAtIndex(i); + NSMutableDictionary d = new NSMutableDictionary(); + r.encodeIntoPropertyList(d); + arr.replaceObjectAtIndex(i, d); + } + dict.setObjectForKey(arr, "relationships"); + } + + //Fetch specifications + NSMutableDictionary d = new NSMutableDictionary(); + loadFetchSpecifications(); + java.util.Enumeration enumeration = _fetchSpecs.keyEnumerator(); + while (enumeration.hasMoreElements()) { + String k = (String)enumeration.nextElement(); + EOFetchSpecification f = (EOFetchSpecification)_fetchSpecs.objectForKey(k); + EOKeyValueArchiver arch = new EOKeyValueArchiver(); + f.encodeWithKeyValueArchiver(arch); + d.setObjectForKey(arch.dictionary(), k); + } + dict.setObjectForKey(d, "fetchSpecificationDictionary"); + + //Other information + dict.setObjectForKey(_classPropertyNames, "classProperties"); + dict.setObjectForKey(_pkAttributeNames, "primaryKeyAttributes"); + arr = new NSMutableArray(_lockingAttributes); + for (int i = 0; i < arr.count(); i++) + arr.replaceObjectAtIndex(i, ((EOAttribute)arr.objectAtIndex(i)).name()); + dict.setObjectForKey(arr, "attributesUsedForLocking"); + if (_userInfo != null && _userInfo.count() > 0 ) + dict.setObjectForKey(_userInfo, "userInfo"); + if (_internalInfo != null && _internalInfo.count() > 0 ) + dict.setObjectForKey(_internalInfo, "internalInfo"); + } + + public EOAttribute _attributeForPath(String path) { + NSArray comps = NSArray.componentsSeparatedByString(path, "."); + if (comps.count() < 2) + return null; + EORelationship r = null; + EOEntity e = this; + for (int i = 0; i < comps.count()-1; i++) { + String name = (String)comps.objectAtIndex(i); + r = e.relationshipNamed(name); + if (r == null) + return null; + e = r.destinationEntity(); + } + return e.attributeNamed((String)comps.lastObject()); + } + +} +/* + * $Log$ + * Revision 1.2 2006/02/16 16:47:14 cgruber + * Move some classes in to "internal" packages and re-work imports, etc. + * + * Also use UnsupportedOperationExceptions where appropriate, instead of WotonomyExceptions. + * + * Revision 1.1 2006/02/16 13:19:57 cgruber + * Check in all sources in eclipse-friendly maven-enabled packages. + * + * Revision 1.9 2005/05/11 15:21:53 cgruber + * Change enum to enumeration, since enum is now a keyword as of Java 5.0 + * + * A few other comments in the code. + * + * Revision 1.8 2003/08/19 19:47:58 chochos + * added some methods to handle EOGlobalIDs and primary keys. + * + * Revision 1.7 2003/08/14 02:13:56 chochos + * implement and use _attributeForPath() + * + * Revision 1.6 2003/08/11 19:38:27 chochos + * Can now read from a file and re-write to another file. + * + * Revision 1.5 2003/08/11 18:19:33 chochos + * encoding into property list seems to work fine now. + * + * Revision 1.4 2003/08/09 01:39:04 chochos + * better handling of class properties; use EOKeyValueArchiving to encode/decode fetch specifications; implement EOPropertyListEncoding + * + * Revision 1.3 2003/08/08 05:52:21 chochos + * gets the class description for the entity. + * + * Revision 1.2 2003/08/08 02:14:20 chochos + * now it can read stored procedures. + * + * Revision 1.1 2003/08/07 02:38:33 chochos + * implementation of EOEntity. What works for now is reading an entity from file. + * + */ -- cgit v1.2.3