Create a gvSIG project
- Before you start with developing a plugin
- Project structure in gvSIG
- Creating our project
- FortuneCookie, a gvSIG plugin
Before you start with developing a plugin
When developing a project for gvSIG 2.0 we must consider several things if we want it to have the official endorsement of gvSIG and become part of the official gvSIG release.
Maven must be used as the tool to build the project.
Maven defines the group name, the groupId, and the identifier, the artifactId for the project. The groupID will be org.gvsig and the artifactId consists of the groupID followed by an identifier of the project.
For example, when creating a topography plugin for gvSIG, all the project packages will start with org.gvsig.topography.
The artifactId is used:
- To identify the root package of our Java project. All our packages begin with the artifactId.
- As name for our Eclipse project. Eclipse projects for gvSIG development have the same name as the artifactId.
- When naming the jars: the names of jars that are generated for our project begin with the artifactId followed by the version of the project and the Maven classifier.
There should be a strict separation between API and implementation.
This seems obvious, but very often there is no such separation, and when there is a separation it is usually not as strict as is required by gvSIG.
The main reason for this are issues such as:
How do we assess the scope of a change in the code? What would be the impact on the gvSIG application if we modify this?
Having the APIs strictly defined greatly facilitates the response to this question.
How can we properly document the use of libraries? When the API and the implementation are separated, it is easier to focus on the API documentation than when it is mixed with the implementation.
How can we run automated tests on our library? If we have a clear and well-defined API, we can focus on preparing automated tests to check the specifications of the API so that we can easily verify whether a change in implementation will affect the usage of the API.
There must be an automated test system to verify the functioning of the API in our project. Until now JUnit is being used to perform these tasks.
The APIs must be documented and this documentation must be uploaded to a public website.
For documentation of interfaces and classes of the APIs, Javadocs will be used. The API documentation should be complete and in English. To generate and deploy the documentation, the Maven tool for generating sites will be used.
The dependencies of our project on other libraries must be indicated.
This is done by keeping the ManageDependencies in the root of the Maven project updated.
The project must come with a test plan. This test plan should work by way of a series of acceptance tests that the project should go through after every gvSIG build until the final version.
User documentation of the project must be prepared in ReST (reStructured Text) format, preferably in English.
The jars of the project must be deployed in a Maven repository, and a versioning policy must be followed corresponding with the changes made to the project. gvSIG has its own Maven repository in which to deploy its libraries, but you can use another if appropriate.
A developers guide, preferably in English, to introduce developers in the use of the libraries of the project would be appreciated.
When generating installable packages of your plugin for gvSIG, make sure that it has a unique build number. There must be a way to uniquely identify a distribution or packaging of your plugin that does not leave any doubt to which version it applies. Therefore, a unique build number must be assigned to each packaging for gvSIG.
Project structure in gvSIG
Maven and Eclipse
One of the most interesting features of Maven is its ability to work with multi-module projects and the options for executing pre-defined targets to perform certain clearly defined tasks, such as code compilation and packaging.
Unfortunately, the current version of Eclipse does not include the necessary mechanisms to support multi-module projects, so that integration with the Maven mechanisms are complex and require the use of certain strategies to simulate such behavior.
Maven uses a Project Object Model (POM) to describe the software project to be built, the structure of the project and its sub-modules, their dependencies on other modules and external components, and the build order of the elements. Using these defined characteristics, you can get Eclipse to use the information in the POMs to simulate multi-module behavior.
Working with Maven in Eclipse
When working with Eclipse, as mentioned above, we will have to follow certain guidelines that will allow us to make use of the functionality Maven offers.
The first thing to note is the naming convention of the directories. The names applied to directories are not random, as they indicate the hierarchical structure of the project. Thus, the name of the parent project will be the name of the artifact_id, and its submodules will include the parent name (for example, if the parent project is org.gvsig.example, the submodule Example1 must be kept in the directory org.gvsig.example/org.gvsig.example.example1, and Example2 in org.gvsig.example/org.gvsig.example.example2. If Example1 has a submodule Example1a, it would be stored in org.gvsig.example/org.gvsig.example.example1/org.gvsig.example.example1a and so on). This gives the project a tree structure:
- org.gvsig.ejemplo
- org.gvsig.ejemplo.ejemplo1
- org.gvsig.ejemplo.ejemplo1.ejemplo1a
- org.gvsig.ejemplo.ejemplo2
- org.gvsig.ejemplo.ejemplo1
The parent nodes are not recognized as Java projects by Eclipse, because they are simply containers of the submodules. These projects contain the POM file with its definition and description of the submodules. In this way, you can launch commands at the parent module to run on that level and all its child nodes automatically (install, compile, etc.).
On the other hand, the child nodes (or leaves of the tree) are Java projects, with their usual project structure. These nodes can take advantage of the parent configuration (dependencies, properties, attributes, ...) if that parent is specified in the POM, simplifying its configuration.
Developing a gvSIG project
When we develop a gvSIG project there should be a strict separation between the API and the implementation of that API. To accomplish this, a basic template for gvSIG projects has been prepared which takes advantage of the Maven capabilities to manage multi-module projects. This template will guide us on how to organize the project, keeping strictly separated the logic of the extension from the user interface, and the API of the logic from its implementation, and the API of the interface from its implementation, in different Eclipse projects and separate jars.
The basic structure of a project will be:
- library
- tags
- branches
- trunk
- org.gvsig.example
- org.gvsig.example.lib
- org.gvsig.example.lib.api
- org.gvsig.example.lib.spi
- org.gvsig.example.lib.impl
- org.gvsig.example.prov
- org.gvsig.example.prov.provider1
- org.gvsig.example.swing
- org.gvsig.example.swing.api
- org.gvsig.example.swing.impl
- org.gvsig.example.main
- org.gvsig.example.lib
- org.gvsig.example
- extensión
- tags
- branches
- trunk
- org.gvsig.example.app
- org.gvsig.example.app.extensión
- org.gvsig.example.app
Compared to gvSIG projects prior to the 2.0 version, this project structure would seem rather complex, but we will look into it with more detail.
The first thing to note is that the project is oriented as a multi-module SVN project compared to what we used to see in the development of gvSIG 1.X. On the one hand we have the development of the library and on the other, the extension(s) for gvSIG. This has been organized like this because normally the changes in the logic of our extension usually have a life cycle that is clearly separated from the integration into gvSIG. After development of the extension has been completed, it is easier to do the modifications from one gvSIG version to the next in the parts of the code that contains the integration with gvSIG, while the logic remains unchanged except for some bug corrections. To achieve this independence, the SVN repository is separated into two main groups:
Library
This contains the logic and user interface that are independent of gvSIG as an application. This does not mean that they can’t depend on some gvSIG libraries such as the ones for data access, geometry or mapcontext. If they need to depend on those libraries, they can be used.
Extension.
This is the part of the code that depends on the gvSIG application, Andami and other gvSIG extensions. This is where the Extension classes are located, as well as the configuration of our Andami plug-in.
In the library we will find the following:
org.gvsig.example.lib
This provides the API, SPI, and the implementation of the API.
org.gvsig.example.prov
If our library needs to interact with a service provider, this is where the different implementations of these service providers would be located.
org.gvsig.example.swing
If our project includes a user interface for the library's logic, it would be located here only. The projects located into org.gvsig.example.lib must not depend on the user interface and, therefore, not on this project.
org.gvsig.example.main
You may find it strange to find a main module within the library, but it is actually quite useful. This is a module that provides a test application that you can use to launch the user interface and the logic of the library without having to start gvSIG to test it. This allows for a more agile development of our project, postponing the integration with gvSIG until it is in a more advanced stage of development.
And finally we come to the separation of some of these modules into API, SPI and implementation. This separation can be found in org.gvsig.example.lib and org.gvsig.example.swing.
Imagine that we are developing a network analysis extension for gvSIG. What projects would we be working with?
In principle, our project would not require special service providers. It would consist of the logic, the user interface, and the actual plugin for gvSIG. We would have the following projects:
- org.gvsig.networkAnalysis.lib.api
- org.gvsig.networkAnalysis.lib.impl
- org.gvsig.networkAnalysis.swing.api
- org.gvsig.networkAnalysis.swing.impl
- org.gvsig.networkAnalysis.main
- org.gvsig.networkAnalysis.app.extensión
Basically we would have these six projects, and each of them would generate its own jar, corresponding to the name of the project. Each of the projects will be will be located in its corresponding folder, and it is important that they have the correct name. This is because when you import these projects into Eclipse, we find that the folder tree is flattened; but thanks to the naming convention, these projects retain their consistency in our workspace.
Although it seems obvious, it should be pointed out which dependencies between those projects are acceptable. The implementation will depend on the API, but not vice versa. Also, our API should be concise and complete. Complete because the client of this API should not need to know the implementation in order to use it, and concise because the details of the implementation do not need to be exposed; the less details are exposed, the easier and safer the maintenance will be.
On the other hand, there is the user interface. This, whether the implementation or its API, should have no dependencies on the implementation of the library, or the logic. It should only depend on its API.
And finally, the test implementation and the extension can only depend on the API of the library and the user interface API.
It should also be noted that pom.xml files are found in each of the different folder. So there is a pom.xml in org.gvsig.example that allows us to interact with all the submodules of our project, and it contains the general configuration of the project. For example, through the pom.xml we can directly build the Eclipse projects for each of our modules. In turn, org.gvsig.example.swing and org.gvsig.example.lib have their own pom.xml files with their specific configuration. Finally, each of the final projects will have their own pom.xml file. Each of these pom.xml will be configured indicating the pom of the higher level folder as the parent pom to inherit the common configurations.
We have mentioned API several times. But what do we mean by API? How do we define it?
The question is not as obvious as it seems. When you ask several developers how they define an API module we can end up with very different answers. So, in gvSIG, how do we define an API? Normally, the API consists of a set of Java interfaces. There may be an abstract class that provides a default implementation for something that should be extended by the API user, but it never contains a class with its implementation. As usual, there are exceptions to this. By their nature, exceptions that trigger this API will be implemented in the API. This set of interfaces, packaged in a project and its jar, is the only dependency that the API user must depend on.
When using swing there will be differences. Swing lacks interfaces to handle graphic components, and therefore when it comes to defining the API of the swing part of our project, instead of using interfaces, we use abstract classes that extend the different swing components, adding abstract methods from our project domain. Usually there are abstract classes that extend JPanel, and these define the user interfaces associated with components of our project.
What does the implementation consist of?
Well, there we have a set of classes that implement the interfaces defined in the API. Normally there will be a manager which will serve as entry point to the functionality of our project and its configuration.
It is helpful to review the tools that org.gvsig.tools provides to manage the separation between API and implementation using the Library, Locators and Manager, and the tools that are available for the management of service providers, so that new projects will not need to reinvent each time how to implement these tools, and to harmonize their use throughout gvSIG.
We must also consider the recommendations when naming the classes and interfaces. The project structure described here is designed to follow a naming system such as described in the document nomenclature for classes and interfaces. So the API interfaces are named using meaningful names from the extension domain, without using any kind of prefix or suffix, while the classes that are found in the implementation project and which implement the API interfaces, are named by adding Default as a prefix to the name of the interface that they implement.
Before moving on to the creation of a gvSIG project according to the structure described above, it is recommended to review the documentation about org.gvsig.tools.service that describes in more detail the classes and interfaces to create, and how they are stored in a Maven subproject.
Creating our project
To work with our project need a gvSIG 2.0 installed. You must also install the Development project wizard addon, available through the addons manager (Tools > Addons manager).
What is going to offer this extension?
Mainly this extension will give us the option Create plugin. Using this utility, will allow the creation of maven projects, following the project structure described above, according to the custom options you choose to work with this installation of gvSIG.
This utility can be found in the menu Tools the option Development:
After accessing Create plugin option, the extension will show a wizard. This wizard will guide you to create a template from our maven project associated with this instance of gvSIG. As the most interesting points, note that the wizard will require that you enter the name of our project, group_id (default org.gvsig) and the location to generate the plugin.
You will have also to select the template to use, being able to select between a basic project with spatial support or a project to show fortune cookies. The first one is the recommended one.
If you select the second template, in addition we need indicate the type of plugin to be developed (for details see section FortuneCookie a _ plugin gvSIG). Finally, we will tell to wizard if we want to generate the extension for gvSIG or not.
As a last step in the generation of our plugin, the tool will perform a prepare_workspace to leave our project ready. Perform maven tasks 'configure-eclipse-workspace','maven install' and 'maven eclipse:eclipse'.
Once created the project, closing gvSIG, start Eclipse and import the folder we created the project. To work with it, we import the parent project (org.gvsig.<project_name>) as all sub-modules (org.gvsig.<project_name>.lib.api, org.gvsig.<project_name>.lib.impl, org.gvsig.<project_name>.main and others according to the variant chosen).
Once the project has been imported into Eclipse, we'll just create our plugin and boot normally, using the project build.xml file, and using the mvn-install target.
Finally, once developed our plugin, use the Pack plugin option of gvSIG installation. A utility to generate binaries from our plugin and will allow us to distribute it as a separate plugin or included in an existing gvSIG installable.
FortuneCookie, a gvSIG plugin
The FortuneCookie project is a very simple example plugin that aims to serve as a template to be followed by the developer when implementing their own plugins.
But, what advantages gives us the use of the diferents FortuneCookies projects? In principle, the most direct benefit is pretty obvious, since the fact of working on fully implemented a complete project that compiles and runs, can focus more on developing the code than in configuration tasks. And is that all FortuneCookies projects have declared their POM files with all the minimum dependences to run, and to establish relationships between them.
Therefore, to say that we have a project that will provide a number of basic, complete, compilable and run structures from which begin our development.
It presents several implementations that allow the developer show the highlights to be covered by your plugin depending on which option best suits the nature of the project. The variants presented are:
- Basic. Develop the essential elements in any project, such as the API and implementation.
- With service providers. Presents the necessary structure to implement a plugin that makes use of service providers to perform their functions. It gives the basic variant of the SPI definition and implementation of two providers: one through FortuneCookies provided by a Web service, and another from a local text file.
- With graphical user interface (GUI). Add the basic variant the entire structure to develop the GUI project. Provides the API and implementation Swing module responsible for the GUI, among which is the definition of the panels and the various tools for management and visualization.
- With service providers and GUI. This project join the above two points into one.
Should you require more information on any of the alternatives mentioned are advised to consult the document org.gvsig.tools.service
Moreover there is the option of GUI providers. This will be the option if, in addition to the above, support is required for the acquisition of user interfaces provided by vendors (currently under construction).