基于 OpenFire 的TVBox管理平台开发笔记

目录

一、開發環境設置.... 3

1.1 JDK 安裝.... 3

1.2 MySql Server安裝.... 4

1.3 OpenFire安裝.... 6

1.4 Openfire Admin 功能.... 14

1.4.1 用戶摘要:.... 16

1.4.2 組摘要:.... 16

1.4.3 用戶組管理:.... 17

1.4.4 發送管理消息:.... 17

二、TVBox Client APK開發.... 18

2.1 自啟動Webview播放視頻.... 18

2.1.1自啟動任務:.... 18

2.1.2WebView 播放視頻.... 19

2.2 登錄Openfire並抓取群組數據.... 20

2.2.1Openfire 登錄設定.... 20

2.2.2Openfire登錄及數據抓取.... 22

2.3 Openfire自動註冊登錄並加入群組.... 25

2.3.1 Openfire自動註冊登錄.... 26

2.3.2加入群組並建立消息監聽.... 27

三、FHWTVBox Manager 開發.... 28

3.1 界面及功能.... 28

3.1.1群組管理.... 29

3.1.2機頂盒管理.... 30

3.2 開發涉及技術點.... 30

3.2.1Java Swing組件.... 30

3.2.2生成可執行jar. 30

3.2.3 HttpClient獲取及操作openfire 數據.... 31

FHWTVBox ClientFHWTVBoxManager整合應用.... 34

4.1FHWTVBox Client端安裝設定.... 34

4.2FHWTVBoxManager 管理操作.... 37

androidFHWTVBox Admin. 42

FHWTVBox Openfire Plugin JSP. 47

6.1 TVBox JSP Plugin插件及部署.... 47

6.2TVBox Plugin登錄及使用.... 48

6.2.1 發送消息.... 49

6.2.2查看回复.... 50

6.2.3 機頂盒管理.... 52

6.3TVBox Plugin開發.... 53

6.3.1Openfire源碼部署及設定.... 53

6.3.2Openfire源碼編譯.... 56

6.3.3Openfire plugin 代碼結構.... 57

6.3.4Openfire plugin Class開發.... 61

6.3.5Openfire plugin JSP開發.... 64

FHW TVBox按群組管理     69

正文

一、开发环境设置

1.1 JDK 安装

 

         运行jdk-6u27-windows-i586.exe(或者其他更高版本的JDK安装程序,64位windows系统,请安装64位JDK),设定好环境变量,按照提示一步一步安装完毕。

1.安装JDK,安装过程中可以自定义安装目录等信息,例如我们选择安装目录为D:/java/jdk1.6.0_27;

2.安装完成后,右击“我的计算机”,点击“属性”;

3.选择“高级”选项卡,点击“环境变量”;

4.在“系统变量”中,设置3项属性,JAVA_HOME,PATH,CLASSPATH(大小写无所谓),若已存在则点击“编辑”,不存在则点击“新建”;

5.JAVA_HOME指明JDK安装路径,就是刚才安装时所选择的路径D:/java/ jdk1.6.0_27,此路径下包括lib,bin,jre等文件夹(此变量最好设置,因为以后运行tomcat,eclipse等都需要依此变量);

Path使得系统可以在任何路径下识别java命令,向已有的PATH变量中继续添加如下:  %JAVA_HOME%/bin;%JAVA_HOME%/jre/bin, 记得要与前一个用; 隔开;

    CLASSPATH为java加载类(class or lib)路径,只有类在classpath中,java命令才能识别,设为:    .;%JAVA_HOME%/lib/dt.jar;%JAVA_HOME%/lib/tools.jar (注意要加 . 表示当前路径)

6.“开始”->;“运行”,键入“cmd”;

7.键入命令“java -version”,“java”,“javac”几个命令,出现以下画面,说明环境变量配置成功;若不成功,请重复前面的步骤仔细检查。

8. 键入命令 java -Xms4095M -Xmx4096M –version 如果报错, 说明为32位JDK因为其理论内存最大为4G;如果不报错,说明为64位JDK。

基于 OpenFire 的TVBox管理平台开发笔记_第1张图片

1.2 MySql Server安装

         先下载MySql Server,目前我们安装的是mysql-5.1.31-win32.msi版本(64位windows系统,请安装mysql-essential-5.1.59-winx64.msi)的,按照提示一步一步安装完毕即可。记住设定的root用户的密码,下面会用到。

         因MySql Server的windows版与linux版对大小写的敏感度不一致,因此需要设定下:

         a. Windows下在MySql Server安装目录下,找到my.ini档,在最后面加上:lower_case_table_names=0, (0为大小写敏感,1为大小写不敏感), 然后重启MySql Server;

         b. Linux下,在/etc/my.cnf中的[mysqld]后添加lower_case_table_names=0 (0为大小写敏感,1为大小写不敏感),重启MySql Server即可。

基于 OpenFire 的TVBox管理平台开发笔记_第2张图片

mySql安装完毕,需打开MySql Query Browser(或者用其他数据库连接工具也可以),创建一个数据库给Openfire使用(通常命名为openfire):

基于 OpenFire 的TVBox管理平台开发笔记_第3张图片

登录后,在Resultset 1中输入create  database  openfire,执行;

基于 OpenFire 的TVBox管理平台开发笔记_第4张图片

或者在右边Schemata里的任一数据库上单击右键,选择create new schema:

基于 OpenFire 的TVBox管理平台开发笔记_第5张图片

Schema name输入openfire后点击OK:

基于 OpenFire 的TVBox管理平台开发笔记_第6张图片

后在右边Schema里的任一数据库上单击右键选择refresh,就会看到openfire数据库:

基于 OpenFire 的TVBox管理平台开发笔记_第7张图片

1.3 OpenFire安装

运行下载的openfire安装程序(openfire_3_7_1.exe) ,按照提示,选择语言(中文简体或英文均可)及安装路径,完成安装。

 

待安装程序运行完后,会运行一个OpenFire的程序(如下图),当出现如图所示的接口时,打开浏览器,访问http://127.0.0.1:9090或单击Launch Admin按钮,进行具体配置:

基于 OpenFire 的TVBox管理平台开发笔记_第8张图片

如果在此界面提示错误:log4j:ERROR setFile(null,true) call failed.
java.io.FileNotFoundException: C:\Program Files (x86)\Openfire\bin\..\logs\error.log (Access is denied)

请在安装完成后,设定以管理员权限运行openfire:

基于 OpenFire 的TVBox管理平台开发笔记_第9张图片

基于 OpenFire 的TVBox管理平台开发笔记_第10张图片

登陆或Launch Admin后,整个界面图如下:

基于 OpenFire 的TVBox管理平台开发笔记_第11张图片

左边可以看到相应的安装进度:

基于 OpenFire 的TVBox管理平台开发笔记_第12张图片

首先选择语言,按个人喜好来;接下来是服务器设置,如果没有特殊设定,可以使用default值;

基于 OpenFire 的TVBox管理平台开发笔记_第13张图片

数据库设置:可按服务器或项目配置设置相应的数据库,在此我们选择标准数据库以连接到目前我们项目同源的MySql数据库中;

基于 OpenFire 的TVBox管理平台开发笔记_第14张图片

基于 OpenFire 的TVBox管理平台开发笔记_第15张图片

 在数据库驱动选项选择MySql,然后修改数据库URL:jdbc:mysql://[host-name]:3306/[database-name] 为
jdbc:mysql://127.0.0.1:3306/openfire

数据库IP请填选正确的MySQL程序安装的服务器IP,openfire为数据库名(请提前在数据库中新建好openfire的DB);

用户名与密码请填写正确的MySQL用户名与密码;剩下的如果没有特殊要求可用默认值;然后在特性设置中,选用初始设置即可;

基于 OpenFire 的TVBox管理平台开发笔记_第16张图片

在设置管理员账户中,请填写好相应的密码并牢记,该密码即为初始admin的密码;

基于 OpenFire 的TVBox管理平台开发笔记_第17张图片

设置完成后,点继续会提示安装完成.

基于 OpenFire 的TVBox管理平台开发笔记_第18张图片

选择登陆到管理控制台,账号为admin,密码即为上面设置的管理员密码。

基于 OpenFire 的TVBox管理平台开发笔记_第19张图片

登录控制台,上传并安装在openfire官方网站下载的Presence Service插件presence.jar:

基于 OpenFire 的TVBox管理平台开发笔记_第20张图片

切换到服务器设置,对presenceservice插件进行设置,确保可允许任何人访问(如果是跨域浏览的话):记得要点击save button!

然后重启openfire。每次安装一个插件,最好都重启以使插件及其设置生效。

在重启之前,可以为openfire 设定环境变量 openfireHome 为openfire的安装目录:

基于 OpenFire 的TVBox管理平台开发笔记_第21张图片

同样安装下载到的broadcast插件:

基于 OpenFire 的TVBox管理平台开发笔记_第22张图片

可使openfire 具备对group或对所有用户广播message的功能。

安装broadcast插件之后,需在openfire 管理控制台的 服务器->服务器管理器->系统属性总增加以下属性设置(红色为必须设定,其他可选):

      Property Key              属性值

plugin.broadcast.serviceName   broadcast

plugin.broadcast.disableGroupPermissions  true

plugin.broadcast.groupMembersAllowed  true.

plugin.broadcast.allowedUsers  the comma-delimitted list of users allowed to broadcast messages to all connected users at once. When this property isn't set, anyone is allowed to broadcast messages to all users. Users should be specified by their bare JID (e.g. [email protected])

plugin.broadcast.all2offline  true.

plugin.broadcast.messagePrefix  (broadcast).

基于 OpenFire 的TVBox管理平台开发笔记_第23张图片

拖动右边滚动条到最下面,依次添加以上属性:

基于 OpenFire 的TVBox管理平台开发笔记_第24张图片

点击保存,确保属性保存成功:

基于 OpenFire 的TVBox管理平台开发笔记_第25张图片

也可以到网上搜索下载或自行开发更多的插件,对openfire的功能进行扩展。

1.4 Openfire Admin 功能

Openfire Server的admin功能也是通过插件方式提供的,可以从Openfire启动后在任务栏的图标

基于 OpenFire 的TVBox管理平台开发笔记_第26张图片

点击launchAdmin

基于 OpenFire 的TVBox管理平台开发笔记_第27张图片

或者直接输入openfire的安装网址和设定的访问端口(缺省为9090)来登录:

例如:http//10.139.8.167:9090

基于 OpenFire 的TVBox管理平台开发笔记_第28张图片

 输入用户名和密码,即可登录到Openfire的管理控制台:

基于 OpenFire 的TVBox管理平台开发笔记_第29张图片

可以在这里完成对Openfire 服务器的各项设定,对Openfire用户/组及客户端会话的管理,也可进行分组聊天,发送广播及进行插件的安装。

FHWTVBox管理主要用到的用户群组管理功能有:

1.4.1 用户摘要:

基于 OpenFire 的TVBox管理平台开发笔记_第30张图片

1.4.2 组摘要:

 基于 OpenFire 的TVBox管理平台开发笔记_第31张图片

1.4.3 用户组管理:

基于 OpenFire 的TVBox管理平台开发笔记_第32张图片

1.4.4 发送管理消息:

基于 OpenFire 的TVBox管理平台开发笔记_第33张图片

上述四项功能,已经完全在FHWTVBox Manager中实现,具体操作见后面FHWTVBoxManager的介绍。

二、TVBox Client 端APK开发  

本项目的需求是要求在控制TVBox上的android系统启动后,自动在连接的TV上播放指定的网站视频内容。由于管理上的原因,不希望端用户改变访问的网站,所以此功能不能使用android 原生的browser来实现,必须自己开发一个开机自启动的应用,完成视频播放;然后,再开发一个服务器端的控制端,实现对TVBox Client端的播放内容的控制。在本项目中,我们使用Openfire push message的机制实现对TVBox的服务器端控制。

2.1 自启动Webview播放视频

2.1.1 自启动任务:

    在android中建立一个自启动任务,是很简单的。首先,在AndroidManifest.xml文件中添加接收boot  complete系统广播消息的权限以及声明一个receiver:

".BootReceiver"> 

               

    "android.intent.action.BOOT_COMPLETED">  

     

然后在工程文件中,建立那个receiver的Class文件:

基于 OpenFire 的TVBox管理平台开发笔记_第34张图片

这个receiver的任务很简单,就是接受到系统启动完毕的广播事件后,启动我们的应用activity。在这里就是TVActivity。

唯一值得注意的是,在android 4.0里面, 已经禁止了未经用户同意的自启动的应用。所以,一个自启动应用要能正常自启动,必须至少手工启动一次。这个TVBox应用需要设定一些数据,所以,在安装完毕之后,需要手工启动,完成设定之后才会真正成为自启动应用。

2.1.2 WebView 播放视频

利用WebView播放视频,最主要的是设定它的两个client WebViewClient:webView.setWebViewClient(new WebViewClient() {

        public boolean shouldOverrideUrlLoading(

                android.webkit.WebView view, java.lang.String url) {

            view.loadUrl(url);

 

            return true;

        }

 

        public void onPageFinished(WebView view, String url) {

            super.onPageFinished(view, url);

            // view.loadUrl("javascript: var v=document.getElementsByTagName('video')[0]; "+"v.play(); ");

        }

 

        public void onPageStarted(WebView view, String url, Bitmap favicon) {

                super.onPageStarted(view, url, favicon);

            }

        });

和WebChromeClient: 

webView.setWebChromeClient(new WebChromeClient() {

            /**

             * 显示自定义视图,无此方法视频不能播放

             */

            private View myView = null;

            private CustomViewCallback myCallback = null;

 

            @Override

            public void onShowCustomView(View view, CustomViewCallback callback) {

                if (myCallback != null) {

                    myCallback.onCustomViewHidden();

                    myCallback = null;

                    return;

                }

 

                long id = Thread.currentThread().getId();

                Log.v("WidgetChromeClient", "rong debug in showCustomView Ex: "

                        + id);

 

                ViewGroup parent = (ViewGroup) webView.getParent();

                String s = parent.getClass().getName();

                Log.v("WidgetChromeClient", "rong debug Ex: " + s);

                parent.removeView(webView);

                parent.addView(view);

                myView = view;

                myCallback = callback;

                chromeClient = this;

                isVideoPlaying = true;

            }

 

            public void onHideCustomView() {

                long id = Thread.currentThread().getId();

                Log.v("WidgetChromeClient", "rong debug in hideCustom Ex: "

                        + id);

                if (myView != null) {

                    if (myCallback != null) {

                        myCallback.onCustomViewHidden();

                        myCallback = null;

                    }

 

                    ViewGroup parent = (ViewGroup) myView.getParent();

                    parent.removeView(myView);

                    parent.addView(webView);

 

                    // added by Dumbbell Yang at 2012-12-04

                    webView.requestFocus();

 

                    myView = null;

                }

 

                isVideoPlaying = false;

            }

        });

还有其他一些WebView的设定需要调整。加载的网页内容有时候也需要调整。当然,不能忘记需要在AndroidManifest.xml文件中添加访问网络的权限:

2.2 登录Openfire并抓取群组数据

2.2.1 Openfire 登录设定

TVBox client端要能接收到Openfire Server端push过来的消息,必须能够登录Openfire Server并建立一个http 的长连接。为此,需要设定openfire server的IP及端口数据。另外,由于用户提出还要对TVBox进行群组管理,所以,还必须能够获取Openfire server上定义的用户群组的列表,供client端设定时选择。界面如下:

基于 OpenFire 的TVBox管理平台开发笔记_第35张图片

需要注意的是,这里的UserID和password,是抓取Openfire server用户群组列表的账号,这个账号必须具有管理员权限。这个设定及抓取动作只在安装完成后执行一次。真正Client每次启动后,连接Openfire server的账户,是用设定的TVBox名称作为前缀,加下划线加TVBox的device ID作为账号,IP Addressz作为名词,固定密码自动注册,然后自动登录的,由于需要获取Client端的IP Address,所以还需要在AndroidManifest.xml文件中添加权限:

  

    

2.2.2 Openfire登录及数据抓取

   利用设定的管理员账号和密码,登录Openfire,是通过WebView的load url功能实现的:

webView.loadDataWithBaseURL(null, util.getOpenfireAutoHTML("http://" + strServer + ":9090", strUserName, strPassword), "text/html", "utf-8", null);

   其中getOpenfireAutoHTML 方法根据Openfire Server IP,账号和密码构造一个自动登录的HTML页面,然后在WebView中加载,完成登录Openfire的功能。具体实现方法,可见代码。

   然后,在WebView中实现JavaScript与WebView内容的交互。

首先定义JavaScript interface:

  /* An instance of this class will be registered as a JavaScript interface */ 

    class MyJavaScriptInterface   { 

        @SuppressWarnings("unused"

        public void loadGroup(String html) { 

        //System.out.println(html);

        //System.out.println("Extract Groups:");

        List groups = util.extractOpenfireGroups(html);

        if (groups.size() > 0){

             notGetGroups = false;

            

             String[] arrGroup = new String[groups.size()];

             int i = 0;

             for(Link group:groups){

                 Log.i(TAG, "Group:" + group.getText() + "," + group.getRef());

                 arrGroup[i++] = group.getText();

             }

       

             cmbGroups.setSuggestionData(arrGroup);

       

            showGroupMessage(arrGroup.length);

        }

        } 

      

        @SuppressWarnings("unused"

        public void add2Group(String html) { 

        //System.out.println(html);

        if (html.indexOf("success") != -1){

             notAdd2Group = false;

             System.out.println("add to Group Success!");

        }

        }

       

        //added by Dumbbell Yang at 2013-02-28

        //取得用户所在group的admin账号,和他建立chat

        @SuppressWarnings("unused"

        public void getGroupAdmin(String html) { 

        //System.out.println("Get Group Admin:" + html);

        TVBox.adminUsers = util.extractHTMLPageAllAdminUsers(html);

        if (TVBox.adminUsers.size() > 0){

             notGetGroupAdmin = false;

             System.out.println("got Group Administrator!");

            

             showGroupAdminMessage(TVBox.adminUsers.size());

        }

        else{

             System.out.println("Not got Group Administrator!");

        }

        }

    } 

   然后,在WebView的WebViewClient中,增加方法:

public void onPageFinished(WebView view, String url) {  

                super.onPageFinished(view,url);

                /* This call inject JavaScript into the page which just finished loading. */ 

                //从加载的session-summary.jsp页面的内容中提取Openfire用户

                if (url.endsWith("group-summary.jsp") && notGetGroups){

                webView.loadUrl("javascript:window.HTMLOUT.loadGroup(''+document.getElementsByTagName('html')[0].innerHTML+'');"); 

                }

                //added by Dumbbell Yang at 2013-02-28

                else if (url.indexOf("group-edit.jsp") != -1 && notGetGroupAdmin){

                webView.loadUrl("javascript:window.HTMLOUT.getGroupAdmin(''+document.getElementsByTagName('html')[0].innerHTML+'');"); 

                }

                else if (url.indexOf("group-edit.jsp") != -1 && notAdd2Group){

                    webView.loadUrl("javascript:window.HTMLOUT.add2Group(''+document.URL+'');"); 

                }

            }

   在WebView中的页面加载完成后,依次执行loadGroup 获取群组列表;getGroupAdmin,获取群组所有的管理员(因为用户要求可以有多个管理员同时来控制Client端,所以,每个group的管理员账号可能有多个);add2Group 把自动注册的client用户加入群组。

     上面三项功能都是通过解析WebView加载完成后的HTML page内容的方式完成的。具体实现方法,可见代码。当获取用户群组数据后,效果图如下

基于 OpenFire 的TVBox管理平台开发笔记_第36张图片

在这里选定一个群组,设定TVBox名称前缀及缺省打开的网站URL,单击保存,完成设定。

基于 OpenFire 的TVBox管理平台开发笔记_第37张图片

2.3 Openfire自动注册登录并加入群组

第一次启动TVBox Activity,会进入2.2的Settings Dialog,完成设定后,进入TVBox Activity,创建XMPP connection,自动注册openfire账号,加入设定的群组,自动登录,并和群组的管理员建立chat,并对chat设定message listener,监听管理员发来的信息,达到Server端对Client的控制。

2.3.1 Openfire自动注册登录

   自动注册登录的流程大致如下代码所示:

// added by Dumbbell Yang at 2012-11-20

        new Thread(new Runnable() {

            @Override

            public void run() {

                if (createXMPPConnection()) {

                    String username = getTVBoxName();

                    if (autoRegister(username, XMPPPassword)) {

                        if (autoLoginToOpenfire(username, XMPPPassword)) {

                            addChatListener();

                        }

                    }

                }

            }

        }).start();

    具体实现可见代码。要注意的是,在android 4.0中,已不允许同步访问网络;另外,由于android的线程现在,所以,这些注册登录动作最好都另起线程来做。最后的结果,需要更新界面的话,如下使用给handler发消息的方式:

  browseHandler = new Handler() {

            // @Override

            public void handleMessage(android.os.Message msg) {

                // TODO Auto-generated method stub

                // browseURL();

                if (msg.what == LOADING) {

                    browseWebView();

                }

                else if (msg.what == REFRESH) {

                    Message message = (Message)msg.obj;

                   

                    refreshWebView(message.getBody(),message.getFrom());

                    //refreshWebView(msg.obj.toString());

                }

            }

        };

 

        browseHandler.sendEmptyMessageDelayed(LOADING, 5000);

2.3.2 加入群组并建立消息监听

   登录成功后,加入群组,是采用在settings dialog中加载相应web 页面,并同过javascript interface,解析WebView的HTML内容方式完成的:

// add current user into group

String strGroup = prefs.getString(SettingsDialog.GROUP,FHWTVBOX_GROUP);

String strServer = prefs.getString(SettingsDialog.SERVER,XMPPHost);

if (isAdd2Group == false) {

    mDialog.addUserToGroup(strServer, xmppConn.getUser(),strGroup);

}

获取群组的admin 账号列表:

mDialog.getGroupAdminUserList(strServer,

    prefs.getString(SettingsDialog.USERNAME, FHW_ADMIN),

    prefs.getString(SettingsDialog.PASSWORD, FHW_ADMIN_PASSWORD), strGroup);

然后和dmin及群组的所有admin账号建立chat并监听chat message:

createChatListener(cm, FHW_ADMIN + "@" + xmppConn.getServiceName());

 

// added by Dumbbell Yang at 2013-02-28 和Group里的每个admin都建立聊天

if ((this.adminUsers != null) && (this.adminUsers.size() > 0)) {

    for (String adminUser : this.adminUsers) {

        createChatListener(cm,adminUser + "@" + xmppConn.getServiceName());

    }

}

下面是createChatListener的代码:

private void createChatListener(ChatManager cm, String strChatUser) {

        cm.createChat(strChatUser, null);

        cm.addChatListener(new ChatManagerListener() {

            @Override

            public void chatCreated(Chat chat, boolean able) {

                chat.addMessageListener(new MessageListener() {

                    @Override

                    public void processMessage(Chat chat, Message message) {

                        String strMessage = message.getBody();

                        Log.i(TAG, "received message:" + strMessage + " from "

                                + message.getFrom());

                        if (strMessage != null) {

                            android.os.Message msg = browseHandler

                                    .obtainMessage();

                            msg.what = REFRESH;

                            msg.obj = message;//strMessage;

                            msg.sendToTarget();

                        }

                    }

                });

            }

        });

  }

接收到消息时,会调用前面handler里面refreshview的方法,切换WebView的内容到消息指定的网页。

至此,client端的开发就完成了。

三、FHWTVBox Manager 开发

要对Client端的TVBox进行控制,还必须得有Server端的程序。FHWTVBox Manager是一个桌面的Java Application,实现了对TVBox的控制功能,安装了jre就可以运行,最新程序可以从本机openfire的安装网站下载,路径通常为:

http//10.139.8.167:9090/FHWTVBoxManager.jar

3.1 界面及功能

在浏览器中输入上面的地址,下载FHWTVBox Manager到本地,双击打开,界面如下:

基于 OpenFire 的TVBox管理平台开发笔记_第38张图片

最上面是openfire server的各项设定,输入openfire各项设定及管理员用户名和密码,后单击登录按钮,就会登录到openfire  server,把用户及群组信息抓取出来:

基于 OpenFire 的TVBox管理平台开发笔记_第39张图片

中间有群组管理和机顶盒管理两个Tab:

3.1.1 群组管理

群组管理中,列表显示openfire上所有的用户(也就是FHWTVBox),绿色为online,灰色为offline。选择群组下拉框显示里openfire server 上目前所有的用户群组,最低部的FHWTV 频道下拉框显示了从指定网站抓取的所有电视频道,可用于发送切换消息。

可以使用新增,更新和删除按钮,管理openfire server上的用户群组。

可以使用加入和移除按钮,将选定的用户加入指定的群组或从其中移除。

也可以在此删除选中的TVBox。

基于 OpenFire 的TVBox管理平台开发笔记_第40张图片

3.1.2 机顶盒管理

机顶盒管理界面如下:

基于 OpenFire 的TVBox管理平台开发笔记_第41张图片

er的数据。

3.2.1 Java Swing组件

在开发中主要用到了JTree和JList两种组件,用来显示TVBox的群组树状结构及列表结构。其数据Adapter是参考网上的代码修改而成,比较简单,在此不再赘述。

3.2.2生成可执行jar

生成可执行jar的方法网上也有很多数据可供参考,也一并略过。

3.2.3 HttpClient获取及操作openfire 数据

此处利用的是apache 开源的HttpClient 3.0.1的版本,最新的4.0的版本改动比较大,需要注意。

首先是用户点击login之后,createXMPPConnection成功,并调用autoLoginToOpenfire 登录一个管理员账号到Openfire,做好对client端发消息的准备,并建立一个PacketListner,接收Client对push的回馈:

private void addMessageListener(){

        System.out.println("addMessageListener");

        //添加chat message listener

        PacketFilter filter = new MessageTypeFilter(Message.Type.chat);

        xmppConn.addPacketListener(new PacketListener() {

            public void processPacket(Packet packet) {

                Message message = (Message) packet;

                System.out.println("Got message");

具体实现请参见详细代码。

然后调用fillTVBoxes方法,使用httpClient,去抓取openfire的用户信息,群组信息,在线用户信息等,填充JList和JTree及群组combox。以后每次openfire群组及用户数据有改变, 都会重新调用fillTVBoxes方法,刷新显示数据。

在fillTVBox中,使用httpClient抓取数据,示例如下:

首先判断是否已经有session:

//如果已有cookie,直接GET

        if (sessionID.equals("") == false){

            return getURLContent(client, strServerPort + "/" + strURL);

        }

        //否则

        //使用POST方法

        PostMethod postMethod = new PostMethod(strServerPort + "/login.jsp"){

            @Override

            public boolean getFollowRedirects(){

                return true;

            }

};

然后,构造需要提交的数据:

/**

        * 使用POST方式提交数据

        */

        NameValuePair[] loginInfo = {

             new NameValuePair("url",strServerPort + "/" + strURL),

             new NameValuePair("login","true"),

             new NameValuePair("username",strUserName),

             new NameValuePair("password",strPassword),};

   postMethod.setRequestBody(loginInfo);

提交数据后,处理返回值并解析:

String info = null;

        try {

            client.executeMethod(postMethod);

       

            if (sessionID.equals("")){

                Cookie[] cookies = client.getState().getCookies();

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

                    Cookie cookie = cookies[i];

                    if (cookie.getName().trim().equalsIgnoreCase("JSESSIONID")){

                        sessionID = cookie.getValue().trim();

                    }

                }

            }

            int code = postMethod.getStatusCode();

           

            //System.out.println("Status:" + code);

            if (code == HttpStatus.SC_OK){

                info = new String(postMethod.getResponseBodyAsString());

        }

如果调用返回的数据不为空,则调用不同的方法解析出所需要的值,可能会用到正则表达式,例如:

extractFHWTVChannels 解析出指定的URL web 页面上能够播放的TV频道的URL;

extractOpenfireOnlineUsers解析出所有online的openfire user lis;

extractOpenfireUsersInGroup解析出某一个openfire group所包含的user list。

    这些都是通过构造不同的post 数据,利用httpClient提交到相应的页面,然后解析返回的HTML内容的方式完成的。

    对用户群组数据的操作同样也是利用httpClient,提交不同的post数据到指定页面来完成的。例如增加用户到群组:

public static String addOpenfireUserToGroup(HttpClient client,

            String strServerPort, String strUserName, String strGroupName){

        //使用POST方法

        PostMethod postMethod = new PostMethod(strServerPort + "/group-edit.jsp?group=" + strGroupName);//{

    //      @Override

    //      public boolean getFollowRedirects(){

    //          return true;

    //      }

    //  };

 

        /**

        * 使用POST方式提交数据

        */

        NameValuePair[] postInfo = {

                new NameValuePair("group", strGroupName),

                new NameValuePair("add", "Add"),

                new NameValuePair("username", strUserName),

                new NameValuePair("addbutton", "添加"),};

        postMethod.setRequestBody(postInfo);

        String info = null;

        try {

            client.executeMethod(postMethod);

       

            int code = postMethod.getStatusCode();

            //添加成功,会跳转,添加失败,则不跳转

            if (postMethod.getResponseHeader("location") == null){

                return "Faield!";

            }

           

            String strRedirectURL = postMethod.getResponseHeader("location").getValue();

           if (code == HttpStatus.SC_OK){

                info = new String(postMethod.getResponseBodyAsString());

            }

            else if (strRedirectURL.endsWith("/group-edit.jsp?group=" +

                    strGroupName + "&success=true")){

             return "success";

        }

        }

        catch (HttpException e) {

            // TODO Auto-generated catch block

            e.printStackTrace();

        }

        catch (IOException e) {

            // TODO Auto-generated catch block

            e.printStackTrace();

        }

        finally {

            postMethod.releaseConnection();

        }

 

        return info;

    }

其他删除群组用户,增加群组,修改群组,删除群组代码逻辑完全类似。

四、FHWTVBox Client和FHWTVBoxManager整合应用

4.1 FHWTVBox Client端安装设定

FHWTVBox Client端是一个运行在android 4.0.3平台上的apk,可以从以下网址下载安装:。

http://10.139.8.167:9090/FHWTVBox.apk

安装完毕后,单击打开或者重新启动,程序界面如下,首先出现设定界面(此为仿真器所截取的竖屏,在TVBox上为横屏,内容一致):基于 OpenFire 的TVBox管理平台开发笔记_第42张图片

输入openfire  server的ip,端口,service及管理员的用户名和密码,系统会去抓取openfire、 server上已建立的用户群组,显示在下面的下拉框中,供用户选择:

基于 OpenFire 的TVBox管理平台开发笔记_第43张图片

 

选择一个当前TVBox要加入的群组,输入TVBox的名称前缀(TVBox命名为前缀_设备ID),以及TVBox启动后打开的缺省网站地址:

基于 OpenFire 的TVBox管理平台开发笔记_第44张图片

单击保存,就会自动注册用户到openfire  server,加入到选择的群组,并进入预设的网站:

基于 OpenFire 的TVBox管理平台开发笔记_第45张图片

4.2 FHWTVBoxManager 管理操作

此时,打开FHWTVBox Manager,登录成功后,可以看到有三个用户在线:(admin,一个测试TVBox,一个仿真器):

基于 OpenFire 的TVBox管理平台开发笔记_第46张图片

此时可以在列表中选中相应的TVBox,进行删除。

基于 OpenFire 的TVBox管理平台开发笔记_第47张图片

删除完成,系统会给出提示:

基于 OpenFire 的TVBox管理平台开发笔记_第48张图片

点击确定,可看到刚才选择的TVBox已经不见了:

基于 OpenFire 的TVBox管理平台开发笔记_第49张图片

切换到机顶盒管理Tab,选择仿真器及测试TVBox,选择湖南卫视,发送切换消息:

基于 OpenFire 的TVBox管理平台开发笔记_第50张图片

在Manager上会得到频道切换成功的消息:

基于 OpenFire 的TVBox管理平台开发笔记_第51张图片

基于 OpenFire 的TVBox管理平台开发笔记_第52张图片

点击确定后,展开群组,可以看到频道已经切换:

基于 OpenFire 的TVBox管理平台开发笔记_第53张图片

由于仿真器缺少播放视频所需的硬件支持,所以虽然频道已经切换,但内容无法播放。

基于 OpenFire 的TVBox管理平台开发笔记_第54张图片

频道切换的实际效果在测试TVBox上可以看到。

五、android版FHWTVBox Admin

前面开发的FHWTVBoxManager是一个PC端的TVBox的管理工具,必须在计算机上完成。后来用户提出要把管理功能在手机实现,于是,就有了FHWTVBox Admin。这是一个可以运行在android设备(android智能手机或TVBox机顶盒)上的FHWTVBox的管理工具。安装路径与FHWTVBox android client端一样,只是apk名称不同:

http://10.139.8.167:9090/FHWTVBoxAdmin.apk

安装完成后,界面如下所示(手机和仿真器上是竖屏,机顶盒上是横屏,但内容一致):

FHWTVBoxManager一样,也是分了三个Tab,服务器设定,群组管理和机顶盒管理。功能也和HWTVBoxManager类似。在服务器设定tab输入openfire 服务器相关设定及登录用户名密码后,点击登录,会登录到openfire server上,抓取所有群组,机顶盒用户及在线机顶盒信息,填充在群组管理和机顶盒管理的列表中:

基于 OpenFire 的TVBox管理平台开发笔记_第55张图片

在这个界面上,可以和FHWTVBoxManager一样,进行群组增删改,把机顶盒用户加入群组或从群组中移除,以及删除机顶盒用户等操作。操作完成后,系统会给出提示信息并刷新显示数据。

可以在机顶盒管理 Tab进行机顶盒频道切换的消息发送操作:

基于 OpenFire 的TVBox管理平台开发笔记_第56张图片

和FHWTVBoxManager同样操作,先选中要切换频道或发送信息的机顶盒,然后在频道下拉选框中选择频道,然后频道的网址就会显示在推送消息的输入框中(如果要发送消息,可以在此直接输入),点击发送按钮,就会把相应的内容推送到选中的机顶盒中。机顶盒成功接收消息或切换频道后,会回送一个消息通知,显示在FHWTVBoxAdmin的状态区:(手机及仿真器在顶部,FHWTVBox机顶盒在底部)

基于 OpenFire 的TVBox管理平台开发笔记_第57张图片

点击状态区的消息通知,可以查看消息的内容。点击之后,消息通知就自动关掉了。

基于 OpenFire 的TVBox管理平台开发笔记_第58张图片

 

FHWTVBox admin所用到的开发技术,android的界面显示有ExpandableListView和checkable的listView,都是很简单的,其余获取及操作Openfire的数据,和PC上的FHWTVBoxManager一样,是通过httpClient进行的,代码几乎都完全一样,在此不再赘述。

六、FHWTVBox Openfire Plugin JSP

本来到这里项目开发已经可以结束了,但可惜用户的需求是永无止境的。Android手机上可以管理TVBox了,那么iPad上呢?iPhone上呢?这一来,我就不得不考虑采用plugin JSP的方式来开发这个TVBox的管理平台了。虽然这样界面体验在移动端不是很好,但是作为管理应用,功能实现才是首要目标。所以才有了TVBox plugin

6.1 TVBox JSP Plugin插件及部署

TVBox plugin是一个可以运行在openfire Server上的插件,用JSP的形式实现了FHWTVBoxManager的全部功能:TVBox组添加修改删除,TVBox加入组或从组中移除,TVBox删除,TVBox消息推送以及TVBox回复消息显示及TVBox消息推送历史记录。这个插件JSP可以从PC浏览器或android平台浏览器或IOS平台的浏览器访问,实现了移动Web形式的通用TVBox管理平台,可以使用电脑或android平板,anroid手机,机顶盒或iPhoneiPad等等任一支持http浏览的终端上访问。

    插件部署步骤:

    1.       复制tvbox.jar插件安装包到openfire的安装目录下的plugins目录。

重新启动openfire,会看到如下包含hello,TVBox Plugin!的提示:

基于 OpenFire 的TVBox管理平台开发笔记_第59张图片

openfire的安装目录下的pluginstvbox目录下的Web文件夹中,发现tvbox.htm:

基于 OpenFire 的TVBox管理平台开发笔记_第60张图片

 2.   openfire的安装目录下的pluginsadmin目录的webapp下。

登录openfire服务器后,在插件tab中能看到如下FHWTVBox Plugin的条目:

基于 OpenFire 的TVBox管理平台开发笔记_第61张图片

6.2 TVBox Plugin登录及使用

要访问插件jsp,可以在浏览器中输入http://10.139.8.167:9090,登录openfire后,点击用户/tab,选择富鸿网机顶盒项目;也可以在浏览器中直接输入http://10.139.8.167:9090/tvbox.htm

基于 OpenFire 的TVBox管理平台开发笔记_第62张图片

 

登录后直接转到用户/组tab的富鸿网机顶盒项目的消息推送页面:

基于 OpenFire 的TVBox管理平台开发笔记_第63张图片

其中tvboxclient_c22b13562afa5c05是测试用机顶盒,test是电脑上登录spark端用户,绿色图标表示在线,灰色图标表示离线。

6.2.1 发送消息

在这里,可以选择频道:

基于 OpenFire 的TVBox管理平台开发笔记_第64张图片

然后选中要推送消息的机顶盒:

基于 OpenFire 的TVBox管理平台开发笔记_第65张图片

单击发送后,系统就会推送消息到选择的机顶盒,切换机顶盒播放频道:

基于 OpenFire 的TVBox管理平台开发笔记_第66张图片

并将页面自动转到查看机顶盒回复的页面:

基于 OpenFire 的TVBox管理平台开发笔记_第67张图片

而PC上的Spark登录用户,则会收到一条消息通知:

基于 OpenFire 的TVBox管理平台开发笔记_第68张图片

6.2.2查看回复

 

在消息历史页面,可以查询某段时间内推送到某些机顶盒上的消息:

基于 OpenFire 的TVBox管理平台开发笔记_第69张图片

输入机顶盒部分或全部ID,选择起止时间:

基于 OpenFire 的TVBox管理平台开发笔记_第70张图片

点击搜索,可看到如下搜索结果,包括消息推送时保存在数据库的所有栏位: 
基于 OpenFire 的TVBox管理平台开发笔记_第71张图片

6.2.3 机顶盒管理

而在机顶盒管理页面,可以和FHWTVBoxManager中一样,完成TVBox群组的增加修改和删除,完成机顶盒加入群组,从群组移除及删除机顶盒功能,界面如下所示:

基于 OpenFire 的TVBox管理平台开发笔记_第72张图片

机顶盒管理的功能和操作步骤和FHWTVBoxManagerFHWTVBox Admin都是基本一致的,同样可以把TVBox加入群组,从群组中移除,对群组增删改查及删除TVBox

基于 OpenFire 的TVBox管理平台开发笔记_第73张图片

上图同样显示的是openfire server是定义的群组。

6.3 TVBox Plugin开发

要进行Openfire plugin的开发,首先必须下载openfire 的源码,并进行部署编译,然后安装官方的文档,增加自己的plugin的配置文件及代码,最后编译成jar檔,放在openfire的安装目录下的plugins目录。

6.3.1 Openfire源码部署及设定

可以从http://www.igniterealtime.org/downloads/source.jsp下载打包的openfire 的最新source code ,解压到本地目录,例如:F:\Openfire Software\openfire_src_3_7_1      

或者使用svn http://svn.igniterealtime.org/svn/repos/openfire/trunk checkout整个openfire 项目到同样的本地目录。

然后在Eclipse中,新建Java Project,根据Eclipse版本不同,操作有点差别。

Eclpse Europa 3.3.2版早期版本,如下图勾选' create project from existing source' 浏览到解压的openfire 源码目录下的'openfire_src' ,完成创建(网上很多openfire源码部署都是这样写的,可是我在我的Eclpse上怎么也找不到那个' create project from existing source'的勾选框,后来才知道是Eclipse的版本升级啦):

基于 OpenFire 的TVBox管理平台开发笔记_第74张图片

而对于我正在使用的Eclipse indigo 3.7.0版,则界面如下:不要选择use default location,然后点击浏览,选择Openfire source code本地目录,完成工程创建。

基于 OpenFire 的TVBox管理平台开发笔记_第75张图片

然后右键项目 --> BuildPath -->Configure BuildPath-->library --add jars openfire下所有的lib 及其子目录中的jar包都添加到进来,把插件中的lib目录下的jar 包添加进来。

接下来配置运行参数,Run::Open Run Dialog... menu.

或者 Run -- Run configuration

选择Java Application 右键新建一个Java application 重新命名为openfire

选择刚才建的项目openfire371

设定Main class:(search) org.jivesoftware.openfire.starter.ServerStarter

基于 OpenFire 的TVBox管理平台开发笔记_第76张图片

单击 Arguments 选框

VM-Arguments 键入 -DopenfireHome="${workspace_loc:openfire}/target/openfire"

此处实际上是告诉 openfire ,openfireHome 在什么地方,用于eclipse执行

java命令时传递的参数,openfire程序可以通过System.getProperty("openfireHome")得到 openfire的本地位置。

基于 OpenFire 的TVBox管理平台开发笔记_第77张图片

点击classpath 选项 User entries --->Advanced-->Add Folder---> OK添加以下三目录

Openfire371::src::i18n

Openfire371::src::resources::jar

Openfire371::build::lib::dist

基于 OpenFire 的TVBox管理平台开发笔记_第78张图片

点击Common tab

勾选 DebugRun复选框

基于 OpenFire 的TVBox管理平台开发笔记_第79张图片

6.3.2 Openfire源码编译

现在可以使用源码中自带的ant脚本,对Openfiresource code进行编译了。

选择openfire371 project, 选择EclipseTools菜单window –> Show View -> Ant

就会在右边ant页面列出所有openfire中预定义的编译任务:

基于 OpenFire 的TVBox管理平台开发笔记_第80张图片

ant view里面双击openfire(default),开始编译,编译成功,界面如下:

基于 OpenFire 的TVBox管理平台开发笔记_第81张图片

如果编译不成功,请检查相关配置及jar文件,确保编译成功,才可以进行下一步plugin的开发。

6.3.3 Openfire plugin 代码结构

根据openfire官方的plugin develop guide:

http://www.igniterealtime.org/builds/openfire/docs/latest/documentation/plugin-dev-guide.html

openfire plugin 的代码结构如下:

基于 OpenFire 的TVBox管理平台开发笔记_第82张图片

其中,plugin.xml是必须的plugin的定义文件,其中定义了plugin的配置信息以及包含的页面信息。如下图是TVBox plugin的定义文件:

基于 OpenFire 的TVBox管理平台开发笔记_第83张图片

其中class定义了plugin的包含包名在内的主类(似乎必须是定义在org.jivesoftware.plugin 包内);

databaseKey定义了plugin要执行的数据库SQL脚本文件,如果在plugin中需要建立table的话,就要准备这份文件,按数据库类型命名放在如下的目录:

基于 OpenFire 的TVBox管理平台开发笔记_第84张图片

然后下面的部分指定了pluginopenfire 服务器控制面板访问时的路径。表示放在用户/tab下:

基于 OpenFire 的TVBox管理平台开发笔记_第85张图片

如果是则表示放在服务器tab下。要放入其他tab,相应的id可以在openfire源码自带的plugin的定义文件中查找。

表示plugin

/” tab下子tabid和名字,其中${users.sidebar.tvboxes.name}是采用多语言资源文件的方式,取资源文件中key users.sidebar.tvboxes.name的相应值:

基于 OpenFire 的TVBox管理平台开发笔记_第86张图片

中文的资源文件如下图,文字都被变成了unicode编码。开始我还以为要去一个字一个字查找其unicode编码,后来才发现在英文资源文件(编码设定为ISO-8859-1)中,直接输入中文,就会自动转换为unicode编码,然后直接copy到中文资源文件(编码UTF-8)就可以了。

基于 OpenFire 的TVBox管理平台开发笔记_第87张图片

下面的每一个item,都定义了一个jsp页面,这里才是plugin的核心内容。

例如发送消息页面定义如下:

         url="push_message.jsp" description="${tvbox.item.pushmessage.description}" />

id是页面的标识,url是页面的名称,namedescription是资源文件里面的key

这里定义有多少个item,这个plugin里面就包含有多少个jsp页面。

Plugin里面的jspweb资源,被放在在web目录中:

基于 OpenFire 的TVBox管理平台开发笔记_第88张图片

其中,WEB-INF下的web-custom.xml,是用来定义plugin中用到的Servlet的。在TVBox插件中并没有用到。

web目录下的其他活页夹,imagesscriptsstyle和一般的web应用是一样的,用来存放图片,javascript脚本以及css文件。

到这里,已经基本上把一个插件源代码的主要结构讲解完毕了,现在总结一下:

基于 OpenFire 的TVBox管理平台开发笔记_第89张图片

readme.xmlplugin的自述说明文件

changelog.htmlplugin的发布日志文件。

logo_large.pnglogo_small.pngplugin显示在openfire 插件列表中的图标文件。

plugin.xmlplugin的定义文件,前面已经详细讲过。

 

database目录是用来存放plugin中用到的数据库创建tablesql脚本文件。

I18n目录是用来存放plugin中用到的多语言资源文件。

lib目录是用来存放plugin中引用的的第三方library

web 目录是用来存放plugin中用到的jsp页面,servlet定义及其他web资源。

Java目录中存放的是plugin中用到的所有java code。(openfire source code中的plugin源码中都是java,但是在官方的plugin结构中改为了classes,可能以后会有变化)。

6.3.4 Openfire plugin Class开发

下面我们来看如何进行Openfire plugin Class的开发。一共包含如下8Class:

public class TVBoxPlugin implements Plugin

public class EchoInterceptor implements PacketInterceptor

public class EchoMessage extends Message

public class LinkItem

public class ServletUtil

public class TVBoxBean

public class TVBoxMessage

public class TVBoxServlet extends HttpServlet

首先是创建在plugin.xml文件中定义的plugclass并实现plugin接口,保持包名和类名一致。在这里就是org.jivesoftware.openfire.plugin.tvbox.TVBoxPlugin,如下图所示:

基于 OpenFire 的TVBox管理平台开发笔记_第90张图片

其实,在这个plugin的主类TVBoxPlugin中,能做的事并不多。

首先,定义了一个回报消息的拦截器,并在plugin初始化时将其加入统一的拦截器管理器中。代码如下:

public class TVBoxPlugin implements Plugin{

        private EchoInterceptor echoInter = null;

   

        @Override

        public void initializePlugin(PluginManager manager, File pluginDirectory) {

            System.out.println("hello,TVBox Plugin!");

 

             echoInter = new EchoInterceptor();

             InterceptorManager.getInstance().addInterceptor(echoInter);

}

plugin初始化时做的另一件事就是在控制台输出TVBox Plugin的初始化信息,在前面openfire server console启动界面截图中可以看到。

然后是重载的一个plugin销毁时的方法:

    @Override

    public void destroyPlugin() {

        System.out.println("TVBox Plugin Destroyed!");

   

        if(echoInter != null){

            echoInter.closeDB();

              InterceptorManager.getInstance().removeInterceptor(echoInter);

        }

}

输出控制台信息,并关闭DB,移除回报消息拦截器。

其他方法都是对拦截器的方法做了一次封装,让用户可以通过plugin对象直接去操作消息拦截器里面定义的保存消息,查询消息的方法。代码如下:

public void setSendID(long value){

        echoInter.setSendID(value);

    }

   

    public List getEchoMessage(){

        return echoInter.getEchoMessage();

    }

   

    public List searchTVBoxMessage(String sendTo, long sendTimeFrom, long sendTimeTo){

        return echoInter.searchTVBoxMessage(sendTo, sendTimeFrom, sendTimeTo);

    }

   

    public void saveTVBoxMessage(TVBoxMessage msg){

        echoInter.saveTVBoxMessage(msg);

}

第二个ClassEchoInterceptor,实现了openfire预定义的PacketInterceptor接口,负责在plugin里对接收到的回报消息进行处理。

首先是定义消息列表和sendID以及数据库操作的SQL语句。

private List echoMessage = new ArrayList();

    private long sendID = -1;

   

    private static final String CREATE_TVBOXMESSAGE =

             "INSERT INTO ofTVBoxMessage (sendID, sendFrom, sendTo, message, sendTime) " +

             "VALUES (?, ?, ?, ?, ?); ";

    private static final String RECIEVE_ECHOMESSAGE =

             "UPDATE ofTVBoxMessage SET echoTime = ? WHERE sendID = ? AND sendTo = ? ;";

    private static final String SEARCH_TVBOXMESSAGE =

             "SELECT * FROM ofTVBoxMessage WHERE sendTo LIKE ? AND sendTime >= ? AND sendTime <= ? ORDER BY sendTime DESC;";

    private static Connection con = null;

 

主要方法是重载的interceptPacket方法,对接收到的chat message进行保存。

  @Override

    public void interceptPacket(Packet packet, Session session,

        boolean incoming, boolean processed) throws PacketRejectedException {

        // TODO Auto-generated method stub

        if(!processed && packet instanceof Message){

        if(incoming && Type.chat == ((Message)packet).getType()){

             //System.out.println("Chat echo " + packet.toString());

             EchoMessage curMsg = new EchoMessage((Message)packet);

             echoMessage.add(curMsg);

            

             recieveEchoMessage(curMsg);

        }

       }

    }

这个类里的其他方法还包括保存和查询回报消息。在plugin主类中已有调用,这里是其具体实现的地方。代码比较简单,不再赘述。

第三个ClassEchoMessage,对openfire预定义的message类进行扩展,增加了sendIDrecieveDate两个属性。

第四个ClassLinkItem,封装了从HTML 内容中解析出来的超链接对象。

第五个ClassServletUtil,定义了一些公用方法。

第六个ClassTVBoxBean,定义了对openfire用户和群组数据的操作。

第七个ClassTVBoxMessage,定义了对应数据库保存的EchoMessage的实体类。

第八个ClassTVBoxServlet,扩展子HttpServlet,定义了Plugin中用到的需要用Servlet完成的功能。

6.3.5 Openfire plugin JSP开发

TVBox plugin里主要包括以下四个JSP页面,以后可能还会增加。每个jsp页面首先在plugin.xml中有定义,sidebar中的每一个Item都对应一个JSP页面:        

sidebar-tvboxes" name="${users.sidebar.tvboxes.name}"

            description="${users.sidebar.tvboxes.description}">

    url="push_message.jsp" description="${tvbox.item.pushmessage.description}" />

   url="client_echo.jsp"

          description="${tvbox.item.clientecho.description}" />

   url="message_history.jsp"

         description="${tvbox.item.messagehistory.description}" />

  tvbox-manager" name="${tvbox.item.tvboxmanage.name}" url="tvbox_manage.jsp"

         description="${tvbox.item.tvboxmanage.description}" />

下面以PushMessaget.jsp为例,讲解一下如何进行JSP的开发。(其实可以首先从source code所带插件中复制一个功能相近或相关的JSP过来,修改成自己需要的就好了。)

JSP最开始的<%@ page import 部分无需多说,上一步class开发中写的class用到的都需要在此导入。

下来的两行引用了标准的Taglib,用于多语言处理,从前面定义的资源文件中提取字符串。

<%@ taglib uri="http://java.sun.com/jstl/core_rt" prefix="c" %>

<%@ taglib uri="http://java.sun.com/jstl/fmt_rt" prefix="fmt" %>

接下来三行是:

<% webManager.init(request, response, session, application, out );

定义了两个JavaBean,一个是Openfire预定义的,一个是自己写的,并照例对webManager bean进行了初始化。

然后的java代码主要是获取所有的频道数据,openfire用户组和在线用户数据。

  List tvChannels = new ArrayList();

    tvChannels = boxBean.getFHWTVChannels("http://tv.lh.efoxconn.com/channel.htm");

    List groups = boxBean.getAllGroups();

    List onlineUsers = boxBean.getOnlineUsers();

随后是处理页面提交的代码,获取用户选择的TVBox以及输入的信息,或者选择的频道,发送消息到TVBox,并在页面显示结果消息。其中调用plugin中的saveTVBoxMessage方法对消息进行了保存:

String strMessage = request.getParameter("message");

   String strSendTo = request.getParameter("tvboxes");

   List selectedBoxes = new ArrayList();

   String strSendResult = "消息发送结果:";

   boolean isMessageSent = false;

   if ((strMessage != null) && (strSendTo != null)){

SessionManager sessionManager = webManager.getSessionManager();

          PresenceManager presenceManager = webManager.getPresenceManager();

           UserManager userManager = webManager.getUserManager();

          String[] users = strSendTo.split(",");

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

              selectedBoxes.add(users[i]);

         }

        

         String serverDomainName = XMPPServer.getInstance().getServerInfo().getXMPPDomain();

        

          // Get handle on the TVBox plugin

        TVBoxPlugin plugin = (TVBoxPlugin)XMPPServer.getInstance().getPluginManager().getPlugin(

        "tvbox");

        long sendID = ServletUtil.getCurrentID();

        plugin.setSendID(sendID);

       

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

              //由于选择TVBox会自动选择器群组,所以发送消息时需将群组剔除

              if (groups.contains(users[i]) == false){

                   try{

                    sessionManager.sendServerMessage(new JID(users[i] + "@" + serverDomainName), null, strMessage);

                      

                       long sendTime = ServletUtil.date2long(new Date());

                       TVBoxMessage msg = new TVBoxMessage();

                      

                       msg.setSendID(sendID);

                       msg.setSendFrom("admin@" + serverDomainName);

                       msg.setSendTo(users[i] + "@" + serverDomainName);

                       msg.setMessage(strMessage);

                       msg.setSendTime(sendTime);

                      

                       plugin.saveTVBoxMessage(msg);

                      

                       strSendResult += "
发送到 " + users[i] + " 成功!";

                   }

                   catch(Exception e){

                       strSendResult += "
发送到 " + users[i] + " 失败 for !" + e.toString();

                   }

              }

         }

        

         isMessageSent = true;

   }

   else{

        strMessage = "";

   }

  

   strSendResult = new String(strSendResult.getBytes("ISO-8859-1"),"utf-8");

下面都是HTML的内容了。

首先是HTMLhead,其中包含的pageID就是在plugin.xml中定义过的,是调用标

Taglib引用资源文件,其中的相对目录都是位于plugin 代码目录的Web活页夹下:

    <fmt:message key="tvbox.pushmessage.title"/>

    

     rel="stylesheet" type="text/css" href="style/treelistcontrol.css">

   

随后的JavaScript代码中,构造了显示TVBox群组用户的树型结构以及页面交互的响应函数,并且通过javascript定时函数,实现在消息发送成功之后,延时三秒,自动转向回报信息页面client_echo.jsp,可以查看到Client端接收消息后的回馈信息。

    其他几个JSP页面大体相同,唯一值得注意的是引用的imagesjavascript等等web资源,都要用相对路径,放在web下的相应目录中。然后就是多参照source code中附带的其他plugin里面的类似功能的代码,依葫芦画瓢就可以啦。

    到这里,tvbox插件的所有东东都齐备了,整个源码位于openfire371项目下的src目录下的plugins里面,目录结构如下:

开发工作至此大功告成,接下来就是编译plugin,生成jar档,然后按前述方法部署就可以了。

Openfire 的源码工程里,Ant view中预先定义了许多build任务,如前面build源码是运行的openfire(default)Build plugin可以运行其中的pluginsbuild所有plugin;或者plugin,仅build某一个指定的plugin,比如TVBox,专门用来build自己开发的这一个TVBox plugin

EclipseWindow 菜单,选择Show View  ->  Ant,就会在右边列出openfire source code源码工程中预定义的Openfire XMPP Server build task列表。

然后向下拖动,右键选中其中的plugin->   Run As   ->  External Tools Configurations…

Arguments中输入:-Dplugin=tvbox,其中tvbox就是你的pluginsrc目录下的源码目录名称。

基于 OpenFire 的TVBox管理平台开发笔记_第91张图片

Run,运行build task,如果Eclipse Console输出有编译错误,请修改java classjsp page,保证最终build successful

成功编译后,生成的plugin插件可以在target目录下的plugins中看到:

基于 OpenFire 的TVBox管理平台开发笔记_第92张图片基于 OpenFire 的TVBox管理平台开发笔记_第93张图片

七、FHW TVBox按群组管理

前面实现的FHW TVBox的管理功能,使用一个admin账号去管理所有的TVBox。当TVBox很多时,可能会出现不同的组需要由不同的管理员来管理这中需求。

为实现这一需求,首先,要在openfire server上注册管理员用户(新增用户,勾选最下面的Is Administrator 选择框):

基于 OpenFire 的TVBox管理平台开发笔记_第94张图片

这样创建的用户都具有管理员权限,登录到openfire server上,能够查看到所有群组中的TVBox。如果没有勾选这个选项,将不能看到其它的群组。

然后,在编辑用户组 Tab的编辑组界面:

基于 OpenFire 的TVBox管理平台开发笔记_第95张图片

将这个管理员用户加入被它管理的群组:

基于 OpenFire 的TVBox管理平台开发笔记_第96张图片

这样,在FHWTVBoxManager中,admin登录后,就只能看到它能够管理的用户组了:

(如果一个管理员需要管理多个组,可以把他加入多个组中。)

基于 OpenFire 的TVBox管理平台开发笔记_第97张图片

FHWTVBox client 程序已经修改,client在登录openfire server后,除了与缺省admin建立连接外,还会与同组内的所有具有管理员权限的账号建立连接(在前面的代码示例中可以看到)。这样,除了admin账号仍然可以管理外,所有与client账号同在一组的具有管理员权限的账号,都可以使用push message的方式对这个TVBox进行管理了。

本博客中相关工程源码可到CSDN下载:

http://download.csdn.net/detail/yangdanbo1975/5825753

 

转载于:https://www.cnblogs.com/dumbbellyang/archive/2013/06/02/3114328.html

你可能感兴趣的:(java,javascript,数据库)