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