001/** 002 * 003 * Copyright 2016 Fernando Ramirez 004 * 005 * Licensed under the Apache License, Version 2.0 (the "License"); 006 * you may not use this file except in compliance with the License. 007 * You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017package org.jivesoftware.smackx.muclight; 018 019import java.lang.ref.WeakReference; 020import java.util.ArrayList; 021import java.util.HashMap; 022import java.util.List; 023import java.util.Map; 024import java.util.WeakHashMap; 025 026import org.jivesoftware.smack.Manager; 027import org.jivesoftware.smack.SmackException.NoResponseException; 028import org.jivesoftware.smack.SmackException.NotConnectedException; 029import org.jivesoftware.smack.XMPPConnection; 030import org.jivesoftware.smack.XMPPException.XMPPErrorException; 031import org.jivesoftware.smack.filter.IQReplyFilter; 032import org.jivesoftware.smack.filter.StanzaFilter; 033import org.jivesoftware.smack.packet.IQ; 034import org.jivesoftware.smack.packet.IQ.Type; 035import org.jivesoftware.smackx.disco.ServiceDiscoveryManager; 036import org.jivesoftware.smackx.disco.packet.DiscoverItems; 037import org.jivesoftware.smackx.muclight.element.MUCLightBlockingIQ; 038import org.jxmpp.jid.DomainBareJid; 039import org.jxmpp.jid.EntityBareJid; 040import org.jxmpp.jid.Jid; 041 042/** 043 * Multi-User Chat Light manager class. 044 * 045 * @author Fernando Ramirez 046 * 047 */ 048public final class MultiUserChatLightManager extends Manager { 049 050 private static final Map<XMPPConnection, MultiUserChatLightManager> INSTANCES = new WeakHashMap<XMPPConnection, MultiUserChatLightManager>(); 051 052 /** 053 * Get a instance of a MUC Light manager for the given connection. 054 * 055 * @param connection 056 * @return a MUCLight manager. 057 */ 058 public static synchronized MultiUserChatLightManager getInstanceFor(XMPPConnection connection) { 059 MultiUserChatLightManager multiUserChatLightManager = INSTANCES.get(connection); 060 if (multiUserChatLightManager == null) { 061 multiUserChatLightManager = new MultiUserChatLightManager(connection); 062 INSTANCES.put(connection, multiUserChatLightManager); 063 } 064 return multiUserChatLightManager; 065 } 066 067 /** 068 * A Map of MUC Light JIDs to instances. We use weak references for the 069 * values in order to allow those instances to get garbage collected. 070 */ 071 private final Map<EntityBareJid, WeakReference<MultiUserChatLight>> multiUserChatLights = new HashMap<>(); 072 073 private MultiUserChatLightManager(XMPPConnection connection) { 074 super(connection); 075 } 076 077 /** 078 * Obtain the MUC Light. 079 * 080 * @param jid 081 * @return the MUCLight. 082 */ 083 public synchronized MultiUserChatLight getMultiUserChatLight(EntityBareJid jid) { 084 WeakReference<MultiUserChatLight> weakRefMultiUserChat = multiUserChatLights.get(jid); 085 if (weakRefMultiUserChat == null) { 086 return createNewMucLightAndAddToMap(jid); 087 } 088 MultiUserChatLight multiUserChatLight = weakRefMultiUserChat.get(); 089 if (multiUserChatLight == null) { 090 return createNewMucLightAndAddToMap(jid); 091 } 092 return multiUserChatLight; 093 } 094 095 private MultiUserChatLight createNewMucLightAndAddToMap(EntityBareJid jid) { 096 MultiUserChatLight multiUserChatLight = new MultiUserChatLight(connection(), jid); 097 multiUserChatLights.put(jid, new WeakReference<MultiUserChatLight>(multiUserChatLight)); 098 return multiUserChatLight; 099 } 100 101 /** 102 * Returns true if Multi-User Chat Light feature is supported by the server. 103 * 104 * @param mucLightService 105 * @return true if Multi-User Chat Light feature is supported by the server. 106 * @throws NotConnectedException 107 * @throws XMPPErrorException 108 * @throws NoResponseException 109 * @throws InterruptedException 110 */ 111 public boolean isFeatureSupported(DomainBareJid mucLightService) 112 throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException { 113 return ServiceDiscoveryManager.getInstanceFor(connection()).discoverInfo(mucLightService) 114 .containsFeature(MultiUserChatLight.NAMESPACE); 115 } 116 117 /** 118 * Returns a List of the rooms the user occupies. 119 * 120 * @param mucLightService 121 * @return a List of the rooms the user occupies. 122 * @throws XMPPErrorException 123 * @throws NoResponseException 124 * @throws NotConnectedException 125 * @throws InterruptedException 126 */ 127 public List<Jid> getOccupiedRooms(DomainBareJid mucLightService) 128 throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException { 129 DiscoverItems result = ServiceDiscoveryManager.getInstanceFor(connection()).discoverItems(mucLightService); 130 List<DiscoverItems.Item> items = result.getItems(); 131 List<Jid> answer = new ArrayList<>(items.size()); 132 133 for (DiscoverItems.Item item : items) { 134 Jid mucLight = item.getEntityID(); 135 answer.add(mucLight); 136 } 137 138 return answer; 139 } 140 141 /** 142 * Returns a collection with the XMPP addresses of the MUC Light services. 143 * 144 * @return a collection with the XMPP addresses of the MUC Light services. 145 * @throws XMPPErrorException 146 * @throws NoResponseException 147 * @throws NotConnectedException 148 * @throws InterruptedException 149 */ 150 public List<DomainBareJid> getLocalServices() 151 throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException { 152 ServiceDiscoveryManager sdm = ServiceDiscoveryManager.getInstanceFor(connection()); 153 return sdm.findServices(MultiUserChatLight.NAMESPACE, false, false); 154 } 155 156 /** 157 * Get users and rooms blocked. 158 * 159 * @param mucLightService 160 * @return the list of users and rooms blocked 161 * @throws NoResponseException 162 * @throws XMPPErrorException 163 * @throws NotConnectedException 164 * @throws InterruptedException 165 */ 166 public List<Jid> getUsersAndRoomsBlocked(DomainBareJid mucLightService) 167 throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException { 168 MUCLightBlockingIQ muclIghtBlockingIQResult = getBlockingList(mucLightService); 169 170 List<Jid> jids = new ArrayList<>(); 171 if (muclIghtBlockingIQResult.getRooms() != null) { 172 jids.addAll(muclIghtBlockingIQResult.getRooms().keySet()); 173 } 174 175 if (muclIghtBlockingIQResult.getUsers() != null) { 176 jids.addAll(muclIghtBlockingIQResult.getUsers().keySet()); 177 } 178 179 return jids; 180 } 181 182 /** 183 * Get rooms blocked. 184 * 185 * @param mucLightService 186 * @return the list of rooms blocked 187 * @throws NoResponseException 188 * @throws XMPPErrorException 189 * @throws NotConnectedException 190 * @throws InterruptedException 191 */ 192 public List<Jid> getRoomsBlocked(DomainBareJid mucLightService) 193 throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException { 194 MUCLightBlockingIQ muclIghtBlockingIQResult = getBlockingList(mucLightService); 195 196 List<Jid> jids = new ArrayList<>(); 197 if (muclIghtBlockingIQResult.getRooms() != null) { 198 jids.addAll(muclIghtBlockingIQResult.getRooms().keySet()); 199 } 200 201 return jids; 202 } 203 204 /** 205 * Get users blocked. 206 * 207 * @param mucLightService 208 * @return the list of users blocked 209 * @throws NoResponseException 210 * @throws XMPPErrorException 211 * @throws NotConnectedException 212 * @throws InterruptedException 213 */ 214 public List<Jid> getUsersBlocked(DomainBareJid mucLightService) 215 throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException { 216 MUCLightBlockingIQ muclIghtBlockingIQResult = getBlockingList(mucLightService); 217 218 List<Jid> jids = new ArrayList<>(); 219 if (muclIghtBlockingIQResult.getUsers() != null) { 220 jids.addAll(muclIghtBlockingIQResult.getUsers().keySet()); 221 } 222 223 return jids; 224 } 225 226 private MUCLightBlockingIQ getBlockingList(DomainBareJid mucLightService) 227 throws NoResponseException, XMPPErrorException, InterruptedException, NotConnectedException { 228 MUCLightBlockingIQ mucLightBlockingIQ = new MUCLightBlockingIQ(null, null); 229 mucLightBlockingIQ.setType(Type.get); 230 mucLightBlockingIQ.setTo(mucLightService); 231 232 StanzaFilter responseFilter = new IQReplyFilter(mucLightBlockingIQ, connection()); 233 IQ responseIq = connection().createStanzaCollectorAndSend(responseFilter, mucLightBlockingIQ) 234 .nextResultOrThrow(); 235 MUCLightBlockingIQ muclIghtBlockingIQResult = (MUCLightBlockingIQ) responseIq; 236 237 return muclIghtBlockingIQResult; 238 } 239 240 /** 241 * Block a room. 242 * 243 * @param mucLightService 244 * @param roomJid 245 * @throws NoResponseException 246 * @throws XMPPErrorException 247 * @throws NotConnectedException 248 * @throws InterruptedException 249 */ 250 public void blockRoom(DomainBareJid mucLightService, Jid roomJid) 251 throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException { 252 HashMap<Jid, Boolean> rooms = new HashMap<>(); 253 rooms.put(roomJid, false); 254 sendBlockRooms(mucLightService, rooms); 255 } 256 257 /** 258 * Block rooms. 259 * 260 * @param mucLightService 261 * @param roomsJids 262 * @throws NoResponseException 263 * @throws XMPPErrorException 264 * @throws NotConnectedException 265 * @throws InterruptedException 266 */ 267 public void blockRooms(DomainBareJid mucLightService, List<Jid> roomsJids) 268 throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException { 269 HashMap<Jid, Boolean> rooms = new HashMap<>(); 270 for (Jid jid : roomsJids) { 271 rooms.put(jid, false); 272 } 273 sendBlockRooms(mucLightService, rooms); 274 } 275 276 private void sendBlockRooms(DomainBareJid mucLightService, HashMap<Jid, Boolean> rooms) 277 throws NoResponseException, XMPPErrorException, InterruptedException, NotConnectedException { 278 MUCLightBlockingIQ mucLightBlockingIQ = new MUCLightBlockingIQ(rooms, null); 279 mucLightBlockingIQ.setType(Type.set); 280 mucLightBlockingIQ.setTo(mucLightService); 281 connection().createStanzaCollectorAndSend(mucLightBlockingIQ).nextResultOrThrow(); 282 } 283 284 /** 285 * Block a user. 286 * 287 * @param mucLightService 288 * @param userJid 289 * @throws NoResponseException 290 * @throws XMPPErrorException 291 * @throws NotConnectedException 292 * @throws InterruptedException 293 */ 294 public void blockUser(DomainBareJid mucLightService, Jid userJid) 295 throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException { 296 HashMap<Jid, Boolean> users = new HashMap<>(); 297 users.put(userJid, false); 298 sendBlockUsers(mucLightService, users); 299 } 300 301 /** 302 * Block users. 303 * 304 * @param mucLightService 305 * @param usersJids 306 * @throws NoResponseException 307 * @throws XMPPErrorException 308 * @throws NotConnectedException 309 * @throws InterruptedException 310 */ 311 public void blockUsers(DomainBareJid mucLightService, List<Jid> usersJids) 312 throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException { 313 HashMap<Jid, Boolean> users = new HashMap<>(); 314 for (Jid jid : usersJids) { 315 users.put(jid, false); 316 } 317 sendBlockUsers(mucLightService, users); 318 } 319 320 private void sendBlockUsers(DomainBareJid mucLightService, HashMap<Jid, Boolean> users) 321 throws NoResponseException, XMPPErrorException, InterruptedException, NotConnectedException { 322 MUCLightBlockingIQ mucLightBlockingIQ = new MUCLightBlockingIQ(null, users); 323 mucLightBlockingIQ.setType(Type.set); 324 mucLightBlockingIQ.setTo(mucLightService); 325 connection().createStanzaCollectorAndSend(mucLightBlockingIQ).nextResultOrThrow(); 326 } 327 328 /** 329 * Unblock a room. 330 * 331 * @param mucLightService 332 * @param roomJid 333 * @throws NoResponseException 334 * @throws XMPPErrorException 335 * @throws NotConnectedException 336 * @throws InterruptedException 337 */ 338 public void unblockRoom(DomainBareJid mucLightService, Jid roomJid) 339 throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException { 340 HashMap<Jid, Boolean> rooms = new HashMap<>(); 341 rooms.put(roomJid, true); 342 sendUnblockRooms(mucLightService, rooms); 343 } 344 345 /** 346 * Unblock rooms. 347 * 348 * @param mucLightService 349 * @param roomsJids 350 * @throws NoResponseException 351 * @throws XMPPErrorException 352 * @throws NotConnectedException 353 * @throws InterruptedException 354 */ 355 public void unblockRooms(DomainBareJid mucLightService, List<Jid> roomsJids) 356 throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException { 357 HashMap<Jid, Boolean> rooms = new HashMap<>(); 358 for (Jid jid : roomsJids) { 359 rooms.put(jid, true); 360 } 361 sendUnblockRooms(mucLightService, rooms); 362 } 363 364 private void sendUnblockRooms(DomainBareJid mucLightService, HashMap<Jid, Boolean> rooms) 365 throws NoResponseException, XMPPErrorException, InterruptedException, NotConnectedException { 366 MUCLightBlockingIQ mucLightBlockingIQ = new MUCLightBlockingIQ(rooms, null); 367 mucLightBlockingIQ.setType(Type.set); 368 mucLightBlockingIQ.setTo(mucLightService); 369 connection().createStanzaCollectorAndSend(mucLightBlockingIQ).nextResultOrThrow(); 370 } 371 372 /** 373 * Unblock a user. 374 * 375 * @param mucLightService 376 * @param userJid 377 * @throws NoResponseException 378 * @throws XMPPErrorException 379 * @throws NotConnectedException 380 * @throws InterruptedException 381 */ 382 public void unblockUser(DomainBareJid mucLightService, Jid userJid) 383 throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException { 384 HashMap<Jid, Boolean> users = new HashMap<>(); 385 users.put(userJid, true); 386 sendUnblockUsers(mucLightService, users); 387 } 388 389 /** 390 * Unblock users. 391 * 392 * @param mucLightService 393 * @param usersJids 394 * @throws NoResponseException 395 * @throws XMPPErrorException 396 * @throws NotConnectedException 397 * @throws InterruptedException 398 */ 399 public void unblockUsers(DomainBareJid mucLightService, List<Jid> usersJids) 400 throws NoResponseException, XMPPErrorException, NotConnectedException, InterruptedException { 401 HashMap<Jid, Boolean> users = new HashMap<>(); 402 for (Jid jid : usersJids) { 403 users.put(jid, true); 404 } 405 sendUnblockUsers(mucLightService, users); 406 } 407 408 private void sendUnblockUsers(DomainBareJid mucLightService, HashMap<Jid, Boolean> users) 409 throws NoResponseException, XMPPErrorException, InterruptedException, NotConnectedException { 410 MUCLightBlockingIQ mucLightBlockingIQ = new MUCLightBlockingIQ(null, users); 411 mucLightBlockingIQ.setType(Type.set); 412 mucLightBlockingIQ.setTo(mucLightService); 413 connection().createStanzaCollectorAndSend(mucLightBlockingIQ).nextResultOrThrow(); 414 } 415 416}