JMap Server extensions are modules developed in Java that are added to JMap Server to respond to new types of queries and perform tasks on the server side. Server extensions can contain configuration interfaces that are integrated to the Extensions section of JMap Admin. Often, a server extension works with a client extension.
To develop a server extension and make it available, you must perform the two following steps:
Develop an extension by creating a Java class that implements the JMapServerExtension interface.
(Optional) Develop a JMap Admin configuration interface for your extension.
Deploy your extension in JMap Server.
See the following sections for more information.
The first step towards developing a JMap Server extension is to write a class that implements the JMapServerExtension interface. This interface includes the following 3 methods, which are called at different moments in the life cycle of the extension:
To do its job, your extension can use the services offered by JMap Server. This includes spatial data extraction, access to relational databases connected to JMap Server, access to the system log (log files), etc.
For more information on the services offered by JMap Server, see the JMap Server Services section.
You must implement a class derived from the JMapExtensionRequest class. This class provides your extension with all the information it needs to perform its work. Requests are typically initiated on the client side and passed to JMap Server for processing by your extension. In this class, you can include all the required properties, but make sure these are all serializable.
When your extension is initialized, the type of your query (full class name, including package) is associated with your extension. This way, when JMap Server receives this type of query, it is automatically directed to your extension (processRequest method). For more information on how to make the connection between your query and your extension, refer to the Deploying Server Extensions section.
For more information on programming requests, refer to the Client-Server Communication section.
You must also implement a class derived from the JMapServerResponse class. This class is intended to provide information resulting from the execution of your query. The processRequest method of your extension must return an instance of this class. Depending on the nature of the query, the response may either return a large amount of information or just a query execution status (success, failure, etc.). You can include all the required properties in your class, but make sure they are all serializable.
For more information on programming responses, see the Client-Server Communication section.
The JMapServer class is the main class from which you can access JMap Server’s various services. This class is a singleton. You can therefore access it from anywhere using the static method JMapServer.getInstance().
JMap Server’s home path is accessed using the static method getJMapHome() of the JMapServer class. It can be useful to know this path when you wish to read or write data in JMap Server’s subdirectories.
The JMap Server logging tool can record events in log files. The tool’s class is Logger and it is a singleton. Thus, you can access the single instance using the static Logger.getInstance() method.
The various versions of the log method are used to store messages, depending on the type of information to be recorded.
The following table shows the most commonly used methods of the Logger class.
The various message levels are defined by constants of the Logger class.
LEVEL_DEBUG
LEVEL_INFO
LEVEL_WARNING
LEVEL_ERROR
LEVEL_FATAL
The following code example shows how to log a message with the various methods.
// Logs a message of level INFO
Logger.getInstance().log(Logger.LEVEL_INFO, "Extension ABC recieved a request for ...");
// Logs a message of level WARNING, tagged to user etardif
Logger.getInstance().log(Logger.LEVEL_WARNING, "Something occurred in Extension ABC ...", "etardif");
// Logs a message of level ERROR, and includes the exception stack trace
Exception e = ...;
Logger.getInstance().log(Logger.LEVEL_ERROR, "An unexpected error occurred in Extension ABC ...", e);
The connections to the relational databases that JMap Server is connected are available through programming. This greatly simplifies data access because you do not need to open, close and manage the connections to these databases.
JMap Server manages database connections in connection pools. These pools function as follows: when a connection is required, it is borrowed from the pool. It is then used briefly to execute one or more queries. Lastly and most importantly, the connection is returned to the pool and is once again available for other needs. Thus, connections are never closed.
The getDBConnPool(int) and getDBConnPool(String) methods allow you to get a connection pool (instance of the DatabaseConnectionPool class) using its numeric ID or name.
The following table shows the most commonly used methods of the DatabaseConnectionPool class.
The following source code example shows how to use a pool of connections to databases.
DatabaseConnectionPool pool = JMapServer.getInstance().getDBConnPool("parcels");
Connection conn = null;
try
{
conn = pool.borrowConnection();
// use connection to do queries.....
}
catch (SQLException e)
{
e.printStackTrace();
} finally
{
// It is very important to return the connection to the pool.
// Doing it in a finally clause is a good practice
if (conn != null)
pool.returnConnection(conn);
}
Spatial data can be extracted using the JMap Server data manager (JMapServerDataManager class). The data manager can be accessed using the getDataManager() method of the JMapServer class.
The following table shows the most commonly used methods of the JMapServerDataManager class.
To extract data, you can also use filters. Filters are objects that control what data must be extracted based on various criteria.
Filter classes are all derived from the abstract class QueryFilter. The following table shows all the types of filters that are available.
The following source code example shows how to extract spatial data using a spatial filter.
JMapServerProject serverProject = ...
JMapServerVectorLayer serverLayer = ...
Polygon region = ...
final JMapServerDataManager dataMgr = JMapServer.getInstance().getDataManager();
// Create a new spatial filter for all elements that intersect the polygon
final SpatialQueryFilter newFilter = new SpatialQueryFilter();
newFilter.setGeometry(region);
newFilter.setType(SpatialQueryFilter.SPATIAL_OP_INTERSECTS);
// Set the projection on the filter to indicate the coordinate system of the geometry
newFilter.setProjection(serverProject.getProject().getMapProjection());
// Do the extraction using the data manager. All attributes of the layer will be included
JMapGeoElement[] result = dataMgr.extractElements(serverProject, serverLayer,
new QueryFilter[]{newFilter},
serverLayer.getBoundAttributes() );
The sendMail() static method of the MailService class allows you to send emails from JMap Server. In order for the emails to be sent successfully, JMap Server must be connected to an SMTP server. This connection can be configured during the JMap installation or it can be defined in the Settings section of JMap Admin.
String to = "jo32@gmail.com;ann122@hotmail.com";
String from = "admin@123map.com";
try
{
MailService.sendMail(MailService.toAddresses(to), "Map extraction completed", "The data was extracted successfully and is available here.", new InternetAddress(from));
}
catch (AddressException e)
{
e.printStackTrace();
}
catch (Exception e)
{
e.printStackTrace();
}
The JMap Server Session Manager (JMapServerSessionManager class) is responsible for managing active sessions in the system. Among other things, it provides access to the user connected to a session by using the session ID. This session number is accessible from every request received by JMap Server, including queries destined to server extensions. The session manager can therefore be used to know the identity of the user who initiated a query.
The following code example shows how to access the user who initiated a query.
public JMapExtensionResponse processRequest(JMapExtensionRequest request)
{
int sessionId = request.getSessionId();
User user = JMapServer.getInstance().getSessionManager().getSessionUser(sessionId);
System.out.println("##### Request originating from user: " + user.getName() + " (" + user.getFullName() + ")");
...
}
The User Manager (UserManager interface) provides access to the list of users and groups used by JMap Server for access control. It also allows you to access user information. If you develop a server extension that must manage its own list of permissions, it can be very useful to access the list of users that the system uses.
The getUserManager() method of the JMapServer class returns the User Manager (class that implements the UserManager interface) being used.
The following table shows the most useful methods of the UserManager class.
The User class contains the information on a user (full name, email address, etc.).
In JMap, workspaces are spaces used for individual storage of user data. Each workspace is actually a separate subdirectory of JMap Server. The workspaces are used to store contexts created by users. As a programmer, you can use them to store data.
The getWorkSpaceManager() method of the JMapServer class allows you to access the workspaces manager (WorkSpaceManager class), which provides some useful methods related to worskpaces. By default, workspaces are located in the JMap_HOME / workspaces directory.
The following table shows the most useful methods of the WorkSpaceManager class.
To be deployed in JMap Server, server extensions must follow certain rules. If these rules are met, the extension appears in the Extensions section of JMap Admin.
Group extension classes in an archive (JAR)
All the classes of the extension must be contained in a single JAR archive file. Use a meaningful and unique name.
Include a manifest file
The extension archive must include a manifest.mf file with the following entries:
Here is an example of the contents of a manifest file:
extension_class: jmap.extensions.tracking.server.TrackingExtension
extension_name: Tracking
extension_request: jmap.extensions.tracking.common.TrackingRequest
extension_response: jmap.extensions.tracking.common.TrackingResponse
extension_version: 5.0.0010
Place the file in the correct directory
The JAR file of the extension must be placed in the server extensions directory (JMAP_HOME/extensions).
(Optional) Place the files from the configuration interface of the extension in the appropriate directory
The files that make up the configuration interface (JSP pages) must be copied to the directory used for this purpose (JMAP_HOME/jmapadmin/extensions).
Each server extension may include a configuration interface integrated to JMap Admin. Using this interface, JMap administrators can configure the operational parameters of your extension (e.g. security, database connectivity, a layer selection, etc.). Note that this interface is completely optional.
This interface consists of one or more JSP pages. The main JSP page (which is called first) must absolutely have the same name as the extension class. For example, if the class name of the server extension is
jmap.extensions.tracking.server.TrackingServerExtension
then the main JSP page must be
jmap.extensions.tracking.server.TrackingServerExtension.jsp
For more information on programming these JSP pages, refer to the examples included in the SDK.
This method is called when JMap Server is launched, when extensions are initially loaded or when the administrator requests to reset the extension from JMap Admin. It is used to initialize the extension. In this method, you can put any code used to prepare the operation of your extension. This could include loading a settings file, checking dependencies, etc.
This method is called when JMap Server receives a request destined to your extension. In this method, you must include the code needed to process the request. In addition, the method must return a response resulting from processing the request.
This method is called when JMap Server shuts down or when the administrator requests to reset the extension from JMap Admin. It is used to execute the code needed to close the extension. This could include closing files or connections to other systems.
Logs a message of the specified level.
Logs a message of the specified level associated with the specified user.
Logs a message of the specified level and the trace of the exception passed as a parameter.
Logs a message of the specified level, associated with the specified user, and the trace of the exception passed as a parameter.
Changes the level of the messages that will be recorded.
Borrows a JDBC connection from the pool. The connection is then reserved exclusively.
Returns a JDBC connection borrowed from the pool. It is very important to call this method after using a connection.
Provides the status of the connection pool. Can be called to validate that the pool is working correctly before borrowing a connection. The possible statuses are defined by constants of the ConnectionPoolInfo class (CONNECTION_NOT_TESTED, CONNECTION_ERROR or CONNECTION_OK).
Extracts the spatial data and attributes that pass the filters passed as parameters, for the specified of the specified project. Only attributes that are specified in the last parameter are included in the result.
Extracts spatial data and its attributes based on the query passed as parameters. The general syntax for queries is the following:
select element from $ $ source {$ {project} $ PROJECT_NAME layer layer_name {}} WHERE condition
Example:
select element from $ $ source {$ {project} The World Countries {$ layer}} Where COUNTRY = 'Peru'
Extracts spatial data and its attributes based on to the query passed as parameters and the list of identifiers specified. Only items whose identifier is in the list are returned.
Extracts spatial data and its attributes based on the query passed as parameters, the list of identifiers and the region specified. Only elements whose identifier is in the list and who intersect the region are returned.
Sets a condition based on a data attribute. The condition is defined by an attribute and a set of values. Only data for which the attribute has a value included in the set of values will pass the filter.
Sets a condition based on the type of data geometry. The condition is defined by one or more types of geometries. Only data with a geometry type matching the filter will pass the filter.
Sets a spatial condition. Only data meeting the condition will pass the filter. The condition is defined by a geometry and a constraint. For example: all geometries that intersect the specified polygon, all geometries that contain the specified point, etc.
Sets a condition in SQL. This is the equivalent of the where clause in an SQL query. The where clause is interpreted by the database system that contains the data.
Returns the user (instance of the User class) whose name is specified as a parameter.
Returns the group (instance of the Group class) whose name is specified as a parameter.
Returns the list of users (instances of the User class) used by JMap Server.
Returns the list of groups (instances of the Group class) used by JMap Server.
Returns the full path to the workspace directory for the user specified as a parameter.
Erases all the content of the workspace for the user specified as a parameter.
Clears the workspace directory of the user specified as a parameter.
Variable
Description
extension_class
Identifies the main class of the extension. This is the class that implements the JMapServerExtension interface.
extension_request
Identifies the class used as the query for this extension. This is the entry that will route requests to your extension. If your extension supports multiple classes of requests, they must all derive from this class.
extension_response
Identifies the class used as a response to this extension. If your extension supports several classes of responses, they must all be derived from this class.
extension_name
Specifies the name of the extension. This name appears in JMap Admin in the Extensions section.
extension_version
Specifies the version number of the extension. This information appears in JMap Admin in the Extensions section. The version number is used only to simplify the management of extensions.
It may be useful to have remote debugging for the JMap Server extensions. Once deployed, these extensions are executed directly in the JMap Server process. It is therefore only possible to debug such extensions remotely. The Java Runtime Environment allows for remote debugging by adding a special parameter in the JMap Server environment. You will then be able to perform a server connection from Eclipse and monitor the execution of your JMap extensions step by step.
To activate remote debugging in JMap Server, you must modify the file startjmapserver.vmoptions located in the JMap_HOME/bin directory. The line starting with -Xdebug should be added.
-Xmx768m
-XX:MaxPermSize=256m
-Djava.awt.headless=true
-Dfile.encoding=ISO-8859-1
-Xdebug
-Xrunjdwp:transport=dt_socket,server=y,suspend=n,address=8000
Next, you must restart JMap Server. JMap Server will then be in debug mode and it will be awaiting commands from Eclipse. It is not recommended to activate the debug mode in a production environment, as it significantly decreases system performance.
In Eclipse, you must create a remote debugging configuration using the same parameters given in the configuration file shown above (these are the default parameters).