• 关于将XMPP server部署到Tomcat上的一些问题



    1. 在XMPP消息推送这个问题上,网上已经有很多资料了,本人觉得很好的一篇资料是:http://www.iteye.com/topic/1117043
    2. 提供了一个连接下载源码:http://115.com/file/bhkfse3i#%20Androidpn.rar
    3. 很感谢前辈们的研究结果。
    4. 在源码的使用过程中要注意的地方有两点,网上的那篇资料好像忽略了一个重要的地方,就是要改resources文件夹下面的jdbc.properties,将里面关于数据库的配置改为自己的,另一个需要注意的地方就是改android端的ip了。

    在项目部署到tomcat下之后,发现了不少的bug,其中一个就是当tomcat重新启动,客户端的连接将断开,不能进行自动重连。

    对于这个BUG,我们可以在Androidpn-clieng下的XmppManager这个类中做简要的处理即可修改。源码如下:

    复制代码
      1 /*
      2  * Copyright (C) 2010 Moduad Co., Ltd.
      3  *
      4  * Licensed under the Apache License, Version 2.0 (the "License");
      5  * you may not use this file except in compliance with the License.
      6  * You may obtain a copy of the License at
      7  *
      8  *      http://www.apache.org/licenses/LICENSE-2.0
      9  *
     10  * Unless required by applicable law or agreed to in writing, software
     11  * distributed under the License is distributed on an "AS IS" BASIS,
     12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     13  * See the License for the specific language governing permissions and
     14  * limitations under the License.
     15  */
     16 package org.androidpn.client;
     17 
     18 import java.util.ArrayList;
     19 import java.util.List;
     20 import java.util.UUID;
     21 import java.util.concurrent.Future;
     22 
     23 import org.jivesoftware.smack.ConnectionConfiguration;
     24 import org.jivesoftware.smack.ConnectionListener;
     25 import org.jivesoftware.smack.PacketListener;
     26 import org.jivesoftware.smack.XMPPConnection;
     27 import org.jivesoftware.smack.XMPPException;
     28 import org.jivesoftware.smack.ConnectionConfiguration.SecurityMode;
     29 import org.jivesoftware.smack.filter.AndFilter;
     30 import org.jivesoftware.smack.filter.PacketFilter;
     31 import org.jivesoftware.smack.filter.PacketIDFilter;
     32 import org.jivesoftware.smack.filter.PacketTypeFilter;
     33 import org.jivesoftware.smack.packet.IQ;
     34 import org.jivesoftware.smack.packet.Packet;
     35 import org.jivesoftware.smack.packet.Registration;
     36 import org.jivesoftware.smack.provider.ProviderManager;
     37 
     38 import android.content.Context;
     39 import android.content.SharedPreferences;
     40 import android.content.SharedPreferences.Editor;
     41 import android.os.Handler;
     42 import android.util.Log;
     43 
     44 
     45 /**
     46  * This class is to manage the XMPP connection between client and server.
     47  * 
     48  * @author Sehwan Noh (devnoh@gmail.com)
     49  */
     50 public class XmppManager {
     51 
     52     private static final String LOGTAG = LogUtil.makeLogTag(XmppManager.class);
     53 
     54     private static final String XMPP_RESOURCE_NAME = "AndroidpnClient";
     55 
     56     private Context context;
     57 
     58     private NotificationService.TaskSubmitter taskSubmitter;
     59 
     60     private NotificationService.TaskTracker taskTracker;
     61 
     62     private SharedPreferences sharedPrefs;
     63 
     64     private String xmppHost;
     65 
     66     private int xmppPort;
     67 
     68     private XMPPConnection connection;
     69 
     70     private String username;
     71 
     72     private String password;
     73 
     74     private ConnectionListener connectionListener;
     75 
     76     private PacketListener notificationPacketListener;
     77 
     78     private Handler handler;
     79 
     80     private List<Runnable> taskList;
     81 
     82     private boolean running = false;
     83 
     84     private Future<?> futureTask;
     85 
     86     private Thread reconnection;
     87 
     88     public XmppManager(NotificationService notificationService) {
     89         context = notificationService;
     90         taskSubmitter = notificationService.getTaskSubmitter();
     91         taskTracker = notificationService.getTaskTracker();
     92         sharedPrefs = notificationService.getSharedPreferences();
     93 
     94         xmppHost = sharedPrefs.getString(Constants.XMPP_HOST, "localhost");
     95         xmppPort = sharedPrefs.getInt(Constants.XMPP_PORT, 5222);
     96         username = sharedPrefs.getString(Constants.XMPP_USERNAME, "");
     97         password = sharedPrefs.getString(Constants.XMPP_PASSWORD, "");
     98 
     99         connectionListener = new PersistentConnectionListener(this);
    100         notificationPacketListener = new NotificationPacketListener(this);
    101 
    102         handler = new Handler();
    103         taskList = new ArrayList<Runnable>();
    104         reconnection = new ReconnectionThread(this);
    105     }
    106 
    107     public Context getContext() {
    108         return context;
    109     }
    110 
    111     public void connect() {
    112         Log.d(LOGTAG, "connect()...");
    113         submitLoginTask();
    114     }
    115 
    116     public void disconnect() {
    117         Log.d(LOGTAG, "disconnect()...");
    118         terminatePersistentConnection();
    119     }
    120 
    121     public void terminatePersistentConnection() {
    122         Log.d(LOGTAG, "terminatePersistentConnection()...");
    123         Runnable runnable = new Runnable() {
    124 
    125             final XmppManager xmppManager = XmppManager.this;
    126 
    127             public void run() {
    128                 if (xmppManager.isConnected()) {
    129                     Log.d(LOGTAG, "terminatePersistentConnection()... run()");
    130                     xmppManager.getConnection().removePacketListener(
    131                             xmppManager.getNotificationPacketListener());
    132                     xmppManager.getConnection().disconnect();
    133                 }
    134                 xmppManager.runTask();
    135             }
    136 
    137         };
    138         addTask(runnable);
    139     }
    140 
    141     public XMPPConnection getConnection() {
    142         return connection;
    143     }
    144 
    145     public void setConnection(XMPPConnection connection) {
    146         this.connection = connection;
    147     }
    148 
    149     public String getUsername() {
    150         return username;
    151     }
    152 
    153     public void setUsername(String username) {
    154         this.username = username;
    155     }
    156 
    157     public String getPassword() {
    158         return password;
    159     }
    160 
    161     public void setPassword(String password) {
    162         this.password = password;
    163     }
    164 
    165     public ConnectionListener getConnectionListener() {
    166         return connectionListener;
    167     }
    168 
    169     public PacketListener getNotificationPacketListener() {
    170         return notificationPacketListener;
    171     }
    172 
    173     public void startReconnectionThread() {
    174         synchronized (reconnection) {
    175             if (!reconnection.isAlive()) {
    176                 reconnection.setName("Xmpp Reconnection Thread");
    177                 reconnection.start();
    178             }
    179         }
    180     }
    181 
    182     public Handler getHandler() {
    183         return handler;
    184     }
    185 
    186     public void reregisterAccount() {
    187         removeAccount();
    188         submitLoginTask();
    189         runTask();
    190     }
    191 
    192     public List<Runnable> getTaskList() {
    193         return taskList;
    194     }
    195 
    196     public Future<?> getFutureTask() {
    197         return futureTask;
    198     }
    199 
    200     public void runTask() {
    201         Log.d(LOGTAG, "runTask()...");
    202         synchronized (taskList) {
    203             running = false;
    204             futureTask = null;
    205             if (!taskList.isEmpty()) {
    206                 Runnable runnable = (Runnable) taskList.get(0);
    207                 taskList.remove(0);
    208                 running = true;
    209                 futureTask = taskSubmitter.submit(runnable);
    210                 if (futureTask == null) {
    211                     taskTracker.decrease();
    212                 }
    213             }
    214         }
    215         taskTracker.decrease();
    216         Log.d(LOGTAG, "runTask()...done");
    217     }
    218 
    219     private String newRandomUUID() {
    220         String uuidRaw = UUID.randomUUID().toString();
    221         return uuidRaw.replaceAll("-", "");
    222     }
    223 
    224     private boolean isConnected() {
    225         return connection != null && connection.isConnected();
    226     }
    227 
    228     private boolean isAuthenticated() {
    229         return connection != null && connection.isConnected()
    230                 && connection.isAuthenticated();
    231     }
    232 
    233     private boolean isRegistered() {
    234         return sharedPrefs.contains(Constants.XMPP_USERNAME)
    235                 && sharedPrefs.contains(Constants.XMPP_PASSWORD);
    236     }
    237 
    238     private void submitConnectTask() {
    239         Log.d(LOGTAG, "submitConnectTask()...");
    240         addTask(new ConnectTask());
    241     }
    242 
    243     private void submitRegisterTask() {
    244         Log.d(LOGTAG, "submitRegisterTask()...");
    245         submitConnectTask();
    246         addTask(new RegisterTask());
    247     }
    248 
    249     private void submitLoginTask() {
    250         Log.d(LOGTAG, "submitLoginTask()...");
    251         submitRegisterTask();
    252         addTask(new LoginTask());
    253     }
    254 
    255     private void addTask(Runnable runnable) {
    256         Log.d(LOGTAG, "addTask(runnable)...");
    257         taskTracker.increase();
    258         synchronized (taskList) {
    259             if (taskList.isEmpty() && !running) {
    260                 running = true;
    261                 futureTask = taskSubmitter.submit(runnable);
    262                 if (futureTask == null) {
    263                     taskTracker.decrease();
    264                 }
    265             } else {
    266                 taskList.add(runnable);
    267             }
    268         }
    269         Log.d(LOGTAG, "addTask(runnable)... done");
    270     }
    271 
    272     private void removeAccount() {
    273         Editor editor = sharedPrefs.edit();
    274         editor.remove(Constants.XMPP_USERNAME);
    275         editor.remove(Constants.XMPP_PASSWORD);
    276         editor.commit();
    277     }
    278 
    279     /**
    280      * A runnable task to connect the server. 
    281      */
    282     private class ConnectTask implements Runnable {
    283 
    284         final XmppManager xmppManager;
    285 
    286         private ConnectTask() {
    287             this.xmppManager = XmppManager.this;
    288         }
    289 
    290         public void run() {
    291             Log.i(LOGTAG, "ConnectTask.run()...");
    292 
    293             if (!xmppManager.isConnected()) {
    294                 // Create the configuration for this new connection
    295                 ConnectionConfiguration connConfig = new ConnectionConfiguration(
    296                         xmppHost, xmppPort);
    297                 // connConfig.setSecurityMode(SecurityMode.disabled);
    298                 connConfig.setSecurityMode(SecurityMode.required);
    299                 connConfig.setSASLAuthenticationEnabled(false);
    300                 connConfig.setCompressionEnabled(false);
    301 
    302                 XMPPConnection connection = new XMPPConnection(connConfig);
    303                 xmppManager.setConnection(connection);
    304 
    305                 try {
    306                     // Connect to the server
    307                     connection.connect();
    308                     Log.i(LOGTAG, "XMPP connected successfully");
    309 
    310                     // packet provider
    311                     ProviderManager.getInstance().addIQProvider("notification",
    312                             "androidpn:iq:notification",
    313                             new NotificationIQProvider());
    314 
    315                 } catch (XMPPException e) {
    316                     Log.e(LOGTAG, "XMPP connection failed", e);
    317                 }
    318 
    319                 xmppManager.runTask();
    320 
    321             } else {
    322                 Log.i(LOGTAG, "XMPP connected already");
    323                 xmppManager.runTask();
    324             }
    325         }
    326     }
    327 
    328     /**
    329      * A runnable task to register a new user onto the server. 
    330      */
    331     private class RegisterTask implements Runnable {
    332 
    333         final XmppManager xmppManager;
    334 
    335         private RegisterTask() {
    336             xmppManager = XmppManager.this;
    337         }
    338 
    339         public void run() {
    340             Log.i(LOGTAG, "RegisterTask.run()...");
    341 
    342             //如果账号不存在的话,随机生成一个uuid的用户名和mima
    343             if (!xmppManager.isRegistered()) {
    344                 final String newUsername = newRandomUUID();
    345                 final String newPassword = newRandomUUID();
    346                 // final String newUsername = "af100042487d4b06a49adda8c3a82d41";
    347                 // final String newPassword = "af100042487d4b06a49adda8c3a82d41";
    348                 
    349                 Registration registration = new Registration();
    350 
    351                 PacketFilter packetFilter = new AndFilter(new PacketIDFilter(
    352                         registration.getPacketID()), new PacketTypeFilter(
    353                         IQ.class));
    354 
    355                 PacketListener packetListener = new PacketListener() {
    356 
    357                     public void processPacket(Packet packet) {
    358                         Log.d("RegisterTask.PacketListener",
    359                                 "processPacket().....");
    360                         Log.d("RegisterTask.PacketListener", "packet="
    361                                 + packet.toXML());
    362 
    363                         if (packet instanceof IQ) {
    364                             IQ response = (IQ) packet;
    365                             if (response.getType() == IQ.Type.ERROR) {
    366                                 if (!response.getError().toString().contains(
    367                                         "409")) {
    368                                     Log.e(LOGTAG,
    369                                             "Unknown error while registering XMPP account! "
    370                                                     + response.getError()
    371                                                             .getCondition());
    372                                 }
    373                             } else if (response.getType() == IQ.Type.RESULT) {
    374                                 xmppManager.setUsername(newUsername);
    375                                 xmppManager.setPassword(newPassword);
    376                                 Log.d(LOGTAG, "username=" + newUsername);
    377                                 Log.d(LOGTAG, "password=" + newPassword);
    378 
    379                                 Editor editor = sharedPrefs.edit();
    380                                 editor.putString(Constants.XMPP_USERNAME,
    381                                         newUsername);
    382                                 editor.putString(Constants.XMPP_PASSWORD,
    383                                         newPassword);
    384                                 editor.commit();
    385                                 Log
    386                                         .i(LOGTAG,
    387                                                 "Account registered successfully");
    388                                 xmppManager.runTask();
    389                             }
    390                         }
    391                     }
    392                 };
    393 
    394                 connection.addPacketListener(packetListener, packetFilter);
    395 
    396                 registration.setType(IQ.Type.SET);
    397                 // registration.setTo(xmppHost);
    398                 // Map<String, String> attributes = new HashMap<String, String>();
    399                 // attributes.put("username", rUsername);
    400                 // attributes.put("password", rPassword);
    401                 // registration.setAttributes(attributes);
    402                 registration.addAttribute("username", newUsername);
    403                 registration.addAttribute("password", newPassword);
    404                 connection.sendPacket(registration);
    405 
    406             } else {
    407                 Log.i(LOGTAG, "Account registered already");
    408                 xmppManager.runTask();
    409             }
    410         }
    411     }
    412 
    413     /**
    414      * A runnable task to log into the server. 
    415      */
    416     private class LoginTask implements Runnable {
    417 
    418         final XmppManager xmppManager;
    419 
    420         private LoginTask() {
    421             this.xmppManager = XmppManager.this;
    422         }
    423 
    424         public void run() {
    425             Log.i(LOGTAG, "LoginTask.run()...");
    426 
    427             if (!xmppManager.isAuthenticated()) {
    428                 Log.d(LOGTAG, "username=" + username);
    429                 Log.d(LOGTAG, "password=" + password);
    430 
    431                 try {
    432                     xmppManager.getConnection().login(
    433                             xmppManager.getUsername(),
    434                             xmppManager.getPassword(), XMPP_RESOURCE_NAME);
    435                     Log.d(LOGTAG, "Loggedn in successfully");
    436 
    437                     // connection listener
    438                     if (xmppManager.getConnectionListener() != null) {
    439                         xmppManager.getConnection().addConnectionListener(
    440                                 xmppManager.getConnectionListener());
    441                     }
    442 
    443                     // packet filter
    444                     PacketFilter packetFilter = new PacketTypeFilter(
    445                             NotificationIQ.class);
    446                     // packet listener
    447                     PacketListener packetListener = xmppManager
    448                             .getNotificationPacketListener();
    449                     connection.addPacketListener(packetListener, packetFilter);
    450                   //判断是否处于连接状态(添加)
    451                     if(!getConnection().isConnected())
    452                     {
    453                          xmppManager.runTask();
    454                     }
    455                     xmppManager.runTask();
    456                 } catch (XMPPException e) {
    457                     Log.e(LOGTAG, "LoginTask.run()... xmpp error");
    458                     Log.e(LOGTAG, "Failed to login to xmpp server. Caused by: "
    459                             + e.getMessage());
    460                     String INVALID_CREDENTIALS_ERROR_CODE = "401";
    461                     String errorMessage = e.getMessage();
    462                     if (errorMessage != null
    463                             && errorMessage
    464                                     .contains(INVALID_CREDENTIALS_ERROR_CODE)) {
    465                         xmppManager.reregisterAccount();
    466                         return;
    467                     }
    468                     xmppManager.startReconnectionThread();
    469 
    470                 } catch (Exception e) {
    471                     Log.e(LOGTAG, "LoginTask.run()... other error");
    472                     Log.e(LOGTAG, "Failed to login to xmpp server. Caused by: "
    473                             + e.getMessage());
    474                     xmppManager.startReconnectionThread();
    475                 }
    476                 //添加
    477                 xmppManager.runTask();
    478             } else {
    479                 Log.i(LOGTAG, "Logged in already");
    480                 xmppManager.runTask();
    481             }
    482 
    483         }
    484     }
    485 
    486 }
    复制代码

    新添加代码450-454行和477行

        还有一个问题是:当客户端的用户有不在线的时候,消息应怎么进行推送,是直接忽略呢还是下次登录的时候在进行推送,想qq那样,很显然对已一个具体的实用项目来说是不能忽略的,那么怎么进行消息的离线推送呢,下次告诉大家,因为我现在还没解决,不过快了。和大家说下我的思路吧:在androidpn服务端有一个UserController这个类,源码如下:

    View Code

    该源码里面有用户是否在线的判断,我们只要将用户的列表取出来,如果用户在线就将消息进行推送,如果有不在线的用户,我们就把该消息放到缓存中(也可以放到数据库中更加保险),当然为了防止用户过长没有登陆系统,导致下次登录时出现过多托送过来的消息,我们还可以在服务端进行设置时间,比如服务端只缓存近N天的消息,利用

      session.getCreationDate();
      session.getLastActiveDate();

    这两句代码应该可以完成,本人没尝试过,还不知道。效果如如下:

     
     
  • 相关阅读:
    python: 第三方时间库 arrow
    PyQt5程序打包的2种方式
    python:多任务(线程、进程、协程)
    python:网络编程(udp 和 tcp)
    python:使用matplotlib画图时,中文乱码的问题
    python:浅拷贝和深拷贝
    使用scrapy编写爬虫:爬取豆瓣Top250读书的评论
    爬虫小案例:多协程工作
    selenium:指挥浏览器工作
    爬虫小案例:联想词汇搜索
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/2475816.html
Copyright © 2020-2023  润新知