1
2
3
4
5
6
7
8
9
10
11
12
13
14
15 package com.finalist.mmbase2uml;
16
17 import net.sf.mmapps.modules.config.*;
18
19 import java.net.URL;
20 import java.io.IOException;
21 import java.io.FileOutputStream;
22 import java.io.File;
23 import java.io.OutputStream;
24 import java.util.*;
25
26 import com.finalist.uml14.simpleuml.*;
27 import com.finalist.mmbase.umlprofile.MMBaseUMLProfile;
28
29 /***
30 * The MMBase2UMLTester reads an MMBase application and creates a XMI file containg
31 * a UML description of the MMBase application.
32 *
33 * @author kors
34 * @version $Revision: 1.3 $, $Date: 2004/10/23 08:54:40 $
35 */
36 public class MMBase2UML {
37
38 private HashMap typeMappings = new HashMap();
39
40 /***
41 * This application parses an MMBase application and than writes an XMI file
42 * that contains the UML description of the MMBase application.
43 *
44 * @param args The first argument parsed is either a directory with multiple
45 * MMBase-applications, a directory with one single MMBase application or a
46 * remote url to a online MMBase application.
47 * The second argument may be the name of the output directory.
48 */
49 public static void main(String args[]) {
50
51 MMBase2UML mmbase2uml = new MMBase2UML();
52
53 if (args.length > 2) {
54 mmbase2uml.parseApplication(args[0], args[1], args[2]);
55 }
56 if (args.length > 1) {
57 mmbase2uml.parseApplication(args[0], args[1]);
58 }
59 else if (args.length > 0) {
60 mmbase2uml.parseApplication(args[0], null);
61 }
62 else {
63 new DirChooserGui();
64 }
65 }
66
67
68 /***
69 * Analyses the sourcePath that was given. Than start generating the correct XMI
70 * file(s). Also generate a class diagram in DI format.
71 *
72 * @param sourcePath The path to be parsed.
73 * @param targetPath The path to write the XMI files to.
74 */
75 public void parseApplication(String sourcePath, String targetPath) {
76 parseApplication(sourcePath, targetPath, "true");
77 }
78
79 /***
80 * Analyses the sourcePath that was given. Than start generating the correct XMI
81 * file(s).
82 *
83 * @param sourcePath The path to be parsed.
84 * @param targetPath The path to write the XMI files to.
85 * @param createClassDiagram "true" if a class diagram in DI format should be generated.
86 */
87 public void parseApplication(String sourcePath, String targetPath, String createClassDiagram) {
88
89 boolean offline = true;
90 boolean singleApp = true;
91 boolean addClassDiagram = true;
92 if (createClassDiagram != null && !createClassDiagram.equals("true")) {
93 addClassDiagram = false;
94 }
95
96 if (sourcePath.endsWith(File.separator)) {
97 sourcePath = sourcePath.substring(0, sourcePath.length() - 1);
98 }
99 if (sourcePath.indexOf("rmi://") >= 0) {
100 offline = false;
101 }
102 else if (!new File(sourcePath + ".xml").isFile()) {
103 singleApp = false;
104 }
105
106 ApplicationConfiguration appConf = null;
107 SimpleModel simpleModel = null;
108
109 if (singleApp) {
110 if (offline) {
111
112 System.out.println("Parsing a single offline application");
113 appConf = readSingleApp(sourcePath);
114 }
115 else {
116
117 System.out.println("Parsing a single online remote cloud.");
118 appConf = readRemoteApp(sourcePath);
119 }
120
121 if (appConf != null) {
122 simpleModel = createModel(appConf, addClassDiagram);
123 writeModel(simpleModel, targetPath);
124 }
125 }
126 else {
127
128 System.out.println("Parsing multiple offline applications");
129
130 Configuration conf = readMultipleApp(sourcePath);
131 if (conf != null) {
132 ApplicationConfigurations appConfs = conf.getApplicationConfigurations();
133 System.out.println("Found " + appConfs.size() + " application(s).");
134
135 for (int i = 0; i < appConfs.size(); i++) {
136 appConf = appConfs.getApplicationConfiguration(i);
137 simpleModel = createModel(appConf, addClassDiagram);
138
139 writeModel(simpleModel, targetPath);
140 }
141 }
142 }
143
144
145 if (appConf == null) {
146 System.out.println("No application found.");
147 }
148 }
149
150 /***
151 * Reads the MMBase application from the filepath.
152 *
153 * @param filePath A reference to a directory with a single MMBase application.
154 * @return A Configuration containing all the information about the MMBase
155 * application.
156 */
157 public ApplicationConfiguration readSingleApp(String filePath) {
158
159 MMBaseFileConfigurationReader reader = new MMBaseFileConfigurationReader();
160 ApplicationConfiguration appConf = null;
161
162 try {
163 File file = new File(filePath + ".xml");
164 appConf = ConfigurationXMLReader.createApplicationConfiguration(new Configuration(), reader.readFile(file));
165
166 File dir = new File(filePath);
167
168 NodeManagerConfigurations nodes = null;
169
170 try {
171 Configuration configuration = new Configuration();
172 reader.readConfiguration(configuration, dir);
173 nodes = configuration.getNodeManagerConfigurations();
174 }
175 catch (Exception e) {
176 System.out.println("Couldn't read all the nodes.");
177 e.printStackTrace();
178 }
179
180 if (nodes != null) {
181 for (int i = 0; i < nodes.size(); i++) {
182 appConf.addNodeManagerConfiguration(nodes.getNodeManagerConfiguration(i));
183 }
184 }
185 }
186 catch (IOException e) {
187 System.out.println("Error while reading a single MMBase application from: ");
188 e.printStackTrace();
189 }
190 return appConf;
191 }
192
193 /***
194 * Reads multiple applications from the specified directory.
195 *
196 * @param dirPath A reference to a directory with multiple applications.
197 * @return A configuration containing multiple ApplicationConfigurations.
198 */
199 public Configuration readMultipleApp(String dirPath) {
200 File file = new File(dirPath);
201 Configuration conf = new Configuration();
202
203 try {
204 if (file.getCanonicalPath().endsWith(("applications"))) {
205 file = file.getParentFile();
206 }
207 MMBaseFileConfigurationReader reader = new MMBaseFileConfigurationReader();
208 reader.readConfiguration(conf, file);
209
210 return conf;
211 }
212 catch (IOException e) {
213 System.out.println("Error while reading multiple applications from a directory.");
214 e.printStackTrace();
215 }
216 return conf;
217 }
218
219 /***
220 * Reads a remote MMBase cloud and returns a Configuration with all the
221 * information about one application.
222 *
223 * @param url A reference to the remotecloud.
224 * @return A Configuration containing the information of one application.
225 */
226 public ApplicationConfiguration readRemoteApp(String url) {
227
228 ApplicationConfiguration conf = null;
229
230 try {
231 URLApplicationConfigurationReader urlReader = new URLApplicationConfigurationReader();
232 conf = urlReader.getConfiguration(new URL(url));
233 }
234 catch (Exception mfue) {
235 System.out.println("Error reading the remote MMBase application.");
236 mfue.printStackTrace();
237 }
238 return conf;
239 }
240
241 /***
242 * Initialize a model with some standard needed features.
243 *
244 * @param appConf configuration of the application.
245 * @return The initialized model which can be extended with the needed classes.
246 */
247 public SimpleModel initModel(ApplicationConfiguration appConf) {
248
249
250 SimpleModel simpleModel = new SimpleModel();
251
252
253 SimpleClassifier stringClass = new SimpleDataType(MMBaseUMLProfile.MMBASE_STRING_TYPE, SimpleModelElement.PUBLIC);
254 SimpleClassifier intClass = new SimpleDataType(MMBaseUMLProfile.MMBASE_INT_TYPE, SimpleModelElement.PUBLIC);
255 SimpleClassifier htmlClass = new SimpleDataType(MMBaseUMLProfile.MMBASE_HTML_TYPE, SimpleModelElement.PUBLIC);
256 SimpleClassifier byteClass = new SimpleDataType(MMBaseUMLProfile.MMBASE_BYTE_TYPE, SimpleModelElement.PUBLIC);
257 SimpleClassifier floatClass = new SimpleDataType(MMBaseUMLProfile.MMBASE_FLOAT_TYPE, SimpleModelElement.PUBLIC);
258 SimpleClassifier dateClass = new SimpleDataType(MMBaseUMLProfile.MMBASE_DATE_TYPE, SimpleModelElement.PUBLIC);
259 SimpleClassifier booleanClass = new SimpleDataType(MMBaseUMLProfile.MMBASE_BOOLEAN_TYPE, SimpleModelElement.PUBLIC);
260
261 simpleModel.addSimpleClassifier(stringClass);
262 simpleModel.addSimpleClassifier(intClass);
263 simpleModel.addSimpleClassifier(htmlClass);
264 simpleModel.addSimpleClassifier(byteClass);
265 simpleModel.addSimpleClassifier(floatClass);
266 simpleModel.addSimpleClassifier(dateClass);
267 simpleModel.addSimpleClassifier(booleanClass);
268
269 typeMappings.put(MMBaseUMLProfile.MMBASE_STRING_TYPE, stringClass);
270 typeMappings.put(MMBaseUMLProfile.MMBASE_INT_TYPE, intClass);
271 typeMappings.put(MMBaseUMLProfile.MMBASE_HTML_TYPE, htmlClass);
272 typeMappings.put(MMBaseUMLProfile.MMBASE_BYTE_TYPE, byteClass);
273 typeMappings.put(MMBaseUMLProfile.MMBASE_FLOAT_TYPE, floatClass);
274 typeMappings.put(MMBaseUMLProfile.MMBASE_DATE_TYPE, dateClass);
275 typeMappings.put(MMBaseUMLProfile.MMBASE_BOOLEAN_TYPE, booleanClass);
276 typeMappings.put(MMBaseUMLProfile.MMBASE_EVENTTIME_TYPE, dateClass);
277 typeMappings.put(MMBaseUMLProfile.MMBASE_HTML_TYPE, htmlClass);
278 typeMappings.put(MMBaseUMLProfile.MMBASE_INTEGER_TYPE, intClass);
279 typeMappings.put(MMBaseUMLProfile.MMBASE_FIELD_TYPE, stringClass);
280 typeMappings.put(MMBaseUMLProfile.MMBASE_NEWFILE_TYPE, byteClass);
281 typeMappings.put(MMBaseUMLProfile.MMBASE_NEWIMAGE_TYPE, byteClass);
282
283
284 if (appConf.getNodeManagerConfigurations().getNodeManagerConfiguration("images") == null) {
285 SimpleClassifier imagesClass = new SimpleUmlClass("images", SimpleModelElement.PUBLIC);
286 SimpleAttribute imagesTitleAttribute = new SimpleAttribute("title", SimpleModelElement.PUBLIC, stringClass);
287 SimpleAttribute imagesDescriptionAttribute = new SimpleAttribute("description", SimpleModelElement.PUBLIC, stringClass);
288 SimpleAttribute imagesHandleAttribute = new SimpleAttribute("handle", SimpleModelElement.PUBLIC, byteClass);
289 imagesClass.addSimpleAttribute(imagesTitleAttribute);
290 imagesClass.addSimpleAttribute(imagesDescriptionAttribute);
291 imagesClass.addSimpleAttribute(imagesHandleAttribute);
292 simpleModel.addSimpleClassifier(imagesClass);
293 }
294
295
296 if (appConf.getNodeManagerConfigurations().getNodeManagerConfiguration("attachments") == null) {
297 SimpleClassifier attachmentsClass = new SimpleUmlClass("attachments", SimpleModelElement.PUBLIC);
298 SimpleAttribute attachmentsTitleAttribute = new SimpleAttribute("title", SimpleModelElement.PUBLIC, stringClass);
299 SimpleAttribute attachmentsdescriptionAttribute = new SimpleAttribute("description", SimpleModelElement.PUBLIC, stringClass);
300 SimpleAttribute attachmentsFilenameAttribute = new SimpleAttribute("filename", SimpleModelElement.PUBLIC, byteClass);
301 attachmentsClass.addSimpleAttribute(attachmentsTitleAttribute);
302 attachmentsClass.addSimpleAttribute(attachmentsdescriptionAttribute);
303 attachmentsClass.addSimpleAttribute(attachmentsFilenameAttribute);
304 simpleModel.addSimpleClassifier(attachmentsClass);
305 }
306
307
308 if (appConf.getNodeManagerConfigurations().getNodeManagerConfiguration("urls") == null) {
309 SimpleClassifier urlsClass = new SimpleUmlClass("urls", SimpleModelElement.PUBLIC);
310 SimpleAttribute urlsNameAttribute = new SimpleAttribute("name", SimpleModelElement.PUBLIC, stringClass);
311 SimpleAttribute urlsDescriptionAttribute = new SimpleAttribute("description", SimpleModelElement.PUBLIC, stringClass);
312 SimpleAttribute urlsUrlAttribute = new SimpleAttribute("url", SimpleModelElement.PUBLIC, stringClass);
313 urlsClass.addSimpleAttribute(urlsNameAttribute);
314 urlsClass.addSimpleAttribute(urlsDescriptionAttribute);
315 urlsClass.addSimpleAttribute(urlsUrlAttribute);
316 simpleModel.addSimpleClassifier(urlsClass);
317 }
318
319 return simpleModel;
320 }
321
322 /***
323 * Parses the information of the MMBase application and returns a SimpleModel
324 * representing the application. Include a Class Diagram as well.
325 *
326 * @param appConf The application configuration.
327 * @return A SimpleModel that represents the given application.
328 */
329 public SimpleModel createModel(ApplicationConfiguration appConf) {
330 return createModel(appConf, true);
331 }
332
333 /***
334 * Parses the information of the MMBase application and returns a SimpleModel
335 * representing the application. Optional a class diagram will be added.
336 *
337 * @param appConf The application configuration.
338 * @param addClassDiagram if true, a class diagram will be added to the model im DI format.
339 * @return A SimpleModel that represents the given application.
340 */
341 public SimpleModel createModel(ApplicationConfiguration appConf, boolean addClassDiagram) {
342
343 if (appConf == null) {
344 System.out.println("!! The application is null");
345 }
346
347 System.out.println("PARSING APPLICATION: " + appConf.getName());
348 SimpleModel simpleModel = initModel(appConf);
349 if (simpleModel == null) {
350 System.out.println("Model is null!");
351 }
352 simpleModel.setName(appConf.getName());
353
354 NodeManagerConfigurations nodeConfs = appConf.getNodeManagerConfigurations();
355 if (nodeConfs == null) {
356 System.out.println("nodeConfs is null!");
357 }
358 RelationManagerConfigurations relConfs = appConf.getRelationManagerConfigurations();
359 if (relConfs == null) {
360 System.out.println("relConfs is null!");
361 }
362
363 SimpleClassifier appClass = null;
364 SimpleAttribute appAttribute = null;
365 NodeManagerConfiguration nodeConf = null;
366 FieldConfiguration fieldConf = null;
367
368
369 for (int i = 0; i < nodeConfs.size(); i++) {
370 nodeConf = nodeConfs.getNodeManagerConfiguration(i);
371
372 appClass = new SimpleUmlClass(nodeConf.getName(), SimpleModelElement.PUBLIC);
373
374 String extendsClassName = nodeConf.getExtends();
375 if (extendsClassName.equalsIgnoreCase(MMBaseUMLProfile.POSREL_RELATION_BUILDER)
376 || extendsClassName.equalsIgnoreCase(MMBaseUMLProfile.INSREL_RELATION_BUILDER)) {
377 simpleModel.setStereoType(MMBaseUMLProfile.STEREOTYPE_CLASS_RELATION , appClass);
378 }
379 else {
380 simpleModel.setStereoType(MMBaseUMLProfile.STEREOTYPE_CLASS_MMBASE, appClass);
381 }
382
383
384 Properties descriptions = nodeConf.getDescriptions();
385 String description = descriptions.getProperty(MMBaseUMLProfile.DUTCH_LANGUAGE_ID);
386
387 if (description == null) {
388 description = descriptions.getProperty(MMBaseUMLProfile.ENGLISH_LANGUAGE_ID);
389 }
390 if (description == null) {
391 if (descriptions.elements().hasMoreElements()) {
392 description = "" + descriptions.elements().nextElement();
393 }
394 }
395 if (description != null) {
396 simpleModel.addTaggedValue("documentation", description, appClass);
397 }
398
399 FieldConfigurations fieldConfs = nodeConf.getFieldConfigurations();
400 for (int j = 0; j < fieldConfs.size(); j++) {
401 fieldConf = fieldConfs.getFieldConfiguration(j);
402 if (fieldConf == null) {
403 System.out.println("Fieldconf is null!");
404 }
405 if (fieldConf.getGUIType() == null) {
406 System.out.println("ERROR: guiType is not set for field: " + fieldConf.getName() + " in builder: " + nodeConf.getName());
407 System.out.println("Using string now as gui type.");
408 }
409 String guiType = fieldConf.getGUIType();
410 if (guiType != null) {
411 guiType = guiType.toLowerCase();
412 }
413 else {
414 guiType = MMBaseUMLProfile.MMBASE_STRING_TYPE.toLowerCase();
415 }
416 SimpleClassifier type = (SimpleClassifier) typeMappings.get(guiType);
417
418 if (type == null) {
419 System.out.println("Type unknown: " + guiType + ". Using string instead.");
420 type = (SimpleClassifier) typeMappings.get(MMBaseUMLProfile.MMBASE_STRING_TYPE);
421 }
422
423 appAttribute = new SimpleAttribute(fieldConf.getName(), SimpleModelElement.PUBLIC, type);
424
425 if (fieldConf.isNotNull()) {
426 simpleModel.setStereoType(MMBaseUMLProfile.STEREOTYPE_ATTRIBUTE_REQUIRED, appAttribute);
427 }
428
429 if (guiType.equalsIgnoreCase(type.getName())) {
430 if (fieldConf.isNotNull()) {
431 simpleModel.addTaggedValue(MMBaseUMLProfile.TAGGED_VALUE_ATTRIBUTE_MINSIZE, "1", appAttribute);
432 }
433 else {
434 simpleModel.addTaggedValue(MMBaseUMLProfile.TAGGED_VALUE_ATTRIBUTE_MINSIZE, "0", appAttribute);
435 }
436 String maxSize = fieldConf.getSize();
437 if (maxSize == null) {
438 maxSize = MMBaseUMLProfile.TAGGED_VALUE_ATTRIBUTE_MAXSIZE;
439 }
440 simpleModel.addTaggedValue(MMBaseUMLProfile.TAGGED_VALUE_ATTRIBUTE_MAXSIZE, maxSize, appAttribute);
441 }
442
443 appClass.addSimpleAttribute(appAttribute);
444 }
445 simpleModel.addSimpleClassifier(appClass);
446 }
447
448
449 SimpleGeneralization simpleGeneralization = null;
450 for (int i = 0; i < nodeConfs.size(); i++) {
451 nodeConf = nodeConfs.getNodeManagerConfiguration(i);
452
453 SimpleClassifier childClass = simpleModel.getSimpleClassifierRelative(nodeConf.getName());
454 SimpleClassifier parentClass = simpleModel.getSimpleClassifierRelative(nodeConf.getExtends());
455 if (childClass != null && parentClass != null) {
456 simpleGeneralization = new SimpleGeneralization(childClass, parentClass);
457 simpleModel.addSimpleGeneralization(simpleGeneralization);
458 }
459 }
460
461
462 RelationManagerConfiguration relConf = null;
463
464 if (relConfs != null) {
465 for (int i = 0; i < relConfs.size(); i++) {
466 relConf = relConfs.getRelationManagerConfiguration(i);
467 SimpleClassifier sourceClass = simpleModel.getSimpleClassifierRelative(relConf.getSourceNodeManagerName());
468 SimpleClassifier destinationClass = simpleModel.getSimpleClassifierRelative(relConf.getDestinationNodeManagerName());
469
470 if (sourceClass != null && destinationClass != null) {
471 SimpleAssociationEnd sourceEnd = new SimpleAssociationEnd(sourceClass.getName(), sourceClass, 0, -1, true);
472 SimpleAssociationEnd destinationEnd = new SimpleAssociationEnd(destinationClass.getName(), destinationClass, 0, -1, true);
473 SimpleAssociation assoc = new SimpleAssociation(relConf.getRelationTypeName(), sourceEnd, destinationEnd);
474 simpleModel.addSimpleAssociation(assoc);
475 }
476 }
477 }
478
479 if (addClassDiagram) {
480 SimpleDiagram simpleDiagram = new SimpleDiagram(simpleModel.getName());
481 simpleModel.addSimpleDiagram(simpleDiagram);
482 }
483
484 return simpleModel;
485 }
486
487 /***
488 * Writes the model to a file. The file has the "<<name of the model>>.xmi".
489 *
490 * @param simpleModel The model that has to be written to the file.
491 * @param outputDir the directory to write the model to.
492 */
493 public void writeModel(SimpleModel simpleModel, String outputDir) {
494 String dir = "";
495 if (outputDir != null && !"".equals(outputDir)) {
496 dir = outputDir + File.separator;
497 }
498
499 System.out.println("Writing the model to a file.");
500 try {
501 OutputStream outputStream = new FileOutputStream(dir + simpleModel.getName() + ".xmi");
502 simpleModel.writeModel(outputStream);
503 }
504 catch (IOException ioe) {
505 System.out.println("Error writing the file.");
506 ioe.printStackTrace();
507 }
508 }
509 }
510
511 /***
512 * $Log: MMBase2UML.java,v $
513 * Revision 1.3 2004/10/23 08:54:40 ekkelenkamp
514 * magicdraw 8 support
515 *
516 * Revision 1.16 2004/06/25 08:25:49 jeoffrey
517 * fixed bug that reads defaultdata as builders for a singleapp
518 *
519 * Revision 1.15 2004/01/28 07:32:24 rudie
520 * Fixed package name
521 *
522 * Revision 1.14 2004/01/20 10:12:13 rudie
523 * Style fixes.
524 *
525 * Revision 1.13 2004/01/20 08:45:29 rudie
526 * Added more checks on empty guiTypes so no null pointers will occur.
527 *
528 * Revision 1.12 2004/01/14 15:33:41 rudie
529 * Fixed style
530 *
531 * Revision 1.11 2004/01/12 10:42:19 kors
532 * Added a check to see if images, urls and attachments are already defined. If so, dont add them to the model automatically.
533 *
534 * Revision 1.10 2003/11/20 16:02:40 kors
535 * SimpleUml was changed. Relations can now only be added to the SimpleModel and not to the SimpleUmlPackages anymore.
536 *
537 * Revision 1.9 2003/11/12 14:19:57 kors
538 * Removed debug code.
539 *
540 * Revision 1.8 2003/11/12 07:45:37 kors
541 * Stylecheck fix.
542 *
543 * Revision 1.7 2003/11/11 13:40:29 kors
544 * An applications directory instead of an config directory can now be passed to the multiapp application.
545 *
546 * Revision 1.6 2003/11/11 09:39:17 kors
547 * The createModel function now also adds an empty diagram to the model.
548 *
549 * Revision 1.5 2003/11/07 15:59:17 kors
550 * added newfile and newimage mappings
551 *
552 * Revision 1.4 2003/11/07 14:46:27 kors
553 * Changed the application so it now uses the new SimpleUml API.
554 *
555 * Revision 1.3 2003/10/30 15:58:14 kors
556 * The relationname is changed from getName into getRelationTypeName.
557 *
558 * Revision 1.2 2003/10/30 13:01:38 kors
559 * Bugs fixed: incorrect output dir, maxfieldsize nullpointer, guitype unknown nullpointer.
560 *
561 * Revision 1.1 2003/10/30 09:13:10 rudie
562 * moved to other src tree
563 *
564 * Revision 1.1 2003/10/29 13:41:58 kors
565 * *** empty log message ***
566 *
567 *
568 */
569