/*
* Copyright (C) 2009 eXo Platform SAS.
*
* This is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as
* published by the Free Software Foundation; either version 2.1 of
* the License, or (at your option) any later version.
*
* This software is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this software; if not, write to the Free
* Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
* 02110-1301 USA, or see the FSF site: http://www.fsf.org.
*/
package org.exoplatform.services.ftp.command;
import org.exoplatform.commons.utils.MimeTypeResolver;
import org.exoplatform.services.ftp.FtpConst;
import org.exoplatform.services.ftp.FtpTextUtils;
import org.exoplatform.services.ftp.config.FtpConfig;
import org.exoplatform.services.jcr.util.IdGenerator;
import org.exoplatform.services.log.ExoLogger;
import org.exoplatform.services.log.Log;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.util.ArrayList;
import java.util.Calendar;
import javax.jcr.Node;
import javax.jcr.PathNotFoundException;
import javax.jcr.RepositoryException;
import javax.jcr.Session;
/**
* Created by The eXo Platform SAS Author : Vitaly Guly <gavrik-vetal@ukr.net/mail.ru>
*
* @version $Id: CmdStor.java 34445 2009-07-24 07:51:18Z dkatayev $
*/
public class CmdStor extends FtpCommandImpl
{
private static Log log = ExoLogger.getLogger(FtpConst.FTP_PREFIX + "CmdStor");
public CmdStor()
{
commandName = FtpConst.Commands.CMD_STOR;
}
public void run(String[] params) throws IOException
{
if (clientSession().getDataTransiver() == null)
{
reply(FtpConst.Replyes.REPLY_425);
return;
}
try
{
// TODO: Add TimeOut here
while (!clientSession().getDataTransiver().isConnected())
{
Thread.sleep(100);
}
}
catch (Exception exc)
{
log.info("Unhandled exception. " + exc.getMessage(), exc);
}
if (params.length < 2)
{
reply(String.format(FtpConst.Replyes.REPLY_500_PARAMREQUIRED, FtpConst.Commands.CMD_STOR));
return;
}
String fileName = params[1];
try
{
ArrayList<String> newPath = clientSession().getFullPath(fileName);
FtpConfig ftpConfig = clientSession().getFtpServer().getConfiguration();
if (ftpConfig.isReplaceForbiddenChars())
{
String fName = newPath.get(newPath.size()-1);
String newfName = FtpTextUtils.replaceForbiddenChars(fName, ftpConfig.getForbiddenChars(), ftpConfig.getReplaceChar());
fileName = fileName.substring(0, fileName.indexOf(fName)) + newfName;
}
Session curSession = clientSession().getSession(newPath.get(0));
Node resourceNode = getExistedFileNode(curSession, fileName);
boolean isNeedCheckIn = false;
if (resourceNode == null)
{
if (FtpConst.Commands.CMD_REST.equals(clientSession().getPrevCommand()))
{
reply(String.format(FtpConst.Replyes.REPLY_550, "Requested file not exist"));
return;
}
resourceNode = createNewFileNode(curSession, fileName);
}
else
{
if (FtpConst.Commands.CMD_REST.equals(clientSession().getPrevCommand()))
{
int restOffset = new Integer(clientSession().getPrevParams());
if (restOffset > (resourceNode.getProperty(FtpConst.NodeTypes.JCR_DATA).getLength() + 1))
{
reply(String.format(FtpConst.Replyes.REPLY_550, "Restore value invalid"));
return;
}
}
if (resourceNode.getParent().isNodeType(FtpConst.NodeTypes.MIX_VERSIONABLE))
{
resourceNode.getParent().checkout();
isNeedCheckIn = true;
}
}
InputStream inputStream = null;
String cacheFileName = null;
if (FtpConst.Commands.CMD_REST.equals(clientSession().getPrevCommand()))
{
String cacheFolderName = clientSession().getFtpServer().getConfiguration().getCacheFolderName();
cacheFileName = cacheFolderName + "/" + IdGenerator.generate() + FtpConst.FTP_CACHEFILEEXTENTION;
File cacheFile = new File(cacheFileName);
boolean created = cacheFile.createNewFile();
if (!created)
{
reply(String.format(FtpConst.Replyes.REPLY_550, "STOR"));
return;
}
FileOutputStream cacheOutStream = new FileOutputStream(cacheFile);
InputStream nodeInputStream = resourceNode.getProperty(FtpConst.NodeTypes.JCR_DATA).getStream();
if (nodeInputStream == null)
{
reply(String.format(FtpConst.Replyes.REPLY_550, "STOR"));
return;
}
byte[] buffer = new byte[32 * 1024];
while (true)
{
int readed = nodeInputStream.read(buffer);
if (readed < 0)
{
break;
}
cacheOutStream.write(buffer, 0, readed);
}
cacheOutStream.close();
RandomAccessFile cacheFilePoint = new RandomAccessFile(cacheFile, "rw");
int restOffset = new Integer(clientSession().getPrevParams());
cacheFilePoint.seek(restOffset);
InputStream socketInputStream = clientSession().getDataTransiver().getInputStream();
reply(FtpConst.Replyes.REPLY_125);
while (true)
{
int readed = socketInputStream.read(buffer);
if (readed < 0)
{
break;
}
cacheFilePoint.write(buffer, 0, readed);
}
cacheFilePoint.close();
inputStream = new FileInputStream(cacheFile);
}
else
{
inputStream = clientSession().getDataTransiver().getInputStream();
reply(FtpConst.Replyes.REPLY_125);
}
resourceNode.setProperty(FtpConst.NodeTypes.JCR_LASTMODIFIED, Calendar.getInstance());
resourceNode.setProperty(FtpConst.NodeTypes.JCR_DATA, inputStream);
curSession.save();
clientSession().closeDataTransiver();
try
{
inputStream.close();
}
catch (Exception exc)
{
log.info("Failurinc closing input stream");
}
if (cacheFileName != null)
{
File cacheFile = new File(cacheFileName);
cacheFile.delete();
}
if (isNeedCheckIn)
{
resourceNode.getParent().checkin();
}
reply(FtpConst.Replyes.REPLY_226);
return;
}
catch (RepositoryException rexc)
{
}
catch (Exception exc)
{
log.info("Unhandled exception. " + exc.getMessage(), exc);
}
clientSession().closeDataTransiver();
reply(String.format(FtpConst.Replyes.REPLY_550, fileName));
}
protected Node getExistedFileNode(Session curSession, String resName)
{
try
{
ArrayList<String> newPath = clientSession().getFullPath(resName);
String repoPath = clientSession().getRepoPath(newPath);
Node fileNode = (Node)curSession.getItem(repoPath);
return fileNode.getNode(FtpConst.NodeTypes.JCR_CONTENT);
}
catch (RepositoryException rexc)
{
}
catch (Exception exc)
{
log.info("Unhandled exception. " + exc.getMessage(), exc);
}
return null;
}
protected Node createNewFileNode(Session curSession, String resName)
{
try
{
ArrayList<String> newPath = clientSession().getFullPath(resName);
String repoPath = clientSession().getRepoPath(newPath);
String onlyName = repoPath.substring(repoPath.lastIndexOf("/") + 1);
String onlyPath = repoPath.substring(0, repoPath.length() - onlyName.length());
if (onlyPath.length() > 1)
{
if (onlyPath.endsWith("/"))
{
onlyPath = onlyPath.substring(0, onlyPath.length() - 1);
}
}
Node parentNode = (Node)curSession.getItem(onlyPath);
FtpConfig configuration = clientSession().getFtpServer().getConfiguration();
String fileNodeType = configuration.getDefFileNodeType();
Node fileNode = parentNode.addNode(onlyName, fileNodeType);
Node dataNode = fileNode.addNode(FtpConst.NodeTypes.JCR_CONTENT, FtpConst.NodeTypes.NT_RESOURCE);
MimeTypeResolver mimeTypeResolver = new MimeTypeResolver();
mimeTypeResolver.setDefaultMimeType(configuration.getDefFileMimeType());
String mimeType = mimeTypeResolver.getMimeType(onlyName);
dataNode.setProperty(FtpConst.NodeTypes.JCR_MIMETYPE, mimeType);
dataNode.setProperty(FtpConst.NodeTypes.JCR_LASTMODIFIED, Calendar.getInstance());
return dataNode;
}
catch (PathNotFoundException pexc)
{
}
catch (Exception exc)
{
log.info("Unhandled exception. " + exc.getMessage(), exc);
}
return null;
}
}