设为首页 收藏本站
查看: 903|回复: 0

[经验分享] 关于将XMPP server部署到Tomcat上的一些问题

[复制链接]
累计签到:1 天
连续签到:1 天
发表于 2015-8-6 11:27:19 | 显示全部楼层 |阅读模式

  • 在XMPP消息推送这个问题上,网上已经有很多资料了,本人觉得很好的一篇资料是:http://www.iteye.com/topic/1117043
  • 提供了一个连接下载源码:http://115.com/file/bhkfse3i#%20Androidpn.rar
  • 很感谢前辈们的研究结果。
  • 在源码的使用过程中要注意的地方有两点,网上的那篇资料好像忽略了一个重要的地方,就是要改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 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();
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 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 attributes = new HashMap();
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这个类,源码如下:


http://images.iyunv.com/OutliningIndicators/ContractedBlock.gifhttp://images.iyunv.com/OutliningIndicators/ExpandedBlockStart.gifView Code


1 /*
2  * Copyright (C) 2010 Moduad Co., Ltd.
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License along
15  * with this program; if not, write to the Free Software Foundation, Inc.,
16  * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
17  */
18 package org.androidpn.server.console.controller;
19
20 import java.util.List;
21
22 import javax.servlet.http.HttpServletRequest;
23 import javax.servlet.http.HttpServletResponse;
24
25 import org.androidpn.server.model.User;
26 import org.androidpn.server.service.ServiceLocator;
27 import org.androidpn.server.service.UserService;
28 import org.androidpn.server.xmpp.presence.PresenceManager;
29 import org.springframework.web.servlet.ModelAndView;
30 import org.springframework.web.servlet.mvc.multiaction.MultiActionController;
31
32 /**
33  * A controller class to process the user related requests.  
34  *
35  * @author Sehwan Noh (devnoh@gmail.com)
36  */
37 public class UserController extends MultiActionController {
38
39     private UserService userService;
40
41     public UserController() {
42         userService = ServiceLocator.getUserService();
43     }
44
45     //用户列表
46     public ModelAndView list(HttpServletRequest request,
47             HttpServletResponse response) throws Exception {
48         PresenceManager presenceManager = new PresenceManager();
49         List userList = userService.getUsers();
50         for (User user : userList) {
51             if (presenceManager.isAvailable(user)) {
52                 // Presence presence = presenceManager.getPresence(user);
53                 user.setOnline(true);
54             } else {
55                 user.setOnline(false);
56             }
57             // logger.debug("user.online=" + user.isOnline());
58         }
59         ModelAndView mav = new ModelAndView();
60         mav.addObject("userList", userList);
61         mav.setViewName("user/list");
62         return mav;
63     }
64
65 }
  该源码里面有用户是否在线的判断,我们只要将用户的列表取出来,如果用户在线就将消息进行推送,如果有不在线的用户,我们就把该消息放到缓存中(也可以放到数据库中更加保险),当然为了防止用户过长没有登陆系统,导致下次登录时出现过多托送过来的消息,我们还可以在服务端进行设置时间,比如服务端只缓存近N天的消息,利用



  session.getCreationDate();
session.getLastActiveDate();
  这两句代码应该可以完成,本人没尝试过,还不知道。效果如如下:
http://pic002.iyunv.com/images/2012/379107/2012042818595916.png

运维网声明 1、欢迎大家加入本站运维交流群:群②:261659950 群⑤:202807635 群⑦870801961 群⑧679858003
2、本站所有主题由该帖子作者发表,该帖子作者与运维网享有帖子相关版权
3、所有作品的著作权均归原作者享有,请您和我们一样尊重他人的著作权等合法权益。如果您对作品感到满意,请购买正版
4、禁止制作、复制、发布和传播具有反动、淫秽、色情、暴力、凶杀等内容的信息,一经发现立即删除。若您因此触犯法律,一切后果自负,我们对此不承担任何责任
5、所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其内容的准确性、可靠性、正当性、安全性、合法性等负责,亦不承担任何法律责任
6、所有作品仅供您个人学习、研究或欣赏,不得用于商业或者其他用途,否则,一切后果均由您自己承担,我们对此不承担任何法律责任
7、如涉及侵犯版权等问题,请您及时通知我们,我们将立即采取措施予以解决
8、联系人Email:admin@iyunv.com 网址:www.yunweiku.com

所有资源均系网友上传或者通过网络收集,我们仅提供一个展示、介绍、观摩学习的平台,我们不对其承担任何法律责任,如涉及侵犯版权等问题,请您及时通知我们,我们将立即处理,联系人Email:kefu@iyunv.com,QQ:1061981298 本贴地址:https://www.yunweiku.com/thread-94760-1-1.html 上篇帖子: 部署ArcGIS JS API 离线包(Tomcat与IIS) 下篇帖子: Tomcat配置多数据源
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

扫码加入运维网微信交流群X

扫码加入运维网微信交流群

扫描二维码加入运维网微信交流群,最新一手资源尽在官方微信交流群!快快加入我们吧...

扫描微信二维码查看详情

客服E-mail:kefu@iyunv.com 客服QQ:1061981298


QQ群⑦:运维网交流群⑦ QQ群⑧:运维网交流群⑧ k8s群:运维网kubernetes交流群


提醒:禁止发布任何违反国家法律、法规的言论与图片等内容;本站内容均来自个人观点与网络等信息,非本站认同之观点.


本站大部分资源是网友从网上搜集分享而来,其版权均归原作者及其网站所有,我们尊重他人的合法权益,如有内容侵犯您的合法权益,请及时与我们联系进行核实删除!



合作伙伴: 青云cloud

快速回复 返回顶部 返回列表