1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
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;
53 private boolean bidirectional = false;
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")) {
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;
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 }