1d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen/**
2d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * $RCSfile$
3d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * $Revision$
4d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * $Date$
5d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen *
6d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Copyright 2003-2007 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.smack;
22d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
23d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.util.concurrent.ArrayBlockingQueue;
24d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport java.util.concurrent.TimeUnit;
25d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
26d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.jivesoftware.smack.filter.PacketFilter;
27d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenimport org.jivesoftware.smack.packet.Packet;
28d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
29d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen/**
30d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Provides a mechanism to collect packets into a result queue that pass a
31d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * specified filter. The collector lets you perform blocking and polling
32d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * operations on the result queue. So, a PacketCollector is more suitable to
33d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * use than a {@link PacketListener} when you need to wait for a specific
34d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * result.<p>
35d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen *
36d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * Each packet collector will queue up a configured number of packets for processing before
37d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * older packets are automatically dropped.  The default number is retrieved by
38d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * {@link SmackConfiguration#getPacketCollectorSize()}.
39d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen *
40d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @see Connection#createPacketCollector(PacketFilter)
41d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen * @author Matt Tucker
42d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen */
43d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chenpublic class PacketCollector {
44d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
45d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    private PacketFilter packetFilter;
46d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    private ArrayBlockingQueue<Packet> resultQueue;
47d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    private Connection connection;
48d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    private boolean cancelled = false;
49d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
50d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
51d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Creates a new packet collector. If the packet filter is <tt>null</tt>, then
52d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * all packets will match this collector.
53d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
54d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @param conection the connection the collector is tied to.
55d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @param packetFilter determines which packets will be returned by this collector.
56d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
57d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    protected PacketCollector(Connection conection, PacketFilter packetFilter) {
58d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    	this(conection, packetFilter, SmackConfiguration.getPacketCollectorSize());
59d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
60d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
61d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
62d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Creates a new packet collector. If the packet filter is <tt>null</tt>, then
63d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * all packets will match this collector.
64d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
65d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @param conection the connection the collector is tied to.
66d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @param packetFilter determines which packets will be returned by this collector.
67d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @param maxSize the maximum number of packets that will be stored in the collector.
68d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
69d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    protected PacketCollector(Connection conection, PacketFilter packetFilter, int maxSize) {
70d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        this.connection = conection;
71d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        this.packetFilter = packetFilter;
72d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        this.resultQueue = new ArrayBlockingQueue<Packet>(maxSize);
73d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
74d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
75d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
76d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Explicitly cancels the packet collector so that no more results are
77d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * queued up. Once a packet collector has been cancelled, it cannot be
78d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * re-enabled. Instead, a new packet collector must be created.
79d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
80d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public void cancel() {
81d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        // If the packet collector has already been cancelled, do nothing.
82d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (!cancelled) {
83d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            cancelled = true;
84d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            connection.removePacketCollector(this);
85d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
86d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
87d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
88d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
89d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Returns the packet filter associated with this packet collector. The packet
90d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * filter is used to determine what packets are queued as results.
91d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
92d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @return the packet filter.
93d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
94d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public PacketFilter getPacketFilter() {
95d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        return packetFilter;
96d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
97d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
98d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
99d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Polls to see if a packet is currently available and returns it, or
100d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * immediately returns <tt>null</tt> if no packets are currently in the
101d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * result queue.
102d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
103d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @return the next packet result, or <tt>null</tt> if there are no more
104d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *      results.
105d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
106d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public Packet pollResult() {
107d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    	return resultQueue.poll();
108d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
109d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
110d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
111d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Returns the next available packet. The method call will block (not return)
112d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * until a packet is available.
113d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
114d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @return the next available packet.
115d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
116d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public Packet nextResult() {
117d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        try {
118d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			return resultQueue.take();
119d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		}
120d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		catch (InterruptedException e) {
121d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			throw new RuntimeException(e);
122d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		}
123d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
124d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
125d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
126d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Returns the next available packet. The method call will block (not return)
127d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * until a packet is available or the <tt>timeout</tt> has elapased. If the
128d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * timeout elapses without a result, <tt>null</tt> will be returned.
129d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
130d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @param timeout the amount of time to wait for the next packet (in milleseconds).
131d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @return the next available packet.
132d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
133d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    public Packet nextResult(long timeout) {
134d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    	try {
135d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			return resultQueue.poll(timeout, TimeUnit.MILLISECONDS);
136d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		}
137d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		catch (InterruptedException e) {
138d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen			throw new RuntimeException(e);
139d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen		}
140d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
141d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
142d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    /**
143d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * Processes a packet to see if it meets the criteria for this packet collector.
144d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * If so, the packet is added to the result queue.
145d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     *
146d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     * @param packet the packet to process.
147d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen     */
148d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    protected void processPacket(Packet packet) {
149d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (packet == null) {
150d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen            return;
151d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
152d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen
153d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        if (packetFilter == null || packetFilter.accept(packet)) {
154d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        	while (!resultQueue.offer(packet)) {
155d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        		// Since we know the queue is full, this poll should never actually block.
156d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        		resultQueue.poll();
157d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        	}
158d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen        }
159d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen    }
160d7955ce24d294fb2014c59d11fca184471056f44Shuyi Chen}
161