KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > cayenne > map > ObjEntity


1 /*****************************************************************
2  * Licensed to the Apache Software Foundation (ASF) under one
3  * or more contributor license agreements. See the NOTICE file
4  * distributed with this work for additional information
5  * regarding copyright ownership. The ASF licenses this file
6  * to you under the Apache License, Version 2.0 (the
7  * "License"); you may not use this file except in compliance
8  * with the License. You may obtain a copy of the License at
9  *
10  * http://www.apache.org/licenses/LICENSE-2.0
11  *
12  * Unless required by applicable law or agreed to in writing,
13  * software distributed under the License is distributed on an
14  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
15  * KIND, either express or implied. See the License for the
16  * specific language governing permissions and limitations
17  * under the License.
18  ****************************************************************/

19
20 package org.apache.cayenne.map;
21
22 import java.util.ArrayList JavaDoc;
23 import java.util.Arrays JavaDoc;
24 import java.util.Collection JavaDoc;
25 import java.util.Collections JavaDoc;
26 import java.util.Iterator JavaDoc;
27 import java.util.List JavaDoc;
28 import java.util.Map JavaDoc;
29 import java.util.SortedMap JavaDoc;
30 import java.util.TreeMap JavaDoc;
31
32 import org.apache.cayenne.CayenneRuntimeException;
33 import org.apache.cayenne.exp.Expression;
34 import org.apache.cayenne.exp.ExpressionException;
35 import org.apache.cayenne.exp.ExpressionFactory;
36 import org.apache.cayenne.map.event.AttributeEvent;
37 import org.apache.cayenne.map.event.EntityEvent;
38 import org.apache.cayenne.map.event.ObjAttributeListener;
39 import org.apache.cayenne.map.event.ObjEntityListener;
40 import org.apache.cayenne.map.event.ObjRelationshipListener;
41 import org.apache.cayenne.map.event.RelationshipEvent;
42 import org.apache.cayenne.util.CayenneMapEntry;
43 import org.apache.cayenne.util.Util;
44 import org.apache.cayenne.util.XMLEncoder;
45 import org.apache.commons.collections.Transformer;
46
47 /**
48  * ObjEntity is a mapping descriptor for a DataObject Java class. It contains the
49  * information about the Java class itself, as well as its mapping to the DbEntity layer.
50  *
51  * @author Misha Shengaout
52  * @author Andrus Adamchik
53  */

54 public class ObjEntity extends Entity implements ObjEntityListener, ObjAttributeListener,
55         ObjRelationshipListener {
56
57     final public static int LOCK_TYPE_NONE = 0;
58     final public static int LOCK_TYPE_OPTIMISTIC = 1;
59
60     // do not import CayenneDataObject as it introduces unneeded client dependency
61
static final String JavaDoc CAYENNE_DATA_OBJECT_CLASS = "org.apache.cayenne.CayenneDataObject";
62     /**
63      * A collection of default "generic" entity classes excluded from class generation.
64      *
65      * @since 1.2
66      */

67     protected static final Collection JavaDoc DEFAULT_GENERIC_CLASSES = Arrays
68             .asList(new String JavaDoc[] {
69                 CAYENNE_DATA_OBJECT_CLASS
70             });
71
72     protected String JavaDoc superClassName;
73     protected String JavaDoc className;
74     protected String JavaDoc dbEntityName;
75     protected String JavaDoc superEntityName;
76     protected Expression qualifier;
77     protected boolean readOnly;
78     protected int lockType;
79
80     protected boolean serverOnly;
81     protected String JavaDoc clientClassName;
82     protected String JavaDoc clientSuperClassName;
83
84     protected List JavaDoc entityListeners;
85     protected CallbackMap callbacks;
86     protected boolean excludingDefaultListeners;
87     protected boolean excludingSuperclassListeners;
88
89     public ObjEntity() {
90         this(null);
91     }
92
93     public ObjEntity(String JavaDoc name) {
94         setName(name);
95         this.lockType = LOCK_TYPE_NONE;
96         this.callbacks = new CallbackMap();
97         this.entityListeners = new ArrayList JavaDoc(2);
98     }
99
100     /**
101      * Prints itself as XML to the provided XMLEncoder.
102      *
103      * @since 1.1
104      */

105     public void encodeAsXML(XMLEncoder encoder) {
106         encoder.print("<obj-entity name=\"");
107         encoder.print(getName());
108
109         // additionally validate that superentity exists
110
if (getSuperEntityName() != null && getSuperEntity() != null) {
111             encoder.print("\" superEntityName=\"");
112             encoder.print(getSuperEntityName());
113         }
114
115         if (isServerOnly()) {
116             encoder.print("\" serverOnly=\"true");
117         }
118
119         if (getClassName() != null) {
120             encoder.print("\" className=\"");
121             encoder.print(getClassName());
122         }
123
124         if (getClientClassName() != null) {
125             encoder.print("\" clientClassName=\"");
126             encoder.print(getClientClassName());
127         }
128
129         if (isReadOnly()) {
130             encoder.print("\" readOnly=\"true");
131         }
132
133         if (getDeclaredLockType() == LOCK_TYPE_OPTIMISTIC) {
134             encoder.print("\" lock-type=\"optimistic");
135         }
136
137         if (getSuperEntityName() == null && getDbEntity() != null) {
138             encoder.print("\" dbEntityName=\"");
139             encoder.print(Util.encodeXmlAttribute(getDbEntityName()));
140         }
141
142         if (getSuperEntityName() == null && getSuperClassName() != null) {
143             encoder.print("\" superClassName=\"");
144             encoder.print(getSuperClassName());
145         }
146
147         if (getSuperEntityName() == null && getClientSuperClassName() != null) {
148             encoder.print("\" clientSuperClassName=\"");
149             encoder.print(getClientSuperClassName());
150         }
151
152         encoder.println("\">");
153         encoder.indent(1);
154
155         if (qualifier != null) {
156             encoder.print("<qualifier>");
157             qualifier.encodeAsXML(encoder);
158             encoder.println("</qualifier>");
159         }
160
161         // store attributes
162
encoder.print(getDeclaredAttributes());
163
164         encoder.indent(-1);
165         encoder.println("</obj-entity>");
166     }
167
168     /**
169      * Returns an ObjEntity stripped of any server-side information, such as DbEntity
170      * mapping. "clientClassName" property of this entity is used to intialize "className"
171      * property of returned entity.
172      *
173      * @since 1.2
174      */

175     public ObjEntity getClientEntity() {
176
177         ObjEntity entity = new ObjEntity(getName());
178         entity.setClassName(getClientClassName());
179         entity.setSuperClassName(getClientSuperClassName());
180         entity.setSuperEntityName(getSuperEntityName());
181
182         // TODO: should we also copy lock type?
183

184         // copy attributes
185
Iterator JavaDoc attributes = getDeclaredAttributes().iterator();
186         while (attributes.hasNext()) {
187             ObjAttribute attribute = (ObjAttribute) attributes.next();
188             entity.addAttribute(attribute.getClientAttribute());
189         }
190
191         // copy relationships
192
Iterator JavaDoc relationships = getDeclaredRelationships().iterator();
193         while (relationships.hasNext()) {
194             ObjRelationship relationship = (ObjRelationship) relationships.next();
195             entity.addRelationship(relationship.getClientRelationship());
196         }
197
198         // TODO: andrus 2/5/2007 - copy embeddables
199
// TODO: andrus 2/5/2007 - copy listeners and callback methods
200

201         return entity;
202     }
203
204     /**
205      * Returns a non-null class name. For generic entities with no class specified
206      * explicitly, default DataMap superclass is used, and if it is not set -
207      * CayenneDataObject is used.
208      */

209     String JavaDoc getJavaClassName() {
210         String JavaDoc name = getClassName();
211
212         if (name == null && getDataMap() != null) {
213             name = getDataMap().getDefaultSuperclass();
214         }
215
216         if (name == null) {
217             name = CAYENNE_DATA_OBJECT_CLASS;
218         }
219
220         return name;
221     }
222
223     /**
224      * Returns Java class of persistent objects described by this entity. For generic
225      * entities with no class specified explicitly, default DataMap superclass is used,
226      * and if it is not set - CayenneDataObject is used. Casts any thrown exceptions into
227      * CayenneRuntimeException.
228      *
229      * @since 1.2
230      */

231     public Class JavaDoc getJavaClass() {
232         String JavaDoc name = getJavaClassName();
233
234         try {
235             return Util.getJavaClass(name);
236         }
237         catch (ClassNotFoundException JavaDoc e) {
238             throw new CayenneRuntimeException("Failed to load class "
239                     + name
240                     + ": "
241                     + e.getMessage(), e);
242         }
243     }
244
245     /**
246      * Returns an unmodifiable list of registered {@link EntityListener} objects. Note
247      * that since the order of listeners is significant a list, not just a generic
248      * Collection is returned.
249      *
250      * @since 3.0
251      */

252     public List JavaDoc getEntityListeners() {
253         return Collections.unmodifiableList(entityListeners);
254     }
255
256     /**
257      * Adds a new EntityListener.
258      *
259      * @since 3.0
260      * @throws IllegalArgumentException if a listener for the same class name is already
261      * registered.
262      */

263     public void addEntityListener(EntityListener listener) {
264         Iterator JavaDoc it = entityListeners.iterator();
265         while (it.hasNext()) {
266             EntityListener next = (EntityListener) it.next();
267             if (listener.getClassName().equals(next.getClassName())) {
268                 throw new IllegalArgumentException JavaDoc("Duplicate listener for "
269                         + next.getClassName());
270             }
271         }
272
273         entityListeners.add(listener);
274     }
275
276     /**
277      * Removes a listener matching class name.
278      *
279      * @since 3.0
280      */

281     public void removeEntityListener(String JavaDoc className) {
282         Iterator JavaDoc it = entityListeners.iterator();
283         while (it.hasNext()) {
284             EntityListener next = (EntityListener) it.next();
285             if (className.equals(next.getClassName())) {
286                 it.remove();
287                 break;
288             }
289         }
290     }
291
292     /**
293      * @since 3.0
294      */

295     public EntityListener getEntityListener(String JavaDoc className) {
296         Iterator JavaDoc it = entityListeners.iterator();
297         while (it.hasNext()) {
298             EntityListener next = (EntityListener) it.next();
299             if (className.equals(next.getClassName())) {
300                 return next;
301             }
302         }
303
304         return null;
305     }
306
307     /**
308      * Returns an object that stores callback methods of this entity.
309      *
310      * @since 3.0
311      */

312     public CallbackMap getCallbackMap() {
313         return callbacks;
314     }
315
316     /**
317      * Returns the type of lock used by this ObjEntity. If this entity is not locked, this
318      * method would look in a super entity recursively, until it finds a lock somewhere in
319      * the inheritance hierarchy.
320      *
321      * @since 1.1
322      */

323     public int getLockType() {
324         // if this entity has an explicit lock,
325
// no need to lookup inheritance hierarchy
326
if (lockType != LOCK_TYPE_NONE) {
327             return lockType;
328         }
329
330         ObjEntity superEntity = getSuperEntity();
331         return (superEntity != null) ? superEntity.getLockType() : lockType;
332     }
333
334     /**
335      * Returns the type of lock used by this ObjEntity, regardless of what locking type is
336      * used by super entities.
337      *
338      * @since 1.1
339      */

340     public int getDeclaredLockType() {
341         return lockType;
342     }
343
344     /**
345      * Sets the type of lock used by this ObjEntity.
346      *
347      * @since 1.1
348      */

349     public void setDeclaredLockType(int i) {
350         lockType = i;
351     }
352
353     /**
354      * Returns whether this entity is "generic", meaning it is not mapped to a unique Java
355      * class. Criterion for generic entities is that it either has no Java class mapped or
356      * its class is the same as DataMap's default superclass, or it is CayenneDataObject.
357      *
358      * @since 1.2
359      */

360     public boolean isGeneric() {
361         String JavaDoc className = getClassName();
362         return className == null
363                 || DEFAULT_GENERIC_CLASSES.contains(className)
364                 || (getDataMap() != null && className.equals(getDataMap()
365                         .getDefaultSuperclass()));
366     }
367
368     /**
369      * Returns true if this entity is allowed to be used on the client. Checks that parent
370      * DataMap allows client entities and also that this entity is not explicitly disabled
371      * for the client use.
372      *
373      * @since 1.2
374      */

375     public boolean isClientAllowed() {
376         return (getDataMap() == null || isServerOnly()) ? false : getDataMap()
377                 .isClientSupported();
378     }
379
380     /**
381      * Returns true if this entity is not available on the client.
382      *
383      * @since 1.2
384      */

385     public boolean isServerOnly() {
386         return serverOnly;
387     }
388
389     /**
390      * Sets whether this entity is available on the client.
391      *
392      * @since 1.2
393      */

394     public void setServerOnly(boolean serverOnly) {
395         this.serverOnly = serverOnly;
396     }
397
398     /**
399      * Returns a qualifier that imposes a restriction on what objects belong to this
400      * entity. Returned qualifier is the one declared in this entity, and does not include
401      * qualifiers declared in super entities.
402      *
403      * @since 1.1
404      */

405     public Expression getDeclaredQualifier() {
406         return qualifier;
407     }
408
409     /**
410      * Returns an entity name for a parent entity in the inheritance hierarchy.
411      *
412      * @since 1.1
413      */

414     public String JavaDoc getSuperEntityName() {
415         return superEntityName;
416     }
417
418     /**
419      * Sets a qualifier that imposes a limit on what objects belong to this entity.
420      *
421      * @since 1.1
422      */

423     public void setDeclaredQualifier(Expression qualifier) {
424         this.qualifier = qualifier;
425     }
426
427     /**
428      * Sets an entity name for a parent entity in the inheritance hierarchy.
429      *
430      * @since 1.1
431      */

432     public void setSuperEntityName(String JavaDoc superEntityName) {
433         this.superEntityName = superEntityName;
434     }
435
436     /**
437      * Returns the name of DataObject class described by this entity.
438      */

439     public String JavaDoc getClassName() {
440         return className;
441     }
442
443     /**
444      * Sets the name of the DataObject class described by this entity.
445      */

446     public void setClassName(String JavaDoc className) {
447         this.className = className;
448     }
449
450     /**
451      * Returns the name of ClientDataObject class described by this entity.
452      *
453      * @since 1.2
454      */

455     public String JavaDoc getClientClassName() {
456         return clientClassName;
457     }
458
459     /**
460      * Sets the name of the ClientDataObject class described by this entity.
461      *
462      * @since 1.2
463      */

464     public void setClientClassName(String JavaDoc clientClassName) {
465         this.clientClassName = clientClassName;
466     }
467
468     /**
469      * Returns a fully-qualified name of the super class of the DataObject class. This
470      * value is used as a hint for class generation. If the entity inherits from another
471      * entity, a superclass is the class of that entity.
472      */

473     public String JavaDoc getSuperClassName() {
474         ObjEntity superEntity = getSuperEntity();
475         return (superEntity != null) ? superEntity.getClassName() : superClassName;
476     }
477
478     /**
479      * Sets a fully-qualified name of the super class of the DataObject class. This value
480      * is used as a hint for class generation.
481      * <p>
482      * <i>An attempt to set superclass on an inherited entity has no effect, since a class
483      * of the super entity is always used as a superclass.</i>
484      * </p>
485      */

486     public void setSuperClassName(String JavaDoc superClassName) {
487         this.superClassName = superClassName;
488     }
489
490     /**
491      * Returns a fully-qualified name of the client-side super class of the DataObject
492      * class. This value is used as a hint for class generation. If the entity inherits
493      * from another entity, a superclass is the class of that entity.
494      *
495      * @since 1.2
496      */

497     public String JavaDoc getClientSuperClassName() {
498         ObjEntity superEntity = getSuperEntity();
499         return (superEntity != null)
500                 ? superEntity.getClientClassName()
501                 : clientSuperClassName;
502     }
503
504     /**
505      * Sets a fully-qualified name of the client-side super class of the ClientDataObject
506      * class. This value is used as a hint for class generation.
507      * <p>
508      * <i>An attempt to set superclass on an inherited entity has no effect, since a class
509      * of the super entity is always used as a superclass. </i>
510      * </p>
511      *
512      * @since 1.2
513      */

514     public void setClientSuperClassName(String JavaDoc clientSuperClassName) {
515         this.clientSuperClassName = clientSuperClassName;
516     }
517
518     /**
519      * Returns a "super" entity in the entity inheritance hierarchy.
520      *
521      * @since 1.1
522      */

523     public ObjEntity getSuperEntity() {
524         return (superEntityName != null) ? getNonNullNamespace().getObjEntity(
525                 superEntityName) : null;
526     }
527
528     /**
529      * Returns a DbEntity associated with this ObjEntity.
530      */

531     public DbEntity getDbEntity() {
532
533         // since 1.2 - allow overriding DbEntity in the inheritance hierarchy...
534
if (dbEntityName != null) {
535             return getNonNullNamespace().getDbEntity(dbEntityName);
536         }
537
538         ObjEntity superEntity = getSuperEntity();
539         if (superEntity != null) {
540             return superEntity.getDbEntity();
541         }
542
543         return null;
544     }
545
546     /**
547      * Sets the DbEntity used by this ObjEntity.
548      * <p>
549      * <i>Setting DbEntity on an inherited entity has no effect, since a class of the
550      * super entity is always used as a superclass. </i>
551      * </p>
552      */

553     public void setDbEntity(DbEntity dbEntity) {
554         this.dbEntityName = (dbEntity != null) ? dbEntity.getName() : null;
555     }
556
557     /**
558      * Returns a named attribute that either belongs to this ObjEntity or is inherited.
559      * Returns null if no matching attribute is found.
560      */

561     public Attribute getAttribute(String JavaDoc name) {
562         Attribute attribute = super.getAttribute(name);
563         if (attribute != null) {
564             return attribute;
565         }
566
567         // check embedded attribute
568
int dot = name.indexOf('.');
569         if (dot > 0 && dot < name.length() - 1) {
570             Attribute embedded = getAttribute(name.substring(0, dot));
571             if (embedded instanceof EmbeddedAttribute) {
572                 return ((EmbeddedAttribute) embedded).getAttribute(name
573                         .substring(dot + 1));
574             }
575         }
576
577         if (superEntityName == null) {
578             return null;
579         }
580
581         ObjEntity superEntity = getSuperEntity();
582         return (superEntity != null) ? superEntity.getAttribute(name) : null;
583     }
584
585     /**
586      * Returns a SortedMap of all attributes that either belong to this ObjEntity or
587      * inherited.
588      */

589     public SortedMap JavaDoc getAttributeMap() {
590         if (superEntityName == null) {
591             return super.getAttributeMap();
592         }
593
594         SortedMap JavaDoc attributeMap = new TreeMap JavaDoc();
595         appendAttributes(attributeMap);
596         return attributeMap;
597     }
598
599     /**
600      * Recursively appends all attributes in the entity inheritance hierarchy.
601      */

602     final void appendAttributes(Map JavaDoc map) {
603         map.putAll(super.getAttributeMap());
604
605         ObjEntity superEntity = getSuperEntity();
606         if (superEntity != null) {
607             superEntity.appendAttributes(map);
608         }
609     }
610
611     /**
612      * Returns a Collection of all attributes that either belong to this ObjEntity or
613      * inherited.
614      */

615     public Collection JavaDoc getAttributes() {
616         if (superEntityName == null) {
617             return super.getAttributes();
618         }
619
620         return getAttributeMap().values();
621     }
622
623     /**
624      * Returns a Collection of all attributes that belong to this ObjEntity, excluding
625      * inherited attributes.
626      *
627      * @since 1.1
628      */

629     public Collection JavaDoc getDeclaredAttributes() {
630         return super.getAttributes();
631     }
632
633     /**
634      * Returns a named Relationship that either belongs to this ObjEntity or is inherited.
635      * Returns null if no matching attribute is found.
636      */

637     public Relationship getRelationship(String JavaDoc name) {
638         Relationship relationship = super.getRelationship(name);
639         if (relationship != null) {
640             return relationship;
641         }
642
643         if (superEntityName == null) {
644             return null;
645         }
646
647         ObjEntity superEntity = getSuperEntity();
648         return (superEntity != null) ? superEntity.getRelationship(name) : null;
649     }
650
651     public SortedMap JavaDoc getRelationshipMap() {
652         if (superEntityName == null) {
653             return super.getRelationshipMap();
654         }
655
656         SortedMap JavaDoc relationshipMap = new TreeMap JavaDoc();
657         appendRelationships(relationshipMap);
658         return relationshipMap;
659     }
660
661     /**
662      * Recursively appends all relationships in the entity inheritance hierarchy.
663      */

664     final void appendRelationships(Map JavaDoc map) {
665         map.putAll(super.getRelationshipMap());
666
667         ObjEntity superEntity = getSuperEntity();
668         if (superEntity != null) {
669             superEntity.appendRelationships(map);
670         }
671     }
672
673     public Collection JavaDoc getRelationships() {
674         if (superEntityName == null) {
675             return super.getRelationships();
676         }
677
678         return getRelationshipMap().values();
679     }
680
681     /**
682      * Returns a Collection of all relationships that belong to this ObjEntity, excluding
683      * inherited attributes.
684      *
685      * @since 1.1
686      */

687     public Collection JavaDoc getDeclaredRelationships() {
688         return super.getRelationships();
689     }
690
691     /**
692      * Returns ObjAttribute of this entity that maps to <code>dbAttribute</code>
693      * parameter. Returns null if no such attribute is found.
694      */

695     public ObjAttribute getAttributeForDbAttribute(DbAttribute dbAttribute) {
696         Iterator JavaDoc it = getAttributeMap().values().iterator();
697         while (it.hasNext()) {
698             Object JavaDoc next = it.next();
699
700             if (next instanceof EmbeddedAttribute) {
701                 ObjAttribute embeddedAttribute = ((EmbeddedAttribute) next)
702                         .getAttributeForDbPath(dbAttribute.getName());
703                 if (embeddedAttribute != null) {
704                     return embeddedAttribute;
705                 }
706             }
707             else {
708                 ObjAttribute objAttr = (ObjAttribute) next;
709                 if (objAttr.getDbAttribute() == dbAttribute) {
710                     return objAttr;
711                 }
712             }
713         }
714
715         return null;
716     }
717
718     /**
719      * Returns ObjRelationship of this entity that maps to <code>dbRelationship</code>
720      * parameter. Returns null if no such relationship is found.
721      */

722     public ObjRelationship getRelationshipForDbRelationship(DbRelationship dbRelationship) {
723         Iterator JavaDoc it = getRelationshipMap().entrySet().iterator();
724         while (it.hasNext()) {
725             Map.Entry JavaDoc entry = (Map.Entry JavaDoc) it.next();
726             ObjRelationship objRel = (ObjRelationship) entry.getValue();
727
728             List JavaDoc relList = objRel.getDbRelationships();
729             if (relList.size() != 1) {
730                 continue;
731             }
732
733             if (relList.get(0) == dbRelationship) {
734                 return objRel;
735             }
736         }
737         return null;
738     }
739
740     /**
741      * Clears all the mapping between this obj entity and its current db entity. Clears
742      * mapping between entities, attributes and relationships.
743      */

744     public void clearDbMapping() {
745         if (dbEntityName == null)
746             return;
747
748         Iterator JavaDoc it = getAttributeMap().values().iterator();
749         while (it.hasNext()) {
750             ObjAttribute objAttr = (ObjAttribute) it.next();
751             DbAttribute dbAttr = objAttr.getDbAttribute();
752             if (null != dbAttr) {
753                 objAttr.setDbAttribute(null);
754             }
755         }
756
757         Iterator JavaDoc rels = this.getRelationships().iterator();
758         while (rels.hasNext()) {
759             ((ObjRelationship) rels.next()).clearDbRelationships();
760         }
761
762         dbEntityName = null;
763     }
764
765     /**
766      * Returns <code>true</code> if this ObjEntity represents a set of read-only
767      * objects.
768      *
769      * @return boolean
770      */

771     public boolean isReadOnly() {
772         return readOnly;
773     }
774
775     public void setReadOnly(boolean readOnly) {
776         this.readOnly = readOnly;
777     }
778
779     /**
780      * Returns true if this entity directly or indirectly inherits from a given entity,
781      * false otherwise.
782      *
783      * @since 1.1
784      */

785     public boolean isSubentityOf(ObjEntity entity) {
786         if (entity == null) {
787             return false;
788         }
789
790         if (entity == this) {
791             return false;
792         }
793
794         ObjEntity superEntity = getSuperEntity();
795         if (superEntity == entity) {
796             return true;
797         }
798
799         return (superEntity != null) ? superEntity.isSubentityOf(entity) : false;
800     }
801
802     public Iterator JavaDoc resolvePathComponents(Expression pathExp) throws ExpressionException {
803
804         // resolve DB_PATH if we can
805
if (pathExp.getType() == Expression.DB_PATH) {
806             if (getDbEntity() == null) {
807                 throw new ExpressionException("Can't resolve DB_PATH '"
808                         + pathExp
809                         + "', DbEntity is not set.");
810             }
811
812             return getDbEntity().resolvePathComponents(pathExp);
813         }
814
815         if (pathExp.getType() == Expression.OBJ_PATH) {
816             return new PathIterator((String JavaDoc) pathExp.getOperand(0));
817         }
818
819         throw new ExpressionException("Invalid expression type: '"
820                 + pathExp.expName()
821                 + "', OBJ_PATH is expected.");
822     }
823
824     /**
825      * Transforms an Expression to an analogous expression in terms of the underlying
826      * DbEntity.
827      *
828      * @since 1.1
829      */

830     public Expression translateToDbPath(Expression expression) {
831
832         if (expression == null) {
833             return null;
834         }
835
836         if (getDbEntity() == null) {
837             throw new CayenneRuntimeException(
838                     "Can't translate expression to DB_PATH, no DbEntity for '"
839                             + getName()
840                             + "'.");
841         }
842
843         // converts all OBJ_PATH expressions to DB_PATH expressions
844
// and pass control to the DB entity
845
return expression.transform(new DBPathConverter());
846     }
847
848     /**
849      * Transforms an Expression rooted in this entity to an analogous expression rooted in
850      * related entity.
851      *
852      * @since 1.1
853      */

854     public Expression translateToRelatedEntity(
855             Expression expression,
856             String JavaDoc relationshipPath) {
857
858         if (expression == null) {
859             return null;
860         }
861
862         if (relationshipPath == null) {
863             return expression;
864         }
865
866         if (getDbEntity() == null) {
867             throw new CayenneRuntimeException(
868                     "Can't transform expression, no DbEntity for '" + getName() + "'.");
869         }
870
871         // converts all OBJ_PATH expressions to DB_PATH expressions
872
// and pass control to the DB entity
873

874         DBPathConverter transformer = new DBPathConverter();
875
876         String JavaDoc dbPath = transformer.toDbPath(resolvePathComponents(relationshipPath));
877         Expression dbClone = expression.transform(transformer);
878
879         return getDbEntity().translateToRelatedEntity(dbClone, dbPath);
880     }
881
882     final class DBPathConverter implements Transformer {
883
884         // TODO: make it a public method - resolveDBPathComponents or something...
885
// seems generally useful
886
String JavaDoc toDbPath(Iterator JavaDoc objectPathComponents) {
887             StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
888             while (objectPathComponents.hasNext()) {
889                 Object JavaDoc component = objectPathComponents.next();
890
891                 Iterator JavaDoc dbSubpath;
892
893                 if (component instanceof ObjRelationship) {
894                     dbSubpath = ((ObjRelationship) component)
895                             .getDbRelationships()
896                             .iterator();
897                 }
898                 else if (component instanceof ObjAttribute) {
899                     dbSubpath = ((ObjAttribute) component).getDbPathIterator();
900                 }
901                 else {
902                     throw new CayenneRuntimeException("Unknown path component: "
903                             + component);
904                 }
905
906                 while (dbSubpath.hasNext()) {
907                     CayenneMapEntry subComponent = (CayenneMapEntry) dbSubpath.next();
908                     if (buf.length() > 0) {
909                         buf.append(Entity.PATH_SEPARATOR);
910                     }
911
912                     buf.append(subComponent.getName());
913                 }
914             }
915
916             return buf.toString();
917         }
918
919         public Object JavaDoc transform(Object JavaDoc input) {
920
921             if (!(input instanceof Expression)) {
922                 return input;
923             }
924
925             Expression expression = (Expression) input;
926
927             if (expression.getType() != Expression.OBJ_PATH) {
928                 return input;
929             }
930
931             // convert obj_path to db_path
932

933             String JavaDoc converted = toDbPath(resolvePathComponents(expression));
934             Expression exp = ExpressionFactory.expressionOfType(Expression.DB_PATH);
935             exp.setOperand(0, converted);
936             return exp;
937         }
938     }
939
940     /**
941      * Returns the name of the underlying DbEntity.
942      *
943      * @since 1.1
944      */

945     public String JavaDoc getDbEntityName() {
946         return dbEntityName;
947     }
948
949     /**
950      * Sets the name of underlying DbEntity.
951      *
952      * @since 1.1
953      */

954     public void setDbEntityName(String JavaDoc string) {
955         dbEntityName = string;
956     }
957
958     /**
959      * ObjEntity property changed. May be name, attribute or relationship added or
960      * removed, etc. Attribute and relationship property changes are handled in respective
961      * listeners.
962      *
963      * @since 1.2
964      */

965     public void objEntityChanged(EntityEvent e) {
966         if ((e == null) || (e.getEntity() != this)) {
967             // not our concern
968
return;
969         }
970
971         // handle entity name changes
972
if (e.getId() == EntityEvent.CHANGE && e.isNameChange()) {
973             String JavaDoc oldName = e.getOldName();
974             String JavaDoc newName = e.getNewName();
975
976             DataMap map = getDataMap();
977             if (map != null) {
978                 ObjEntity oe = (ObjEntity) e.getEntity();
979                 Iterator JavaDoc rit = oe.getRelationships().iterator();
980                 while (rit.hasNext()) {
981                     ObjRelationship or = (ObjRelationship) rit.next();
982                     or = or.getReverseRelationship();
983                     if (null != or && or.targetEntityName.equals(oldName)) {
984                         or.targetEntityName = newName;
985                     }
986                 }
987             }
988         }
989     }
990
991     /** New entity has been created/added. */
992     public void objEntityAdded(EntityEvent e) {
993         // does nothing currently
994
}
995
996     /** Entity has been removed. */
997     public void objEntityRemoved(EntityEvent e) {
998         // does nothing currently
999
}
1000
1001    /** Attribute property changed. */
1002    public void objAttributeChanged(AttributeEvent e) {
1003        // does nothing currently
1004
}
1005
1006    /** New attribute has been created/added. */
1007    public void objAttributeAdded(AttributeEvent e) {
1008        // does nothing currently
1009
}
1010
1011    /** Attribute has been removed. */
1012    public void objAttributeRemoved(AttributeEvent e) {
1013        // does nothing currently
1014
}
1015
1016    /** Relationship property changed. */
1017    public void objRelationshipChanged(RelationshipEvent e) {
1018        // does nothing currently
1019
}
1020
1021    /** Relationship has been created/added. */
1022    public void objRelationshipAdded(RelationshipEvent e) {
1023        // does nothing currently
1024
}
1025
1026    /** Relationship has been removed. */
1027    public void objRelationshipRemoved(RelationshipEvent e) {
1028        // does nothing currently
1029
}
1030
1031    /**
1032     * Returns true if the default lifecycle listeners should not be notified of this
1033     * entity lifecycle events.
1034     *
1035     * @since 3.0
1036     */

1037    public boolean isExcludingDefaultListeners() {
1038        return excludingDefaultListeners;
1039    }
1040
1041    public void setExcludingDefaultListeners(boolean excludingDefaultListeners) {
1042        this.excludingDefaultListeners = excludingDefaultListeners;
1043    }
1044
1045    /**
1046     * Returns true if the lifeycle listeners defined on the superclasses should not be
1047     * notified of this entity lifecycle events.
1048     *
1049     * @since 3.0
1050     */

1051    public boolean isExcludingSuperclassListeners() {
1052        return excludingSuperclassListeners;
1053    }
1054
1055    public void setExcludingSuperclassListeners(boolean excludingSuperclassListeners) {
1056        this.excludingSuperclassListeners = excludingSuperclassListeners;
1057    }
1058
1059}
1060
Popular Tags