| /** |
| * $RCSfile$ |
| * $Revision$ |
| * $Date$ |
| * |
| * Copyright 2003-2007 Jive Software. |
| * |
| * All rights reserved. Licensed under the Apache License, Version 2.0 (the "License"); |
| * you may not use this file except in compliance with the License. |
| * You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, software |
| * distributed under the License is distributed on an "AS IS" BASIS, |
| * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| * See the License for the specific language governing permissions and |
| * limitations under the License. |
| */ |
| |
| package org.jivesoftware.smack; |
| |
| import java.util.concurrent.ArrayBlockingQueue; |
| import java.util.concurrent.TimeUnit; |
| |
| import org.jivesoftware.smack.filter.PacketFilter; |
| import org.jivesoftware.smack.packet.Packet; |
| |
| /** |
| * Provides a mechanism to collect packets into a result queue that pass a |
| * specified filter. The collector lets you perform blocking and polling |
| * operations on the result queue. So, a PacketCollector is more suitable to |
| * use than a {@link PacketListener} when you need to wait for a specific |
| * result.<p> |
| * |
| * Each packet collector will queue up a configured number of packets for processing before |
| * older packets are automatically dropped. The default number is retrieved by |
| * {@link SmackConfiguration#getPacketCollectorSize()}. |
| * |
| * @see Connection#createPacketCollector(PacketFilter) |
| * @author Matt Tucker |
| */ |
| public class PacketCollector { |
| |
| private PacketFilter packetFilter; |
| private ArrayBlockingQueue<Packet> resultQueue; |
| private Connection connection; |
| private boolean cancelled = false; |
| |
| /** |
| * Creates a new packet collector. If the packet filter is <tt>null</tt>, then |
| * all packets will match this collector. |
| * |
| * @param conection the connection the collector is tied to. |
| * @param packetFilter determines which packets will be returned by this collector. |
| */ |
| protected PacketCollector(Connection conection, PacketFilter packetFilter) { |
| this(conection, packetFilter, SmackConfiguration.getPacketCollectorSize()); |
| } |
| |
| /** |
| * Creates a new packet collector. If the packet filter is <tt>null</tt>, then |
| * all packets will match this collector. |
| * |
| * @param conection the connection the collector is tied to. |
| * @param packetFilter determines which packets will be returned by this collector. |
| * @param maxSize the maximum number of packets that will be stored in the collector. |
| */ |
| protected PacketCollector(Connection conection, PacketFilter packetFilter, int maxSize) { |
| this.connection = conection; |
| this.packetFilter = packetFilter; |
| this.resultQueue = new ArrayBlockingQueue<Packet>(maxSize); |
| } |
| |
| /** |
| * Explicitly cancels the packet collector so that no more results are |
| * queued up. Once a packet collector has been cancelled, it cannot be |
| * re-enabled. Instead, a new packet collector must be created. |
| */ |
| public void cancel() { |
| // If the packet collector has already been cancelled, do nothing. |
| if (!cancelled) { |
| cancelled = true; |
| connection.removePacketCollector(this); |
| } |
| } |
| |
| /** |
| * Returns the packet filter associated with this packet collector. The packet |
| * filter is used to determine what packets are queued as results. |
| * |
| * @return the packet filter. |
| */ |
| public PacketFilter getPacketFilter() { |
| return packetFilter; |
| } |
| |
| /** |
| * Polls to see if a packet is currently available and returns it, or |
| * immediately returns <tt>null</tt> if no packets are currently in the |
| * result queue. |
| * |
| * @return the next packet result, or <tt>null</tt> if there are no more |
| * results. |
| */ |
| public Packet pollResult() { |
| return resultQueue.poll(); |
| } |
| |
| /** |
| * Returns the next available packet. The method call will block (not return) |
| * until a packet is available. |
| * |
| * @return the next available packet. |
| */ |
| public Packet nextResult() { |
| try { |
| return resultQueue.take(); |
| } |
| catch (InterruptedException e) { |
| throw new RuntimeException(e); |
| } |
| } |
| |
| /** |
| * Returns the next available packet. The method call will block (not return) |
| * until a packet is available or the <tt>timeout</tt> has elapased. If the |
| * timeout elapses without a result, <tt>null</tt> will be returned. |
| * |
| * @param timeout the amount of time to wait for the next packet (in milleseconds). |
| * @return the next available packet. |
| */ |
| public Packet nextResult(long timeout) { |
| try { |
| return resultQueue.poll(timeout, TimeUnit.MILLISECONDS); |
| } |
| catch (InterruptedException e) { |
| throw new RuntimeException(e); |
| } |
| } |
| |
| /** |
| * Processes a packet to see if it meets the criteria for this packet collector. |
| * If so, the packet is added to the result queue. |
| * |
| * @param packet the packet to process. |
| */ |
| protected void processPacket(Packet packet) { |
| if (packet == null) { |
| return; |
| } |
| |
| if (packetFilter == null || packetFilter.accept(packet)) { |
| while (!resultQueue.offer(packet)) { |
| // Since we know the queue is full, this poll should never actually block. |
| resultQueue.poll(); |
| } |
| } |
| } |
| } |