KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > objectstyle > cayenne > modeler > dialog > objentity > ObjRelationshipInfoModel


1 /* ====================================================================
2  *
3  * The ObjectStyle Group Software License, version 1.1
4  * ObjectStyle Group - http://objectstyle.org/
5  *
6  * Copyright (c) 2002-2005, Andrei (Andrus) Adamchik and individual authors
7  * of the software. All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without
10  * modification, are permitted provided that the following conditions
11  * are met:
12  *
13  * 1. Redistributions of source code must retain the above copyright
14  * notice, this list of conditions and the following disclaimer.
15  *
16  * 2. Redistributions in binary form must reproduce the above copyright
17  * notice, this list of conditions and the following disclaimer in
18  * the documentation and/or other materials provided with the
19  * distribution.
20  *
21  * 3. The end-user documentation included with the redistribution, if any,
22  * must include the following acknowlegement:
23  * "This product includes software developed by independent contributors
24  * and hosted on ObjectStyle Group web site (http://objectstyle.org/)."
25  * Alternately, this acknowlegement may appear in the software itself,
26  * if and wherever such third-party acknowlegements normally appear.
27  *
28  * 4. The names "ObjectStyle Group" and "Cayenne" must not be used to endorse
29  * or promote products derived from this software without prior written
30  * permission. For written permission, email
31  * "andrus at objectstyle dot org".
32  *
33  * 5. Products derived from this software may not be called "ObjectStyle"
34  * or "Cayenne", nor may "ObjectStyle" or "Cayenne" appear in their
35  * names without prior written permission.
36  *
37  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED
38  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
39  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
40  * DISCLAIMED. IN NO EVENT SHALL THE OBJECTSTYLE GROUP OR
41  * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
42  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
43  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF
44  * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
45  * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
46  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
47  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
48  * SUCH DAMAGE.
49  * ====================================================================
50  *
51  * This software consists of voluntary contributions made by many
52  * individuals and hosted on ObjectStyle Group web site. For more
53  * information on the ObjectStyle Group, please see
54  * <http://objectstyle.org/>.
55  */

56 package org.objectstyle.cayenne.modeler.dialog.objentity;
57
58 import java.util.ArrayList JavaDoc;
59 import java.util.Collection JavaDoc;
60 import java.util.Collections JavaDoc;
61 import java.util.Iterator JavaDoc;
62 import java.util.List JavaDoc;
63
64 import org.apache.log4j.Logger;
65 import org.objectstyle.cayenne.CayenneRuntimeException;
66 import org.objectstyle.cayenne.map.DbEntity;
67 import org.objectstyle.cayenne.map.DbRelationship;
68 import org.objectstyle.cayenne.map.Entity;
69 import org.objectstyle.cayenne.map.ObjEntity;
70 import org.objectstyle.cayenne.map.ObjRelationship;
71 import org.objectstyle.cayenne.map.Relationship;
72 import org.objectstyle.cayenne.modeler.util.Comparators;
73 import org.objectstyle.cayenne.util.Util;
74 import org.scopemvc.core.IntIndexSelector;
75 import org.scopemvc.core.ModelChangeEvent;
76 import org.scopemvc.core.Selector;
77 import org.scopemvc.model.basic.BasicModel;
78 import org.scopemvc.model.collection.ListModel;
79
80 /**
81  * A Scope model for mapping an ObjRelationship to one or
82  * more DbRelationships.
83  *
84  * @since 1.1
85  * @author Andrei Adamchik
86  */

87 public class ObjRelationshipInfoModel extends BasicModel {
88     static final Logger logObj = Logger.getLogger(ObjRelationshipInfoModel.class);
89
90
91     public static final Selector DB_RELATIONSHIP_PATH_SELECTOR =
92         Selector.fromString("dbRelationshipPath");
93     public static final Selector SOURCE_ENTITY_NAME_SELECTOR =
94         Selector.fromString("relationship.sourceEntity.name");
95     public static final Selector SELECTED_PATH_COMPONENT_SELECTOR =
96         Selector.fromString("selectedPathComponent");
97     public static final Selector OBJECT_TARGET_SELECTOR =
98         Selector.fromString("objectTarget");
99     public static final Selector OBJECT_TARGETS_SELECTOR =
100         Selector.fromString("objectTargets");
101     public static final Selector RELATIONSHIP_NAME_SELECTOR =
102         Selector.fromString("relationshipName");
103
104     protected ObjRelationship relationship;
105     protected ListModel dbRelationshipPath;
106     protected EntityRelationshipsModel selectedPathComponent;
107     protected ObjEntity objectTarget;
108     protected List JavaDoc objectTargets;
109     protected String JavaDoc relationshipName;
110
111     public ObjRelationshipInfoModel(
112         ObjRelationship relationship,
113         Collection JavaDoc objEntities) {
114
115         this.relationship = relationship;
116         this.relationshipName = relationship.getName();
117         this.objectTarget = (ObjEntity) relationship.getTargetEntity();
118
119         // prepare entities - copy those that have DbEntities mapped, and then sort
120

121         this.objectTargets = new ArrayList JavaDoc(objEntities.size());
122         Iterator JavaDoc entities = objEntities.iterator();
123         while (entities.hasNext()) {
124             ObjEntity entity = (ObjEntity) entities.next();
125             if (entity.getDbEntity() != null) {
126                 objectTargets.add(entity);
127             }
128         }
129
130         Collections.sort(objectTargets, Comparators.getNamedObjectComparator());
131
132         // validate -
133
// current limitation is that an ObjRelationship must have source
134
// and target entities present, with DbEntities chosen.
135
validateCanMap();
136
137         // wrap path
138
this.dbRelationshipPath = new ListModel();
139         Iterator JavaDoc it = relationship.getDbRelationships().iterator();
140         while (it.hasNext()) {
141             DbRelationship dbRelationship = (DbRelationship) it.next();
142             this.dbRelationshipPath.add(new EntityRelationshipsModel(dbRelationship));
143         }
144
145         // add dummy last relationship if we are not connected
146
connectEnds();
147         this.dbRelationshipPath.addModelChangeListener(this);
148     }
149
150     public ObjRelationship getRelationship() {
151         return relationship;
152     }
153
154     public ListModel getDbRelationshipPath() {
155         return dbRelationshipPath;
156     }
157
158     public EntityRelationshipsModel getSelectedPathComponent() {
159         return selectedPathComponent;
160     }
161
162     public void setSelectedPathComponent(EntityRelationshipsModel selectedPathComponent) {
163         if (this.selectedPathComponent != selectedPathComponent) {
164             unlistenOldSubmodel(SELECTED_PATH_COMPONENT_SELECTOR);
165             this.selectedPathComponent = selectedPathComponent;
166             listenNewSubmodel(SELECTED_PATH_COMPONENT_SELECTOR);
167             fireModelChange(
168                 ModelChangeEvent.VALUE_CHANGED,
169                 SELECTED_PATH_COMPONENT_SELECTOR);
170         }
171     }
172
173     /**
174      * Returns currently selected target of the ObjRelationship.
175      */

176     public ObjEntity getObjectTarget() {
177         return objectTarget;
178     }
179
180     /**
181      * Sets a new target
182      */

183     public void setObjectTarget(ObjEntity objectTarget) {
184         if (this.objectTarget != objectTarget) {
185             unlistenOldSubmodel(OBJECT_TARGET_SELECTOR);
186             this.objectTarget = objectTarget;
187             listenNewSubmodel(OBJECT_TARGET_SELECTOR);
188             fireModelChange(ModelChangeEvent.VALUE_CHANGED, OBJECT_TARGET_SELECTOR);
189
190             // change the list of relationships
191
breakChain(-1);
192             connectEnds();
193             fireModelChange(
194                 ModelChangeEvent.VALUE_CHANGED,
195                 DB_RELATIONSHIP_PATH_SELECTOR);
196         }
197     }
198
199     /**
200      * Returns a list of ObjEntities available for target mapping.
201      */

202     public List JavaDoc getObjectTargets() {
203         return objectTargets;
204     }
205
206     public String JavaDoc getRelationshipName() {
207         return relationshipName;
208     }
209
210     public void setRelationshipName(String JavaDoc relationshipName) {
211         this.relationshipName = relationshipName;
212     }
213
214     public void modelChanged(ModelChangeEvent event) {
215
216         // if a different relationship was selected, we may need to rebuild the list
217
Selector selector = event.getSelector();
218         while (selector != null) {
219             if (selector instanceof IntIndexSelector) {
220                 IntIndexSelector indexSel = (IntIndexSelector) selector;
221                 relationshipChanged(indexSel.getIndex());
222                 break;
223             }
224
225             selector = selector.getNext();
226         }
227
228         super.modelChanged(event);
229     }
230
231     /**
232      * Processes relationship path when path component at index was changed.
233      */

234     public synchronized void relationshipChanged(int index) {
235         // strip everything starting from the index
236
breakChain(index);
237
238         // connect the ends
239
connectEnds();
240         
241         // must fire with null selector, or refresh won't happen
242
dbRelationshipPath.fireModelChange(VALUE_CHANGED, null);
243     }
244
245     /**
246      * Stores current state of the model in the internal ObjRelationship.
247      */

248     public synchronized boolean savePath() {
249         // check for modifications
250
if (relationship.getTargetEntity() == objectTarget) {
251             if (Util.nullSafeEquals(relationship.getName(), relationshipName)) {
252                 List JavaDoc oldPath = relationship.getDbRelationships();
253                 if (oldPath.size() == dbRelationshipPath.size()) {
254                     boolean hasChanges = false;
255                     for (int i = 0; i < oldPath.size(); i++) {
256                         EntityRelationshipsModel next =
257                             (EntityRelationshipsModel) dbRelationshipPath.get(i);
258                         if (oldPath.get(i) != next.getSelectedRelationship()) {
259                             hasChanges = true;
260                             break;
261                         }
262                     }
263
264                     if (!hasChanges) {
265                         return false;
266                     }
267                 }
268             }
269         }
270
271         // detected modifications, save...
272
relationship.clearDbRelationships();
273
274         // note on events notification - this needs to be propagated
275
// via old modeler events, but we leave this to the controller
276
// since model knows nothing about Modeler mediator.
277
relationship.setTargetEntity(objectTarget);
278         relationship.setName(relationshipName);
279
280         Iterator JavaDoc it = dbRelationshipPath.iterator();
281         while (it.hasNext()) {
282             EntityRelationshipsModel next = (EntityRelationshipsModel) it.next();
283             Relationship nextPathComponent = next.getSelectedRelationship();
284             if (nextPathComponent == null) {
285                 break;
286             }
287
288             relationship.addDbRelationship((DbRelationship) nextPathComponent);
289         }
290
291         return true;
292     }
293
294     private void breakChain(int index) {
295         // strip everything starting from the index
296
dbRelationshipPath.makeActive(false);
297
298         try {
299             while (dbRelationshipPath.size() > (index + 1)) {
300                 // remove last
301
dbRelationshipPath.remove(dbRelationshipPath.size() - 1);
302             }
303         }
304         finally {
305             dbRelationshipPath.makeActive(true);
306         }
307     }
308
309     // Connects last selected DbRelationship in the path to the
310
// last DbEntity, creating a dummy relationship if needed.
311
private void connectEnds() {
312         Relationship last = null;
313
314         int size = dbRelationshipPath.size();
315         if (size > 0) {
316             EntityRelationshipsModel wrapper =
317                 (EntityRelationshipsModel) dbRelationshipPath.get(size - 1);
318             last = wrapper.getSelectedRelationship();
319
320         }
321
322         Entity target = getEndEntity();
323
324         if (last == null || last.getTargetEntity() != target) {
325             // try to connect automatically, if we can't use dummy connector
326

327             Entity source = (last == null) ? getStartEntity() : last.getTargetEntity();
328             Relationship anyConnector = source.getAnyRelationship(target);
329             EntityRelationshipsModel connector = null;
330
331             connector =
332                 (anyConnector == null)
333                     ? new EntityRelationshipsModel(source, getEndEntity())
334                     : new EntityRelationshipsModel(anyConnector);
335
336             dbRelationshipPath.makeActive(false);
337             try {
338                 dbRelationshipPath.add(connector);
339             }
340             finally {
341                 dbRelationshipPath.makeActive(true);
342             }
343         }
344     }
345
346     private void validateCanMap() {
347         if (relationship.getSourceEntity() == null) {
348             throw new CayenneRuntimeException("Can't map relationship without source entity.");
349         }
350
351         if (relationship.getTargetEntity() == null) {
352             throw new CayenneRuntimeException("Can't map relationship without target entity.");
353         }
354
355         if (getStartEntity() == null) {
356             throw new CayenneRuntimeException("Can't map relationship without source DbEntity.");
357         }
358
359         if (getEndEntity() == null) {
360             throw new CayenneRuntimeException("Can't map relationship without target DbEntity.");
361         }
362     }
363
364     public DbEntity getStartEntity() {
365         return ((ObjEntity) relationship.getSourceEntity()).getDbEntity();
366     }
367
368     public DbEntity getEndEntity() {
369         return objectTarget.getDbEntity();
370     }
371 }
372
Popular Tags