Commit 38e760b4 authored by Gaston Dombiak's avatar Gaston Dombiak Committed by gaston

Initial version. JM-218


git-svn-id: http://svn.igniterealtime.org/svn/repos/messenger/trunk@1151 b35dd754-fafc-0310-a699-88a17e54d16e
parent 8df84b7f
/**
* $RCSfile$
* $Revision$
* $Date$
*
* Copyright (C) 2004 Jive Software. All rights reserved.
*
* This software is published under the terms of the GNU Public License (GPL),
* a copy of which is included in this distribution.
*/
package org.jivesoftware.messenger.interceptor;
import org.jivesoftware.messenger.Session;
import org.xmpp.packet.Packet;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;
/**
* An InterceptorManager holds the list of global interceptors and interceptors per-user that will
* be invoked before and after a packet was read in SocketReadThead and also when the packet is
* about to be sent in SocketConnection. If the interceptor is related to a user then it will
* get all the packets sent or received for <b>any</b> connection of the user.<p>
*
* PacketInterceptors that are invoked before the packet is sent or processed (when read) may
* change the original packet or may even reject the packet by throwing an exception. If the
* interceptor rejects a received packet then the sender of the packet will get a not_allowed
* answer.<p>
*
* @see PacketInterceptor
* @author Gaston Dombiak
*/
public class InterceptorManager {
private static InterceptorManager instance = new InterceptorManager();
private List<PacketInterceptor> globalInterceptors = new CopyOnWriteArrayList<PacketInterceptor>();
private Map<String, List<PacketInterceptor>> usersInterceptors = new ConcurrentHashMap<String, List<PacketInterceptor>>();
public static InterceptorManager getInstance() {
return instance;
}
/**
* Returns the list of global packet interceptors. These are the interceptors that will be
* used for all the read and sent packets.
*
* @return the list of global packet interceptors.
*/
public Collection<PacketInterceptor> getInterceptors() {
return Collections.unmodifiableCollection(globalInterceptors);
}
/**
* Inserts a new interceptor at the end of the list of currently configured
* interceptors. This interceptor will be used for all the sent and received packets.
*
* @param interceptor the interceptor to add.
*/
public void addInterceptor(PacketInterceptor interceptor) {
addInterceptor(globalInterceptors.size(), interceptor);
}
/**
* Inserts a new interceptor at specified index in the list of currently configured
* interceptors. This interceptor will be used for all the sent and received packets.
*
* @param index the index in the list to insert the new interceptor at.
* @param interceptor the interceptor to add.
*/
public void addInterceptor(int index, PacketInterceptor interceptor) {
// Remove the interceptor from the list since the position might have changed
if (globalInterceptors.contains(interceptor)) {
globalInterceptors.remove(interceptor);
}
globalInterceptors.add(index, interceptor);
}
/**
* Removes the global interceptor from the list.
*
* @param interceptor the interceptor to remove.
* @return true if the item was present in the list
*/
public boolean removeInterceptor(PacketInterceptor interceptor) {
return globalInterceptors.remove(interceptor);
}
/**
* Returns the list of packet interceptors that are related to the specified username. These
* are the interceptors that will be used only when a packet was sent or received by the
* specified username.
*
* @param username the name of the user.
* @return the list of packet interceptors that are related to the specified username.
*/
public Collection<PacketInterceptor> getUserInterceptors(String username) {
List<PacketInterceptor> userInterceptors = usersInterceptors.get(username);
if (userInterceptors == null) {
return new ArrayList<PacketInterceptor>();
}
else {
return Collections.unmodifiableCollection(userInterceptors);
}
}
/**
* Inserts a new interceptor at specified index in the list of currently configured
* interceptors for a specific username. This interceptor will be used only when a packet
* was sent or received by the specified username.
*
* @param username the name of the user.
* @param index the index in the list to insert the new interceptor at.
* @param interceptor the interceptor to add.
*/
public void addUserInterceptor(String username, int index, PacketInterceptor interceptor) {
List<PacketInterceptor> userInterceptors = usersInterceptors.get(username);
if (userInterceptors == null) {
userInterceptors = new CopyOnWriteArrayList<PacketInterceptor>();
usersInterceptors.put(username, userInterceptors);
}
else {
// Remove the interceptor from the list since the position might have changed
if (userInterceptors.contains(interceptor)) {
userInterceptors.remove(interceptor);
}
}
userInterceptors.add(index, interceptor);
}
/**
* Removes the interceptor from the list of interceptors that are related to a specific
* username.
*
* @param username the name of the user.
* @param interceptor the interceptor to remove.
* @return true if the item was present in the list
*/
public boolean removeUserInterceptor(String username, PacketInterceptor interceptor) {
boolean answer = false;
List<PacketInterceptor> userInterceptors = usersInterceptors.get(username);
if (userInterceptors != null) {
answer = userInterceptors.remove(interceptor);
// Remove the entry for this username if the list is now empty
if (userInterceptors.isEmpty()) {
usersInterceptors.remove(username);
}
}
return answer;
}
/**
* Invokes all currently-installed interceptors on the specified packet. All global
* interceptors will be invoked as well as interceptors that are related to the address of the
* session that received or is sending the packet.<p>
*
* Interceptors may be executed before processing a read packet or sending a packet to a user.
* This means that interceptors are able to alter the read or packet to send. If possible
* interceptors should perform their work in a short time so the overall performance is not
* compromised.
*
* @param packet the packet that has been read or sent.
* @param session the session that received the packet or the packet was sent to.
* @param read flag that indicates if the packet was read or sent.
* @param processed flag that indicates if the action (read/send) was performed. (PRE vs. POST).
* @throws PacketRejectedException if the packet should be prevented from being processed.
*/
public void invokeInterceptors(Packet packet, Session session, boolean read, boolean processed)
throws PacketRejectedException {
// Invoke the global interceptors for this packet
for (PacketInterceptor interceptor : globalInterceptors) {
interceptor.interceptPacket(packet, session, read, processed);
}
// Invoke the interceptors that are related to the address of the session
String username = session.getAddress().getNode();
if (username != null) {
Collection<PacketInterceptor> userInterceptors = usersInterceptors.get(username);
if (userInterceptors != null && !userInterceptors.isEmpty()) {
for (PacketInterceptor interceptor : userInterceptors) {
interceptor.interceptPacket(packet, session, read, processed);
}
}
}
}
}
/**
* $RCSfile$
* $Revision$
* $Date$
*
* Copyright (C) 2004 Jive Software. All rights reserved.
*
* This software is published under the terms of the GNU Public License (GPL),
* a copy of which is included in this distribution.
*/
package org.jivesoftware.messenger.interceptor;
import org.jivesoftware.messenger.Session;
import org.xmpp.packet.Packet;
/**
* A packet interceptor encapsulates an action that is invoked on a packet immediately
* before or after it was received by a SocketReadThread and also when the packet is about to
* be sent in SocketConnection. These types of actions fall into two broad categories:<ul>
* <li> Interceptors that reject the packet by throwing an exception (only when the packet
* has not been processed yet).
* <li> Interceptors that dynamically transform the packet content.
* </ul>
*
* Any number of interceptors can be installed and removed at run-time. They can be installed
* globally or per-user. Global interceptors are run first, followed by any that are installed
* for the username.<p>
*
* @see InterceptorManager
* @author Gaston Dombiak
*/
public interface PacketInterceptor {
/**
* Invokes the interceptor on the specified packet. The interceptor can either modify
* the packet, or throw a PacketRejectedException to block it from being sent or processed
* (when read).<p>
*
* The exception can only be thrown when <tt>processed</tt> is false which means that the read
* packet has not been processed yet or the packet was not sent yet. If the exception is thrown
* with a "read" packet then the sender of the packet will receive an answer with an error. But
* if the exception is thrown with a "sent" packet then nothing will happen.
*
* @param packet the packet to take action on.
* @param session the session that received or is sending the packet.
* @param read flag that indicates if the packet was read or sent.
* @param processed flag that indicates if the action (read/send) was performed. (PRE vs. POST).
* @throws PacketRejectedException if the packet should be prevented from being processed.
*/
void interceptPacket(Packet packet, Session session, boolean read, boolean processed)
throws PacketRejectedException;
}
/**
* $RCSfile$
* $Revision$
* $Date$
*
* Copyright (C) 2004 Jive Software. All rights reserved.
*
* This software is published under the terms of the GNU Public License (GPL),
* a copy of which is included in this distribution.
*/
package org.jivesoftware.messenger.interceptor;
import java.io.PrintStream;
import java.io.PrintWriter;
/**
* Thrown by a PacketInterceptor when a packet is prevented from being processed. If the packet was
* received then it will not be processed and a not_allowed error will be sent back to the sender
* of the packet. If the packet was going to be sent then the sending will be aborted.
*
* @see PacketInterceptor
* @author Gaston Dombiak
*/
public class PacketRejectedException extends Exception {
private static final long serialVersionUID = 1L;
private Throwable nestedThrowable = null;
public PacketRejectedException() {
super();
}
public PacketRejectedException(String msg) {
super(msg);
}
public PacketRejectedException(Throwable nestedThrowable) {
this.nestedThrowable = nestedThrowable;
}
public PacketRejectedException(String msg, Throwable nestedThrowable) {
super(msg);
this.nestedThrowable = nestedThrowable;
}
public void printStackTrace() {
super.printStackTrace();
if (nestedThrowable != null) {
nestedThrowable.printStackTrace();
}
}
public void printStackTrace(PrintStream ps) {
super.printStackTrace(ps);
if (nestedThrowable != null) {
nestedThrowable.printStackTrace(ps);
}
}
public void printStackTrace(PrintWriter pw) {
super.printStackTrace(pw);
if (nestedThrowable != null) {
nestedThrowable.printStackTrace(pw);
}
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment