/** | |
* $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(); | |
} |