KickJava   Java API By Example, From Geeks To Geeks.

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


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.io.Serializable JavaDoc;
23 import java.util.Collection JavaDoc;
24 import java.util.Collections JavaDoc;
25 import java.util.Iterator JavaDoc;
26 import java.util.SortedMap JavaDoc;
27 import java.util.StringTokenizer JavaDoc;
28 import java.util.TreeMap JavaDoc;
29
30 import org.apache.cayenne.CayenneRuntimeException;
31 import org.apache.cayenne.exp.Expression;
32 import org.apache.cayenne.exp.ExpressionException;
33 import org.apache.cayenne.util.CayenneMapEntry;
34 import org.apache.cayenne.util.XMLSerializable;
35
36 /**
37  * An Entity is an abstract descriptor for an entity mapping concept. Entity can represent
38  * either a descriptor of database table or a persistent object.
39  *
40  * @author Andrus Adamchik
41  */

42 public abstract class Entity implements CayenneMapEntry, XMLSerializable, Serializable JavaDoc {
43
44     public static final String JavaDoc PATH_SEPARATOR = ".";
45
46     protected String JavaDoc name;
47     protected DataMap dataMap;
48
49     protected SortedMap JavaDoc attributes;
50     protected SortedMap JavaDoc relationships;
51
52     /**
53      * Creates an unnamed Entity.
54      */

55     public Entity() {
56         this(null);
57     }
58
59     /**
60      * Creates a named Entity.
61      */

62     public Entity(String JavaDoc name) {
63         this.attributes = new TreeMap JavaDoc();
64         this.relationships = new TreeMap JavaDoc();
65
66         setName(name);
67     }
68
69     /**
70      * Returns entity name. Name is a unique identifier of the entity within its DataMap.
71      */

72     public String JavaDoc getName() {
73         return name;
74     }
75
76     public void setName(String JavaDoc name) {
77         this.name = name;
78     }
79
80     public Object JavaDoc getParent() {
81         return getDataMap();
82     }
83
84     public void setParent(Object JavaDoc parent) {
85         if (parent != null && !(parent instanceof DataMap)) {
86             throw new IllegalArgumentException JavaDoc("Expected null or DataMap, got: " + parent);
87         }
88
89         setDataMap((DataMap) parent);
90     }
91
92     /**
93      * @return parent DataMap of this entity.
94      */

95     public DataMap getDataMap() {
96         return dataMap;
97     }
98
99     /**
100      * Sets parent DataMap of this entity.
101      */

102     public void setDataMap(DataMap dataMap) {
103         this.dataMap = dataMap;
104     }
105
106     /**
107      * Returns attribute with name <code>attributeName</code> or null if no attribute
108      * with this name exists.
109      */

110     public Attribute getAttribute(String JavaDoc attributeName) {
111         return (Attribute) attributes.get(attributeName);
112     }
113
114     /**
115      * Adds new attribute to the entity, setting its parent entity to be this object. If
116      * attribute has no name, IllegalArgumentException is thrown.
117      */

118     public void addAttribute(Attribute attribute) {
119         if (attribute.getName() == null) {
120             throw new IllegalArgumentException JavaDoc("Attempt to insert unnamed attribute.");
121         }
122
123         // block overrides
124

125         // TODO: change method signature to return replaced attribute and make sure the
126
// Modeler handles it...
127
Object JavaDoc existingAttribute = attributes.get(attribute.getName());
128         if (existingAttribute != null) {
129             if (existingAttribute == attribute) {
130                 return;
131             }
132             else {
133                 throw new IllegalArgumentException JavaDoc("An attempt to override attribute '"
134                         + attribute.getName()
135                         + "'");
136             }
137         }
138         
139         // Check that there aren't any relationships with the same name as the given attribute.
140
Object JavaDoc existingRelationship = relationships.get(attribute.getName());
141         if (existingRelationship != null) {
142             throw new IllegalArgumentException JavaDoc(
143                     "Attribute name conflict with existing relationship '"
144                             + attribute.getName()
145                             + "'");
146         }
147
148         attributes.put(attribute.getName(), attribute);
149         attribute.setEntity(this);
150     }
151
152     /** Removes an attribute named <code>attrName</code>. */
153     public void removeAttribute(String JavaDoc attrName) {
154         attributes.remove(attrName);
155     }
156
157     public void clearAttributes() {
158         attributes.clear();
159     }
160
161     /**
162      * Returns relationship with name <code>relName</code>. Will return null if no
163      * relationship with this name exists in the entity.
164      */

165     public Relationship getRelationship(String JavaDoc relName) {
166         return (Relationship) relationships.get(relName);
167     }
168
169     /** Adds new relationship to the entity. */
170     public void addRelationship(Relationship relationship) {
171         if (relationship.getName() == null) {
172             throw new IllegalArgumentException JavaDoc("Attempt to insert unnamed relationship.");
173         }
174
175         // block overrides
176

177         // TODO: change method signature to return replaced attribute and make sure the
178
// Modeler handles it...
179
Object JavaDoc existingRelationship = relationships.get(relationship.getName());
180         if (existingRelationship != null) {
181             if (existingRelationship == relationship) {
182                 return;
183             }
184             else {
185                 throw new IllegalArgumentException JavaDoc(
186                         "An attempt to override relationship '"
187                                 + relationship.getName()
188                                 + "'");
189             }
190         }
191         
192         // Check that there aren't any attributes with the same name as the given relationship.
193
Object JavaDoc existingAttribute = attributes.get(relationship.getName());
194         if (existingAttribute != null) {
195             throw new IllegalArgumentException JavaDoc(
196                     "Relationship name conflict with existing attribute '"
197                             + relationship.getName()
198                             + "'");
199         }
200
201         relationships.put(relationship.getName(), relationship);
202         relationship.setSourceEntity(this);
203     }
204
205     /** Removes a relationship named <code>attrName</code>. */
206     public void removeRelationship(String JavaDoc relName) {
207         relationships.remove(relName);
208     }
209
210     public void clearRelationships() {
211         relationships.clear();
212     }
213
214     /**
215      * Returns an unmodifiable map of relationships sorted by name.
216      */

217     public SortedMap JavaDoc getRelationshipMap() {
218         // create a new instance ... earlier attempts to cache it in the entity caused
219
// serialization issues (esp. with Hessian).
220
return Collections.unmodifiableSortedMap(relationships);
221     }
222
223     /**
224      * Returns a relationship that has a specified entity as a target. If there is more
225      * than one relationship for the same target, it is unpredictable which one will be
226      * returned.
227      *
228      * @since 1.1
229      */

230     public Relationship getAnyRelationship(Entity targetEntity) {
231         if (getRelationships().isEmpty()) {
232             return null;
233         }
234
235         Iterator JavaDoc it = getRelationships().iterator();
236         while (it.hasNext()) {
237             Relationship r = (Relationship) it.next();
238             if (r.getTargetEntity() == targetEntity) {
239                 return r;
240             }
241         }
242         return null;
243     }
244
245     /**
246      * Returns an unmodifiable collection of Relationships that exist in this entity.
247      */

248     public Collection JavaDoc getRelationships() {
249         // create a new instance ... earlier attempts to cache it in the entity caused
250
// serialization issues (esp. with Hessian).
251
return Collections.unmodifiableCollection(relationships.values());
252     }
253
254     /**
255      * Returns an unmodifiable sorted map of entity attributes.
256      */

257     public SortedMap JavaDoc getAttributeMap() {
258         // create a new instance ... earlier attempts to cache it in the entity caused
259
// serialization issues (esp. with Hessian).
260
return Collections.unmodifiableSortedMap(attributes);
261     }
262
263     /**
264      * Returns an unmodifiable collection of entity attributes.
265      */

266     public Collection JavaDoc getAttributes() {
267         // create a new instance ... earlier attempts to cache it in the entity caused
268
// serialization issues (esp. with Hessian).
269
return Collections.unmodifiableCollection(attributes.values());
270     }
271
272     /**
273      * Translates Expression rooted in this entity to an analogous expression rooted in
274      * related entity.
275      *
276      * @since 1.1
277      */

278     public abstract Expression translateToRelatedEntity(
279             Expression expression,
280             String JavaDoc relationshipPath);
281
282     /**
283      * Convenience method returning the last component in the path iterator.
284      *
285      * @since 1.1
286      * @see #resolvePathComponents(Expression)
287      */

288     public Object JavaDoc lastPathComponent(Expression pathExp) {
289         Object JavaDoc last = null;
290         Iterator JavaDoc it = resolvePathComponents(pathExp);
291         while (it.hasNext()) {
292             last = it.next();
293         }
294
295         return last;
296     }
297
298     /**
299      * Processes expression <code>pathExp</code> and returns an Iterator of path
300      * components that contains a sequence of Attributes and Relationships. Note that if
301      * path is invalid and can not be resolved from this entity, this method will still
302      * return an Iterator, but an attempt to read the first invalid path component will
303      * result in ExpressionException.
304      */

305     public abstract Iterator JavaDoc resolvePathComponents(Expression pathExp)
306             throws ExpressionException;
307
308     /**
309      * Returns an Iterator over the path components that contains a sequence of Attributes
310      * and Relationships. Note that if path is invalid and can not be resolved from this
311      * entity, this method will still return an Iterator, but an attempt to read the first
312      * invalid path component will result in ExpressionException.
313      */

314     public Iterator JavaDoc resolvePathComponents(String JavaDoc path) throws ExpressionException {
315         return new PathIterator(path);
316     }
317
318     // An iterator resolving mapping components represented by the path string.
319
// This entity is assumed to be the root of the path.
320
final class PathIterator implements Iterator JavaDoc {
321
322         private StringTokenizer JavaDoc toks;
323         private Entity currentEnt;
324         private String JavaDoc path;
325
326         PathIterator(String JavaDoc path) {
327             super();
328             this.currentEnt = Entity.this;
329             this.toks = new StringTokenizer JavaDoc(path, PATH_SEPARATOR);
330             this.path = path;
331         }
332
333         public boolean hasNext() {
334             return toks.hasMoreTokens();
335         }
336
337         public Object JavaDoc next() {
338             String JavaDoc pathComp = toks.nextToken();
339
340             // see if this is an attribute
341
Attribute attr = currentEnt.getAttribute(pathComp);
342             if (attr != null) {
343                 // do a sanity check...
344
if (toks.hasMoreTokens()) {
345                     throw new ExpressionException(
346                             "Attribute must be the last component of the path: '"
347                                     + pathComp
348                                     + "'.",
349                             path,
350                             null);
351                 }
352
353                 return attr;
354             }
355
356             Relationship rel = currentEnt.getRelationship(pathComp);
357             if (rel != null) {
358                 currentEnt = rel.getTargetEntity();
359                 return rel;
360             }
361
362             // build error message
363
StringBuffer JavaDoc buf = new StringBuffer JavaDoc();
364             buf
365                     .append("Can't resolve path component: [")
366                     .append(currentEnt.getName())
367                     .append('.')
368                     .append(pathComp)
369                     .append("].");
370             throw new ExpressionException(buf.toString(), path, null);
371         }
372
373         public void remove() {
374             throw new UnsupportedOperationException JavaDoc(
375                     "'remove' operation is not supported.");
376         }
377     }
378
379     final MappingNamespace getNonNullNamespace() {
380         MappingNamespace parent = getDataMap();
381         if (parent == null) {
382             throw new CayenneRuntimeException("Entity '"
383                     + getName()
384                     + "' has no parent MappingNamespace (such as DataMap)");
385         }
386
387         return parent;
388     }
389 }
390
Popular Tags