1d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen/** 2d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * $RCSfile$ 3d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * $Revision: 2779 $ 4d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * $Date: 2005-09-05 17:00:45 -0300 (Mon, 05 Sep 2005) $ 5d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * 6d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Copyright 2003-2006 Jive Software. 7d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * 8d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); 9d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * you may not use this file except in compliance with the License. 10d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * You may obtain a copy of the License at 11d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * 12d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * http://www.apache.org/licenses/LICENSE-2.0 13d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * 14d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Unless required by applicable law or agreed to in writing, software 15d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * distributed under the License is distributed on an "AS IS" BASIS, 16d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * See the License for the specific language governing permissions and 18d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * limitations under the License. 19d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */ 20d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 21d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpackage org.jivesoftware.smackx.muc; 22d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 23d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.jivesoftware.smack.ConnectionListener; 24d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.jivesoftware.smack.PacketListener; 25d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.jivesoftware.smack.Connection; 26d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.jivesoftware.smack.filter.PacketFilter; 27d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.jivesoftware.smack.packet.Packet; 28d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.jivesoftware.smack.util.StringUtils; 29d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 30d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.lang.ref.WeakReference; 31d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.util.Map; 32d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.util.WeakHashMap; 33d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.util.concurrent.ConcurrentHashMap; 34d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 35d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen/** 36d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * A <code>RoomListenerMultiplexor</code> multiplexes incoming packets on 37d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * a <code>Connection</code> using a single listener/filter pair. 38d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * A single <code>RoomListenerMultiplexor</code> is created for each 39d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * {@link org.jivesoftware.smack.Connection} that has joined MUC rooms 40d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * within its session. 41d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * 42d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @author Larry Kirschner 43d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */ 44d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenclass RoomListenerMultiplexor implements ConnectionListener { 45d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 46d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen // We use a WeakHashMap so that the GC can collect the monitor when the 47d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen // connection is no longer referenced by any object. 48d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen private static final Map<Connection, WeakReference<RoomListenerMultiplexor>> monitors = 49d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen new WeakHashMap<Connection, WeakReference<RoomListenerMultiplexor>>(); 50d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 51d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen private Connection connection; 52d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen private RoomMultiplexFilter filter; 53d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen private RoomMultiplexListener listener; 54d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 55d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen /** 56d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Returns a new or existing RoomListenerMultiplexor for a given connection. 57d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * 58d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @param conn the connection to monitor for room invitations. 59d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @return a new or existing RoomListenerMultiplexor for a given connection. 60d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */ 61d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen public static RoomListenerMultiplexor getRoomMultiplexor(Connection conn) { 62d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen synchronized (monitors) { 63d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen if (!monitors.containsKey(conn) || monitors.get(conn).get() == null) { 64d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen RoomListenerMultiplexor rm = new RoomListenerMultiplexor(conn, new RoomMultiplexFilter(), 65d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen new RoomMultiplexListener()); 66d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 67d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen rm.init(); 68d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 69d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen // We need to use a WeakReference because the monitor references the 70d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen // connection and this could prevent the GC from collecting the monitor 71d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen // when no other object references the monitor 72d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen monitors.put(conn, new WeakReference<RoomListenerMultiplexor>(rm)); 73d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 74d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen // Return the InvitationsMonitor that monitors the connection 75d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen return monitors.get(conn).get(); 76d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 77d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 78d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 79d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen /** 80d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * All access should be through 81d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * the static method {@link #getRoomMultiplexor(Connection)}. 82d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */ 83d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen private RoomListenerMultiplexor(Connection connection, RoomMultiplexFilter filter, 84d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen RoomMultiplexListener listener) { 85d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen if (connection == null) { 86d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen throw new IllegalArgumentException("Connection is null"); 87d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 88d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen if (filter == null) { 89d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen throw new IllegalArgumentException("Filter is null"); 90d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 91d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen if (listener == null) { 92d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen throw new IllegalArgumentException("Listener is null"); 93d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 94d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen this.connection = connection; 95d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen this.filter = filter; 96d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen this.listener = listener; 97d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 98d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 99d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen public void addRoom(String address, PacketMultiplexListener roomListener) { 100d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen filter.addRoom(address); 101d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen listener.addRoom(address, roomListener); 102d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 103d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 104d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen public void connectionClosed() { 105d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen cancel(); 106d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 107d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 108d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen public void connectionClosedOnError(Exception e) { 109d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen cancel(); 110d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 111d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 112d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen public void reconnectingIn(int seconds) { 113d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen // ignore 114d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 115d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 116d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen public void reconnectionSuccessful() { 117d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen // ignore 118d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 119d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 120d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen public void reconnectionFailed(Exception e) { 121d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen // ignore 122d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 123d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 124d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen /** 125d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Initializes the listeners to detect received room invitations and to detect when the 126d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * connection gets closed. As soon as a room invitation is received the invitations 127d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * listeners will be fired. When the connection gets closed the monitor will remove 128d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * his listeners on the connection. 129d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */ 130d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen public void init() { 131d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen connection.addConnectionListener(this); 132d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen connection.addPacketListener(listener, filter); 133d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 134d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 135d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen public void removeRoom(String address) { 136d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen filter.removeRoom(address); 137d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen listener.removeRoom(address); 138d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 139d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 140d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen /** 141d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Cancels all the listeners that this InvitationsMonitor has added to the connection. 142d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */ 143d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen private void cancel() { 144d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen connection.removeConnectionListener(this); 145d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen connection.removePacketListener(listener); 146d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 147d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 148d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen /** 149d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * The single <code>Connection</code>-level <code>PacketFilter</code> used by a {@link RoomListenerMultiplexor} 150d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * for all muc chat rooms on an <code>Connection</code>. 151d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Each time a muc chat room is added to/removed from an 152d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * <code>Connection</code> the address for that chat room 153d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * is added to/removed from that <code>Connection</code>'s 154d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * <code>RoomMultiplexFilter</code>. 155d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */ 156d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen private static class RoomMultiplexFilter implements PacketFilter { 157d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 158d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen private Map<String, String> roomAddressTable = new ConcurrentHashMap<String, String>(); 159d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 160d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen public boolean accept(Packet p) { 161d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen String from = p.getFrom(); 162d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen if (from == null) { 163d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen return false; 164d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 165d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen return roomAddressTable.containsKey(StringUtils.parseBareAddress(from).toLowerCase()); 166d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 167d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 168d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen public void addRoom(String address) { 169d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen if (address == null) { 170d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen return; 171d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 172d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen roomAddressTable.put(address.toLowerCase(), address); 173d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 174d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 175d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen public void removeRoom(String address) { 176d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen if (address == null) { 177d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen return; 178d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 179d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen roomAddressTable.remove(address.toLowerCase()); 180d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 181d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 182d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 183d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen /** 184d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * The single <code>Connection</code>-level <code>PacketListener</code> 185d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * used by a {@link RoomListenerMultiplexor} 186d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * for all muc chat rooms on an <code>Connection</code>. 187d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Each time a muc chat room is added to/removed from an 188d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * <code>Connection</code> the address and listener for that chat room 189d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * are added to/removed from that <code>Connection</code>'s 190d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * <code>RoomMultiplexListener</code>. 191d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * 192d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @author Larry Kirschner 193d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */ 194d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen private static class RoomMultiplexListener implements PacketListener { 195d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 196d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen private Map<String, PacketMultiplexListener> roomListenersByAddress = 197d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen new ConcurrentHashMap<String, PacketMultiplexListener>(); 198d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 199d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen public void processPacket(Packet p) { 200d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen String from = p.getFrom(); 201d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen if (from == null) { 202d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen return; 203d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 204d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 205d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen PacketMultiplexListener listener = 206d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen roomListenersByAddress.get(StringUtils.parseBareAddress(from).toLowerCase()); 207d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 208d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen if (listener != null) { 209d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen listener.processPacket(p); 210d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 211d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 212d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 213d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen public void addRoom(String address, PacketMultiplexListener listener) { 214d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen if (address == null) { 215d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen return; 216d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 217d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen roomListenersByAddress.put(address.toLowerCase(), listener); 218d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 219d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen 220d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen public void removeRoom(String address) { 221d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen if (address == null) { 222d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen return; 223d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 224d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen roomListenersByAddress.remove(address.toLowerCase()); 225d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 226d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen } 227d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen} 228