JMap Pro Extensions
JMap Pro extensions are modules developed in Java that can be added to JMap Pro to enhance its features. Extensions are specified as parameters for applications and are initialized when said applications are launched. Typically, extensions are integrated to the GUI of a JMap Pro application by inserting the buttons and menus that activate the functions provided by the extension.
To develop an extension and make it available to users, you must perform the following two steps:
Develop your extension by creating a Java class derived from the JMapClientExtension class;
Deploy your extension in JMap Server so it may be accessed by the JMap Pro applications.
See the following sections for more information.
Programming JMap Pro Extensions
To program JMap Pro extensions, it is important to follow a set of simple rules. This section describes these programming rules.
JMapClientExtension class
The first step towards developing a JMap Pro extension consists of programming a class derived from the abstract class JMapClientExtension. This class contains the following 3 methods, which are called at different moments in the life cycle of the extension:
This method is called when the extension is loaded by the JMap Pro application. At this point, the graphical interfaces have not yet been initialized. In this method, you can put any code that will prepare the operation of your extension. This could include loading a settings file, verifying dependencies, etc. The method receives an instance of JMapApplicationContext as a parameter. This class provides access to all the resources of the JMap application. The method also receives a collection (map) of parameters. These parameters provide useful information for the extension. See below for more information.
This method is called by the JMap application when its graphical interface has been initialized. In this method, you should put the code that initializes the GUI of your extension. This could include adding buttons or toolbars, menus, windows, etc. See the GUI Integration section for more information. This GUI will allow users to access the functions offered by your extension.
This method is called by the JMap application just before it exits. In this method, you must put the code required to terminate your extension. This could include the code to release resources, save settings, etc.
Parameters are passed to the extension with the init() method, using a Map<String, String> collection. In JMap, there are two predefined parameters that match constants defined in the JMapClientExtension class:
EXTENSION_PARAMETER_GUI_VISIBLE: Indicates whether the extension’s GUI components (other than toolbars) must be visible when the application is launched.
EXTENSION_PARAMETER_TOOLBAR_VISIBLE: Indicates whether the extension’s toolbars must be visible when the application is launched.
These parameters contain true or false values and they are set by the JMap Administrator when a JMap Pro application is deployed. Your extension must comply with these parameters. An extension can also receive its own settings, which would be set by the JMap Administrator.
The following code example shows how to access the settings from the init() method.
public void init(JMapApplicationContext appContext, Map<String, String> mapExtensionParameters)
{
String param = mapExtensionParameters.get(JMapClientExtension.EXTENSION_PARAMETER_TOOLBAR_VISIBLE);
boolean toolbarVisible = Boolean.parseBoolean(param);
...
}
JMapApplicationContext class
The JMapApplicationContext class is very useful for extension development because it provides access to a set of general application resources. This class is a singleton. Therefore, the instance can easily be accessed from anywhere using the static JMapApplicationContext.getInstance() method.
Returns the instance of the connection (JMapSrvConnection class) to JMap Server.
Returns the instance of the main application window.
Returns the instance of the View Manager (ViewManager class) of the application.
Returns the instance of the JMap application (JMapApplication class).
Returns the path to the main JMap folder on the user's computer. This is where JMap writes its data.
JMapApplication class
The JMapApplication class represents the JMap application. It offers methods that provide access to application resources (GUI, event logs, etc.). It also provides methods to perform tasks in a simple way (create a new map, close the project, etc.).
Most commonly used methods of the JMapApplication class:
Creates a new map view that automatically appears in the application.
Returns the instance of the project (Project class) opened in the application.
Returns the instance of the application’s JMapGuiService class. See the GUI Integration section for more information.
Returns the instance of the application’s Logger class. Used to record messages from your extension in the JMap application’s logs.
Programming Extension Requests
As a developer of JMap Pro extensions, you will probably be developing applications that need to communicate between the client side and JMap Server. Whether you need to communicate with your own extension on the server side or to make general requests to JMap Server, the programming principle is the same.
For more information on client-server communication in JMap, refer to the Client-Server Communication section.
Programming the request
To create your request class, you must observe the two following rules:
The class should be derived from the JMapExtensionRequest class;
All of the class’s properties must be serializable.
You are free to add all the properties and methods that are useful to executing your request. These properties and methods can be used by your extension on the server side.
The following source code example demonstrates how to program a simple request.
// This request is used to save a new citizen complaint
public class SaveComplaintExtensionRequest extends JMapExtensionRequest
{
private String citizenName;
private int requestType;
public void setCitizenName(String citizenName)
{
this.citizenName = citizenName;
}
public String getCitizenName()
{
return this.citizenName;
}
public void setRequestType(int requestType)
{
this.requestType = requestType;
}
public int getRequestType()
{
return this.requestType;
}
}
Programming the response
To create your response class, you must observe the two following rules:
The class should be derived from the JMapExtensionResponse class;
All of the class’ properties should be serializable.
You are free to add all properties and methods that are useful to returning the information regarding the request’s execution to the client. These properties and methods can operate from the client side by your extension after the request is executed on the server.
The following source code example demonstrates how to program a simple response.
// This response is returned to client after a citizen complaint save request was executed
public class SaveComplaintExtensionResponse extends JMapExtensionResponse
{
private long uniqueId;
public void setUniqueId(long uniqueId)
{
this.uniqueId = uniqueId;
}
public long getUniqueId()
{
return this.uniqueId;
}
}
Being derived from the JMapExtensionResponse class, your response class will inherit some useful properties, including the response status and an explanatory message in case of a problem.
Response status
Each response has a status that indicates if the request was executed successfully or if a problem occurred. The getStatus() method of the JMapExtensionResponse class allows you to get the status of the response. For the list of possible statuses and their description, refer to the documentation of the JMapExtensionResponse class.
Your extension should always check the status of a response before using it. If the status is not equal to JMapSRV_STS_SUCCESS, a special process must occur in order to manage the error. In this case, the getMessage() method allows you to generate a message explaining the cause of the error.
GUI Integration
Some client extensions can be completely invisible to the user but the majority of extensions are integrated into the JMap Pro GUI. This integration can take many forms. The initGui() method must be used to initialize the graphical interface of an extension.
JMapGuiService class
The JMapGuiService class is used to access the components of the graphical user interface (menus, toolbars, etc.) and to add or remove components. To simplify access to the graphical components, each component has a unique key. This key must be provided when a component is added or removed. For a complete list of available keys, see the section List of GUI components. The JMapGuiFactory class described below provides methods for creating GUI components.
The main methods of the JMapGuiService class are listed below:
Adds an item to an existing menu by specifying the menu key.
Retrieves a menu using its key. The returned object can then be used to modify the menu.
Adds a toolbar to a specific position in the application interface.
Retrieves a toolbar using its key. The returned object can then be used to modify the toolbar.
Adds a dockable window at a specific position in the application interface.
Allows you to remove a dockable window using its key.
Returns the JMapGuiFactory instance. This class allows you to create GUI components such as buttons and toolbars.
JMapGuiFactory class
The JMapGuiFactory class is used to create buttons, menus and toolbars that are compatible with JMap applications. Methods such as createButton (), createMenu (), createToolBar (), etc. are called to create the appropriate components.
Integration examples
Adding a button to an existing toolbar
The following code shows how to add a button to an existing toolbar. The toolbar is retrieved using its key. For a complete list of available keys, see section List of GUI components. Note that the action associated with the button is not shown in the example.
// This button will be in a group thus only onebutton can be pressed among this group.
AbstractButton button = guiFactory.createToggleButton(new ButtonAction(),
appContext.getApplication().getGuiService().getMainButtonGroup());
// Add the button on the Zoom and Pan toolbar.
appContext.getApplication().getGuiService().getToolBar("ZOOM_PAN").add(button);
Adding a toolbar
The following code example shows how to create a toolbar using the JMapGuiFactory class. In this example, the JMapApplicationActionManager class is used to access the buttons’ actions. This class can manage single instances of actions. Afterwards, two buttons are created and added to the bar. Finally, the toolbar is added vertically, on the right side of the application. Notice the HashMap of properties that is used to place the toolbar. This principle is used with all components to specify their characteristics.
// Create the new toolbar final ToolBar
toolBar = guiFactory.createToolBar("SHOWCASE", "JMap example showcase");
// Create and add buttons on toolbar
toolBar.add( guiFactory.createToggleButton(applicationActionManager.getAction(CreatePolygonAction.class), jmapGuiService.getMainButtonGroup())
);
toolBar.add( guiFactory.createButton(applicationActionManager.getAction(ShowDockingPanelAction.class))
);
// Adds the new toolbar vectically to the right side of the application frame.
HashMap<String, Object> properties = new HashMap<String, Object>();
properties.put("CONTEXT_INIT_SIDE", new Integer(SwingConstants.EAST)); // Dock to the east
jmapGuiService.addToolBar(toolBar, properties);
Adding a window
The addDockableComponent() method adds components such as windows to the interface. It takes a HashMap of key-value pairs as a parameter to define the display settings of the new window. All keys and possible values are defined in the method’s documentation.
// Create a panel with the needed components
final JPanel panel = new JPanel();
...
// Set the properties of the dockable panel.
HashMap<String, Object> properties = new HashMap<String, Object>();
properties.put("KEY", COMPONENT_KEY); // Will be used to reference the panel
properties.put("TITLE", "JMap 7 SDK showcase."); // Will be displayed on the title bar
properties.put("CONTEXT_INIT_SIDE", SwingConstants.EAST); // Tells JMap to dock the panel to the east of the frame
appContext.getApplication().getGuiService().addDockableComponent(panel, properties);
Adding a menu
The following code example shows how to create and add a menu to the interface.
// Create menu and add items to it
JMenu menu = new JMenu("SDK");
JMenuItem item1 = new JMenuItem("Item 1");
JMenuItem item2 = new JMenuItem("Item 2");
this.menu.add(item1); this.menu.add(item2);
// Add menu to menu bar at position 4
appContext.getApplication().getGuiService().getMenuBar().add(menu, 4);
Adding a menu item to an existing menu
The following code example shows how to add items to existing application menus. Note that a key is used to retrieve existing menus. For a complete list of available keys, see the section List of GUI components.
// Add 2 menu items to existing menus TOOLS and HELP
JMenuItem item3 = new JMenuItem("Item 3");
JMenuItem item4 = new JMenuItem("Item 4");
appContext.getApplication().getGuiService().addMenuItem("TOOLS", item3, false);
appContext.getApplication().getGuiService().addMenuItem("HELP", item4, false);
Adding an item to the map pop-up menu
The following code shows how to add a section of items to the map’s pop-up menu. This menu appears when the user right-clicks on the map. In addition, the menu item is only active if the user has clicked on at least one element of a map layer. Otherwise, the menu item will be disabled.
final ViewMenuAction menuAction = new ViewMenuAction();
// Obtain the currently active view
View view = JMapApplicationContext.getInstance().getViewManager().getActiveView();
if (view != null)
{
// Add a separatr and a menu item
view.addPopupMenuSeparator();
view.addPopupMenuAction(menuAction);
}
// Register an event listener with the View Manager so that we are notified when the view popup menu is about to be displayed
JMapApplicationContext.getInstance().getViewManager().addViewEventListener(new ViewAdapter()
{
@Override
public void viewPopupMenuShowing(ViewPopupMenuShowingEvent e)
{
// Enable map menu item only if the user clicked on some element
K2DElement[] elements = e.getView().getLayerManager().getElementsAtPoint(e.getWcCoord(), e.getView().getViewState(), false);
menuAction.setEnabled(elements.length > 0);
}
});
Adding a section to a layer’s settings window
It is possible to add sections to the settings window of a layer, as shown in the image below. To do this, you must implement your own class derived from the abstract class AbstractLayerSettingsCustomPage and implement that class’s 3 abstract methods. You must provide a title and icon for your section by passing them to the constructor of the superclass; they will be displayed in the settings window.
Abstract methods of the AbstractLayerSettingsCustomPage class:
In this method, you must create and return the the instance of JPanel that displays the GUI of the settings in your section. This is the graphical interface that will be displayed.
This method is called when the user clicks on the OK button to confirm the changes and close the window. Your method should return true only if the parameters entered are valid. Otherwise, the window will refuse to close.
This method is called when the user clicks on the OK button to confirm the changes and close the window, and after calling the validateSetting() method. You must apply the parameter changes on the layer.
The getLayer() method of the AbstractLayerSettingsCustomPage class lets you know to which layer the parameters apply. To save your settings section, you must use the method addLayerSettingsCustomPage of the ShowLayerSettingsAction class, as shown in the following source code example.
// Obtain a reference to the ShowLayerSettingsAction
instance ShowLayerSettingsAction showLayerSettingsAction = (ShowLayerSettingsAction)appContext.getApplicationActionManager()
.getAction(ShowLayerSettingsAction.class);
// Add the custom panel for the Cities layer
showLayerSettingsAction.addLayerSettingsCustomPage(SDKLayerSettingsPanel.class.getName(), layerCities.getId());
Adding a custom button to the layer manager
You can add buttons associated with a layer in the layer manager. These buttons can be used to trigger custom actions that are specific to a layer. The buttons are added in different ways in the hierarchical section and list section.
The following source code example shows how to add a button to the Cities layer.
// Obtain layer instance from layer manager
Layer layerCities = appContext.getViewManager().getLayerManager().getLayer("Cities");
JMapGuiService guiService = appContext.getApplication().getGuiService();
JMapGuiFactory guiFactory = guiService.getGuiFactory();
AbstractButton abstractButton = guiFactory.createButton(new ButtonAction());
// Add the button to the 'More options' of the LayerTreeBar (hierarchy) for the layer Cities
guiService.getLayerTreeBar().addCustomButton(abstractButton, layerCities.getId());
// Add the button to the LayerPanel of the LayerBar (list) for the layer Cities
LayerPanel layerPanel = guiService.getLayerBar().getLayerPanel(layerCities.getId());
Button button = new Button(new ButtonAction(), false, new Dimension(18, 18));
layerPanel.addCustomButton(button);
Deploying JMap Pro Extensions
To be deployed within JMap Pro applications, client extensions must follow certain rules. If these rules are met, the extension appears in the deployment section of JMap Admin.
Group extension classes in an archive (JAR)
All classes and resources (images, etc.) of the extension must be contained in a single JAR archive file. Use a meaningful and unique name, as this name will be used in the following steps.
Include a manifest file
The extension archive must include a manifest.mf file with the following entries:
Variable
Description
extension_class
Identifies the main class of the extension, derived from the abstract class JMapClientExtension.
extension_name
Specifies the name of the extension. This name appears in JMapAdmin when deploying applications.
extension_version
Specifies the version number of the extension. This information appears in JMapAdmin when deploying applications. The version number is used only to simplify the management of extensions.
Here is an example of a manifest file's content:
extension_class: jmap.extensions.edition.EditionExtension
extension_name: Edition
extension_version: 1.0.0049
Provide a JNLP file
The JNLP file is required. It describes the deployed library. The file must have the same name as the extension's JAR file (except for the .jnlp extension). The following example shows the parts that must be changed in bold.
<?xml version="1.0" encoding="utf-8"?>
<!-- JNLP File for Extension libraries -->
<jnlp
spec="1.0+" codebase="http://$JMAPSERVER_HOST$:$JMAPSERVER_WEBPORT$$PATH$/edition_client"
href="edition_client.jnlp">
<information>
<title>Edition Extension</title>
<vendor>K2 Geospatial</vendor>
<description>Edition Extension</description>
<description kind="short">Edition Extension</description>
</information>
<security> <all-permissions/> </security>
<resources> <jar href="edition_client.jar"/> </resources>
<component-desc/>
</jnlp>
Place the files in the correct directory.
All files that make up the extension (JAR, JNLP, and other files) must be placed in a directory created specifically for the extension and located within the directory for Client Extensions (JMap_HOME/extensions/client). The name of the extension's directory must be identical to the name of the extension's JAR. The following image shows how files and directories are organized in Windows for K2 Geospatial's Edition extension.
Signing Extensions
The signature of a Java library certifies that the library comes from an identifiable source and that its content has not been altered. The user who executes the library’s code can trust the authenticity of the library. This is even more important when the library requires system access that can cause security issues such as data access, network access, etc.
Signing Java libraries is done using the jarsigner tool included with the Java JDK. To do this, you must have a Java signing certificate issued for your organization. These certificates can be purchased from a reputable security company such as Thawte (http://www.thawte.com/) or Verisign (http://www.verisign.com/). Once you have your certificate, you must import it in a keystore using the keytool, which is also included with the Java JDK. Note that the keytool can also produce development certificates. These certificates are not deemed to be from reliable sources and they will generate warning messages. However, they are helpful for development and in-house testing purposes. For more information on this topic, refer to the documentation on the Java JDK’s security tools (http://docs.oracle.com/javase/8/docs/technotes/tools/index.html).
The libraries of JMap Pro extensions must be signed in order to be properly deployed in a JMap Pro application. If you use the extension builder provided with the JMap SDK, the Ant scripts generated handle the signing of your extension. Thus, when you run these scripts to compile and build the library for your extension, it is signed automatically. This signature is done using the development certificate provided with the SDK. If you want to use your own certificate, you must replace the JDK_HOME/tools/extensionbuilder/RES/keystore.jks file by your own keystore, in which you will have imported your certificate.
Dernière mise à jour