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