There are a lot of different ways to communicate inside companies. In smaller businesses it’s more likely to just talk to each other or send emails. However, if the company grows there is a point where companies need to offer additional ways to exchange information. One of these additional technologies would be instant messaging. There are multiple providers of such applications, most of them are hosted outside of your company. With Intrexx it’s possible to integrate the free real time collaboration server Openfire for XMPP(Jabber) into your company portal using a jQuery XMPP plugin. Openfire can be hosted in your own environment, used for free and is therefor a good alternative for instant messaging.
Openfire is a real time collaboration server which enables you to provide instant messaging inside your company without the need of external services. This server contains its own user- and contact-management. In order to use Openfire, Intrexx users need to be transferred to Openfire somehow. Also there needs to be some interface to access the server over the web.
Install and Activate Rest-API and HTTP-Bind
A lot of plugins are available for Openfire, one in specific is needed to communicate to Openfire from the outside and this is the Rest-API-plugin. This plugin for example enables you to manage users and their contacts. This plugin needs to be installed and activated to be able to manage Openfire users out of Intrexx.
Another feature we need is the http-bind. This feature allows us to keep a connection via http in order to sent and receive instant messages. Since Intrexx doesn’t have a push mechanism yet, the communication needs to be done by a third-party-library which directly communicates with Openfire.
This third-party-library is the jQuery XMPP-plugin I mentioned earlier.
In my previous post “Include JavaScript-Library in your Intrexx Application” I showed you how to include a JavaScript-library.
Copy Intrexx users and contacts to Openfire
But first things first. Without users in Openfire we can’t send any messages.
On the Openfire Rest-API documentation page there are several examples on how to use this interface. On the Intrexx side I use Groovy and the Apache Commons HttpComponents project to communicate with this API. In my example I connect using the Openfire Secret for authentication. After this I retrieve a List of all Openfire users having the custom IsIntrexxUser property set to true. I compare this list to a list of Intrexx users that are allowed to use Instant messaging. The users that don’t exist in Openfire are then created using the Rest-API.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 |
import org.apache.http.impl.client.* import org.apache.http.client.* import org.apache.http.* import org.apache.http.client.methods.* import org.apache.http.auth.* import org.apache.http.entity.* // query to retrieve Openfire users String url = "http://localhost:9090/plugins/restapi/v1/users?propertyKey=IsIntrexxUser&propertyValue=true"; // define Openfire authentication credentials for Rest-API CredentialsProvider provider = new BasicCredentialsProvider(); UsernamePasswordCredentials credentials = new UsernamePasswordCredentials("admin", "******"); provider.setCredentials(AuthScope.ANY, credentials); // initialize HttpClient with credentials HttpClient client = HttpClientBuilder.create() .setDefaultCredentialsProvider(provider) .build(); // initialize GET call HttpGet request = new HttpGet(url) // add request header to GET call request.addHeader("Accept", "application/json") request.addHeader("Authorization", "0ThGJi3xWGlE11sR") // execute GET call HttpResponse response = client.execute(request); // receive and parse JSON result of GET call def result = g_json.parse(new InputStreamReader(response.getEntity().getContent())) // initialize list of Openfire users def ofUsers = [] // iterate through Openfire user list result["user"].each{ // add user to user list if(it.properties != null){ ofUsers.add(it.username.toLowerCase()) } } // query to create and modify Openfire users url = "http://localhost:9090/plugins/restapi/v1/users" // initialize POST call HttpPost pRequest = new HttpPost(url); // add request header pRequest.addHeader("Content-Type", "application/json"); pRequest.addHeader("Authorization", "0ThGJi3xWGlE11sR"); // get all Intrexx-users who are member of certain usergroup def ixUsers = g_om.getMembers("6AA80844C3C99EF93BF4536EB18605BF86FDD3C5", true) // iterate through all found users ixUsers.each{ // add user to Openfire if not already exists if(!ofUsers.contains(it.loginName.toLowerCase())){ // fill Groovy map with user-data def user = [:] user["username"] = it.loginName.toLowerCase() user["password"] = it.guid.toLowerCase() user["name"] = it.fullName user["email"] = it.emailBiz user["properties"] = [:] user["properties"]["property"] = [] def key1 = [:] key1["@key"] = "IsIntrexxUser" key1["@value"] = "true" user["properties"]["property"].add(key1) // cast map to JSON String def jsonString = g_json.stringify(user) StringEntity params =new StringEntity(jsonString) pRequest.setEntity(params) // execute API call response = client.execute(pRequest) } } |
A user can only communicate with people he knows, so the needs to be some kind of buddylist for the user to manage. These buddies also need to be transferred to Openfire.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 |
import org.apache.http.impl.client.* import org.apache.http.client.* import org.apache.http.* import org.apache.http.client.methods.* import org.apache.http.auth.* import org.apache.http.entity.* import de.uplanet.scripting.groovy.util.Safely def conn = g_dbConnections.systemConnection def stmt = null def rs = null try { // prepare statement to select all buddies for a specific user stmt = g_dbQuery.prepare(conn, "SELECT STR_BUDDY FROM DATAGROUP('1BBD033039FDAE2C8764449FA2E8903F13DB3895') WHERE STR_USER=?") // initialize Openfire authentication for Rest API CredentialsProvider provider = new BasicCredentialsProvider() UsernamePasswordCredentials credentials = new UsernamePasswordCredentials("admin", "******") provider.setCredentials(AuthScope.ANY, credentials) //initialize HttpClient HttpClient client = HttpClientBuilder.create() .setDefaultCredentialsProvider(provider) .build() //read all users of a specific group def ixUsers = g_om.getMembers("6AA80844C3C99EF93BF4536EB18605BF86FDD3C5", true) ixUsers.each{ // set parameter of prepared statement stmt.setString(1, it.guid) // execute prepared statement rs = stmt.executeQuery() // define url to access user roster String url = "http://localhost:9090/plugins/restapi/v1/users/${it.getLoginName().toLowerCase()}/roster" // initialize Post request HttpPost pRequest = new HttpPost(url) // add request header pRequest.addHeader("Content-Type", "application/xml") pRequest.addHeader("Authorization", "0ThGJi3xWGlE11sR") while (rs.next()) { def buddy = g_om.getUser(rs.getStringValue(1), true) //initialize Post Content StringEntity params =new StringEntity("""<?xml version="1.0" encoding="UTF-8" standalone="yes"?> <rosterItem> <jid>${buddy.getLoginName().toLowerCase()}@xxtendvb</jid> </rosterItem>""") // set Post Content pRequest.setEntity(params) // execute Post request response = client.execute(pRequest) } rs = Safely.close(rs) } } finally { rs = Safely.close(rs) stmt = Safely.close(stmt) } |
Implement jQuery XMPP chat
On the jQuery plugin page, there is an example of a basic chat which I reuse and adapt to what I need in Intrexx. Username and password are already clear, so these elements can be deleted. The contact-list doesn’t need to show the username, but the fullname. The HTML/CSS needs to be adjusted a little bit, but in general this already works.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
var thisUser = ""; function init_xmpp_client(userGuid, userName){ Loader.loadJsFileOnDemand("./include/custom/xmpp/jquery.xmpp.js"); var chat = $("<div style='position: fixed; bottom: 0;width:100%' id='chat' />"); $("body").append(chat); connectXMPP(userGuid,userName); return true; } function connectXMPP(userGuid, userName){ var jid = userName+"@xxtendvb"; var password = userGuid; var logContainer = $("#log"); var contactList = $("#contacts"); var url ="http://xxtendvb:7070/http-bind/"; $.xmpp.connect({url:url, jid: jid, password: password, onConnect: function(){ logContainer.html("Connected"); $.xmpp.setPresence(null); thisUser = $.xmpp.jid+"/"+$.xmpp.sid; }, onPresence: function(presence){ var jid = presence.from.split("/"); var id = MD5.hexdigest(jid[0]); var con = $("#contact"+id); if(con.length == 0){ var contact = $("<li id='contact"+id+"'>"); contact.append("<a href='javascript:void(0)'>"+ jid[0] +"</a>"); contact.find("a").click(function(){ var conversation = $("#"+id); if(conversation.length == 0) openChat({to:jid[0]}); }); contactList.append(contact); } }, onDisconnect: function(){ logContainer.html("Disconnected"); }, onMessage: function(message){ var jid = message.from.split("/"); var id = MD5.hexdigest(jid[0]); var conversation = $("#"+id); if(conversation.length == 0){ openChat({to:jid[0]}); } conversation = $("#"+id); conversation.find(".conversation").append("<div>"+ jid[0] +": "+ message.body +"</div>"); },onError:function(error){ alert(error.error); } }); } function disconnectXMPP(){ $.xmpp.disconnect(); } function openChat(options){ var jid = options.to.split("/"); var id = MD5.hexdigest(jid[0]); var chat = $("<div style='border: 1px solid #000000; float:left; display: inline-block;' id='"+id+"'><div style='border: 1px solid #000000;'>Chat with "+jid[0]+"</div><div style='height:150px;overflow: auto;' class='conversation'></div><div><input type='text' /><button>Send</button></div></div>"); var input = chat.find("input"); var sendBut = chat.find("button"); var conversation = chat.find(".conversation"); sendBut.click(function(){ $.xmpp.sendMessage({to:options.to, body: input.val()}); conversation.append("<div>"+ $.xmpp.jid +": "+ input.val() +"</div>"); input.val(""); }); $("#chat").append(chat); } |
Test communication between two Intrexx users
To test the functionality of this whole construct you can open two Browser instances to login as two different users, or you can use another Third-party-tool like Pidgin to login to Openfire and chat with the user logged in to Intrexx.
