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间通信

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