UML wouldn't be worth all the sophisticated work if all it came down to was pretty vector graphics. When analyzing and designing a software system, your final goal will be to generate well-implemented code.
Poseidon for UML provides a very powerful and flexible code generation framework, based on a template mechanism. It is currently used to generate a variety of code types including Java and HTML, but it is flexible enough to generate any kind of programming language, or other output, such as XML.
Java code generation is usually based on the classes of a model and other information displayed in the respective Class Diagrams. Additionally, Poseidon can generate setter and getter methods for the fields of each class.
By default, associations between classes in UML are bi-directional; that is, associations allow navigation between classes in both directions. For the common object-oriented programming languages, these need to be transformed into separate uni-directional associations. If one of these is set, the other should be set accordingly. The code for managing bidirectional as well as unidirectional associations is also generated automatically.
Code and documentation generation are both invoked from the Generation menu.
Select the type of generation you would like from the Generation menu and a dialog will appear. Here you can select or deselect model elements from the tree, specify an output and a template folder, and indicate if the destination folder should be cleared. Poseidon can remember your selection of model elements if you enable the checkbox titled, 'Remember current node selection'.
Note that the output and template folders are saved by project and language. This means that output of Java generation can be placed in one folder, and Perl generation from the same project can be placed in another folder. These folder preferences will be saved to the current project, but another project will not recognize these preferences and must have its own preferences set. This is to avoid accidentally overwriting the output from a previous project.
You'll find the generated Java files in the specified output folder, sorted by packages.
Software engineers often run into the problem of having to re-engineer an existing project for which only code and no models are available. This is where reverse-engineering comes into play; a tool analyzes the existing code and auto-generates a model and a set of Class diagrams for it.
Poseidon for UML can do this for Java programs, where source code is available and is in a state where it can be compiled without errors. With the corresponding JAR Import function (available only in the Professional and Enterprise editions), it even works with JAR files of compiled Java classes.
To launch this process, go to themenu and direct the file chooser to the sources' root package. It will then analyze this as well as all sub-packages. The outcome is a model containing the corresponding packages, all the classes, their complete interface, their associations, as well as one Class Diagram for each package. Note that the path that you select here will be automatically adopted by the generation dialog. The next time you open the code generation dialog, this path will be displayed as output folder by default.
If the imported file uses classes that are part of the JDK, these classes will be created in the model as required, so you may see some apparently empty classes in the package java in your model. This is of no concern and is done solely to have a smaller model. But these classes are necessary to have a consistent project. All classes that the imported files use must be present in the model.
Additionally, from the settings dialog you can give an import classpath. This is necessary to make the model complete if a file references classes that are not imported themselves. Here you can specify one or more jar files, each entry separated by a colon. If you want to import files that make use of foo.jar, anotherfoo.jar and stillanotherfoo.jar, then it should look similar to this:
Classes that are needed to make the model complete but are not present in the package structure are created on demand. If you give an import classpath but the imported file does not use any classes from it, then no additional classes will show up in your model.
Generating code and reverse engineering that same code still does not make round-trip engineering. Reverse-engineering generates a new model from existing code, but it does not by itself reconnect the existing code to an existing model. This feature is only available in the Professional and Enterprise Editions, which contain the RoundTrip UML/Java Plug-in. It is one of the most recommended and highly sophisticated features provided by Poseidon for UML.
Generate a UML model from your existing code, change the model, re-generate the code, change the code and so on. All generated Java code files are watched, so that changes you have made with an external editor are imported into Poseidon's model of your project. Use your favorite source code editor to edit method bodies, add or remove methods and member variables. Poseidon keeps track of all changes, and all your project data is in one place - in Poseidon.
Please note that the round-trip plug-in is primarily an import tool; it imports changes in the source code for you and updates the model as necessary. Automatic code generation in the background is not yet implemented, but is planned for a future release.
Create a model with Poseidon, or import sources into Poseidon. See the Section called Importing Files in Chapter 9 for more details on importing.
Enable roundtrip by clicking on the roundtrip button . The button will turn from red to green. If roundtrip is already enabled, the green roundtrip button will appear in the toolbar, and there is no need to click the button. The 'Invalid Roundtrip Settings' dialog will appear because no project root has been set yet. This is normal and expected. Click 'Open Settings Dialog' to set the project root.
Set the project root by clicking on the ellipse button and navigating to the desired project root directory.
Once you have located the proper directory, click the 'Set Project Root' button. Note that soft links cannot be used here. Click 'Apply' in the Settings dialog.
The message in the lower left corner of the Settings dialog will now prompt you to set one or more source paths in order to tell Poseidon where to store the generated code. This directory must be empty, or you will encounter an error message. Click the 'Add Folder...' button.
Once you have located the proper directory, click the 'Add Sourcepath Folder' button. Note that soft links cannot be used here. Click the 'Apply' button in the Settings dialog. Repeat this for all source paths you would like to add.
Poseidon will now check to see if the source and the model are currently in synch. If you have opened an existing project or added elements to a new project and then enabled roundtrip, there will be no corresponding source code so you will be prompted to generate this code.
The synchronization dialog shows any new element that has not been generated yet, even if this element has been previously imported. This means that it is possible for this dialog to open more than once, for instance if you are reloading a modified project.
This dialog is always available from the toolbar.
Classifiers must be assigned to the source paths or explicitly set to be excluded from roundtripping before code generation can begin. Click on the 'Classifier Mapping' tab of the Settings dialog.
Highlight a classifier by clicking on it in the upper field (or hold the control key while clicking to highlight more than one classifier at a time), then double-click the source path to which you would like to assign the classifier from the bottom field. Selecting a package inherently also selects the classifiers contained within that package. Once a classifier has been successfully assigned, the color of the name will change from red to black.
You can also reassign a classifer by following the same procedure, regardless of whether the color of the name is red or black.
After you have enabled roundtrip, you can edit your source files and then import the changes into your Poseidon model.
Edit your source files as you normally would, for instance from a text editor or IDE.
Add the changes by clicking the Roundtrip Import button or use the roundtrip import keyboard shortcut Ctrl-Alt-I in order to integrate the changes from the sources into your Poseidon project. It is important to note that this is completely separate from the regular import function. At this point, you will not be able to use the normal import for this project. An error message will appear if you attempt to import files from the roundtrip directory.
If there are errors such as a missing classes during the import, you will encounter an error dialog alerting you to the problem.
After the import of source files, it is a good idea to then regenerate the code as described in the Section called Edit the Model so that Poseidon identifiers are added where needed. For example, if you add an attribute to a class and import the code, the source code tab within Poseidon will display the Poseidon object ID (which looks something like @poseidon-object-id [Ilsmma581]), but the ID will not be added to the code until explicitly told to do so.
You might temporarily have non-compiling source code that you do not want to import into Poseidon right away. For these instances, you can temporarily disable the automatic import with the button next to the Import sources button. It will turn to red, showing that automatic round-trip is disabled.
By clicking it again, it will turn back to green, designating that round-trip is enabled again.
You may also choose to edit your model and have the changes reflected in your source code.
Poseidon will not generate new source code until it is explicitly told to do so. Edit source code from the Source Code tab in the Details pane, then click the 'Start Roundtrip Code Generation' button from the toolbar or generate code with the roundtrip generation keyboard shortcut Ctrl-Alt-G. Only changed classifiers that have not been excluded from roundtripping will be generated. You can override this and generate all classifiers by holding the Ctrl button while clicking the code generation button.
Poseidon renames a class by generating a new class and deleting the old file.
If both the model and the source code have changed, the Synchronization Dialog can be used to update the model and source. Access this dialog by clicking the 'Synchronization' button on the toolbar. Once the Synchronization dialog has opened, you can select to update the model based on the code or to generate new source code based on the model. Any conflicts will be detected at this point, and you will be asked whether the model or the source code should take precedence. For more information about conflict resolution, see the Section called Conflict Resolution.
When generating source code from a model, Poseidon adds identifiers so that it can intelligently keep track of changes, therefore it is recommended that you first update the model and then generate the code. While it is possible to do this in reverse order, you may find that you have to generate the code twice in order to complete the synchronization.
Alternatively, you can import the source code as described in the Section called Edit Source Files and then generate the model for that code as noted in the Section called Edit the Model without using the synchronization dialog..
When using Roundtrip Engineering, you may encounter conflicts when trying to import source code that conflicts with the model. For instance, perhaps a class has been deleted from the model but still exists in the source code. Poseidon will alert you to these conflicts and allow you to decide whether or not to continue the import.
If you click the Import button, the model will be updated with the information from the source code. For example, if a class has been deleted from the source code, it will also be deleted in the model. A class that has been deleted from the model but still exists in the source code will be added back into the model.
Code Generation Conflicts
The case may also be that conflicts are encountered when generating code from a model that conflicts with the existing source code. In this case, however, changes are applied from the model to the source code. For instance, if a class has been deleted from the source code but still exists in the model, the class source code will be regenerated. A class that has been deleted from the model but still exists in the source code will be deleted from the source code.
Clicking 'Cancel Code Generation' will result in the model and the source code remaining out of synch.
Poseidon keeps track of modifications you make to your code, but some changes like renaming attributes in the source code may render Poseidon unable to update references to these attributes. As a result, your code may not be compilable after this change takes effect. Poseidon helps you avoid this by presenting you with a warning.
This dialog may be turned off by checking 'Do not show this dialog again' in the dialog itself or uncheck 'Warn when doing changes to the model that might harm generated sourcecode' from Settings | General | Modeling.
You should unset the check box 'Generate accessor methods' after you have generated accessors once. Otherwise, they would be generated again, and would clutter up your classes. The preferred way to create set/get methods is by adding them in an attribute's Properties tab, and by checking 'Create accessor methods for new attributes' in the dialog Edit | Settings.
There are several possibilities to fine-tune the appearance of the generated Java source code. Among them are the creation of accessor methods for attributes, the types for collection attributes, and the list of import statements in the files.
From Poseidon 1.4 on, you can create accessor methods for attributes automatically. This way, you can fine-tune the code so that some attributes have accessors, some not. In previous versions of Poseidon, you could only have setters/getters for all attributes, or for none.
In, there is a check box called 'Generate accessor methods for attributes'. Check this box to have accessor methods created for every attribute that is created. If the attribute has a multiplicity of 1..1 or 0..1, two simple getAttribute() and setAttribute() methods are created. For attributes with a finite multiplicity, an array is generated, and the accessor methods include addAttribute() and setAttribute(). For an unbounded multiplicity, a Collection is generated, and the appropriate access methods like addAttribute() and removeAttribute() are produced.
You can fill the bodies of these access methods according to your business logic. Also, you can hide the display of accessors by setting the check box 'Hide accessor methods' in.
Additionally, you can generate the standard accessor methods for your attributes at code generation time. These will be visible only in the generated code, not in your Poseidon project.
Poseidon up to version 1.3.1 used the type Vector whenever an association had a multiplicity of ..*.
From version 1.4 on, the rules are:
Create an attribute of the element's type if the multiplicity is 0..1 or 1..1.
Create a Collection type attribute if the multiplicity has an upper bound of *.
Create an array of the element's type if the multiplicity has an upper bound that is not 1 and not * (that is, it is a number).
In Code Generation-Settings, you can define what type of collection should be used for Collection types. The default is ArrayList, but you can enter any type (e.g., Vector ) that implements Collection. Accessor methods are programmed against Collection.
Beginning with version 2.6, attributes with an unlimited upper bound now use a JavaDoc tag called @gentleware-originalType to note the original type of the attribute that has been replaced with the Collection type. This enables the roundtrip and import functions to determine the original type. Note that this tag can be added manually, just like any other JavaDoc tag.
In this version of Poseidon, you are now able to distinguish between ordered, unordered and sorted attributes, and you will be able to give different kinds of implementation types such as TreeSet for unordered, ArrayList for ordered and Vector for sorted attributes.
Import statements can be added to classes in two ways: By drawing dependencies or by entering tagged values.
The graphical way is to draw a dependency from the class to the class or package that you want to import. An appropriate import statement will be generated: Either import package.* or import package.Class.
The second way (that does not clutter up your diagrams) is to add a Tagged Value called JavaImportStatement to the class. Then enter a number of imports, separated with colons. Qualified names can be given in Java syntax. For example, import java.lang.reflect.* and java.io.IOException by setting the tagged value JavaImportStatement to java.lang.reflect.*:java.io.IOException.
Above, you can see the import statement in the Tagged Values tab, and below is the resulting Java code generated by Poseidon.
Modifying Templates (Not available in the Community Edition)
More advanced customizaton of the generated code is possible if you are using one of the Premium Editions. Modification of the templates that are used for code generation is possible with these editions. We cover this topic briefly in a separate chapter and more deeply in a separate document that is distributed with these editions and online under http://www.gentleware.com/index.php?id=174.
You may not want certain operations to be reverse engineered. Any operations with the Javadoc tag '@poseidon-generated' will be excluded from the reverse engineering process.