DefaultFileTransferManager.java 8.18 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13
/**
 * $RCSfile$
 * $Revision: 1217 $
 * $Date: 2005-04-11 18:11:06 -0300 (Mon, 11 Apr 2005) $
 *
 * Copyright (C) 1999-2006 Jive Software. All rights reserved.
 *
 * This software is published under the terms of the GNU Public License (GPL),
 * a copy of which is included in this distribution.
 */
package org.jivesoftware.wildfire.filetransfer;

import org.jivesoftware.util.JiveGlobals;
14
import org.jivesoftware.util.Cache;
15
import org.jivesoftware.wildfire.auth.UnauthorizedException;
16 17 18 19 20
import org.jivesoftware.wildfire.container.BasicModule;
import org.jivesoftware.wildfire.interceptor.InterceptorManager;
import org.jivesoftware.wildfire.interceptor.PacketInterceptor;
import org.jivesoftware.wildfire.interceptor.PacketRejectedException;
import org.jivesoftware.wildfire.Session;
21 22
import org.jivesoftware.wildfire.filetransfer.proxy.ProxyConnectionManager;
import org.jivesoftware.wildfire.filetransfer.proxy.ProxyTransfer;
23
import org.dom4j.Element;
24 25 26
import org.xmpp.packet.Packet;
import org.xmpp.packet.IQ;
import org.xmpp.packet.JID;
27 28 29

import java.util.Map;
import java.util.List;
30
import java.util.ArrayList;
31 32 33 34 35 36

/**
 * Provides several utility methods for file transfer manager implementaions to utilize.
 *
 * @author Alexander Wenckus
 */
37
public class DefaultFileTransferManager extends BasicModule implements FileTransferManager {
38

39 40 41 42
    private static final String CACHE_NAME = "File Transfer Cache";

    private final Map<String, FileTransfer> fileTransferMap;

43 44 45
    private final List<FileTransferInterceptor> fileTransferInterceptorList
            = new ArrayList<FileTransferInterceptor>();

46 47 48
    /**
     * Default constructor creates the cache.
     */
49
    public DefaultFileTransferManager() {
50
        super("File Transfer Manager");
51
        fileTransferMap = createCache(CACHE_NAME, "fileTransfer", 128 * 1024, 1000 * 60 * 10);
52
        InterceptorManager.getInstance().addInterceptor(new MetaFileTransferInterceptor());
53 54
    }

55 56 57
    private Cache<String, FileTransfer> createCache(String name, String propertiesName, int size,
                                                    long expirationTime)
    {
58 59 60 61
        size = JiveGlobals.getIntProperty("cache." + propertiesName + ".size", size);
        expirationTime = (long) JiveGlobals.getIntProperty(
                "cache." + propertiesName + ".expirationTime", (int) expirationTime);
        return new Cache<String, FileTransfer>(name, size, expirationTime);
62 63 64
    }

    /**
65 66
     * Returns true if the proxy transfer should be matched to an existing file transfer
     * in the system.
67
     *
68 69
     * @return Returns true if the proxy transfer should be matched to an existing file
     * transfer in the system.
70 71
     */
    public boolean isMatchProxyTransfer() {
72
        return JiveGlobals.getBooleanProperty("xmpp.proxy.transfer.required", true);
73 74
    }

75
    protected void cacheFileTransfer(String key, FileTransfer transfer) {
76 77 78
        fileTransferMap.put(key, transfer);
    }

79
    protected FileTransfer retrieveFileTransfer(String key) {
80 81 82
        return fileTransferMap.get(key);
    }

83
    protected static Element getChildElement(Element element, String namespace) {
84 85 86 87 88 89 90 91 92 93 94 95 96 97 98
        List elements = element.elements();
        if (elements.isEmpty()) {
            return null;
        }
        for (int i = 0; i < elements.size(); i++) {
            Element childElement = (Element) elements.get(i);
            String childNamespace = childElement.getNamespaceURI();
            if (namespace.equals(childNamespace)) {
                return childElement;
            }
        }

        return null;
    }

99
    public boolean acceptIncomingFileTransferRequest(FileTransfer transfer)
100
            throws FileTransferRejectedException
101
    {
102
        fireFileTransferIntercept(transfer, false);
103 104 105 106 107 108 109 110 111 112
        if(transfer != null) {
            String streamID = transfer.getSessionID();
            JID from = new JID(transfer.getInitiator());
            JID to = new JID(transfer.getTarget());
            cacheFileTransfer(ProxyConnectionManager.createDigest(streamID, from, to), transfer);
            return true;
        }
        return false;
    }

113 114 115 116 117 118 119 120 121 122 123 124 125 126
    public void registerProxyTransfer(String transferDigest, ProxyTransfer proxyTransfer)
            throws UnauthorizedException
    {
        FileTransfer transfer = retrieveFileTransfer(transferDigest);
        if (isMatchProxyTransfer() && transfer == null) {
            throw new UnauthorizedException("Unable to match proxy transfer with a file transfer");
        }
        else if (transfer == null) {
            return;
        }

        transfer.setProgress(proxyTransfer);
        cacheFileTransfer(transferDigest, transfer);
    }
127

128 129
    private FileTransfer createFileTransfer(JID from,
                                            JID to, Element siElement) {
130 131 132 133 134 135 136 137 138 139 140 141 142
        String streamID = siElement.attributeValue("id");
        String mimeType = siElement.attributeValue("mime-type");
        String profile = siElement.attributeValue("profile");
        // Check profile, the only type we deal with currently is file transfer
        FileTransfer transfer = null;
        if (NAMESPACE_SI_FILETRANSFER.equals(profile)) {
            Element fileTransferElement = getChildElement(siElement, NAMESPACE_SI_FILETRANSFER);
            // Not valid form, reject
            if (fileTransferElement == null) {
                return null;
            }
            String fileName = fileTransferElement.attributeValue("name");
            long size = Long.parseLong(fileTransferElement.attributeValue("size"));
143

144 145 146 147
            transfer = new FileTransfer(from.toString(), to.toString(),
                    streamID, fileName, size, mimeType);
        }
        return transfer;
148 149
    }

150
    public void addFileTransferInterceptor(FileTransferInterceptor interceptor) {
151
        fileTransferInterceptorList.add(interceptor);
152 153 154
    }

    public void removeFileTransferInterceptor(FileTransferInterceptor interceptor) {
155
        fileTransferInterceptorList.remove(interceptor);
156 157
    }

158
    public void fireFileTransferIntercept(FileTransferProgress transfer, boolean isReady)
159 160
            throws FileTransferRejectedException
    {
161
        fireFileTransferIntercept(fileTransferMap.get(transfer.getSessionID()), isReady);
162 163
    }

164 165
    private void fireFileTransferIntercept(FileTransfer transfer, boolean isReady)
            throws FileTransferRejectedException
166
    {
167 168 169
        for(FileTransferInterceptor interceptor : fileTransferInterceptorList) {
            interceptor.interceptFileTransfer(transfer, isReady);
        }
170 171
    }

172 173 174
    /**
     * Interceptor to grab and validate file transfer meta information.
     */
175
    private class MetaFileTransferInterceptor implements PacketInterceptor {
176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193
        public void interceptPacket(Packet packet, Session session, boolean incoming,
                                    boolean processed)
                throws PacketRejectedException
        {
            // We only want packets recieved by the server
            if (!processed && incoming && packet instanceof IQ) {
                IQ iq = (IQ) packet;
                Element childElement = iq.getChildElement();
                if(childElement == null) {
                    return;
                }

                String namespace = childElement.getNamespaceURI();
                if (NAMESPACE_SI.equals(namespace)) {
                    // If this is a set, check the feature offer
                    if (iq.getType().equals(IQ.Type.set)) {
                        JID from = iq.getFrom();
                        JID to = iq.getTo();
194 195

                        FileTransfer transfer =
196
                                createFileTransfer(from, to, childElement);
197

198 199 200 201 202 203 204
                        try {
                            if (transfer == null || !acceptIncomingFileTransferRequest(transfer)) {
                                throw new PacketRejectedException();
                            }
                        }
                        catch (FileTransferRejectedException e) {
                            throw new PacketRejectedException(e);
205 206 207 208 209 210
                        }
                    }
                }
            }
        }
    }
211
}