openfire外部插件(外部組件)開發

openfire插件–外部組件開發

與外部交互

外部組件

openfire外部組件,就是與openfire所在的進程沒有關係,甚至可以不與openfire在同一臺機器上運行的組件,一般是一個可運行的jar包,我們叫做外部組件,使用tcp連接(類似客戶端Socket的監聽端口)與openfire之間進行通信,處理一些服務器需要處理的邏輯。目前可以使用WhackTinder連接操作。

Openfire的外部組件使用tcp連接與openfire之間進行通信。

  1. 發送消息到openfire,格式形如<message to="x.myopenfire.com">內容</message>
  2. Openfire收到這條消息,發現了有一個二級域名x.myopenfire.com,它會在外部組件中尋找誰會處理這個域名的消息,發現了該外部組件並會轉發給外部組件。
  3. 外部組件接受到這條消息,處理後再發回openfire,格式形如<message to="[email protected]" from="x.myopenfire.com">內容</message>
  4. openfire發到用戶上。

配置

先配置子域名和密碼,如下服務器端口默認爲5275,子域名爲chat,密碼爲123456。這裏操作的是ofExtComponentConf數據庫表。

這裏寫圖片描述

Java

外部組件使用Whack(需自行編譯jar包,ver2.0.1)連接openfire,類似Socket監聽服務器端口。注意必須在openfire啓動後在啓動外部組件,不然會報錯。這種方式相當於轉發。

org.xmpp.component.ComponentException: internal-server-error

import org.jivesoftware.whack.ExternalComponentManager;
import org.xmpp.component.ComponentException;  

public class Main {  
    public static void main(String[] args) {  
        ExternalComponentManager mgr = new ExternalComponentManager(  
                "192.168.43.42", 5275); //openfire的IP和相應的端口
        mgr.setSecretKey("chat", "123456");  //設置子域和口令(密碼)
        try {  
            mgr.addComponent("chat", new ChatComponent());  
        } catch (ComponentException e) {
            e.printStackTrace();
            System.exit(-1);  
        }  
        // daemon  
        while (true)  {
            try {
                Thread.sleep(10000);
            } catch (Exception e) {
            }
        }
    }  
} 

業務邏輯實現Component,在public void processPacket(Packet packet)處理具體數據。

import org.xmpp.component.Component;  
import org.xmpp.component.ComponentException;  
import org.xmpp.component.ComponentManager;  
import org.xmpp.packet.JID;  
import org.xmpp.packet.Packet;  

public class ChatComponent implements Component{  
    private static final String name="chat";  
    private static final String description="實現多人通過組件在區域內聊天";  
    private JID jid;  
    private ComponentManager comMgr;  


    public String getName() {  
        return name;  
    }  


    public String getDescription() {  
        return description;  
    }  


    public void processPacket(Packet packet) {
       System.out.println(packet.toXML());
    }  


    public void initialize(JID jid, ComponentManager componentManager)  
            throws ComponentException {  
        this.jid=jid;  
        this.comMgr=componentManager;  
    }  


    public void start() {  
        System.out.println("component start");

    }  


    public void shutdown() {
        System.out.println("component shutdown");
    }  

}  

通過客戶端Spark登錄發送hello,會接收到如下數據(前者爲心跳,後者爲實際文本數據)

K3ekQ1

helloK3ekQ1

主動發送消息 //TODO接收組件發送的消息失敗

package xmpp;

import org.jivesoftware.smack.*;
import org.jivesoftware.smack.chat.ChatManagerListener;
import org.jivesoftware.smack.chat2.Chat;
import org.jivesoftware.smack.chat2.ChatManager;
import org.jivesoftware.smack.chat2.IncomingChatMessageListener;
import org.jivesoftware.smack.chat2.OutgoingChatMessageListener;
import org.jivesoftware.smack.filter.PacketFilter;
import org.jivesoftware.smack.packet.Message;
import org.jivesoftware.smack.tcp.XMPPTCPConnection;
import org.jivesoftware.smack.tcp.XMPPTCPConnectionConfiguration;
import org.jxmpp.jid.EntityBareJid;
import org.jxmpp.jid.impl.JidCreate;
import org.jxmpp.stringprep.XmppStringprepException;

import java.io.IOException;

public class Test {

    public static void main(String args[]) throws XMPPException {

        try{
            //smack ver4.2.3
            //實質上時兩個用戶間的通信,其中一方爲虛擬用戶,代表的時外部組件
            XMPPTCPConnectionConfiguration config = XMPPTCPConnectionConfiguration.builder()
                    .setUsernameAndPassword("a", "a")
                    .setXmppDomain("wang")
                    .setHost("wang")
                    .setPort(5222)

                    //非安全模式下,不校驗證書(todo:安全模式下的)
                    .setSecurityMode(ConnectionConfiguration.SecurityMode.disabled)

                    .setDebuggerEnabled(true)
                    .build();

            AbstractXMPPConnection connection = new XMPPTCPConnection(config);
            connection.connect().login();


            ChatManager chatManager = ChatManager.getInstanceFor(connection);
            chatManager.addIncomingListener(new IncomingChatMessageListener() {
                public void newIncomingMessage(EntityBareJid from, Message message, Chat chat) {
                    System.out.println("New message from " + from + ": " + message.getBody());
                }
            });
            chatManager.addOutgoingListener(new OutgoingChatMessageListener() {
                public void newOutgoingMessage(EntityBareJid to, Message message, Chat chat) {
                    System.out.println("New message to " + to + ": " + message.getBody());
                }

            });

            EntityBareJid jid = JidCreate.entityBareFrom("[email protected]");
            Chat chat = chatManager.chatWith(jid);
            chat.send("Howdy!");

            while(true){
                Thread.sleep(1000);
            }
        } catch (InterruptedException e1) {
            e1.printStackTrace();
        } catch (XmppStringprepException e1) {
            e1.printStackTrace();
        } catch (IOException e1) {
            e1.printStackTrace();
        } catch (SmackException e1) {
            e1.printStackTrace();
        }


    }

}

//TODO 安全模式下發送消息

https://github.com/escline/InstallCert

在%JRE_HOME%/bin 執行如下命令,添加證書,密鑰庫口令爲changeit

keytool -keystore ..\lib\security\cacerts -import -alias myKey -file C:\env\tomcat\wpgl\usr\myKey.crt

javax.net.ssl.SSLHandshakeException: sun.security.validator.ValidatorException: PKIX path building failed: sun.security.provider.certpath.SunCertPathBuilderException: unable to find valid certification path to requested target

NodeJS

openfire裏面有插件,但只是負責啓動NodeJS的應用,不負責數據交互。

和外部組件通信,也是基於用戶間的交流

<!DOCTYPE html>
<html>
<head>
    <title>Latest content</title>
    <script src='http://cdn.bootcss.com/jquery/1.9.1/jquery.min.js'></script>
    <script src='http://cdn.bootcss.com/strophe.js/1.1.3/strophe.min.js'></script>
    <script type="text/javascript">
        var BOSH_SERVICE = 'http://wang:7070/http-bind/';
        var connection = null;

        function log(msg)
        {
            $('#log').append('<div></div>').append(document.createTextNode(msg));
        }

        /**
         * 連接綁定方法
         * @param status
         */
        function onConnect(status)
        {
            if (status == Strophe.Status.CONNECTING) {
                log('Strophe is connecting.');
            } else if (status == Strophe.Status.CONNFAIL) {
                log('Strophe failed to connect.');
                $('#connect').get(0).value = 'connect';
            } else if (status == Strophe.Status.DISCONNECTING) {
                log('Strophe is disconnecting.');
            } else if (status == Strophe.Status.DISCONNECTED) {
                log('Strophe is disconnected.');
                $('#connect').get(0).value = 'connect';
            } else if (status == Strophe.Status.CONNECTED) {
                log('Strophe is connected.');
                log('ECHOBOT: Send a message to ' + connection.jid +
                        ' to talk to me.');

                connection.addHandler(onMessage, null, 'message', null, null,  null);
                connection.send($pres().tree());
            }
        }

        /**
         * 獲取消息時的方法
         * @param msg
         * @returns {Boolean}
         */
        function onMessage(msg) {
            var to = msg.getAttribute('to');
            var from = msg.getAttribute('from');
            var type = msg.getAttribute('type');
            var elems = msg.getElementsByTagName('body');

            if (type == "chat" && elems.length > 0) {
                var body = elems[0];

                log('ECHOBOT: I got a message from ' + from + ': ' +
                        Strophe.getText(body));

                /*  關閉echo機器的自動回覆
                 var reply = $msg({to: from, from: to, type: 'chat'})
                 .cnode(Strophe.copyElement(body));
                 connection.send(reply.tree());

                 log('ECHOBOT: I sent ' + from + ': ' + Strophe.getText(body));*/


            }
            return true;
        }

        /**
         * 發信息
         * @param toId
         * @param fromId
         * @param msg
         */
        function sendMsg(toId,fromId,msg) {
            var reply = $msg({to: toId, from:fromId , type: 'chat'}).cnode(Strophe.xmlElement('body', '' ,msg));
            connection.send(reply.tree());
            log('ECHOBOT: I sent ' + toId + ': ' + msg);
        }

        /**
         * 事件監聽
         */
        $(document).ready(function () {
            connection = new Strophe.Connection(BOSH_SERVICE);

            // Uncomment the following lines to spy on the wire traffic.
            connection.rawInput = function (data) { console.log('RECV: ' + data); };
            connection.rawOutput = function (data) { console.log('SEND: ' + data); };

            // Uncomment the following line to see all the debug output.
            //Strophe.log = function (level, msg) { log('LOG: ' + msg); };

            $('#connect').bind('click', function () {
                var button = $('#connect').get(0);
                if (button.value == 'connect') {
                    button.value = 'disconnect';
                    connection.connect($('#jid').get(0).value,
                            $('#pass').get(0).value,
                            onConnect);
                } else {
                    button.value = 'connect';
                    connection.disconnect();
                }
            });

            $('#replay').bind('click', function () {
                toId = $('#tojid').val();
                fromId = $('#jid').val();
                msg=$('#msg').val();
                sendMsg(toId,fromId,msg);
            });
        });
    </script>
</head>
<body>
<div id='login' style='text-align: left'>
    <form name='cred'>
        <label for='jid'>JID:</label>
        <input type='text' id='jid' value="a@wang" /><br/>
        <label for='pass'>Password:</label>
        <input type='password' id='pass' value="a" /><br/>
        <input type='button' id='connect' value='connect' />
    </form>
</div>
<hr />
<div style="text-align: left">
    <label for='tojid'>tojid</label>
    <input type='text' id='tojid' value="" /><br/>
    <label for='msg'>msg:</label>
    <textarea id="msg">Hello world!!!</textarea>
    <br/>
    <input type='button' id='replay' value='replay' />
</div>
<hr />
<div id='log'></div>
</body>
</html>

NodeJS和Java通過Thrift進行RPC通信.。
附相應例子:Thrift–實現NodeJS和Java間通信

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章