zoukankan      html  css  js  c++  java
  • 关于将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();

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

     
     
  • 相关阅读:
    GhostBSD 3.0RC3,基于GNOME的FreeBSD
    Nagios 3.4.3 发布,企业级监控系统
    Jolokia 1.0.6 发布, JMX远程访问方法
    微软希望开发人员不要使 WebKit 成为新版 IE6
    Kwort Linux 3.5 正式版发布
    EJDB 1.0.24 发布,嵌入式 JSON 数据库引擎
    Pale Moon 15.3 Firefox“苍月”优化版发布
    Galera Load Balancer 0.8.1 发布
    SmartSVN V7.5 正式发布
    PostgresQL建立索引如何避免写数据锁定
  • 原文地址:https://www.cnblogs.com/Leo_wl/p/2475816.html
Copyright © 2011-2022 走看看