/*******************************************************************************
* Copyright (c) 2008-2011 Chair for Applied Software Engineering,
* Technische Universitaet Muenchen.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
******************************************************************************/
package org.eclipse.emf.emfstore.server.core.subinterfaces;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.IOException;
import org.eclipse.emf.emfstore.common.filetransfer.FileChunk;
import org.eclipse.emf.emfstore.common.filetransfer.FileTransferInformation;
import org.eclipse.emf.emfstore.common.model.util.FileUtil;
import org.eclipse.emf.emfstore.server.ServerConfiguration;
import org.eclipse.emf.emfstore.server.core.AbstractEmfstoreInterface;
import org.eclipse.emf.emfstore.server.core.AbstractSubEmfstoreInterface;
import org.eclipse.emf.emfstore.server.core.MonitorProvider;
import org.eclipse.emf.emfstore.server.exceptions.FatalEmfStoreException;
import org.eclipse.emf.emfstore.server.exceptions.FileNotOnServerException;
import org.eclipse.emf.emfstore.server.exceptions.FileTransferException;
import org.eclipse.emf.emfstore.server.filetransfer.FilePartitionerUtil;
import org.eclipse.emf.emfstore.server.model.ProjectId;
/**
* The file transfer subinterface.
*
* @author pfeifferc
*/
public class FileTransferSubInterfaceImpl extends AbstractSubEmfstoreInterface {
private static final String FILELOAD = "filetransfer";
/**
* tmp folder for file uploads to server.
*/
public static final String TEMP_FOLDER = "tmp";
/**
* Attachment folder for uploads and downloads.
*/
public static final String ATTACHMENT_FOLDER = "attachment";
/**
* The delimiter that separates file attachment id, file version and file name in an uploaded file.
*/
public static final String FILE_NAME_DELIMITER = "_";
/**
* @param parentInterface the parent interface
* @throws FatalEmfStoreException if any fatal error occurs
*/
public FileTransferSubInterfaceImpl(AbstractEmfstoreInterface parentInterface) throws FatalEmfStoreException {
super(parentInterface);
}
/**
* Reads a chunk from the file linked to the fileInformation.
*
* @param projectId project attachment folder
* @param fileInformation file information object
* @return FileChunk
* @throws FileTransferException if any error occurs reading the file
*/
public FileChunk readChunk(ProjectId projectId, FileTransferInformation fileInformation)
throws FileTransferException {
synchronized (MonitorProvider.getInstance().getMonitor(FILELOAD)) {
// check if folders exist, otherwise create
createDirectories(projectId);
// try to localize file that is to be downloaded
File file;
try {
file = findFile(fileInformation, projectId);
} catch (FileNotFoundException e) {
throw new FileNotOnServerException(projectId, fileInformation.getFileIdentifier());
}
return FilePartitionerUtil.readChunk(file, fileInformation);
}
}
/**
* Writes a chunk to the file linked to the fileInformation in the fileChunk. If the data in the file chunk is null,
* this is treated as a request for a file version.
*
* @param fileChunk contains data and information about the file attachment, file version and chunk number
* @param projectId project id
* @return fileInformation containing the (new) file version
* @throws FileTransferException if any error occurs writing to the file
*/
public FileTransferInformation writeChunk(FileChunk fileChunk, ProjectId projectId) throws FileTransferException {
synchronized (MonitorProvider.getInstance().getMonitor(FILELOAD)) {
// check if folders exist, otherwise create
createDirectories(projectId);
FileTransferInformation fileInfo = fileChunk.getFileInformation();
// retrieve location for the temp file
File tmpFile;
try {
if (fileChunk.getChunkNumber() == 0) {
tmpFile = getTempFile(fileInfo, projectId);
} else {
tmpFile = findFileInTemp(fileInfo, projectId);
}
} catch (FileNotFoundException e) {
throw new FileTransferException(
"The file has either been removed from the server or is not accessible!", e);
}
// file reslicer for reslicing temp file
FilePartitionerUtil.writeChunk(tmpFile, fileChunk);
// move file from temp folder to attachment folder if last file chunk is received
if (fileChunk.isLast()) {
try {
// retrieve final location for file
File attachmentFile = getCachedFile(fileInfo, projectId);
FileUtil.copyFile(tmpFile, attachmentFile);
tmpFile.delete();
} catch (IOException e) {
throw new FileTransferException("Could not move file to final destination!", e);
}
}
return fileInfo;
}
}
/**
* Creates the file attachment and temporary file attachment folders.
*/
private void createDirectories(ProjectId projectId) {
File createFolders = new File(getProjectAttachmentTempFolder(projectId));
if (!createFolders.exists()) {
createFolders.mkdirs();
}
}
private File findFileInTemp(FileTransferInformation fileInfo, ProjectId projectId) throws FileNotFoundException {
File file = getTempFile(fileInfo, projectId);
if (file.exists()) {
return file;
}
throw new FileNotFoundException("Could not locate the specified file (" + fileInfo.getFileIdentifier()
+ ") in the temp folder.");
}
private File findFile(FileTransferInformation fileInfo, ProjectId projectId) throws FileNotFoundException {
File file = getCachedFile(fileInfo, projectId);
if (file.exists()) {
return file;
}
throw new FileNotFoundException("File " + fileInfo.getFileIdentifier()
+ " could not be located in the cache folder.");
}
private File getTempFile(FileTransferInformation fileInfo, ProjectId projectId) {
return new File(getProjectAttachmentTempFolder(projectId) + File.separator + constructFileName(fileInfo));
}
private File getCachedFile(FileTransferInformation fileInfo, ProjectId projectId) {
return new File(getProjectAttachmentFolder(projectId) + File.separator + constructFileName(fileInfo));
}
private String constructFileName(FileTransferInformation fileInfo) {
return fileInfo.getFileIdentifier();
}
private String getProjectAttachmentFolder(ProjectId projectId) {
return ServerConfiguration.getServerHome() + ServerConfiguration.FILE_PREFIX_PROJECTFOLDER + projectId.getId()
+ File.separator + ATTACHMENT_FOLDER;
}
private String getProjectAttachmentTempFolder(ProjectId projectId) {
return getProjectAttachmentFolder(projectId) + File.separator + TEMP_FOLDER;
}
}