openfire 插件开发

阅读更多

最近在做openfire的ios推送插件,下面介绍下openfire的插件开发

1、 因为在很多使用openfire的过程中,需要更改openfire默认的一些行为,这就涉及到插件的开发。这里我也是写一个HelloWorld的入门案例。

      2、案例插件的功能

      这个插件很简单,就是在openfire Server启动时,和关闭时,在控制台打印出消息。

      3、插件开发的目录结构设计

       先来看一下当前openfire在eclipse中的目录结构:


openfire 插件开发_第1张图片
 

目录太长,我截取一部分,现在,我们开始写插件。在\openfire_src\src\plugins目录下新建一个helloWorld的文件夹,然后在helloWorld目录下新建一个src的文件夹,放页面和源文件,再新建一个lib目录放第三方的jar包,然后在src文件夹下面新建web,java两个文件夹,web下面放置页面,在这个案例没有用到,可以不建,java文件夹下面放置java源文件,现在目录结构如下:


openfire 插件开发_第2张图片
 

changelog.html、plugin.xml、readme.html这三个文件分别是你的插件修改日志文件,插件文件和自述文件,其中plugin.xml这个文件很重要,后面我还要解释,先空着,logo_large.gif和logo_small.gif是插件的logo文件,我随便拷了两个。各位,做好上面的步骤以后,注意了,跟openfire自带插件的目录结构不一样,细心的朋友可能注意到了,我新建的src下面有个java目录,而openfire自带插件则没有,而是跑到上面去了,如下:


openfire 插件开发_第3张图片
 

不要着急,做完这一步,我们的插件就跟openfire自带插件一样了,步骤截图如下:


openfire 插件开发_第4张图片
 

这时,我们看到,src目录下的java目录不见了,而在上面的源码目录有了我们自己插件了,截图如下:


openfire 插件开发_第5张图片
 

好了,我们先建一个包,如下:


openfire 插件开发_第6张图片
 

输入包名:


openfire 插件开发_第7张图片
 

现在包建好了,我们在这个包中建一个java文件,名为:HelloWorldPlugin,我就不截图,这个学过java的人就应该知道,内容如下:

 

[java]  view plain copy 在CODE上查看代码片
 
  1. package com.helloworld;  
  2.   
  3. import java.io.File;  
  4.   
  5. import org.jivesoftware.openfire.XMPPServer;  
  6. import org.jivesoftware.openfire.container.Plugin;  
  7. import org.jivesoftware.openfire.container.PluginManager;  
  8.   
  9. public class HelloWorldPlugin implements Plugin {  
  10.     private XMPPServer server;  
  11.   
  12.     public HelloWorldPlugin() {  
  13.   
  14.     }  
  15.   
  16.     @Override  
  17.     public void initializePlugin(PluginManager manager, File pluginDirectory) {  
  18.         server = XMPPServer.getInstance();  
  19.         System.out.println("HelloWorldPlugin----start");  
  20.         System.out.println(server.getServerInfo());  
  21.     }  
  22.   
  23.     @Override  
  24.     public void destroyPlugin() {  
  25.         System.out.println("HelloWorldPlugin----destroy");  
  26.     }  
  27.   
  28. }  

内容很简单,就是在openfire启动和关闭时,在控制台打印出一条消息。保存好了,我们的java源文件就写好了,现在我们该来写plugin.xml文件了,内容如下:

 

 

[html]  view plain copy 在CODE上查看代码片
 
  1.   
  2.   
  3.   
  4.     com.helloworld.HelloWorldPlugin  
  5.     helloWorld  
  6.     First Openfire Custom Plugin.  
  7.     xieyuan  
  8.     1.0.0  
  9.     14/07/2014  
  10.     3.9.0  
  11.       
  12.       
  13.       
  14.   
  15.   

以及注意上面的class的配置,那个配置是最为重要的,配置的是插件的全路径;name是插件的名称,安装后的插件名称;author是插件作者;adminconsole是配置插件关联的页面的;这里不需要。

 

       4、编译插件

       展开\openfire_src\build目录,我们发现有一个build.properties.template文件,我们将其重命名为:build.properties,在这个build.properties中加上一行:plugin=helloWorld,截图如下:


openfire 插件开发_第8张图片
 

使用ant编译插件,截图操作如下:


openfire 插件开发_第9张图片
 

在弹出的target中选择build one plugin,点击Apply,Run:


openfire 插件开发_第10张图片
 

之后,我们在控制台上看到:


openfire 插件开发_第11张图片
 

构建成功,我们在相应的目录下,可以看到,生成的插件包:helloWorld.jar


openfire 插件开发_第12张图片
 

现在我们来运行我们的插件,看在控制台上能不能打印相应的信息,启动openfire,我们看到在控制台上一句:


openfire 插件开发_第13张图片
 

好了,大功告成,网上有很多人问,怎么调试插件,这不很简单,直接debug openfire不就行了:


openfire 插件开发_第14张图片
 

以上是开发一个简单的openfire的示例,下面贴出ios推送插件代码,新建一个插件offlinemsg;

 

 

package org.jivesoftware.openfire.plugin;

import java.io.BufferedWriter;

import java.io.ByteArrayOutputStream;

import java.io.DataOutputStream;

import java.io.File;

import java.io.FileInputStream;

import java.io.FileOutputStream;

import java.io.FileWriter;

import java.io.IOException;

import java.io.InputStream;

import java.io.OutputStreamWriter;

import java.io.UnsupportedEncodingException;

import java.net.Socket;

import java.security.KeyStore;

import java.sql.Connection;

import java.sql.DriverManager;

import java.sql.PreparedStatement;

import java.sql.ResultSet;

import java.sql.SQLException;

import java.util.HashMap;

import java.util.List;

import java.util.regex.Pattern;

 

import javax.net.ssl.KeyManagerFactory;

import javax.net.ssl.SSLContext;

import javax.net.ssl.SSLSocketFactory;

 

import org.jivesoftware.database.DbConnectionManager;

import org.jivesoftware.openfire.PresenceManager;

import org.jivesoftware.openfire.XMPPServer;

import org.jivesoftware.openfire.container.Plugin;

import org.jivesoftware.openfire.container.PluginManager;

import org.jivesoftware.openfire.interceptor.InterceptorManager;

import org.jivesoftware.openfire.interceptor.PacketInterceptor;

import org.jivesoftware.openfire.interceptor.PacketRejectedException;

import org.jivesoftware.openfire.session.Session;

import org.jivesoftware.openfire.user.UserManager;

import org.jivesoftware.openfire.user.UserNotFoundException;

import org.json.JSONException;

import org.json.JSONObject;

import org.slf4j.Logger;

import org.slf4j.LoggerFactory;

import org.xmpp.packet.IQ;

import org.xmpp.packet.JID;

import org.xmpp.packet.Message;

import org.xmpp.packet.Packet;

import org.xmpp.packet.Presence;

 

 

 

 

public class OfflineMsg implements PacketInterceptor, Plugin {

 

private static final Logger log = LoggerFactory.getLogger(OfflineMsg.class);

 

    //Hook for intercpetorn

    private InterceptorManager interceptorManager;   

    private static PluginManager pluginManager;

    private UserManager userManager;

    private PresenceManager presenceManager;

    

    public OfflineMsg() {

        

    }

    

    public void debug(String str){

    if( true ){

//    System.out.println(str);

    }

    }

    

    public void initializePlugin(PluginManager manager, File pluginDirectory) {

    interceptorManager = InterceptorManager.getInstance();

        interceptorManager.addInterceptor(this);

 

        XMPPServer server = XMPPServer.getInstance();

        userManager = server.getUserManager();

        presenceManager = server.getPresenceManager();        

        

        pluginManager = manager;

        

        this.debug("start offline 1640");

    }

 

    public void destroyPlugin() {

     this.debug("start offline 1640");

    }

 

    /**

     * intercept message

     */

    @Override

    public void interceptPacket(Packet packet, Session session, boolean incoming, boolean processed) throws PacketRejectedException {

 

 

        JID recipient = packet.getTo();

        if (recipient != null) {

 

            String username = recipient.getNode();

            

            // if broadcast message or user is not exist

            if (username == null || !UserManager.getInstance().isRegisteredUser(recipient)) {

 

                return;

 

            } else if (!XMPPServer.getInstance().getServerInfo().getXMPPDomain().equals(recipient.getDomain())) {

            //not from the same domain

 

                return;

 

            } else if ("".equals(recipient.getResource())) {

 

            }

 

        }

 

        this.doAction(packet, incoming, processed, session);

 

    } 

    

    

    /**

     * send offline msg from this function

     */

    private void doAction(Packet packet, boolean incoming, boolean processed, Session session) {

 

        Packet copyPacket = packet.createCopy();

        if (packet instanceof Message) {

 

            Message message = (Message) copyPacket;

 

            if (message.getType() == Message.Type.chat) {

 

                if (processed || !incoming) {

                    return;

                }

 

                Message sendmessage = (Message) packet;

                String content= sendmessage.getBody();

                JID recipient = sendmessage.getTo();

                

                //get message

                try

                {

                

                if (recipient.getNode() == null ||

                        !UserManager.getInstance().isRegisteredUser(recipient.getNode())) {

                    // Sender is requesting presence information of an anonymous user

                    throw new UserNotFoundException("Username is null");

                }

               

                Presence status=presenceManager.getPresence(userManager.getUser(recipient.getNode()));

               

                if( status!=null ){

                this.debug(recipient.getNode()+" online111"+",message: "+content);

                }else{   //这里是离线状态,在这里加上自己的java推送代码

                this.debug(recipient.getNode()+" offline111"+",message: "+content);

                

                //这里是解析openfire发送消息的内容,我经过了json封装

                JSONObject  dataJson=new JSONObject(content);

               

                int type=dataJson.getInt("type");

                String fromUserId=dataJson.getString("fromUserId");

                String msg="";

                if(type==1)

                msg=dataJson.getString("content");

     

                this.sendMsg(recipient.getNode(),msg,type,fromUserId);

 

                /*

                * add your code here to send offline msg

                * recipient.getNode() : receive's id,for example,if  receive's jid is "23@localhost", receive's id is "23"

                * content: message content

                */

               

               

                }//end if

               

            }

                catch (UserNotFoundException e) {

                this.debug("exceptoin "+recipient.getNode()+" not find"+",full jid: "+recipient.toFullJID());

                } catch (JSONException e) {

// TODO Auto-generated catch block

e.printStackTrace();

}

 

            } else if (message.getType() ==  Message.Type.groupchat) {

 

                List els = message.getElement().elements("x");

                if (els != null && !els.isEmpty()) {

 

                } else {

                }

            } else {

 

            }

 

        } else if (packet instanceof IQ) {

 

            IQ iq = (IQ) copyPacket;

 

            if (iq.getType() == IQ.Type.set && iq.getChildElement() != null && "session".equals(iq.getChildElement().getName())) {

 

            }

 

        } else if (packet instanceof Presence) {

 

            Presence presence = (Presence) copyPacket;

 

            if (presence.getType() == Presence.Type.unavailable) {

 

 

            }

 

        } 

 

    } 

    

    

    public void sendMsg(String iid,String msg,int type,String fromUserId) {

        

        String keyPath = "/opt/push.p12";     //我是linux服务器,证书存放目录

        String ksType = "PKCS12";

        String ksPassword = "123456";  证书密码

        String ksAlgorithm = "SunX509";

         

   

        //数据库查询用户对应的推送标识已经发送者的用户名

        HashMap map=this.getDeviceToken(iid, fromUserId);

        String deviceToken=map.get("deviceToken");

        String userName=map.get("userName");

        if(deviceToken!=null && !deviceToken.equals("")){

         

        String serverHost = "gateway.sandbox.push.apple.com";

        int serverPort = 2195;

         

        try {

            InputStream certInput = new FileInputStream(keyPath);

            KeyStore keyStore = KeyStore.getInstance(ksType);

            keyStore.load(certInput, ksPassword.toCharArray());

             

            KeyManagerFactory kmf = KeyManagerFactory.getInstance(ksAlgorithm);

            kmf.init(keyStore, ksPassword.toCharArray());

             

            SSLContext sslContext = SSLContext.getInstance("TLS");

            sslContext.init(kmf.getKeyManagers(), null, null);

             

            SSLSocketFactory socketFactory = sslContext.getSocketFactory();

             

            Socket socket = socketFactory.createSocket(serverHost, serverPort);

             

            StringBuilder content = new StringBuilder();

             

            String text="";

            if(type==1){

            text = userName+":"+msg;

            }else{

            text= userName+"发来一段语音";

            }

             

            content.append("{\"aps\":");

            content.append("{\"alert\":\"").append(text)

                .append("\",\"badge\":1,\"sound\":\"")

                .append("ping1").append("\"}");

             

            //content.append(",\"cpn\":{\"t0\":")

            //    .append(System.currentTimeMillis()).append("}");

            content.append(",\"fromUserId\":\""+fromUserId+"\"");

            content.append(",\"type\":\"chat\"");

            content.append("}");

             

            byte[] msgByte = makebyte((byte)1, deviceToken, content.toString(), 10000001);

             

            System.out.println(msgByte);

             

            socket.getOutputStream().write(msgByte);

            socket.getOutputStream().flush();

             

            socket.close();

             

        } catch (Exception e) {

            e.printStackTrace();

        }

        }

         

         

         

    }

     

    /**

    * ◊È◊∞apnsπÊ∂®µƒ◊÷Ω⁄ ˝◊È   π”√‘ˆ«ø–Õ

    * 

    * @param command

    * @param deviceToken

    * @param payload

    * @return

    * @throws IOException

    */

    private static byte[] makebyte(byte command, String deviceToken, String payload, int identifer) {

         

        byte[] deviceTokenb = decodeHex(deviceToken);

        byte[] payloadBytes = null;

        ByteArrayOutputStream boas = new ByteArrayOutputStream();

        DataOutputStream dos = new DataOutputStream(boas);

 

        try {

            payloadBytes = payload.getBytes("UTF-8");

        } catch (UnsupportedEncodingException e) {

            e.printStackTrace();

            return null;

        }

         

        try {

            dos.writeByte(command);

            dos.writeInt(identifer);//identifer

            dos.writeInt(Integer.MAX_VALUE);

            dos.writeShort(deviceTokenb.length);

            dos.write(deviceTokenb);

            dos.writeShort(payloadBytes.length);

            dos.write(payloadBytes);

            return boas.toByteArray();

        } catch (IOException e) {

            e.printStackTrace();

            return null;

        }

    }

     

    private static final Pattern pattern = Pattern.compile("[ -]");

    private static byte[] decodeHex(String deviceToken) {

        String hex = pattern.matcher(deviceToken).replaceAll("");

         

        byte[] bts = new byte[hex.length() / 2];

        for (int i = 0; i < bts.length; i++) {

            bts[i] = (byte) (charval(hex.charAt(2*i)) * 16 + charval(hex.charAt(2*i + 1)));

        }

        return bts;

    }

 

    private static int charval(char a) {

        if ('0' <= a && a <= '9')

            return (a - '0');

        else if ('a' <= a && a <= 'f')

            return (a - 'a') + 10;

        else if ('A' <= a && a <= 'F')

            return (a - 'A') + 10;

        else{

            throw new RuntimeException("Invalid hex character: " + a);

        }

 

    }

    

  

      

    public HashMap getDeviceToken(String userId,String fromUserId) {

    

    String deviceToken = "";

    String userName = "allen";

    HashMap map=new HashMap();

    

    

        Connection con = null;

    

        String url = "jdbc:mysql://localhost:3306/test";

        String user = "test"; 

        String password = "123456";

    PreparedStatement pstmt = null;

    ResultSet rs = null;

    try {

    

    Class.forName("com.mysql.jdbc.Driver");

    con =  DriverManager.getConnection(url, user, password);;

    pstmt = con.prepareStatement("SELECT sign FROM wood_push where user = ?");

    pstmt.setString(1, userId);

    rs = pstmt.executeQuery();

    if (rs.next()) {

    deviceToken = rs.getString(1);

   

    } 

   

    pstmt = con.prepareStatement("SELECT username,nickname FROM wood_member where id = ?");

    pstmt.setString(1, fromUserId);

    rs = pstmt.executeQuery();

    if (rs.next()) {

    String username=rs.getString(1);

    String nickname = rs.getString(2);

    userName=(nickname!=null && !nickname.equals(""))?nickname:username;

    } 

   

    } catch (SQLException e) {

    e.printStackTrace();

    } catch (ClassNotFoundException e) {

// TODO Auto-generated catch block

e.printStackTrace();

} finally {

    DbConnectionManager.closeConnection(rs, pstmt, con);

    }

 

map.put("deviceToken", deviceToken);

map.put("userName", userName);

    return map;

    } 

 

}

 

注意,刚开始的时候直接运行plugin会报错,这时可以先运行plugins,把全部的插件编译一遍,然后再执行plugin就不会有错了,编译完成后得到offlinemsg.jar 在openfire后台上传至插件即可,上传后最好重启openfire

/etc/init.d/openfire restart  这时再发送消息就可以收到推送了。java如何推送请看我之前的博客。

 附件里给出了完整的插件目录

  • openfire 插件开发_第15张图片
  • 大小: 21.3 KB
  • openfire 插件开发_第16张图片
  • 大小: 36.3 KB
  • openfire 插件开发_第17张图片
  • 大小: 17.1 KB
  • openfire 插件开发_第18张图片
  • 大小: 66.2 KB
  • openfire 插件开发_第19张图片
  • 大小: 65.5 KB
  • openfire 插件开发_第20张图片
  • 大小: 68.1 KB
  • openfire 插件开发_第21张图片
  • 大小: 32.2 KB
  • openfire 插件开发_第22张图片
  • 大小: 59.4 KB
  • openfire 插件开发_第23张图片
  • 大小: 53.9 KB
  • openfire 插件开发_第24张图片
  • 大小: 59.5 KB
  • openfire 插件开发_第25张图片
  • 大小: 21.9 KB
  • openfire 插件开发_第26张图片
  • 大小: 57.9 KB
  • openfire 插件开发_第27张图片
  • 大小: 9.5 KB
  • openfire 插件开发_第28张图片
  • 大小: 96.4 KB
  • offlinemsg.zip (60.2 KB)
  • 下载次数: 73
  • 查看图片附件

你可能感兴趣的:(openfire 插件开发)