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