1
2
3
4
5
6
7 package com.finalist.jaggenerator;
8
9 import com.finalist.jaggenerator.modules.*;
10 import java.util.*;
11 import org.w3c.dom.Document;
12 import org.w3c.dom.Element;
13
14 import javax.swing.*;
15 import javax.swing.event.TreeSelectionEvent;
16 import javax.swing.tree.*;
17 import javax.xml.parsers.DocumentBuilder;
18 import javax.xml.parsers.DocumentBuilderFactory;
19 import javax.xml.parsers.ParserConfigurationException;
20 import javax.xml.transform.dom.DOMSource;
21 import javax.xml.transform.stream.StreamResult;
22 import javax.xml.transform.TransformerFactory;
23 import javax.xml.transform.Transformer;
24 import javax.xml.transform.OutputKeys;
25 import java.awt.*;
26 import java.awt.event.KeyEvent;
27 import java.io.File;
28 import java.io.FileWriter;
29 import java.io.IOException;
30 import java.io.StringWriter;
31 import java.net.URL;
32 import java.util.*;
33 import java.util.List;
34
35 /***
36 *
37 * @author Rudie Ekkelenkamp.
38 */
39 public class SkeletValidator {
40 private Root root = null;
41 private javax.swing.JTree tree = null;
42 private ConsoleLogger logger = null;
43 private HashMap entitiesByTableName = null;
44
45 /*** Creates a new instance of SkeletValidator */
46 public SkeletValidator(Root root, javax.swing.JTree tree, HashMap entitiesByTableName, ConsoleLogger logger) {
47 this.root = root;
48 this.tree = tree;
49 this.logger = logger;
50 this.entitiesByTableName = entitiesByTableName;
51 }
52
53
54 /***
55 * Check on projectname, description, datasource name, jndi-name and mapping, etc..
56 * @return null if valid, returns a message string in case of an error.
57 *
58 */
59 public String validateSkelet() {
60 boolean atLeastOneCompositePK = false;
61 boolean valid = true;
62 boolean autoGeneratedStringInvalidHibernate = false;
63 boolean isRelatedEntityComposite = false;
64 String message = "";
65 String businessTier = (String) root.config.getTemplateSettings().get(JagGenerator.TEMPLATE_BUSINESS_TIER);
66 String appServer = (String) root.config.getTemplateSettings().get(JagGenerator.TEMPLATE_APPLICATION_SERVER);
67 String useJava5 = (String) root.config.getTemplateSettings().get(JagGenerator.TEMPLATE_USE_JAVA5);
68
69
70 try {
71
72 if (root.app.nameText.getText() == null || "".equals(root.app.nameText.getText())) {
73 valid = false;
74 message += "No valid application name has been set in the 'Application settings'.\r\n";
75 } else if (!root.app.nameText.getText().toLowerCase().equals(root.app.nameText.getText())) {
76
77 valid = false;
78 message += "No valid application name in the 'Application settings'. Should be only lowercase!.\r\n";
79 }
80 } catch (Exception e) {
81 valid = false;
82 message += "No valid application name has been set in the 'Application settings'.\r\n";
83 }
84
85 try {
86
87 if (root.app.descriptionText.getText() == null || "".equals(root.app.descriptionText.getText())) {
88 valid = false;
89 message += "No valid application description has been set in the 'Application settings'.\r\n";
90 } else {
91
92 String firstChar = root.app.descriptionText.getText().substring(0, 1);
93 if (!firstChar.toUpperCase().equals(firstChar)) {
94 valid = false;
95 message += "No valid application description has been set in the 'Application settings'. First character should be uppercase!\r\n";
96 }
97 }
98 } catch (Exception e) {
99 valid = false;
100 message += "No valid application description has been set in the 'Application settings'.\r\n";
101 }
102
103 try {
104
105 if (root.app.rootPackageText.getText() == null || "".equals(root.app.rootPackageText.getText())) {
106 valid = false;
107 message += "No valid root package set in the 'Application settings'.\r\n";
108 }
109 } catch (Exception e) {
110 valid = false;
111 message += "No valid root package set in the 'Application settings'.\r\n";
112 }
113
114 try {
115
116 if (root.datasource.jdbcURLCombo.getSelectedItem() == null || "".equals(root.datasource.jdbcURLCombo.getSelectedItem())) {
117 valid = false;
118 message += "No valid datasource URL set in the Datasource form.\r\n";
119 }
120 } catch (Exception e) {
121 valid = false;
122 message += "No valid datasource URL set in the Datasource form.\r\n";
123 }
124
125 try {
126
127 if (root.datasource.jndiText.getText() == null || "".equals(root.datasource.jndiText.getText()) || "jdbc/".equals(root.datasource.jndiText.getText())) {
128 valid = false;
129 message += "No valid datasource jndi-name set in the Datasource form.\r\n";
130 }
131 } catch (Exception e) {
132 valid = false;
133 message += "No valid datasource jndi-name set in the Datasource form.\r\n";
134 }
135
136
137 HashMap entityRefs = new HashMap();
138 ArrayList el = root.getEntityEjbs();
139 for (int i = 0; i < el.size(); i++) {
140 Entity e = (Entity) el.get(i);
141
142 entityRefs.put(e.getRefName(), null);
143 }
144
145
146 try {
147 ArrayList sl = root.getSessionEjbs();
148 for (int i = 0; i < sl.size(); i++) {
149 Session s = (Session) sl.get(i);
150 ArrayList allRefs = s.getEntityRefs();
151 for (int j = 0; j < allRefs.size(); j++) {
152 if (!entityRefs.containsKey(allRefs.get(j))) {
153 valid = false;
154 message += "The reference " + allRefs.get(j) + " in Service Bean " + s.getRefName() + " doesn't exist .\r\n";
155 }
156 }
157
158 }
159 } catch (Exception e) {
160 valid = false;
161 message += "Error in Service Bean.\r\n";
162 }
163
164
165 try {
166
167 ArrayList nl = root.getEntityEjbs();
168 for (int i = 0; i < nl.size(); i++) {
169 Entity e = (Entity) nl.get(i);
170 List relations = e.getRelations();
171 for (int r = 0; r < relations.size(); r++) {
172 Relation relation = (Relation) relations.get(r);
173 if (relation.getRelatedEntity().isCompositeKey()) {
174
175
176 isRelatedEntityComposite = true;
177 }
178
179 }
180
181
182
183
184
185 List fields = e.getFields();
186 for (int j = 0; j < fields.size(); j++) {
187 Field field = (Field) fields.get(j);
188 if (field.autoGeneratedCheckBox.isSelected() && field.foreignKeyCheckBox.isSelected()) {
189 logger.log("Field: " + field.getName() + " of entity : " + e.getName() + " cannot have autogenerated primary key selected and be a foreign key!");
190 valid = false;
191 message += "Field: " + field.getName() + " of entity : " + e.getName() + " cannot have autogenerated primary key selected and be a foreign key!.\r\n";
192 }
193 if (field.autoGeneratedCheckBox.isSelected()) {
194 if ("java.lang.String".equalsIgnoreCase(field.getType())) {
195
196
197 String fieldSize = field.getSize();
198 try {
199 int size = Integer.parseInt(fieldSize);
200 if (size < 32) {
201 autoGeneratedStringInvalidHibernate = true;
202 }
203 } catch (Exception ex) {
204
205
206 }
207 }
208 }
209
210 }
211
212 if (e.isCompositeCombo.getSelectedItem().equals("true")) {
213
214
215
216
217 atLeastOneCompositePK = true;
218
219 if (e.pKeyTypeText.getText() == null || e.pKeyTypeText.getText().equals("")) {
220
221 logger.log("Primary key type is empty, but should be set since composite primary key has been set to true for Entity EJB: " + e.getRefName());
222 valid = false;
223 message += "Primary key type is empty, but should be set since composite primary key has been set to true for Entity EJB: " + e.getRefName() + ".\r\n";
224 }
225
226 if (e.pKeyText.getText() != null && !e.pKeyText.getText().equals("")) {
227
228 logger.log("Primary key should be empty since the since composite primary key has been set to true for Entity EJB: " + e.getRefName());
229 valid = false;
230 message += "Primary key should be empty, since composite primary key has been set to true for Entity EJB: " + e.getRefName() + ".\r\n";
231 }
232
233 if (e.countPrimaryKeyFields() <= 1) {
234 logger.log("In the field specifications for Entity EJB: " + e.getRefName() + " there should be more than one field that has been marked as primary key. Now only " + e.countPrimaryKeyFields() + " have been marked as primary key!");
235 valid = false;
236 message += "In the field specifications for Entity EJB: " + e.getRefName() + " there should be more than one field that has been marked as primary key. Now only " + e.countPrimaryKeyFields() + " have been marked as primary key!.\r\n";
237 }
238
239 } else if ((e.isCompositeCombo.getSelectedItem()).equals("false")) {
240 if (e.pKeyTypeText.getText() == null || e.pKeyTypeText.getText().equals("")) {
241 logger.log("No primary key set for entity bean: " + e.getRefName());
242 valid = false;
243 message += "No primary key set for entity bean: " + e.getRefName() + ".\r\n";
244 }
245
246 if (e.countPrimaryKeyFields() > 1) {
247
248 if (e.countPrimaryKeyFields() > 1) {
249 logger.log("More than 1 primary key declared, while composite primary key is set to false for entity bean '" + e.getRefName() + "' .");
250 valid = false;
251 message += "More than 1 primary key declared, while composite primary key is set to false for entity bean '" + e.getRefName() + "' .\r\n";
252 }
253 }
254
255 if (e.countPrimaryKeyFields() == 1) {
256
257 String name = e.getFirstPrimaryKeyFieldName();
258 String type = e.getPrimaryKeyClass();
259
260 if ((name == null) || e.pKeyText.getText() == null || !name.equals(e.pKeyText.getText())) {
261 logger.log("Non-matching primary keys! In entity bean '" + e.getRefName() + "' the field '" + name + "' has been marked as primary key, yet that entity has primary key '" + e.pKeyText.getText() + "'.");
262 valid = false;
263 message += "Non-matching primary keys! In entity bean '" + e.getRefName() + "' the field '" + name + "' has been marked as primary key, yet that entity has primary key '" + e.pKeyText.getText() + "'.\r\n";
264 }
265 if ((type == null) || e.pKeyTypeText.getText() == null || !type.equals(e.pKeyTypeText.getText())) {
266 logger.log("Non-matching primary key types! In entity bean '" + e.getRefName() + "' the field '" + name + "' has been marked as primary key and has type '" + type + "', yet the entity has primary key type '" + e.pKeyTypeText.getText() + "'.");
267 valid = false;
268 message += "Non-matching primary key types! In entity bean '" + e.getRefName() + "' the field '" + name + "' has been marked as primary key and has type '" + type + "', yet the entity has primary key type '" + e.pKeyTypeText.getText() + "'.\r\n";
269 }
270 }
271 }
272 }
273
274 } catch (Exception e) {
275 valid = false;
276 message += "Error in Entity Bean.\r\n";
277 }
278
279
280 String badEntity = getEntityWithDuplicateRelationNames();
281 if (badEntity != null) {
282 valid = false;
283 message += "Entity bean " + badEntity + " has more than one relation with the same 'relation name'.\n" +
284 "This is not allowed! Please rename at least one of the relation names.\r\n";
285 }
286
287
288 List unreferencedEntities = getEntityWithUnreferencedRelations();
289 if (!unreferencedEntities.isEmpty()) {
290 valid = false;
291 StringBuffer tmp = new StringBuffer();
292 Iterator i = unreferencedEntities.iterator();
293 while (i.hasNext()) {
294 String[] details = (String[]) i.next();
295 if (!"".equals(details[2])) {
296 tmp.append("Entity bean '" + details[0] + "' contains a relation '" + details[1] +
297 "' that references a table '" + details[2] + "',\n" +
298 "which doesn't correspond to any entity bean. Please either:\n" +
299 "\ta) delete the relation,\n" +
300 "\tb) create an entity bean for the table '" + details[2] + "', or\n" +
301 "\tc) in the relation, correct the 'foreign table' value.\r\n");
302 }
303 }
304 message += tmp.toString();
305 }
306
307
308 String relationErrorMessage = getRelationWithInvalidData();
309 if (relationErrorMessage != null) {
310 valid = false;
311 message += relationErrorMessage;
312 }
313
314 if (isRelatedEntityComposite) {
315 String msg = "At least one target entity of a relation has a composite primary key. JAG doesn't support this.\r\n";
316 logger.log(msg);
317 valid = false;
318 message += msg;
319 }
320
321 String templateValue = (String) root.config.getTemplateSettings().get(JagGenerator.TEMPLATE_USE_RELATIONS);
322 if ("false".equalsIgnoreCase(templateValue)) {
323
324
325
326 if (isRelationPresentInModel()) {
327 valid = false;
328 message += "The Container-managed relations checkbox in the Configuration screen was unchecked,\r\n" +
329 "but there are still relations defined in the project.\r\n" +
330 "Either enable Container-managed relations or remove the relations from the project.\r\n";
331 }
332 }
333
334
335 if (atLeastOneCompositePK) {
336
337 if (JagGenerator.TEMPLATE_BUSINESS_TIER_HIBERNATE2.equalsIgnoreCase(businessTier) ||
338 (JagGenerator.TEMPLATE_BUSINESS_TIER_HIBERNATE3.equalsIgnoreCase(businessTier) &&
339 "false".equals(useJava5)
340 )
341 ) {
342 logger.log("JAG does not support composite primary keys for Hibernate.");
343 valid = false;
344 message += "JAG does not support composite primary keys for Hibernate.\r\n";
345 }
346 }
347
348 if (autoGeneratedStringInvalidHibernate) {
349
350 if (JagGenerator.TEMPLATE_BUSINESS_TIER_HIBERNATE2.equalsIgnoreCase(businessTier) ||
351 JagGenerator.TEMPLATE_BUSINESS_TIER_HIBERNATE3.equalsIgnoreCase(businessTier)
352 ) {
353 String msg = "At least one autogenerated primary key field of type string has size < 32. Hibernate cannot autogenerate this primary key.\r\n";
354 logger.log(msg);
355 valid = false;
356 message += msg;
357 }
358 }
359
360
361
362 if (JagGenerator.TEMPLATE_APPLICATION_SERVER_TOMCAT_5.equalsIgnoreCase(appServer)) {
363
364
365 if (!JagGenerator.TEMPLATE_BUSINESS_TIER_HIBERNATE2.equalsIgnoreCase(businessTier) &&
366 !JagGenerator.TEMPLATE_BUSINESS_TIER_HIBERNATE3.equalsIgnoreCase(businessTier)
367 )
368 {
369 String msg = "Only hibernate can be selected for the Tomcat application server.\r\n";
370 logger.log(msg);
371 valid = false;
372 message += msg;
373 }
374
375 }
376
377 if (!JagGenerator.TEMPLATE_APPLICATION_SERVER_JBOSS_4_X.equalsIgnoreCase(appServer)) {
378 if (JagGenerator.TEMPLATE_BUSINESS_TIER_EJB3.equalsIgnoreCase(businessTier)) {
379
380 logger.log("EJB3 is only supported for the JBoss 4.x application server.");
381 valid = false;
382 message += "EJB3 is only supported for the JBoss 4.x application server.\r\n";
383 }
384 }
385
386 if (!valid) {
387 return message;
388 } else {
389 return null;
390 }
391 }
392
393 private String getEntityWithDuplicateRelationNames() {
394 Iterator entities = root.getEntityEjbs().iterator();
395 while (entities.hasNext()) {
396 Entity entity = (Entity) entities.next();
397 Set relationNames = new HashSet();
398 for (int i = 0; i < entity.getChildCount(); i++) {
399 TreeNode child = entity.getChildAt(i);
400 if (child instanceof Relation) {
401 Relation relation = (Relation) child;
402 String relName = relation.getName();
403 if (relationNames.contains(relName)) {
404 tree.setSelectionPath(new TreePath(relation.getPath()));
405 return entity.getRefName();
406 }
407 relationNames.add(relName);
408 }
409 }
410 }
411 return null;
412 }
413 /***
414 * Finds any invalid relations, whose referenced foreign tables do not correspond to entity beans.
415 *
416 * @return List of String[] (never null), where:
417 * [0] is the name of the entity bean containing the relation
418 * [1] is the name of the relation
419 * [2] is the name of the referenced table, for which there is no entity bean.
420 */
421 private List getEntityWithUnreferencedRelations() {
422 ArrayList result = new ArrayList();
423 Iterator entities = root.getEntityEjbs().iterator();
424 while (entities.hasNext()) {
425 Entity entity = (Entity) entities.next();
426 for (int i = 0; i < entity.getChildCount(); i++) {
427 TreeNode child = entity.getChildAt(i);
428 if (child instanceof Relation) {
429 Relation relation = (Relation) child;
430 String referencedTable = relation.getForeignTable();
431 if (entitiesByTableName.get(referencedTable) == null) {
432 result.add(new String[]{entity.getName().toString(), relation.getName(), referencedTable});
433 }
434 }
435 }
436 }
437 return result;
438 }
439
440 private String getRelationWithInvalidData() {
441 Iterator entities = root.getEntityEjbs().iterator();
442 while (entities.hasNext()) {
443 Entity entity = (Entity) entities.next();
444 for (int i = 0; i < entity.getChildCount(); i++) {
445 TreeNode child = entity.getChildAt(i);
446 if (child instanceof Relation) {
447 Relation relation = (Relation) child;
448
449 String foreignTable = relation.getForeignTable();
450 if (foreignTable == null || "".equals(foreignTable.trim())) {
451 return "Relation '" + relation + "' within entity '" + entity.getName() +
452 "' has no value for 'foreign table' \n" +
453 "(the name of the table at the foreign side of this relation). \n" +
454 "Please provide a value!";
455 }
456
457 if (entitiesByTableName.get(foreignTable) == null) {
458 return null;
459
460
461 }
462
463 String foreignPkColumn = relation.getForeignColumn();
464 if (foreignPkColumn == null || "".equals(foreignPkColumn.trim())) {
465 return "Relation '" + relation + "' within entity '" + entity.getName() +
466 "' has no value for 'foreign table primary key' \n" +
467 "(the name of the PK imported from table '" + relation.getForeignTable() +
468 "' that represents the foreign side of this relation). \n" +
469 "Please provide a value!";
470 }
471
472 boolean found = false;
473 List fields = relation.getRelatedEntity().getFields();
474 Iterator j = fields.iterator();
475 while (j.hasNext()) {
476 Field field = (Field) j.next();
477 if (field.getColumnName().equalsIgnoreCase(foreignPkColumn)) {
478 found = true;
479 break;
480 }
481 }
482
483 if (!found) {
484 return "Relation '" + relation + "' within entity '" + relation.getRelatedEntity().getName() +
485 "' has an invalid value (" + foreignPkColumn + ") for 'foreign table primary key' \n" +
486 "(the name of the PK imported from table '" + relation.getRelatedEntity().getLocalTableName() +
487 "' that represents the foreign side of this relation). \n" +
488 "Please provide a valid value!";
489 }
490
491 }
492 }
493 }
494 return null;
495 }
496
497 /***
498 * Helper method to check if there are any relations present in the model.
499 */
500 private boolean isRelationPresentInModel() {
501 Iterator entities = root.getEntityEjbs().iterator();
502 while (entities.hasNext()) {
503 Entity entity = (Entity) entities.next();
504
505 for (int i = 0; i < entity.getChildCount(); i++) {
506 TreeNode child = entity.getChildAt(i);
507
508 if (child instanceof Relation) {
509 return true;
510 }
511 }
512 }
513 return false;
514 }
515
516
517
518 }