mirror of
https://codeberg.org/Mercury-IM/Smack
synced 2024-11-30 02:02:06 +01:00
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:
parent
dd57b64570
commit
d67b49289b
2 changed files with 143 additions and 0 deletions
|
@ -43,6 +43,16 @@ class PacketWriter {
|
||||||
private boolean listenersDeleted = false;
|
private boolean listenersDeleted = false;
|
||||||
private Thread listenerThread;
|
private Thread listenerThread;
|
||||||
private LinkedList sentPackets = new LinkedList();
|
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.
|
* Creates a new packet writer with the specified connection.
|
||||||
|
@ -87,6 +97,10 @@ class PacketWriter {
|
||||||
*/
|
*/
|
||||||
public void sendPacket(Packet packet) {
|
public void sendPacket(Packet packet) {
|
||||||
if (!done) {
|
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) {
|
synchronized(queue) {
|
||||||
queue.addFirst(packet);
|
queue.addFirst(packet);
|
||||||
queue.notifyAll();
|
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
|
* Starts the packet writer thread and opens a connection to the server. The
|
||||||
* packet writer will continue writing packets until {@link #shutdown} or an
|
* 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
|
* 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
|
* 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
|
* A TimerTask that keeps connections to the server alive by sending a space
|
||||||
* character on an interval.
|
* character on an interval.
|
||||||
|
|
|
@ -724,6 +724,32 @@ public class XMPPConnection {
|
||||||
packetWriter.removePacketListener(packetListener);
|
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
|
* Creates a new packet collector for this connection. A packet filter determines
|
||||||
* which packets will be accumulated by the collector.
|
* which packets will be accumulated by the collector.
|
||||||
|
|
Loading…
Reference in a new issue