View Javadoc

1   /*
2    Wotonomy: OpenStep design patterns for pure Java applications.
3    Copyright (C) 2001 Michael Powers
4   
5    This library is free software; you can redistribute it and/or
6    modify it under the terms of the GNU Lesser General Public
7    License as published by the Free Software Foundation; either
8    version 2.1 of the License, or (at your option) any later version.
9   
10   This library is distributed in the hope that it will be useful,
11   but WITHOUT ANY WARRANTY; without even the implied warranty of
12   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13   Lesser General Public License for more details.
14  
15   You should have received a copy of the GNU Lesser General Public
16   License along with this library; if not, see http://www.gnu.org
17   */
18  package net.wotonomy.access;
19  
20  import java.io.File;
21  import java.io.FileInputStream;
22  import java.io.IOException;
23  import java.util.Map;
24  
25  import net.wotonomy.control.EOAndQualifier;
26  import net.wotonomy.control.EOClassDescription;
27  import net.wotonomy.control.EOFetchSpecification;
28  import net.wotonomy.control.EOGenericRecord;
29  import net.wotonomy.control.EOGlobalID;
30  import net.wotonomy.control.EOIntegralKeyGlobalID;
31  import net.wotonomy.control.EOKeyGlobalID;
32  import net.wotonomy.control.EOKeyValueArchiver;
33  import net.wotonomy.control.EOKeyValueQualifier;
34  import net.wotonomy.control.EOKeyValueUnarchiver;
35  import net.wotonomy.control.EOQualifier;
36  import net.wotonomy.control.EOVectorKeyGlobalID;
37  import net.wotonomy.foundation.NSArray;
38  import net.wotonomy.foundation.NSDictionary;
39  import net.wotonomy.foundation.NSKeyValueCoding;
40  import net.wotonomy.foundation.NSMutableArray;
41  import net.wotonomy.foundation.NSMutableDictionary;
42  import net.wotonomy.foundation.NSPropertyListSerialization;
43  
44  /***
45  * An EOEntity is a mapping between a Java class and a database table or view.
46  * It indicates which attributes should be fetched from the table/view, what
47  * attributes are part of the primary key, what class the entity should map to.
48  *
49  * @author ezamudio@nasoft.com
50  * @author $Author: cgruber $
51  * @version $Revision: 894 $
52  */
53  public class EOEntity implements EOPropertyListEncoding {
54  
55  	protected NSMutableDictionary _attributes = new NSMutableDictionary();
56  	protected NSMutableDictionary _relations = new NSMutableDictionary();
57  	private NSMutableArray _classPropertyNames = new NSMutableArray();
58  	private NSMutableArray _classProperties = new NSMutableArray();
59  	private NSMutableArray _classPropertyAttributes = new NSMutableArray();
60  	private NSMutableArray _classPropertyManyRelationships = new NSMutableArray();
61  	private NSMutableArray _classPropertyOneRelationships = new NSMutableArray();
62  	protected NSArray _pkAttributes = NSArray.EmptyArray;
63  	protected NSArray _pkAttributeNames = NSArray.EmptyArray;
64  	protected NSMutableDictionary _fetchSpecs = new NSMutableDictionary();
65  	protected NSMutableArray _lockingAttributes = new NSMutableArray();
66  
67  	protected String _className;
68  	protected String _name;
69  	protected String _externalName;
70  	protected boolean _isAbstract;
71  	protected boolean _isReadOnly;
72  	protected EOModel _model;
73  	protected NSDictionary _userInfo;
74  	protected NSDictionary _internalInfo;
75  	private boolean _loadedFetchSpecs;
76  
77  	public EOEntity() {
78  		super();
79  	}
80  
81  	public EOEntity(NSDictionary dict, Object obj) {
82  		super();
83  		_model = (EOModel)obj;
84  		setName((String)dict.objectForKey("name"));
85  		setExternalName((String)dict.objectForKey("externalName"));
86  		setClassName((String)dict.objectForKey("className"));
87  		if (dict.objectForKey("internalInfo") != null)
88  			_internalInfo = (NSDictionary)dict.objectForKey("internalInfo");
89  		if (dict.objectForKey("userInfo") != null)
90  			_userInfo = (NSDictionary)dict.objectForKey("userInfo");
91  
92  		//Read the attributes
93  		NSArray atr = (NSArray)dict.objectForKey("attributes");
94  		for (int i = 0; i < atr.count(); i++) {
95  			NSDictionary d = (NSDictionary)atr.objectAtIndex(i);
96  			EOAttribute atrib = new EOAttribute(d, this);
97  			addAttribute(atrib);
98  		}
99  
100 		//Set the primary key
101 		atr = (NSArray)dict.objectForKey("primaryKeyAttributes");
102 		NSMutableArray pka = new NSMutableArray();
103 		for (int i = 0; i < atr.count(); i++) {
104 			EOAttribute a = attributeNamed((String)atr.objectAtIndex(i));
105 			pka.addObject(a);
106 		}
107 		_pkAttributes = new NSArray(pka);
108 		_pkAttributeNames = atr;
109 
110 		//attributes used for locking
111 		_lockingAttributes.removeAllObjects();
112 		atr = (NSArray)dict.objectForKey("attributesUsedForLocking");
113 		for (int i = 0; i < atr.count(); i++) {
114 			String x = (String)atr.objectAtIndex(i);
115 			EOAttribute a = attributeNamed(x);
116 			_lockingAttributes.addObject(a);
117 		}
118 
119 		//class properties
120 		atr = (NSArray)dict.objectForKey("classProperties");
121 		if (atr != null) {
122 			for (int i = 0; i < atr.count(); i++)
123 				if (!_classPropertyNames.containsObject((atr.objectAtIndex(i))))
124 					_classPropertyNames.addObject(atr.objectAtIndex(i));
125 		}
126 
127 		//Read the relationships
128 		atr = (NSArray)dict.objectForKey("relationships");
129 		if (atr != null) {
130 			for (int i = 0; i < atr.count(); i++) {
131 				NSDictionary d = (NSDictionary)atr.objectAtIndex(i);
132 				EORelationship rel = new EORelationship(d, this);
133 				addRelationship(rel);
134 			}
135 		}
136 	}
137 
138 	public void addAttribute(EOAttribute atr) {
139 		if (atr.name() == null)
140 			throw new IllegalArgumentException("Cannot add an unnamed attribute to an entity.");
141 		if (_attributes.objectForKey(atr.name()) != null)
142 			throw new IllegalArgumentException("Entity " + name() + " already has an attribute named " + atr.name());
143 		_attributes.setObjectForKey(atr, atr.name());
144 		atr.setEntity(this);
145 		_lockingAttributes.addObject(atr);
146 		_classProperties.addObject(atr);
147 		_classPropertyNames.addObject(atr.name());
148 		_classPropertyAttributes.addObject(atr);
149 	}
150 
151 	public void removeAttribute(EOAttribute atr) {
152 		_attributes.removeObjectForKey(atr.name());
153 		atr.setEntity(null);
154 		_classProperties.removeObject(atr);
155 		_classPropertyNames.removeObject(atr.name());
156 		_classPropertyAttributes.removeObject(atr);
157 	}
158 
159 	public void addFetchSpecification(EOFetchSpecification fspec, String name) {
160 		loadFetchSpecifications();
161 		if (_fetchSpecs.objectForKey(name) != null)
162 			throw new IllegalArgumentException("Entity " + name() + " already has a fetch specification named " + name);
163 		_fetchSpecs.setObjectForKey(fspec, name);
164 	}
165 
166 	public void removeFetchSpecificationNamed(String name) {
167 		_fetchSpecs.removeObjectForKey(name);
168 	}
169 
170 	public EOFetchSpecification fetchSpecificationNamed(String name) {
171 		loadFetchSpecifications();
172 		return (EOFetchSpecification)_fetchSpecs.objectForKey(name);
173 	}
174 
175 	public NSArray fetchSpecificationNames() {
176 		loadFetchSpecifications();
177 		return _fetchSpecs.allKeys();
178 	}
179 
180 	/*** Loads fetch specifications from the .fspec file,
181 	 * if one exists.
182 	 */
183 	private void loadFetchSpecifications() {
184 		if (_loadedFetchSpecs)
185 			return;
186 		_loadedFetchSpecs = true;
187 		if (model().path() == null)
188 			return;
189 		File f = new File(model().path());
190 		//Read the fetch specification file, if it exists
191 		f = new File(f, name() + ".fspec");
192 		if (!f.exists())
193 			return;
194 		NSDictionary fdict = null;
195 		String x = null;
196 		try {
197 			FileInputStream fin = new FileInputStream(f);
198 			byte[] b = new byte[fin.available()];
199 			fin.read(b);
200 			fin.close();
201 			x = new String(b);
202 		} catch (IOException ex) {
203 			throw new IllegalArgumentException("Cannot read file " + f);
204 		}
205 		fdict = NSPropertyListSerialization.dictionaryForString(x);
206 		if (fdict == null)
207 			throw new IllegalArgumentException("Cannot read dictionary from " + f);
208 		NSArray keys = fdict.allKeys();
209 
210 		//Unarchive the fetch specification
211 		EOKeyValueUnarchiver unarch = new EOKeyValueUnarchiver(fdict);
212 		for (int i = 0; i < keys.count(); i++) {
213 			String k = (String)keys.objectAtIndex(i);
214 			EOFetchSpecification fs = (EOFetchSpecification)unarch.decodeObjectForKey(k);
215 			if (fs != null)
216 				_fetchSpecs.setObjectForKey(fs, k);
217 		}
218 	}
219 
220 	public NSArray attributes() {
221 		return _attributes.allValues();
222 	}
223 
224 	public EOAttribute attributeNamed(String name) {
225 		return (EOAttribute)_attributes.objectForKey(name);
226 	}
227 
228 	public NSArray flattenedAttributes() {
229 		return null;
230 	}
231 
232 	public void setClassName(String name) {
233 		_className = name;
234 	}
235 	public String className() {
236 		return _className;
237 	}
238 
239 	public void setName(String name) {
240 		_name = name;
241 	}
242 	public String name() {
243 		return _name;
244 	}
245 
246 	public void setExternalName(String name) {
247 		_externalName = name;
248 	}
249 	public String externalName() {
250 		return _externalName;
251 	}
252 
253 	public void addRelationship(EORelationship rel) {
254 		if (rel.name() == null)
255 			throw new IllegalArgumentException("Cannot add an unnamed relationship to an entity.");
256 		if (_relations.objectForKey(rel.name()) != null)
257 			throw new IllegalArgumentException("Entity " + name() + " already has a relationship named " + rel.name());
258 		if (_attributes.objectForKey(rel.name()) != null)
259 			throw new IllegalArgumentException("Entity " + name() + " has an attribute named " + rel.name());
260 		_relations.setObjectForKey(rel, rel.name());
261 		_classProperties.addObject(rel);
262 		_classPropertyNames.addObject(rel.name());
263 		if (rel.isToMany())
264 			_classPropertyManyRelationships.addObject(rel);
265 		else
266 			_classPropertyOneRelationships.addObject(rel);
267 	}
268 
269 	public void removeRelationship(EORelationship rel) {
270 		_relations.removeObjectForKey(rel.name());
271 		_classProperties.removeObject(rel);
272 		_classPropertyNames.removeObject(rel.name());
273 		_classPropertyManyRelationships.removeObject(rel);
274 		_classPropertyOneRelationships.removeObject(rel);
275 	}
276 
277 	/*** Returns the relationships from this entity to other entities.
278 	 * @return An array of the relationships of this entity.
279 	 */
280 	public NSArray relationships() {
281 		return _relations.allValues();
282 	}
283 
284 	public EORelationship relationshipNamed(String name) {
285 		return (EORelationship)_relations.objectForKey(name);
286 	}
287 	public EOModel model() {
288 		return _model;
289 	}
290 
291 	public void setPrimaryKeyAtributes(NSArray pk) {
292 		_pkAttributes = pk;
293 	}
294 	public NSArray primaryKeyAttributes() {
295 		return _pkAttributes;
296 	}
297 
298 	public NSArray primaryKeyAttributeNames() {
299 		if (_pkAttributeNames.count() != _pkAttributes.count()) {
300 			NSMutableArray arr = new NSMutableArray();
301 			for (int i = 0; i < _pkAttributes.count(); i++) {
302 				EOAttribute a = (EOAttribute)_pkAttributes.objectAtIndex(i);
303 				arr.addObject(a.name());
304 			}
305 			_pkAttributeNames = new NSArray(arr);
306 		}
307 		return _pkAttributeNames;
308 	}
309 
310 	public boolean hasSimplePrimaryKey() {
311 		return _pkAttributes.count() == 1;
312 	}
313 
314 	public boolean isValidPrimaryKeyAttribute(EOAttribute attr) {
315 		return !attr.allowsNull();
316 	}
317 
318 	public void setAttributesUsedForLocking(NSArray value) {
319 		_lockingAttributes.removeAllObjects();
320 		_lockingAttributes.addObjectsFromArray(value);
321 	}
322 	public NSArray attributesUsedForLocking() {
323 		return new NSArray(_lockingAttributes);
324 	}
325 
326 	public void setClassProperties(NSArray value) {
327 		_classProperties.removeAllObjects();
328 		_classProperties.addObjectsFromArray(value);
329 		_classPropertyNames.removeAllObjects();
330 		_classPropertyAttributes.removeAllObjects();
331 		_classPropertyOneRelationships.removeAllObjects();
332 		_classPropertyManyRelationships.removeAllObjects();
333 		for (int i = 0; i < value.count(); i++) {
334 			EOProperty o = (EOProperty)value.objectAtIndex(i);
335 			_classPropertyNames.addObject(o.name());
336 			if (o instanceof EOAttribute) {
337 				_classPropertyAttributes.addObject(o);
338 			} else if (o instanceof EORelationship) {
339 				if (((EORelationship)o).isToMany())
340 					_classPropertyManyRelationships.addObject(o);
341 				else
342 					_classPropertyOneRelationships.addObject(o);
343 			}
344 		}
345 	}
346 	public NSArray classProperties() {
347 		if (_classProperties == null) {
348 			if (_classPropertyNames == null)
349 				return NSArray.EmptyArray;
350 			else {
351 				NSMutableArray props = new NSMutableArray();
352 				NSMutableArray atribs = new NSMutableArray();
353 				NSMutableArray ones = new NSMutableArray();
354 				NSMutableArray manies = new NSMutableArray();
355 				for (int i = 0; i < _classPropertyNames.count(); i++) {
356 					String name = (String)_classPropertyNames.objectAtIndex(i);
357 					EOAttribute a = attributeNamed(name);
358 					EORelationship r = relationshipNamed(name);
359 					if (a != null) {
360 						props.addObject(a);
361 						atribs.addObject(a);
362 					} else if (r != null) {
363 						props.addObject(r);
364 						if (r.isToMany())
365 							manies.addObject(r);
366 						else
367 							ones.addObject(r);
368 					} else
369 						throw new IllegalArgumentException("Cannot find attribute or relationship named " + name);
370 				}
371 				_classProperties = props;
372 				_classPropertyAttributes = atribs;
373 				_classPropertyOneRelationships = ones;
374 				_classPropertyManyRelationships = manies;
375 			}
376 		}
377 		return _classProperties;
378 	}
379 
380 	public NSArray classPropertyNames() {
381 		return _classPropertyNames;
382 	}
383 
384 	public NSArray classPropertyAttributeNames() {
385 		if (_classPropertyAttributes == null)
386 			return NSArray.EmptyArray;
387 		NSMutableArray arr = new NSMutableArray(_classPropertyAttributes.count());
388 		for (int i = 0 ; i < _classPropertyAttributes.count(); i++) {
389 			EOAttribute a = (EOAttribute)_classPropertyAttributes.objectAtIndex(i);
390 			arr.addObject(a.name());
391 		}
392 		return arr;
393 	}
394 
395 	public NSArray classPropertyToManyRelationshipNames() {
396 		if (_classPropertyManyRelationships == null)
397 			return NSArray.EmptyArray;
398 		NSMutableArray arr = new NSMutableArray(_classPropertyManyRelationships.count());
399 		for (int i = 0 ; i < _classPropertyManyRelationships.count(); i++) {
400 			EOAttribute a = (EOAttribute)_classPropertyManyRelationships.objectAtIndex(i);
401 			arr.addObject(a.name());
402 		}
403 		return arr;
404 	}
405 
406 	public NSArray classPropertyToOneRelationshipNames() {
407 		if (_classPropertyOneRelationships == null)
408 			return NSArray.EmptyArray;
409 		NSMutableArray arr = new NSMutableArray(_classPropertyOneRelationships.count());
410 		for (int i = 0 ; i < _classPropertyOneRelationships.count(); i++) {
411 			EOAttribute a = (EOAttribute)_classPropertyOneRelationships.objectAtIndex(i);
412 			arr.addObject(a.name());
413 		}
414 		return arr;
415 	}
416 
417 	public void setIsAbstractEntity(boolean flag) {
418 		_isAbstract = flag;
419 	}
420 	public boolean isAbstractEntity() {
421 		return _isAbstract;
422 	}
423 
424 	public void setReadOnly(boolean flag) {
425 		_isReadOnly = flag;
426 	}
427 	public boolean isReadOnly() {
428 		return _isReadOnly;
429 	}
430 
431 	public void setStoredProcedure(EOStoredProcedure proc, String operation) {
432 	}
433 	public EOStoredProcedure storedProcedureForOperation(String operation) {
434 		return null;
435 	}
436 
437 	public NSArray subEntities() {
438 		return null;
439 	}
440 
441 	public NSArray attributesToFetch() {
442 		return attributes();
443 	}
444 
445 	public NSArray externalModelsReferenced() {
446 		return null;
447 	}
448 
449 	public EOClassDescription classDescriptionForInstances() {
450 		EOClassDescription cd = EOClassDescription.classDescriptionForEntityName(name());
451 		if (cd == null) {
452 			cd = new EOEntityClassDescription(this);
453 			Class cl = null;
454 			try {
455 				cl = Class.forName(className());
456 			} catch (ClassNotFoundException ex) {
457 				cl = EOGenericRecord.class;
458 			}
459 			EOClassDescription.registerClassDescription(cd, cl);
460 		}
461 		return cd;
462 	}
463 
464 	/***
465 	 * Creates a global ID for a row. The row must have values
466 	 * for all the primary key attributes.
467 	 * @param row A raw row for this entity.
468 	 * @return A key global ID to identify this row.
469 	 */
470 	public EOGlobalID globalIDForRow(Map row) {
471 		NSArray pknames = primaryKeyAttributeNames();
472 		EOKeyGlobalID gid = null;
473 		if (pknames.count() == 1 && row.get(pknames.objectAtIndex(0)) instanceof Number) {
474 			Number n = (Number)row.get(pknames.objectAtIndex(0));
475 			gid = new EOIntegralKeyGlobalID(name(), n);
476 		} else {
477 			Object[] vals = new Object[pknames.count()];
478 			for (int i = 0; i < pknames.count(); i++) {
479 				Object v = row.get(pknames.objectAtIndex(i));
480 				vals[i] = v;
481 			}
482 			gid = new EOVectorKeyGlobalID(name(), vals);
483 		}
484 		return gid;
485 	}
486 
487 	/***
488 	 * Returns a dictionary with the primary key values contained in 
489 	 * the global id.
490 	 * @param gid A Key global ID.
491 	 * @return A dictionary with the primary key values for gid.
492 	 */
493 	public NSDictionary primaryKeyForGlobalID(EOGlobalID gid) {
494 		if (!(gid instanceof EOKeyGlobalID))
495 			return null;
496 		Object[] vals = ((EOKeyGlobalID)gid).keyValues();
497 		NSArray pknames = primaryKeyAttributeNames();
498 		return new NSDictionary(vals, pknames.toArray());
499 	}
500 
501 	public EOQualifier qualifierForPrimaryKey(Map pkey) {
502 		NSArray pknames = primaryKeyAttributeNames();
503 		EOQualifier q = null;
504 		NSMutableArray subq = new NSMutableArray(pknames.count());
505 		for (int i = 0; i < pknames.count(); i++) {
506 			String key = (String)pknames.objectAtIndex(i);
507 			Object v = pkey.get(key);
508 			if (v == null || v == NSKeyValueCoding.NullValue)
509 				throw new IllegalArgumentException("Primary key with null values.");
510 			subq.addObject(new EOKeyValueQualifier(key, EOQualifier.QualifierOperatorEqual, v));
511 		}
512 		if (subq.count() == 1)
513 			q = (EOQualifier)subq.objectAtIndex(0);
514 		else
515 			q = new EOAndQualifier(subq);
516 		return q;
517 	}
518 
519 	public void setUserInfo(NSDictionary value) {
520 		_userInfo = value;
521 	}
522 	public NSDictionary userInfo() {
523 		return _userInfo;
524 	}
525 
526 	public void awakeWithPropertyList(NSDictionary plist) {
527 	}
528 
529 	public void encodeIntoPropertyList(NSMutableDictionary dict) {
530 		dict.setObjectForKey(name(), "name");
531 		dict.setObjectForKey(externalName(), "externalName");
532 		dict.setObjectForKey(className(), "className");
533 
534 		//Encode attributes
535 		NSMutableArray arr = new NSMutableArray(_attributes.allValues());
536 		for (int i = 0; i < _attributes.count(); i++) {
537 			EOAttribute a = (EOAttribute)arr.objectAtIndex(i);
538 			NSMutableDictionary d = new NSMutableDictionary();
539 			a.encodeIntoPropertyList(d);
540 			arr.replaceObjectAtIndex(i, d);
541 		}
542 		dict.setObjectForKey(arr, "attributes");
543 		//Encode relationships
544 		if (_relations.count() > 0) {
545 			arr = new NSMutableArray(_relations.allValues());
546 			for (int i = 0; i < _relations.count(); i++) {
547 				EORelationship r = (EORelationship)arr.objectAtIndex(i);
548 				NSMutableDictionary d = new NSMutableDictionary();
549 				r.encodeIntoPropertyList(d);
550 				arr.replaceObjectAtIndex(i, d);
551 			}
552 			dict.setObjectForKey(arr, "relationships");
553 		}
554 
555 		//Fetch specifications
556 		NSMutableDictionary d = new NSMutableDictionary();
557 		loadFetchSpecifications();
558 		java.util.Enumeration enumeration = _fetchSpecs.keyEnumerator();
559 		while (enumeration.hasMoreElements()) {
560 			String k = (String)enumeration.nextElement();
561 			EOFetchSpecification f = (EOFetchSpecification)_fetchSpecs.objectForKey(k);
562 			EOKeyValueArchiver arch = new EOKeyValueArchiver();
563 			f.encodeWithKeyValueArchiver(arch);
564 			d.setObjectForKey(arch.dictionary(), k);
565 		}
566 		dict.setObjectForKey(d, "fetchSpecificationDictionary");
567 
568 		//Other information
569 		dict.setObjectForKey(_classPropertyNames, "classProperties");
570 		dict.setObjectForKey(_pkAttributeNames, "primaryKeyAttributes");
571 		arr = new NSMutableArray(_lockingAttributes);
572 		for (int i = 0; i < arr.count(); i++)
573 			arr.replaceObjectAtIndex(i, ((EOAttribute)arr.objectAtIndex(i)).name());
574 		dict.setObjectForKey(arr, "attributesUsedForLocking");
575 		if (_userInfo != null && _userInfo.count() > 0 )
576 			dict.setObjectForKey(_userInfo, "userInfo");
577 		if (_internalInfo != null && _internalInfo.count() > 0 )
578 			dict.setObjectForKey(_internalInfo, "internalInfo");
579 	}
580 
581 	public EOAttribute _attributeForPath(String path) {
582 		NSArray comps = NSArray.componentsSeparatedByString(path, ".");
583 		if (comps.count() < 2)
584 			return null;
585 		EORelationship r = null;
586 		EOEntity e = this;
587 		for (int i = 0; i < comps.count()-1; i++) {
588 			String name = (String)comps.objectAtIndex(i);
589 			r = e.relationshipNamed(name);
590 			if (r == null)
591 				return null;
592 			e = r.destinationEntity();
593 		}
594 		return e.attributeNamed((String)comps.lastObject());
595 	}
596 
597 }
598 /*
599  * $Log$
600  * Revision 1.2  2006/02/16 16:47:14  cgruber
601  * Move some classes in to "internal" packages and re-work imports, etc.
602  *
603  * Also use UnsupportedOperationExceptions where appropriate, instead of WotonomyExceptions.
604  *
605  * Revision 1.1  2006/02/16 13:19:57  cgruber
606  * Check in all sources in eclipse-friendly maven-enabled packages.
607  *
608  * Revision 1.9  2005/05/11 15:21:53  cgruber
609  * Change enum to enumeration, since enum is now a keyword as of Java 5.0
610  *
611  * A few other comments in the code.
612  *
613  * Revision 1.8  2003/08/19 19:47:58  chochos
614  * added some methods to handle EOGlobalIDs and primary keys.
615  *
616  * Revision 1.7  2003/08/14 02:13:56  chochos
617  * implement and use _attributeForPath()
618  *
619  * Revision 1.6  2003/08/11 19:38:27  chochos
620  * Can now read from a file and re-write to another file.
621  *
622  * Revision 1.5  2003/08/11 18:19:33  chochos
623  * encoding into property list seems to work fine now.
624  *
625  * Revision 1.4  2003/08/09 01:39:04  chochos
626  * better handling of class properties; use EOKeyValueArchiving to encode/decode fetch specifications; implement EOPropertyListEncoding
627  *
628  * Revision 1.3  2003/08/08 05:52:21  chochos
629  * gets the class description for the entity.
630  *
631  * Revision 1.2  2003/08/08 02:14:20  chochos
632  * now it can read stored procedures.
633  *
634  * Revision 1.1  2003/08/07 02:38:33  chochos
635  * implementation of EOEntity. What works for now is reading an entity from file.
636  *
637  */