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 the
menu 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:
folder/subfolder/foo.jar:anotherfolder/anotherfoo.jar:stillanotherfoo.jar
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 Section 9.4 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
Section 14.1.3.1.2
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.
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
Section 14.1.3.2
.
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 Section 14.1.3.1.1 and then generate the model for that code as noted in Section 14.1.3.1.2 without using the synchronization dialog..
Import Conflicts
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.
Refactoring Warning
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.
Accessor Methods
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
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.
Collection Types
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
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 .
Javadoc Tags
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.