Geomajas Community Documentation
A Geomajas command usually consist of three classes, the actual
command (which implements the Command
interface), and two
data transfer objects, one to pass the request parameters (extending
CommandRequest
, LayerIdCommandRequest
or
LayerIdsCommandRequest
), and one which carries the response
(extending CommandResponse
).
It is important to assure your request object extends from LayerIdCommandRequest or LayerIdsRequest when one of the parameters is the layer id (or a list thereof). This can be used by the command dispatcher to assure the layer specific (transaction) interceptors are called.
To create a new command we recommend you use a similar package structure as we used in the geomajas-extension-command module. That is to create a "command" package with under that a "dto" package which contains all the request and response objects, and to put the actual commands in sub packages based on some kind of grouping. This helps to automatically determine a sensible command name.
The basic command implementation looks like this:
package com.my.program.command.mysuper; import com.my.program.command.dto.MySuperDoItRequest; import com.my.program.command.dto.MySuperDoItResponse; import org.geomajas.command.Command; import org.slf4j.LoggerFactory; import org.slf4j.Logger; import org.springframework.stereotype.Component; /** * Simple example command. * * @author Joachim Van der Auwera */ @Component() public class MySuperDoItCommand implements Command<MySuperDoItRequest, MySuperDoItResponse> { private final Logger log = LoggerFactory.getLogger(MySuperDoItCommand.class); public MySuperDoItResponse getEmptyCommandResponse() { return new MySuperDoItResponse(); } public void execute(MySuperDoItRequest request, MySuperDoItResponse response) throws Exception { log.debug("called"); // ..... perform the actual command } }
Example 16.1. Example command template
Note the presence of the "@Component" annotation which assures the command is registered. You could add the name under which the command needs to be registered in the annotation, but when that is omitted, the default command name is derived from the fully qualified class name. In the example given here this results in command name "command.mysuper.DoIt".
The default way to determine the command name assumes there is a package named "command" in the fully qualified name of the implementing class. It will remove everything before that. It will then remove a "Command" suffix if any. Lastly, it will remove duplication between the intermediate package (between "command" and the class name) and the class name itself. Some examples:
Fully qualified class name | Command name |
---|---|
my.app.command.DoIt | command.DoIt |
my.app.command.super.DoIt | command.super.DoIt |
my.app.command.super.DoItCommand | command.super.DoIt |
my.app.command.super.SuperDoItCommand | command.super.DoIt |
my.app.command.super.DoItSuperCommand | command.super.DoIt |
my.app.command.super.CommandDoIt | command.super.CommandDoIt |
my.app.command.super.CommandSuperDoIt | command.super.CommandSuperDoIt |
my.app.command.super.CommandDoItSuper | command.super.CommandDoIt |
Table 16.1. Samples of command name resolution
You have to include a line in your Spring configuration to scan class files for annotation to make the components available. For the case above, this could be done by including the following XML fragment in one of your Spring configuration files.
<context:component-scan base-package="com.my.program" name-generator="org.geomajas.spring.GeomajasBeanNameGenerator" />
Example 16.2. Scan to assure command is available
The command will be executed using a singleton. The use of object variables is not recommended. Any object variables will be shared amongst all command invocation, which can be coming from multiple threads at the same time.
Note that it is not mandatory to create your own request and
response object classes. If you don't require any parameters you can use
EmptyCommandRequest
as request class. If you only require a
layer id, then use LayerIdCommandRequest
. If you only return
a success code, you could use the SuccessCommandResponse
class.
You have to take care that all objects which are referenced by your
request and response objects are actually serializable for the faces in
which the commands need to be used. For the dojo face this may require the
use of the "@Json
" annotation to exclude fields. For GWT you
have to assure the no-arguments constructor exists and that the class can
be compiled by GWT (no Hibernate enhanced classes, no use of
"super.clone()
",...).
When the commands are included in a separate module, you should assure the sources are available as these are needed for GWT compilation. This can easily be done using the Maven source plugin.
<plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-source-plugin</artifactId> <version>2.1.2</version> <executions> <execution> <goals> <goal>jar</goal> </goals> <configuration> <includePom>true</includePom> </configuration> </execution> </executions> </plugin>
Example 16.3. Maven source plugin
Actually including the sources can then be done using a dependency like the following (this includes the staticsecurity module, both the actual code and the sources). You could set "provided" scope on the source dependency to exclude it from the war file. However, this may prevent use of GWT development mode.
<dependency> <groupId>org.geomajas.plugin</groupId> <artifactId>geomajas-plugin-staticsecurity</artifactId> <version>${geomajas-plugin-staticsecurity-version}</version> </dependency> <dependency> <groupId>org.geomajas.plugin</groupId> <artifactId>geomajas-plugin-staticsecurity</artifactId> <version>${geomajas-plugin-staticsecurity-version}</version> <classifier>sources</classifier> </dependency> <dependency> <groupId>org.geomajas.plugin</groupId> <artifactId>geomajas-plugin-staticsecurity-gwt</artifactId> <version>${geomajas-plugin-staticsecurity-version}</version> </dependency> <dependency> <groupId>org.geomajas.plugin</groupId> <artifactId>geomajas-plugin-staticsecurity-gwt</artifactId> <version>${geomajas-plugin-staticsecurity-version}</version> <classifier>sources</classifier> </dependency>
Example 16.4. staticsecurity source plugin - including source