Home | History | Annotate | Download | only in filetransfer
      1 /**
      2  * $RCSfile$
      3  * $Revision$
      4  * $Date$
      5  *
      6  * Copyright 2003-2006 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 package org.jivesoftware.smackx.filetransfer;
     21 
     22 import org.jivesoftware.smack.PacketCollector;
     23 import org.jivesoftware.smack.SmackConfiguration;
     24 import org.jivesoftware.smack.Connection;
     25 import org.jivesoftware.smack.XMPPException;
     26 import org.jivesoftware.smack.filter.PacketFilter;
     27 import org.jivesoftware.smack.packet.IQ;
     28 import org.jivesoftware.smack.packet.Packet;
     29 import org.jivesoftware.smack.packet.XMPPError;
     30 import org.jivesoftware.smackx.Form;
     31 import org.jivesoftware.smackx.FormField;
     32 import org.jivesoftware.smackx.packet.DataForm;
     33 import org.jivesoftware.smackx.packet.StreamInitiation;
     34 
     35 import java.io.InputStream;
     36 import java.io.OutputStream;
     37 
     38 /**
     39  * After the file transfer negotiation process is completed according to
     40  * JEP-0096, the negotiation process is passed off to a particular stream
     41  * negotiator. The stream negotiator will then negotiate the chosen stream and
     42  * return the stream to transfer the file.
     43  *
     44  * @author Alexander Wenckus
     45  */
     46 public abstract class StreamNegotiator {
     47 
     48     /**
     49      * Creates the initiation acceptance packet to forward to the stream
     50      * initiator.
     51      *
     52      * @param streamInitiationOffer The offer from the stream initiator to connect for a stream.
     53      * @param namespaces            The namespace that relates to the accepted means of transfer.
     54      * @return The response to be forwarded to the initiator.
     55      */
     56     public StreamInitiation createInitiationAccept(
     57             StreamInitiation streamInitiationOffer, String[] namespaces)
     58     {
     59         StreamInitiation response = new StreamInitiation();
     60         response.setTo(streamInitiationOffer.getFrom());
     61         response.setFrom(streamInitiationOffer.getTo());
     62         response.setType(IQ.Type.RESULT);
     63         response.setPacketID(streamInitiationOffer.getPacketID());
     64 
     65         DataForm form = new DataForm(Form.TYPE_SUBMIT);
     66         FormField field = new FormField(
     67                 FileTransferNegotiator.STREAM_DATA_FIELD_NAME);
     68         for (String namespace : namespaces) {
     69             field.addValue(namespace);
     70         }
     71         form.addField(field);
     72 
     73         response.setFeatureNegotiationForm(form);
     74         return response;
     75     }
     76 
     77 
     78     public IQ createError(String from, String to, String packetID, XMPPError xmppError) {
     79         IQ iq = FileTransferNegotiator.createIQ(packetID, to, from, IQ.Type.ERROR);
     80         iq.setError(xmppError);
     81         return iq;
     82     }
     83 
     84     Packet initiateIncomingStream(Connection connection, StreamInitiation initiation) throws XMPPException {
     85         StreamInitiation response = createInitiationAccept(initiation,
     86                 getNamespaces());
     87 
     88         // establish collector to await response
     89         PacketCollector collector = connection
     90                 .createPacketCollector(getInitiationPacketFilter(initiation.getFrom(), initiation.getSessionID()));
     91         connection.sendPacket(response);
     92 
     93         Packet streamMethodInitiation = collector
     94                 .nextResult(SmackConfiguration.getPacketReplyTimeout());
     95         collector.cancel();
     96         if (streamMethodInitiation == null) {
     97             throw new XMPPException("No response from file transfer initiator");
     98         }
     99 
    100         return streamMethodInitiation;
    101     }
    102 
    103     /**
    104      * Returns the packet filter that will return the initiation packet for the appropriate stream
    105      * initiation.
    106      *
    107      * @param from     The initiator of the file transfer.
    108      * @param streamID The stream ID related to the transfer.
    109      * @return The <b><i>PacketFilter</b></i> that will return the packet relatable to the stream
    110      *         initiation.
    111      */
    112     public abstract PacketFilter getInitiationPacketFilter(String from, String streamID);
    113 
    114 
    115     abstract InputStream negotiateIncomingStream(Packet streamInitiation) throws XMPPException,
    116             InterruptedException;
    117 
    118     /**
    119      * This method handles the file stream download negotiation process. The
    120      * appropriate stream negotiator's initiate incoming stream is called after
    121      * an appropriate file transfer method is selected. The manager will respond
    122      * to the initiator with the selected means of transfer, then it will handle
    123      * any negotiation specific to the particular transfer method. This method
    124      * returns the InputStream, ready to transfer the file.
    125      *
    126      * @param initiation The initiation that triggered this download.
    127      * @return After the negotiation process is complete, the InputStream to
    128      *         write a file to is returned.
    129      * @throws XMPPException If an error occurs during this process an XMPPException is
    130      *                       thrown.
    131      * @throws InterruptedException If thread is interrupted.
    132      */
    133     public abstract InputStream createIncomingStream(StreamInitiation initiation)
    134             throws XMPPException, InterruptedException;
    135 
    136     /**
    137      * This method handles the file upload stream negotiation process. The
    138      * particular stream negotiator is determined during the file transfer
    139      * negotiation process. This method returns the OutputStream to transmit the
    140      * file to the remote user.
    141      *
    142      * @param streamID  The streamID that uniquely identifies the file transfer.
    143      * @param initiator The fully-qualified JID of the initiator of the file transfer.
    144      * @param target    The fully-qualified JID of the target or receiver of the file
    145      *                  transfer.
    146      * @return The negotiated stream ready for data.
    147      * @throws XMPPException If an error occurs during the negotiation process an
    148      *                       exception will be thrown.
    149      */
    150     public abstract OutputStream createOutgoingStream(String streamID,
    151             String initiator, String target) throws XMPPException;
    152 
    153     /**
    154      * Returns the XMPP namespace reserved for this particular type of file
    155      * transfer.
    156      *
    157      * @return Returns the XMPP namespace reserved for this particular type of
    158      *         file transfer.
    159      */
    160     public abstract String[] getNamespaces();
    161 
    162     /**
    163      * Cleanup any and all resources associated with this negotiator.
    164      */
    165     public abstract void cleanup();
    166 
    167 }
    168