| /** |
| * $RCSfile$ |
| * $Revision$ |
| * $Date$ |
| * |
| * Copyright 2003-2006 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.smackx.filetransfer; |
| |
| import org.jivesoftware.smack.PacketCollector; |
| import org.jivesoftware.smack.SmackConfiguration; |
| import org.jivesoftware.smack.Connection; |
| import org.jivesoftware.smack.XMPPException; |
| import org.jivesoftware.smack.filter.PacketFilter; |
| import org.jivesoftware.smack.packet.IQ; |
| import org.jivesoftware.smack.packet.Packet; |
| import org.jivesoftware.smack.packet.XMPPError; |
| import org.jivesoftware.smackx.Form; |
| import org.jivesoftware.smackx.FormField; |
| import org.jivesoftware.smackx.packet.DataForm; |
| import org.jivesoftware.smackx.packet.StreamInitiation; |
| |
| import java.io.InputStream; |
| import java.io.OutputStream; |
| |
| /** |
| * After the file transfer negotiation process is completed according to |
| * JEP-0096, the negotiation process is passed off to a particular stream |
| * negotiator. The stream negotiator will then negotiate the chosen stream and |
| * return the stream to transfer the file. |
| * |
| * @author Alexander Wenckus |
| */ |
| public abstract class StreamNegotiator { |
| |
| /** |
| * Creates the initiation acceptance packet to forward to the stream |
| * initiator. |
| * |
| * @param streamInitiationOffer The offer from the stream initiator to connect for a stream. |
| * @param namespaces The namespace that relates to the accepted means of transfer. |
| * @return The response to be forwarded to the initiator. |
| */ |
| public StreamInitiation createInitiationAccept( |
| StreamInitiation streamInitiationOffer, String[] namespaces) |
| { |
| StreamInitiation response = new StreamInitiation(); |
| response.setTo(streamInitiationOffer.getFrom()); |
| response.setFrom(streamInitiationOffer.getTo()); |
| response.setType(IQ.Type.RESULT); |
| response.setPacketID(streamInitiationOffer.getPacketID()); |
| |
| DataForm form = new DataForm(Form.TYPE_SUBMIT); |
| FormField field = new FormField( |
| FileTransferNegotiator.STREAM_DATA_FIELD_NAME); |
| for (String namespace : namespaces) { |
| field.addValue(namespace); |
| } |
| form.addField(field); |
| |
| response.setFeatureNegotiationForm(form); |
| return response; |
| } |
| |
| |
| public IQ createError(String from, String to, String packetID, XMPPError xmppError) { |
| IQ iq = FileTransferNegotiator.createIQ(packetID, to, from, IQ.Type.ERROR); |
| iq.setError(xmppError); |
| return iq; |
| } |
| |
| Packet initiateIncomingStream(Connection connection, StreamInitiation initiation) throws XMPPException { |
| StreamInitiation response = createInitiationAccept(initiation, |
| getNamespaces()); |
| |
| // establish collector to await response |
| PacketCollector collector = connection |
| .createPacketCollector(getInitiationPacketFilter(initiation.getFrom(), initiation.getSessionID())); |
| connection.sendPacket(response); |
| |
| Packet streamMethodInitiation = collector |
| .nextResult(SmackConfiguration.getPacketReplyTimeout()); |
| collector.cancel(); |
| if (streamMethodInitiation == null) { |
| throw new XMPPException("No response from file transfer initiator"); |
| } |
| |
| return streamMethodInitiation; |
| } |
| |
| /** |
| * Returns the packet filter that will return the initiation packet for the appropriate stream |
| * initiation. |
| * |
| * @param from The initiator of the file transfer. |
| * @param streamID The stream ID related to the transfer. |
| * @return The <b><i>PacketFilter</b></i> that will return the packet relatable to the stream |
| * initiation. |
| */ |
| public abstract PacketFilter getInitiationPacketFilter(String from, String streamID); |
| |
| |
| abstract InputStream negotiateIncomingStream(Packet streamInitiation) throws XMPPException, |
| InterruptedException; |
| |
| /** |
| * This method handles the file stream download negotiation process. The |
| * appropriate stream negotiator's initiate incoming stream is called after |
| * an appropriate file transfer method is selected. The manager will respond |
| * to the initiator with the selected means of transfer, then it will handle |
| * any negotiation specific to the particular transfer method. This method |
| * returns the InputStream, ready to transfer the file. |
| * |
| * @param initiation The initiation that triggered this download. |
| * @return After the negotiation process is complete, the InputStream to |
| * write a file to is returned. |
| * @throws XMPPException If an error occurs during this process an XMPPException is |
| * thrown. |
| * @throws InterruptedException If thread is interrupted. |
| */ |
| public abstract InputStream createIncomingStream(StreamInitiation initiation) |
| throws XMPPException, InterruptedException; |
| |
| /** |
| * This method handles the file upload stream negotiation process. The |
| * particular stream negotiator is determined during the file transfer |
| * negotiation process. This method returns the OutputStream to transmit the |
| * file to the remote user. |
| * |
| * @param streamID The streamID that uniquely identifies the file transfer. |
| * @param initiator The fully-qualified JID of the initiator of the file transfer. |
| * @param target The fully-qualified JID of the target or receiver of the file |
| * transfer. |
| * @return The negotiated stream ready for data. |
| * @throws XMPPException If an error occurs during the negotiation process an |
| * exception will be thrown. |
| */ |
| public abstract OutputStream createOutgoingStream(String streamID, |
| String initiator, String target) throws XMPPException; |
| |
| /** |
| * Returns the XMPP namespace reserved for this particular type of file |
| * transfer. |
| * |
| * @return Returns the XMPP namespace reserved for this particular type of |
| * file transfer. |
| */ |
| public abstract String[] getNamespaces(); |
| |
| /** |
| * Cleanup any and all resources associated with this negotiator. |
| */ |
| public abstract void cleanup(); |
| |
| } |