View Javadoc

1   /*   Copyright (C) 2003 Finalist IT Group
2    *
3    *   This file is part of JAG - the Java J2EE Application Generator
4    *
5    *   JAG is free software; you can redistribute it and/or modify
6    *   it under the terms of the GNU General Public License as published by
7    *   the Free Software Foundation; either version 2 of the License, or
8    *   (at your option) any later version.
9    *   JAG is distributed in the hope that it will be useful,
10   *   but WITHOUT ANY WARRANTY; without even the implied warranty of
11   *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12   *   GNU General Public License for more details.
13   *   You should have received a copy of the GNU General Public License
14   *   along with JAG; if not, write to the Free Software
15   *   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
16   */
17  
18  package com.finalist.jaggenerator.modules;
19  
20  import com.finalist.jaggenerator.*;
21  import com.finalist.jag.util.TemplateString;
22  
23  import javax.swing.*;
24  import javax.swing.tree.*;
25  
26  import org.w3c.dom.*;
27  
28  
29  /***
30   * This class models a container-managed relation.  A Relation maintains three views: a DefaultMutableTreeNode,
31   * an XML view and a Swing JPanel.  Unfortunately this class is kind of a Model, View and Controller rolled into one,
32   * but that's just the way JagBeans have been designed...
33   * <p>
34   * The relation data is initially generated using foreign key information read from a database table (or just
35   * filled in by hand from the GUI).
36   *
37   * @author Michael O'Connor - Finalist IT Group
38   */
39  public class Relation extends DefaultMutableTreeNode implements JagBean {
40  
41     private String name = "new relation";
42     private String fieldName;
43     private String targetName;
44     private String foreignTable;
45     private String foreignPkFieldName;
46     private String foreignColumn;
47     private String localColumn;
48     private RelationPanel panelView;
49     private Field fieldObject;
50     private Field foreignPkField;
51     private Entity localEntity;
52     private boolean targetMultiple = true;    //not yet implemented
53     private boolean bidirectional = false;    //not yet implemented
54  
55     /***
56      * Constructs a new Relation from scratch.
57      * @param localEntity the parent entity bean on the local side of this relation.
58      */
59     public Relation(Entity localEntity) {
60        this.localEntity = localEntity;
61        panelView = new RelationPanel(this, false);
62     }
63  
64     /***
65      * Constructs a Relation from a ForeignKey object.
66      * @param localEntity the parent entity bean on the local side of this relation.
67      * @param fk the foreign key.
68      */
69     public Relation(Entity localEntity, ForeignKey fk) {
70        this(localEntity, fk, true);
71     }
72  
73     /***
74      * Constructs a Relation from a ForeignKey object.
75      * @param localEntity the parent entity bean on the local side of this relation.
76      * @param fk the foreign key.
77      * @param waitForInitSignal if <code>true</code> panel delays initialisation until notified.
78      */
79     public Relation(Entity localEntity, ForeignKey fk, boolean waitForInitSignal) {
80        this.localEntity = localEntity;
81        String thisTable = Utils.format(localEntity.getLocalTableName().toString());
82        String thatTable = Utils.format(fk.getPkTableName());
83        name = thisTable + '-' + thatTable;
84        targetName = thatTable + '-' + thisTable;
85        foreignTable = fk.getPkTableName();
86        fieldName = fk.getFkName() == null ? Utils.format(fk.getFkColumnName()) : fk.getFkName();
87  
88        foreignPkFieldName = Utils.format(fk.getPkColumnName());
89        foreignColumn = fk.getPkColumnName();
90        localColumn = fk.getFkColumnName();
91        panelView = new RelationPanel(this, waitForInitSignal);
92  
93  
94     }
95  
96  
97     /*** (Re-)Constructs a Relation from an XML element.
98      *
99      * @param localEntity the parent entity bean on the local side of this relation.
100     * @param el the XML element.
101     */
102    public Relation(Entity localEntity, Element el) {
103       this.localEntity = localEntity;
104       NodeList nl = el.getElementsByTagName("module-data");
105 
106       for (int i = 0; i < nl.getLength(); i++) {
107          Element child = (Element) nl.item(i);
108          String attName = child.getAttribute("name");
109          String value = null;
110          if (child.getFirstChild() != null) {
111             value = child.getFirstChild().getNodeValue();
112          }
113          if (value != null) {
114             if (attName.equalsIgnoreCase("name")) {
115                name = value;
116                continue;
117             }
118             if (attName.equalsIgnoreCase("field-name")) {
119                fieldName = Utils.firstToLowerCase(value);
120                continue;
121             }
122             if (attName.equalsIgnoreCase("target-name")) {
123                targetName = value;
124                continue;
125             }
126             if (attName.equalsIgnoreCase("target-multiple")) {
127                targetMultiple = "true".equals(value.trim().toLowerCase());
128                continue;
129             }
130             if (attName.equalsIgnoreCase("bidirectional")) {
131                bidirectional = "true".equals(value.trim().toLowerCase());
132                continue;
133             }
134             if (attName.equalsIgnoreCase("field")) {        //for backwards compatibility (pre v.2.3)
135                fieldName = Utils.firstToLowerCase(value);
136                continue;
137             }
138             if (attName.equalsIgnoreCase("foreign-table")) {
139                foreignTable = value;
140                continue;
141             }
142             if (attName.equalsIgnoreCase("foreign-column")) {
143                foreignColumn = value;
144                continue;
145             }
146             if (attName.equalsIgnoreCase("local-column")) {
147                localColumn = value;
148                continue;
149             }
150             if (attName.equalsIgnoreCase("foreign-field")) {
151                foreignPkFieldName = value;
152                continue;
153             }
154          }
155       }
156 
157       panelView = new RelationPanel(this, true);
158    }
159 
160 
161    public String getRefName() {
162       return name;
163    }
164 
165    /***
166     * Gets the Swing JPanel view of this relation.
167     * @return the JPanel.
168     */
169    public JPanel getPanel() {
170       return panelView;
171    }
172 
173    /***
174     * Creates the XML view of this relation and appends it as a new child to the specified XML element.
175     * @param parent the XML element to become parent to this relation child.
176     */
177    public void getXML(Element parent) {
178       Document doc = parent.getOwnerDocument();
179       Element newModule = doc.createElement("module-data");
180       newModule.setAttribute("name", "relation");
181 
182       newModule.appendChild(createElement(doc, "name", name));
183       newModule.appendChild(createElement(doc, "field-name", fieldName));
184       newModule.appendChild(createElement(doc, "local-column", localColumn));
185       newModule.appendChild(createElement(doc, "target-name", targetName));
186       newModule.appendChild(createElement(doc, "target-multiple", "" + targetMultiple));
187       newModule.appendChild(createElement(doc, "bidirectional", "" + bidirectional));
188       newModule.appendChild(createElement(doc, "foreign-table", foreignTable));
189       newModule.appendChild(createElement(doc, "foreign-column", foreignColumn));
190       newModule.appendChild(createElement(doc, "foreign-field", foreignPkFieldName));
191 
192       parent.appendChild(newModule);
193    }
194 
195    /***
196     * Gets 'name' : the name of this relation.
197     * @return name
198     */
199    public String getName() {
200       return name;
201    }
202 
203    public void setName(String name) {
204       this.name = name;
205       panelView.setName(name);
206    }
207 
208   /***
209     * Gets the name of the imported foreign key field in the parent entity bean on the 'local' side of this relation.
210     * @return field
211     */
212    public TemplateString getFieldName() {
213       return new TemplateString(fieldName);
214    }
215 
216    public void setFieldName(String fieldName) {
217       this.fieldName = Utils.firstToLowerCase(fieldName);
218    }
219 
220    /***
221     * Gets 'targetName' : the name given to the reciprocal end of this relation (if it is bidirectional).
222     * @return targetName
223     */
224    public String getTargetName() {
225       return targetName;
226    }
227 
228    public void setTargetName(String targetName) {
229       this.targetName = targetName;
230    }
231 
232    /***
233     * Gets 'targetMultiple' : whether or not this relation maps to multiple entities at the 'foreign' end.
234     * @return targetMultiple
235     */
236    public boolean isTargetMultiple() {
237       return targetMultiple;
238    }
239 
240    public void setTargetMultiple(boolean targetMultiple) {
241       this.targetMultiple = targetMultiple;
242    }
243 
244    /***
245     * Gets 'bidirectional' : whether or not this relation is also navigable the other way round.
246     * @return bidirectional
247     */
248    public boolean isBidirectional() {
249       return bidirectional;
250    }
251 
252    public void setBidirectional(boolean bidirectional) {
253       this.bidirectional = bidirectional;
254    }
255 
256    /***
257     * Gets 'foreignTable' : the name of the table at the other end of the relation.
258     * @return foreignTable
259     */
260    public String getForeignTable() {
261       return foreignTable;
262    }
263 
264    public void setForeignTable(String foreignTable) {
265       this.foreignTable = foreignTable;
266    }
267 
268    /***
269     * Gets the name of the exported primary key field at the other end of the relation.
270     * @return foreignPkFieldName
271     */
272    public TemplateString getForeignPkFieldName() {
273       return new TemplateString(foreignPkFieldName);
274    }
275 
276    public void setForeignPkFieldName(String foreignField) {
277       this.foreignPkFieldName = foreignField;
278    }
279 
280    public Field getForeignPkField() {
281       return foreignPkField;
282    }
283 
284    public void setForeignPkField(Field foreignPkField) {
285       this.foreignPkField = foreignPkField;
286    }
287 
288    /***
289     * Gets 'foreignColumn' : the name of the primary key column at the other end of the relation.
290     * @return foreignTable
291     */
292    public String getForeignColumn() {
293       return foreignColumn;
294    }
295 
296    public void setForeignColumn(String foreignColumn) {
297       this.foreignColumn = foreignColumn;
298    }
299 
300    /***
301     * Gets 'localColumn' : the name of the column at the local end of the relation.
302     * @return String with local column.
303     */
304    public String getLocalColumn() {
305       return localColumn;
306    }
307 
308    public void setLocalColumn(String localColumn) {
309       this.localColumn = localColumn;
310    }
311 
312    /***
313     * Gets the Entity object that this Relation relates to.
314     * @return
315     */
316    public Entity getRelatedEntity() {
317       return JagGenerator.getEntityByTableName(foreignTable);
318    }
319 
320    public String toString() {
321       return name;               // the name used to display this relation in the tree view.
322    }
323 
324    public void setFkField(Field field) {
325       fieldObject = field;
326    }
327 
328    public Field getFkField() {
329       return fieldObject;
330    }
331 
332    public Entity getLocalEntity() {
333       return localEntity;
334    }
335 
336    /***
337     * RelationPanels can't finish initialising themselves until the local-side entity is completely generated
338     * (until all the entity's fields are generated).  Call this method to wake up the sleeping initialisers.
339     */
340    public void notifyLocalEntityIsComplete() {
341       synchronized(panelView) {
342          panelView.notifyAll();
343       }
344    }
345 
346 
347    public void notifyFieldNameChanged(String oldName, String text) {
348       panelView.updateFieldName(oldName, text);
349    }
350 
351    private Element createElement(Document doc, String name, String value) {
352       Element newElement = doc.createElement("module-data");
353       newElement.setAttribute("name", name);
354       if (value != null) {
355          newElement.appendChild(doc.createTextNode(value));
356       }
357       return newElement;
358    }
359 
360 }