001: /* Copyright (C) 2003 Finalist IT Group
002: *
003: * This file is part of JAG - the Java J2EE Application Generator
004: *
005: * JAG is free software; you can redistribute it and/or modify
006: * it under the terms of the GNU General Public License as published by
007: * the Free Software Foundation; either version 2 of the License, or
008: * (at your option) any later version.
009: * JAG is distributed in the hope that it will be useful,
010: * but WITHOUT ANY WARRANTY; without even the implied warranty of
011: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
012: * GNU General Public License for more details.
013: * You should have received a copy of the GNU General Public License
014: * along with JAG; if not, write to the Free Software
015: * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
016: */
017:
018: package com.finalist.jaggenerator.modules;
019:
020: import com.finalist.jag.util.TemplateString;
021: import com.finalist.jaggenerator.ForeignKey;
022: import com.finalist.jaggenerator.JagGenerator;
023: import com.finalist.jaggenerator.Utils;
024: import org.w3c.dom.Document;
025: import org.w3c.dom.Element;
026: import org.w3c.dom.NodeList;
027:
028: import javax.swing.*;
029: import javax.swing.tree.DefaultMutableTreeNode;
030:
031: /**
032: * This class models a container-managed relation. A Relation maintains three views: a DefaultMutableTreeNode,
033: * an XML view and a Swing JPanel. Unfortunately this class is kind of a Model, View and Controller rolled into one,
034: * but that's just the way JagBeans have been designed...
035: * <p/>
036: * The relation data is initially generated using foreign key information read from a database table (or just
037: * filled in by hand from the GUI).
038: *
039: * @author Michael O'Connor - Finalist IT Group
040: */
041: public class Relation extends DefaultMutableTreeNode implements JagBean {
042:
043: private String name = "new relation";
044: private String fieldName;
045: private String targetName;
046: private String foreignTable;
047: private String foreignPkFieldName;
048: private String foreignColumn;
049: private String localColumn;
050: private RelationPanel panelView;
051: private Field fieldObject;
052: private Field foreignPkField;
053: private Entity localEntity;
054: private boolean targetMultiple = true; //not yet implemented
055: private boolean bidirectional = false; //not yet implemented
056:
057: /**
058: * Constructs a new Relation from scratch.
059: *
060: * @param localEntity the parent entity bean on the local side of this relation.
061: */
062: public Relation(Entity localEntity) {
063: this .localEntity = localEntity;
064: panelView = new RelationPanel(this , false);
065: }
066:
067: /**
068: * Constructs a Relation from a ForeignKey object.
069: *
070: * @param localEntity the parent entity bean on the local side of this relation.
071: * @param fk the foreign key.
072: */
073: public Relation(Entity localEntity, ForeignKey fk) {
074: this (localEntity, fk, true);
075: }
076:
077: /**
078: * Constructs a Relation from a ForeignKey object.
079: *
080: * @param localEntity the parent entity bean on the local side of this relation.
081: * @param fk the foreign key.
082: * @param waitForInitSignal if <code>true</code> panel delays initialisation until notified.
083: */
084: public Relation(Entity localEntity, ForeignKey fk,
085: boolean waitForInitSignal) {
086: this .localEntity = localEntity;
087: String this Table = Utils.format(localEntity.getLocalTableName()
088: .toString());
089: String thatTable = Utils.format(fk.getPkTableName());
090: name = this Table + '-' + thatTable;
091: targetName = thatTable + '-' + this Table;
092: foreignTable = fk.getPkTableName();
093: fieldName = fk.getFkName() == null ? Utils.format(fk
094: .getFkColumnName()) : fk.getFkName();
095:
096: foreignPkFieldName = Utils.format(fk.getPkColumnName());
097: foreignColumn = fk.getPkColumnName();
098: localColumn = fk.getFkColumnName();
099: panelView = new RelationPanel(this , waitForInitSignal);
100:
101: }
102:
103: /**
104: * (Re-)Constructs a Relation from an XML element.
105: *
106: * @param localEntity the parent entity bean on the local side of this relation.
107: * @param el the XML element.
108: */
109: public Relation(Entity localEntity, Element el) {
110: this .localEntity = localEntity;
111: NodeList nl = el.getElementsByTagName("module-data");
112:
113: for (int i = 0; i < nl.getLength(); i++) {
114: Element child = (Element) nl.item(i);
115: String attName = child.getAttribute("name");
116: String value = null;
117: if (child.getFirstChild() != null) {
118: value = child.getFirstChild().getNodeValue();
119: }
120: if (value != null) {
121: if (attName.equalsIgnoreCase("name")) {
122: name = value;
123: continue;
124: }
125: if (attName.equalsIgnoreCase("field-name")) {
126: fieldName = Utils.firstToLowerCase(value);
127: continue;
128: }
129: if (attName.equalsIgnoreCase("target-name")) {
130: targetName = value;
131: continue;
132: }
133: if (attName.equalsIgnoreCase("target-multiple")) {
134: targetMultiple = "true".equals(value.trim()
135: .toLowerCase());
136: continue;
137: }
138: if (attName.equalsIgnoreCase("bidirectional")) {
139: bidirectional = "true".equals(value.trim()
140: .toLowerCase());
141: continue;
142: }
143: if (attName.equalsIgnoreCase("field")) { //for backwards compatibility (pre v.2.3)
144: fieldName = Utils.firstToLowerCase(value);
145: continue;
146: }
147: if (attName.equalsIgnoreCase("foreign-table")) {
148: foreignTable = value;
149: continue;
150: }
151: if (attName.equalsIgnoreCase("foreign-column")) {
152: foreignColumn = value;
153: continue;
154: }
155: if (attName.equalsIgnoreCase("local-column")) {
156: localColumn = value;
157: continue;
158: }
159: if (attName.equalsIgnoreCase("foreign-field")) {
160: foreignPkFieldName = value;
161: continue;
162: }
163: }
164: }
165:
166: panelView = new RelationPanel(this , true);
167: }
168:
169: public String getRefName() {
170: return name;
171: }
172:
173: /**
174: * Gets the Swing JPanel view of this relation.
175: *
176: * @return the JPanel.
177: */
178: public JPanel getPanel() {
179: return panelView;
180: }
181:
182: /**
183: * Creates the XML view of this relation and appends it as a new child to the specified XML element.
184: *
185: * @param parent the XML element to become parent to this relation child.
186: */
187: public void getXML(Element parent) {
188: Document doc = parent.getOwnerDocument();
189: Element newModule = doc.createElement("module-data");
190: newModule.setAttribute("name", "relation");
191:
192: newModule.appendChild(createElement(doc, "name", name));
193: newModule.appendChild(createElement(doc, "field-name",
194: fieldName));
195: newModule.appendChild(createElement(doc, "local-column",
196: localColumn));
197: newModule.appendChild(createElement(doc, "target-name",
198: targetName));
199: newModule.appendChild(createElement(doc, "target-multiple", ""
200: + targetMultiple));
201: newModule.appendChild(createElement(doc, "bidirectional", ""
202: + bidirectional));
203: newModule.appendChild(createElement(doc, "foreign-table",
204: foreignTable));
205: newModule.appendChild(createElement(doc, "foreign-column",
206: foreignColumn));
207: newModule.appendChild(createElement(doc, "foreign-field",
208: foreignPkFieldName));
209:
210: parent.appendChild(newModule);
211: }
212:
213: /**
214: * Gets 'name' : the name of this relation.
215: *
216: * @return name
217: */
218: public String getName() {
219: return name;
220: }
221:
222: public void setName(String name) {
223: this .name = name;
224: panelView.setName(name);
225: }
226:
227: /**
228: * Gets the name of the imported foreign key field in the parent entity bean on the 'local' side of this relation.
229: *
230: * @return field
231: */
232: public TemplateString getFieldName() {
233: return new TemplateString(fieldName);
234: }
235:
236: public void setFieldName(String fieldName) {
237: this .fieldName = Utils.firstToLowerCase(fieldName);
238: }
239:
240: /**
241: * Gets 'targetName' : the name given to the reciprocal end of this relation (if it is bidirectional).
242: *
243: * @return targetName
244: */
245: public String getTargetName() {
246: return targetName;
247: }
248:
249: public void setTargetName(String targetName) {
250: this .targetName = targetName;
251: }
252:
253: /**
254: * Gets 'targetMultiple' : whether or not this relation maps to multiple entities at the 'foreign' end.
255: *
256: * @return targetMultiple
257: */
258: public boolean isTargetMultiple() {
259: return targetMultiple;
260: }
261:
262: public void setTargetMultiple(boolean targetMultiple) {
263: this .targetMultiple = targetMultiple;
264: }
265:
266: /**
267: * Gets 'bidirectional' : whether or not this relation is also navigable the other way round.
268: *
269: * @return bidirectional
270: */
271: public boolean isBidirectional() {
272: return bidirectional;
273: }
274:
275: public void setBidirectional(boolean bidirectional) {
276: this .bidirectional = bidirectional;
277: }
278:
279: /**
280: * Gets 'foreignTable' : the name of the table at the other end of the relation.
281: *
282: * @return foreignTable
283: */
284: public String getForeignTable() {
285: return foreignTable;
286: }
287:
288: public void setForeignTable(String foreignTable) {
289: this .foreignTable = foreignTable;
290: }
291:
292: /**
293: * Gets the name of the exported primary key field at the other end of the relation.
294: *
295: * @return foreignPkFieldName
296: */
297: public TemplateString getForeignPkFieldName() {
298: return new TemplateString(foreignPkFieldName);
299: }
300:
301: public void setForeignPkFieldName(String foreignField) {
302: this .foreignPkFieldName = foreignField;
303: }
304:
305: public Field getForeignPkField() {
306: return foreignPkField;
307: }
308:
309: public void setForeignPkField(Field foreignPkField) {
310: this .foreignPkField = foreignPkField;
311: }
312:
313: /**
314: * Gets 'foreignColumn' : the name of the primary key column at the other end of the relation.
315: *
316: * @return foreignTable
317: */
318: public String getForeignColumn() {
319: return foreignColumn;
320: }
321:
322: public void setForeignColumn(String foreignColumn) {
323: this .foreignColumn = foreignColumn;
324: }
325:
326: /**
327: * Gets 'localColumn' : the name of the column at the local end of the relation.
328: *
329: * @return String with local column.
330: */
331: public String getLocalColumn() {
332: return localColumn;
333: }
334:
335: public void setLocalColumn(String localColumn) {
336: this .localColumn = localColumn;
337: }
338:
339: /**
340: * Gets the Entity object that this Relation relates to.
341: *
342: * @return Entity
343: */
344: public Entity getRelatedEntity() {
345: return JagGenerator.getEntityByTableName(foreignTable);
346: }
347:
348: /**
349: * The relation is a many to many relation if the related entity is an assocation table.
350: *
351: * @return string with 'true' if the relation is a many to many relation. 'false' if not.
352: */
353: public String isManyToManyRelation() {
354: return getRelatedEntity().getIsAssociationEntity();
355: }
356:
357: public String toString() {
358: return name; // the name used to display this relation in the tree view.
359: }
360:
361: public void setFkField(Field field) {
362: fieldObject = field;
363: }
364:
365: public Field getFkField() {
366: return fieldObject;
367: }
368:
369: public Entity getLocalEntity() {
370: return localEntity;
371: }
372:
373: /**
374: * RelationPanels can't finish initialising themselves until the local-side entity is completely generated
375: * (until all the entity's fields are generated). Call this method to wake up the sleeping initialisers.
376: */
377: public void notifyLocalEntityIsComplete() {
378: synchronized (panelView) {
379: panelView.notifyAll();
380: }
381: }
382:
383: public void notifyFieldNameChanged(String oldName, String text) {
384: panelView.updateFieldName(oldName, text);
385: }
386:
387: private Element createElement(Document doc, String name,
388: String value) {
389: Element newElement = doc.createElement("module-data");
390: newElement.setAttribute("name", name);
391: if (value != null) {
392: newElement.appendChild(doc.createTextNode(value));
393: }
394: return newElement;
395: }
396:
397: }
|