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