Home | History | Annotate | Download | only in smack
      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