Added support for PacketInterceptors. SMACK-104

git-svn-id: http://svn.igniterealtime.org/svn/repos/smack/trunk@3020 b35dd754-fafc-0310-a699-88a17e54d16e
This commit is contained in:
Gaston Dombiak 2005-11-01 23:49:07 +00:00 committed by gato
parent dd57b64570
commit d67b49289b
2 changed files with 143 additions and 0 deletions

View File

@ -43,6 +43,16 @@ class PacketWriter {
private boolean listenersDeleted = false;
private Thread listenerThread;
private LinkedList sentPackets = new LinkedList();
/**
* List of PacketInterceptor that will be notified when a new packet is about to be
* sent to the server. These interceptors may modify the packet before it is being
* actually sent to the server.
*/
private List interceptors = new ArrayList();
/**
* Flag that indicates if an interceptor was deleted. This is an optimization flag.
*/
private boolean interceptorDeleted = false;
/**
* Creates a new packet writer with the specified connection.
@ -87,6 +97,10 @@ class PacketWriter {
*/
public void sendPacket(Packet packet) {
if (!done) {
// Invoke interceptors for the new packet that is about to be sent. Interceptors
// may modify the content of the packet.
processInterceptors(packet);
synchronized(queue) {
queue.addFirst(packet);
queue.notifyAll();
@ -144,6 +158,40 @@ class PacketWriter {
}
}
/**
* Registers a packet interceptor with this writer. The interceptor will be
* notified of every packet that this writer is about to send. Interceptors
* may modify the packet to be sent. A packet filter determines which packets
* will be delivered to the interceptor.
*
* @param packetInterceptor the packet interceptor to notify of packets about to be sent.
* @param packetFilter the packet filter to use.
*/
public void addPacketInterceptor(PacketInterceptor packetInterceptor, PacketFilter packetFilter) {
synchronized (interceptors) {
interceptors.add(new InterceptorWrapper(packetInterceptor, packetFilter));
}
}
/**
* Removes a packet interceptor.
*
* @param packetInterceptor the packet interceptor to remove.
*/
public void removePacketInterceptor(PacketInterceptor packetInterceptor) {
synchronized (interceptors) {
for (int i=0; i<interceptors.size(); i++) {
InterceptorWrapper wrapper = (InterceptorWrapper)interceptors.get(i);
if (wrapper != null && wrapper.packetInterceptor.equals(packetInterceptor)) {
interceptors.set(i, null);
// Set the flag to indicate that the interceptor list needs
// to be cleaned up.
interceptorDeleted = true;
}
}
}
}
/**
* Starts the packet writer thread and opens a connection to the server. The
* packet writer will continue writing packets until {@link #shutdown} or an
@ -270,6 +318,40 @@ class PacketWriter {
}
}
/**
* Process interceptors. Interceptors may modify the packet that is about to be sent.
* Since the thread that requested to send the packet will invoke all interceptors, it
* is important that interceptors perform their work as soon as possible so that the
* thread does not remain blocked for a long period.
*
* @param packet the packet that is going to be sent to the server
*/
private void processInterceptors(Packet packet) {
if (packet != null) {
// Clean up null entries in the interceptors list if the flag is set. List
// removes are done seperately so that the main notification process doesn't
// need to synchronize on the list.
synchronized (interceptors) {
if (interceptorDeleted) {
for (int i=interceptors.size()-1; i>=0; i--) {
if (interceptors.get(i) == null) {
interceptors.remove(i);
}
}
interceptorDeleted = false;
}
}
// Notify the interceptors of the new packet to be sent
int size = interceptors.size();
for (int i=0; i<size; i++) {
InterceptorWrapper interceptorWrapper = (InterceptorWrapper)interceptors.get(i);
if (interceptorWrapper != null) {
interceptorWrapper.notifyListener(packet);
}
}
}
}
/**
* Sends to the server a new stream element. This operation may be requested several times
* so we need to encapsulate the logic in one place. This message will be sent while doing
@ -329,6 +411,41 @@ class PacketWriter {
}
}
/**
* A wrapper class to associate a packet filter with an interceptor.
*/
private static class InterceptorWrapper {
private PacketInterceptor packetInterceptor;
private PacketFilter packetFilter;
public InterceptorWrapper(PacketInterceptor packetInterceptor, PacketFilter packetFilter)
{
this.packetInterceptor = packetInterceptor;
this.packetFilter = packetFilter;
}
public boolean equals(Object object) {
if (object == null) {
return false;
}
if (object instanceof InterceptorWrapper) {
return ((InterceptorWrapper) object).packetInterceptor
.equals(this.packetInterceptor);
}
else if (object instanceof PacketInterceptor) {
return object.equals(this.packetInterceptor);
}
return false;
}
public void notifyListener(Packet packet) {
if (packetFilter == null || packetFilter.accept(packet)) {
packetInterceptor.interceptPacket(packet);
}
}
}
/**
* A TimerTask that keeps connections to the server alive by sending a space
* character on an interval.

View File

@ -724,6 +724,32 @@ public class XMPPConnection {
packetWriter.removePacketListener(packetListener);
}
/**
* Registers a packet interceptor with this connection. The interceptor will be
* invoked every time a packet is about to be sent by this connection. Interceptors
* may modify the packet to be sent. A packet filter determines which packets
* will be delivered to the interceptor.
*
* @param packetInterceptor the packet interceptor to notify of packets about to be sent.
* @param packetFilter the packet filter to use.
*/
public void addPacketWriterInterceptor(PacketInterceptor packetInterceptor,
PacketFilter packetFilter) {
if (!isConnected()) {
throw new IllegalStateException("Not connected to server.");
}
packetWriter.addPacketInterceptor(packetInterceptor, packetFilter);
}
/**
* Removes a packet interceptor.
*
* @param packetInterceptor the packet interceptor to remove.
*/
public void removePacketWriterInterceptor(PacketInterceptor packetInterceptor) {
packetWriter.removePacketInterceptor(packetInterceptor);
}
/**
* Creates a new packet collector for this connection. A packet filter determines
* which packets will be accumulated by the collector.