There are several ways to allow communication between a JMap Pro application and another client application, also called an external application.The external application is an application running locally on the same computer as JMap Pro. We are not talking here of web applications (HTML, javascript), but rather client applications. The JMap Socket extension provides this communication in a simple and effective way.
The Socket extension is a generic extension that allows a bidirectional socket communication between external applications and JMap Pro extensions. This extension does not directly process the messages. Its role is limited to providing communication. Here is a typical scenario describing the use of this extension:
An external application sends the identifier of an element to JMap and it is automatically located and selected on the map. Conversely, the user clicks on a map element, and JMap sends the ID of the element to the external application, which displays a form with the properties of the element.
The Socket extension provides a standard means of communication allowing JMap extensions to communicate with external applications. External applications are applications running locally on the same computer as JMap Pro. These applications can be written in any programming language (Java, C + +, Windev, C #, VB.NET, etc.). Note that web applications (HTML, javascript, etc.) are not supported by this integration method. Other methods are better suited to web applications (see Java Communication - Javascript).
To communicate, external applications and JMap extensions send messages that are in fact byte arrays. The contents of these byte arrays is interpreted on either side. The Socket extension does not interpret their content.
The external application always connects to JMap first. It does so by opening a socket to the port configured in the Socket extension. Thereafter, the external application will once again initiate communication. This first contact is a special communication called a handshake. During the handshake, the external application indicates its unique identifier (a character string identifying the application).
As for the JMap extension that wants to communicate with the external application, it must register with the Socket extension. It must provide the same identifier as the external application. This is the identifier that links the two.
Subsequently, the external application and JMap extension can send each other messages in any direction. Each party (the external application or extension) is responsible for interpreting the messages and taking the appropriate actions.
Optionally, the Socket extension can launch the external application if it does not respond. Once it is launched, the external application may initiate communication as described above.
The code examples that follow are written in Java . An external application programmed in another language should implement the same logic, in that application’s language.
Opening a socket using IP address 127.0.0.1 and port 12351):
Socket socket = new Socket(“127.0.0.1”, 12351);
Sending a handshake message
The handshake message is received and interpreted by the Socket extension only. Note that the number of bytes of the message must precede the contents of the message. The message is sent as a byte array. The character encoding (charset) of this message is defined in the configuration of the Socket (socket.properties file) extension.
DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
String handshake = "handshake:MyIdentifier";
dos.writeInt(handshake.getBytes().length);
dos.write(handshake.getBytes());
dos.flush();
Sending other messages
Subsequent messages are sent the same way as the handshake message, however, they will be received and interpreted by the extensions registered with the same identifier. Extensions that receive messages must therefore be able to understand the content of messages and perform the corresponding actions. The character encoding of the message is free and must be agreed to by the extension and the external application.
DataOutputStream dos = new DataOutputStream(socket.getOutputStream());
String message = "locate :id=333";
dos.writeInt(message.getBytes().length);
dos.write(message.getBytes());
dos.flush();
Receiving messages from JMap
Receiving messages is done using the same socket as for sending. The length of the message is read first, followed by the byte array of the message. Message reception should be done asynchronously, in a separate thread.
DataInputStream dis = new DataInputStream(socket.getInputStream());
int length = dis.readInt();
if (length > 0)
{
byte[] messageBytes = new byte[length];
dis.readFully(messageBytes);
}
The following example shows how to register a JMap extension with the socket extension to be notified when a connection or disconnection occurs and when messages from the external application are received. This code could be placed in the init() method of the JMap extension.
SocketClientExtension.register(new SocketClient()
{
@Override
public void socketMessageReceived(byte[] bytes)
{
String data = new String(bytes /*, Charset.forName("ISO-8859-5")*/);
// Interpret content of data…
}
@Override
public void socketConnectionOpened()
{
}
@Override
public void socketConnectionClosed()
{
}
@Override
public String getIdentifier()
{
return "MyIdentifier";
}
@Override
public String getExecutable()
{
// Optional - return null if not needed return "c:/external_app.exe";
}
});
The following example shows how to send a message to the external application from the JMap extension.
String message = "openform: id =99";
byte[] bytes = message.getBytes();
SocketClientManager.getInstance().sendMessage("MyIdentifier" , bytes);
Java applets are executed in the environment of a web browser. Therefore, they can interact, in both directions, with the javascript code in the web page that contains the applet. This communication allows you to create HTML interfaces to control the map and perform simple integrations with other applications running in the environment of the web browser. This does not apply to JMap Pro applications deployed with the JavaWebStart method (not in a web browser) because no web page is involved in these cases.
The following sample web page is a normal startup page for a JMap Pro applet to which javascript functions have been added (pan and zoom). Hyperlinks are also used to call these functions. When triggered, the functions call the JMap API to control the map.
The JMap Pro application has a getApplicationContext() method that is used to access all the components of the application.
<%@page contentType="text/html;charset=ISO-8859-1"%>
<%
String username = request.getParameter("username");
String password = request.getParameter("password");
String parameters = null;
if (username != null && username.length() != 0)
{
parameters = "?username=" + username;
if (password != null)
parameters += "&password=" + password;
}
%>
<html>
<head>
<title>
aa
</title>
<script src="library/deployJava.js"></script>
<script src="library/jmap.js"></script>
</head>
<BODY BGCOLOR="#ffffff" topmargin="0" leftmargin="0" rightmargin="0" bottommargin="0">
<script>
function zoom(factor)
{
document.jmap.getApplicationContext().getViewManager().getActiveView().zoom(factor);
document.jmap.getApplicationContext().getViewManager().getActiveView().refresh();
}
function pan(x, y)
{
document.jmap.getApplicationContext().getViewManager().getActiveView().pan(x, y);
document.jmap.getApplicationContext().getViewManager().getActiveView().refresh();
}
</script>
<a href="javascript:zoom(2.);">Zoom in</a>
<a href="javascript:zoom(0.5);">Zoom out</a>
<a href="javascript:pan(0, 200);">Pan north</a>
<a href="javascript:pan(0, -200);">Pan south</a>
<a href="javascript:pan(200, 0);">Pan west</a>
<a href="javascript:pan(-200, 0);">Pan east</a>
<script>
var attributes =
{
name: "jmap",
codebase: "http://127.0.0.1:8080/aa",
code: "com.kheops.jmap.client.application.JMapApplicationLauncher",
archive: "dockingClient.jar,jmap_application.jar,jmap_client.jar,jmap_client_images.jar,jmap_projections.jar,jmap_symbols.jar,custom_symbols.jar,jmap_metadata.jar,jmap_net.jar,jmap_spatial.jar,kheops_ui.jar,kheops_util.jar,gif4j_pro_2.0.jar,jide-action.jar,jide-common.jar,jide-components.jar,jide-dock.jar,jide-grids.jar",
width: "100%",
height: "100%",
mayscript: true,
separate_jvm: true,
parameters: "-appclassname jmap.viewers.docking.AppDocking -project "The World" -directport 7003 -httpport 8080 <%= username != null ? username : "" %> <%= password != null ? password : "" %> -proxypath /aa/servlet/jmapproxy -serverid "aa" -maxmemory 33554432 -connection direct -donotlistusers false -showconnectionmoredetails false true "
};
var parameters = {fontSize:16, jnlp_href:'dockingClient.jnlp'} ;
deployJava.runApplet(attributes, parameters, '1.6.0_10');
</script>
</body>
</html>
From a JMap Pro applet, it is possible to call javascript functions that are in the web page containing the applet. This allows for interaction between the JMap Pro application and its HTML environment. For example, it would be possible to select an item on the map and display its information in an HTML page.
To enable this java-javascript communication, the mayscript: true parameter must be specified in the attributes used to start the applet, as shown in the following example.
<script>
var attributes =
{
name: "jmap",
codebase: "http://127.0.0.1:8080/aa",
code: "com.kheops.jmap.client.application.JMapApplicationLauncher",
archive: "dockingClient.jar,jmap_application.jar,jmap_client.jar,jmap_client_images.jar,jmap_projections.jar,jmap_symbols.jar,custom_symbols.jar,jmap_metadata.jar,jmap_net.jar,jmap_spatial.jar,kheops_ui.jar,kheops_util.jar,gif4j_pro_2.0.jar,jide-action.jar,jide-common.jar,jide-components.jar,jide-dock.jar,jide-grids.jar",
width: "100%",
height: "100%",
mayscript: true,
separate_jvm: true,
parameters: "-appclassname jmap.viewers.docking.AppDocking -project "The World" -directport 7003 -httpport 8080 <%= username != null ? username : "" %> <%= password != null ? password : "" %> -proxypath /aa/servlet/jmapproxy -serverid "aa" -maxmemory 33554432 -connection direct -donotlistusers false -showconnectionmoredetails false true "
};
var parameters = {fontSize:16, jnlp_href:'dockingClient.jnlp'} ;
deployJava.runApplet(attributes, parameters, '1.6.0_10');
</script>
To call a javascript function from your Java code (possibly your JMap extension), you must use the JSObject API, as shown in the following example.
JSObject w = JSObject.getWindow((Applet)appContext.getRootPaneContainer());
w.eval("show_form(" + id + ");");
In this example, the getWindow method receives the instance of the applet as a parameter. The getRootPaneContainer method of the JMapApplicationContext class returns the top level container of the application, the latter being the instance of the Applet when the application is running inside the web browser.
The javascript function to be called and its parameters are taken as parameters by the eval method. In this example, an ID is passed to the javascript function.