JMap Pro Extensions

Table of contents

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:

  1. Develop your extension by creating a Java class derived from the JMapClientExtension class;

  2. 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:

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.

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:

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:

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:

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.

  1. 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.

  2. Include a manifest file

    The extension archive must include a manifest.mf file with the following entries:

    Here is an example of a manifest file's content:

    extension_class: jmap.extensions.edition.EditionExtension

    extension_name: Edition

    extension_version: 1.0.0049

  3. 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>

  4. 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

K2 Geospatial 2022