001: /**
002: * $RCSfile$
003: * $Revision: 1217 $
004: * $Date: 2005-04-11 18:11:06 -0300 (Mon, 11 Apr 2005) $
005: *
006: * Copyright (C) 1999-2007 Jive Software. All rights reserved.
007: *
008: * This software is published under the terms of the GNU Public License (GPL),
009: * a copy of which is included in this distribution.
010: */package org.jivesoftware.openfire.filetransfer;
011:
012: import org.dom4j.Element;
013: import org.jivesoftware.util.cache.Cache;
014: import org.jivesoftware.util.cache.DefaultCache;
015: import org.jivesoftware.util.cache.CacheFactory;
016: import org.jivesoftware.util.JiveGlobals;
017: import org.jivesoftware.openfire.auth.UnauthorizedException;
018: import org.jivesoftware.openfire.container.BasicModule;
019: import org.jivesoftware.openfire.filetransfer.proxy.ProxyConnectionManager;
020: import org.jivesoftware.openfire.filetransfer.proxy.ProxyTransfer;
021: import org.jivesoftware.openfire.interceptor.InterceptorManager;
022: import org.jivesoftware.openfire.interceptor.PacketInterceptor;
023: import org.jivesoftware.openfire.interceptor.PacketRejectedException;
024: import org.jivesoftware.openfire.session.Session;
025: import org.xmpp.packet.IQ;
026: import org.xmpp.packet.JID;
027: import org.xmpp.packet.Packet;
028:
029: import java.util.ArrayList;
030: import java.util.List;
031: import java.util.Map;
032:
033: /**
034: * Provides several utility methods for file transfer manager implementaions to utilize.
035: *
036: * @author Alexander Wenckus
037: */
038: public class DefaultFileTransferManager extends BasicModule implements
039: FileTransferManager {
040:
041: private static final String CACHE_NAME = "File Transfer Cache";
042:
043: private final Map<String, FileTransfer> fileTransferMap;
044:
045: private final List<FileTransferInterceptor> fileTransferInterceptorList = new ArrayList<FileTransferInterceptor>();
046:
047: /**
048: * Default constructor creates the cache.
049: */
050: public DefaultFileTransferManager() {
051: super ("File Transfer Manager");
052: fileTransferMap = CacheFactory.createCache(CACHE_NAME);
053: InterceptorManager.getInstance().addInterceptor(
054: new MetaFileTransferInterceptor());
055: }
056:
057: /**
058: * Returns true if the proxy transfer should be matched to an existing file transfer
059: * in the system.
060: *
061: * @return Returns true if the proxy transfer should be matched to an existing file
062: * transfer in the system.
063: */
064: public boolean isMatchProxyTransfer() {
065: return JiveGlobals.getBooleanProperty(
066: "xmpp.proxy.transfer.required", true);
067: }
068:
069: protected void cacheFileTransfer(String key, FileTransfer transfer) {
070: fileTransferMap.put(key, transfer);
071: }
072:
073: protected FileTransfer retrieveFileTransfer(String key) {
074: return fileTransferMap.get(key);
075: }
076:
077: protected static Element getChildElement(Element element,
078: String namespace) {
079: //noinspection unchecked
080: List<Element> elements = element.elements();
081: if (elements.isEmpty()) {
082: return null;
083: }
084: for (Element childElement : elements) {
085: String childNamespace = childElement.getNamespaceURI();
086: if (namespace.equals(childNamespace)) {
087: return childElement;
088: }
089: }
090:
091: return null;
092: }
093:
094: public boolean acceptIncomingFileTransferRequest(
095: FileTransfer transfer) throws FileTransferRejectedException {
096: fireFileTransferIntercept(transfer, false);
097: if (transfer != null) {
098: String streamID = transfer.getSessionID();
099: JID from = new JID(transfer.getInitiator());
100: JID to = new JID(transfer.getTarget());
101: cacheFileTransfer(ProxyConnectionManager.createDigest(
102: streamID, from, to), transfer);
103: return true;
104: }
105: return false;
106: }
107:
108: public void registerProxyTransfer(String transferDigest,
109: ProxyTransfer proxyTransfer) throws UnauthorizedException {
110: FileTransfer transfer = retrieveFileTransfer(transferDigest);
111: if (isMatchProxyTransfer() && transfer == null) {
112: throw new UnauthorizedException(
113: "Unable to match proxy transfer with a file transfer");
114: } else if (transfer == null) {
115: return;
116: }
117:
118: transfer.setProgress(proxyTransfer);
119: cacheFileTransfer(transferDigest, transfer);
120: }
121:
122: private FileTransfer createFileTransfer(JID from, JID to,
123: Element siElement) {
124: String streamID = siElement.attributeValue("id");
125: String mimeType = siElement.attributeValue("mime-type");
126: String profile = siElement.attributeValue("profile");
127: // Check profile, the only type we deal with currently is file transfer
128: FileTransfer transfer = null;
129: if (NAMESPACE_SI_FILETRANSFER.equals(profile)) {
130: Element fileTransferElement = getChildElement(siElement,
131: NAMESPACE_SI_FILETRANSFER);
132: // Not valid form, reject
133: if (fileTransferElement == null) {
134: return null;
135: }
136: String fileName = fileTransferElement
137: .attributeValue("name");
138: String sizeString = fileTransferElement
139: .attributeValue("size");
140: if (fileName == null || sizeString == null) {
141: return null;
142: }
143:
144: long size;
145: try {
146: size = Long.parseLong(sizeString);
147: } catch (Exception ex) {
148: return null;
149: }
150:
151: transfer = new FileTransfer(from.toString(), to.toString(),
152: streamID, fileName, size, mimeType);
153: }
154: return transfer;
155: }
156:
157: public void addFileTransferInterceptor(
158: FileTransferInterceptor interceptor) {
159: fileTransferInterceptorList.add(interceptor);
160: }
161:
162: public void removeFileTransferInterceptor(
163: FileTransferInterceptor interceptor) {
164: fileTransferInterceptorList.remove(interceptor);
165: }
166:
167: public void fireFileTransferIntercept(
168: FileTransferProgress transfer, boolean isReady)
169: throws FileTransferRejectedException {
170: fireFileTransferIntercept(fileTransferMap.get(transfer
171: .getSessionID()), isReady);
172: }
173:
174: private void fireFileTransferIntercept(FileTransfer transfer,
175: boolean isReady) throws FileTransferRejectedException {
176: for (FileTransferInterceptor interceptor : fileTransferInterceptorList) {
177: interceptor.interceptFileTransfer(transfer, isReady);
178: }
179: }
180:
181: /**
182: * Interceptor to grab and validate file transfer meta information.
183: */
184: private class MetaFileTransferInterceptor implements
185: PacketInterceptor {
186: public void interceptPacket(Packet packet, Session session,
187: boolean incoming, boolean processed)
188: throws PacketRejectedException {
189: // We only want packets recieved by the server
190: if (!processed && incoming && packet instanceof IQ) {
191: IQ iq = (IQ) packet;
192: Element childElement = iq.getChildElement();
193: if (childElement == null) {
194: return;
195: }
196:
197: String namespace = childElement.getNamespaceURI();
198: if (NAMESPACE_SI.equals(namespace)) {
199: // If this is a set, check the feature offer
200: if (iq.getType().equals(IQ.Type.set)) {
201: JID from = iq.getFrom();
202: JID to = iq.getTo();
203:
204: FileTransfer transfer = createFileTransfer(
205: from, to, childElement);
206:
207: try {
208: if (transfer == null
209: || !acceptIncomingFileTransferRequest(transfer)) {
210: throw new PacketRejectedException();
211: }
212: } catch (FileTransferRejectedException e) {
213: throw new PacketRejectedException(e);
214: }
215: }
216: }
217: }
218: }
219: }
220: }
|