1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
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
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
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
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
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
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
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
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
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
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
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
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
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637