/**
This file is part of Waarp Project.
Copyright 2009, Frederic Bregier, and individual contributors by the @author
tags. See the COPYRIGHT.txt in the distribution for a full listing of
individual contributors.
All Waarp Project is free software: you can redistribute it and/or
modify it under the terms of the GNU General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Waarp 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 General Public License for more details.
You should have received a copy of the GNU General Public License
along with Waarp . If not, see <http://www.gnu.org/licenses/>.
*/
package org.waarp.openr66.thrift;
import java.sql.Timestamp;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import org.apache.thrift.TException;
import org.waarp.common.command.exception.CommandAbstractException;
import org.waarp.common.database.data.AbstractDbData;
import org.waarp.common.database.exception.WaarpDatabaseException;
import org.waarp.common.logging.WaarpLogger;
import org.waarp.common.logging.WaarpLoggerFactory;
import org.waarp.openr66.commander.ClientRunner;
import org.waarp.openr66.context.R66Session;
import org.waarp.openr66.context.filesystem.R66File;
import org.waarp.openr66.database.DbConstant;
import org.waarp.openr66.database.data.DbRule;
import org.waarp.openr66.database.data.DbTaskRunner;
import org.waarp.openr66.protocol.configuration.Configuration;
import org.waarp.openr66.protocol.configuration.PartnerConfiguration;
import org.waarp.openr66.protocol.localhandler.LocalChannelReference;
import org.waarp.openr66.protocol.localhandler.packet.ErrorPacket;
import org.waarp.openr66.protocol.localhandler.packet.RequestPacket;
import org.waarp.openr66.protocol.utils.ChannelUtils;
import org.waarp.openr66.protocol.utils.TransferUtils;
import org.waarp.thrift.r66.Action;
import org.waarp.thrift.r66.ErrorCode;
import org.waarp.thrift.r66.R66Request;
import org.waarp.thrift.r66.R66Result;
import org.waarp.thrift.r66.R66Service;
import org.waarp.thrift.r66.RequestMode;
/**
* Embedded service attached with the Thrift service
*
* @author Frederic Bregier
*
*/
public class R66EmbeddedServiceImpl implements R66Service.Iface {
/**
* Internal Logger
*/
private static final WaarpLogger logger = WaarpLoggerFactory
.getLogger(R66EmbeddedServiceImpl.class);
private DbTaskRunner initRequest(R66Request request) {
Timestamp ttimestart = null;
if (request.isSetStart()) {
Date date;
try {
SimpleDateFormat dateFormat = new SimpleDateFormat("yyyyMMddHHmmss");
date = dateFormat.parse(request.getStart());
ttimestart = new Timestamp(date.getTime());
} catch (ParseException e) {
}
} else if (request.isSetDelay()) {
if (request.getDelay().charAt(0) == '+') {
ttimestart = new Timestamp(System.currentTimeMillis() +
Long.parseLong(request.getDelay().substring(1)));
} else {
ttimestart = new Timestamp(Long.parseLong(request.getDelay()));
}
}
DbRule rule;
try {
rule = new DbRule(DbConstant.admin.getSession(), request.getRule());
} catch (WaarpDatabaseException e) {
logger.warn("Cannot get Rule: " + request.getRule(), e);
return null;
}
int mode = rule.getMode();
if (request.isMd5()) {
mode = RequestPacket.getModeMD5(mode);
}
DbTaskRunner taskRunner = null;
long tid = DbConstant.ILLEGALVALUE;
if (request.isSetTid()) {
tid = request.getTid();
}
if (tid != DbConstant.ILLEGALVALUE) {
try {
taskRunner = new DbTaskRunner(DbConstant.admin.getSession(), tid,
request.getDestuid());
// requested
taskRunner.setSenderByRequestToValidate(true);
} catch (WaarpDatabaseException e) {
logger.warn("Cannot get task", e);
return null;
}
} else {
String sep = PartnerConfiguration.getSeparator(request.getDestuid());
RequestPacket requestPacket = new RequestPacket(request.getRule(),
mode, request.getFile(), request.getBlocksize(), 0,
tid, request.getInfo(), -1, sep);
// Not isRecv since it is the requester, so send => isRetrieve is true
boolean isRetrieve = !RequestPacket.isRecvMode(requestPacket.getMode());
try {
taskRunner =
new DbTaskRunner(DbConstant.admin.getSession(), rule, isRetrieve, requestPacket,
request.getDestuid(), ttimestart);
} catch (WaarpDatabaseException e) {
logger.warn("Cannot get task", e);
return null;
}
}
return taskRunner;
}
public R66Result transferRequestQuery(R66Request request) throws TException {
DbTaskRunner runner = initRequest(request);
if (runner != null) {
runner.changeUpdatedInfo(AbstractDbData.UpdatedInfo.TOSUBMIT);
boolean isSender = runner.isSender();
if (!runner.forceSaveStatus()) {
logger.warn("Cannot prepare task");
return new R66Result(request.getMode(), ErrorCode.CommandNotFound,
"ERROR: Cannot prepare transfer");
}
R66Result result = new R66Result(request.getMode(), ErrorCode.InitOk,
"Transfer Scheduled");
if (request.getMode() == RequestMode.SYNCTRANSFER) {
// now need to wait but first, reload the runner
try {
runner.select();
while (!runner.isFinished()) {
try {
Thread.sleep(1000);
runner.select();
} catch (InterruptedException e) {
break;
}
}
runner.setSender(isSender);
} catch (WaarpDatabaseException e1) {
}
setResultFromRunner(runner, result);
if (runner.isAllDone()) {
result.setCode(ErrorCode.CompleteOk);
result.setResultinfo("Transfer Done");
} else {
result.setCode(ErrorCode.valueOf(runner.getErrorInfo().name()));
result.setResultinfo(runner.getErrorInfo().mesg);
}
} else {
try {
runner.select();
} catch (WaarpDatabaseException e) {
}
runner.setSender(isSender);
setResultFromRunner(runner, result);
}
return result;
} else {
logger.warn("ERROR: Transfer NOT scheduled");
R66Result result = new R66Result(request.getMode(), ErrorCode.Internal,
"ERROR: Transfer NOT scheduled");
return result;
}
}
private void setResultFromRunner(DbTaskRunner runner, R66Result result) {
result.setDestuid(runner.getRequested());
result.setFromuid(runner.getRequester());
result.setTid(runner.getSpecialId());
result.setRule(runner.getRuleId());
result.setBlocksize(runner.getBlocksize());
result.setFile(runner.getFilename());
result.setOriginalfilename(runner.getOriginalFilename());
result.setIsmoved(runner.isFileMoved());
result.setModetransfer(runner.getMode());
result.setRetrievemode(runner.isSender());
result.setStep(runner.getStep());
result.setGloballaststep(runner.getGloballaststep());
result.setRank(runner.getRank());
result.setStart(runner.getStart().toString());
result.setStop(runner.getStop().toString());
result.setResultinfo(runner.getFileInformation());
}
private void setResultFromLCR(LocalChannelReference lcr, R66Result result) {
R66Session session = lcr.getSession();
DbTaskRunner runner = null;
if (session != null) {
runner = session.getRunner();
} else {
ClientRunner run = lcr.getClientRunner();
if (run != null) {
runner = run.getTaskRunner();
}
}
if (runner != null) {
setResultFromRunner(runner, result);
}
}
private int stopOrCancelRunner(long id, String reqd, String reqr, org.waarp.openr66.context.ErrorCode code) {
try {
DbTaskRunner taskRunner =
new DbTaskRunner(DbConstant.admin.getSession(), null,
null, id, reqr, reqd);
return taskRunner.stopOrCancelRunner(code) ? 1 : 0;
} catch (WaarpDatabaseException e) {
}
logger.warn("Cannot accomplished action on task: " + id + " " + code.name());
return -1;
}
private R66Result stopOrCancel(R66Request request, LocalChannelReference lcr,
org.waarp.openr66.context.ErrorCode r66code) {
// stop the current transfer
R66Result resulttest;
if (lcr != null) {
int rank = 0;
if (r66code == org.waarp.openr66.context.ErrorCode.StoppedTransfer && lcr.getSession() != null) {
DbTaskRunner taskRunner = lcr.getSession().getRunner();
if (taskRunner != null) {
rank = taskRunner.getRank();
}
}
ErrorPacket error = new ErrorPacket(r66code.name() + " " + rank,
r66code.getCode(), ErrorPacket.FORWARDCLOSECODE);
try {
// inform local instead of remote
ChannelUtils.writeAbstractLocalPacketToLocal(lcr, error);
} catch (Exception e) {
}
resulttest = new R66Result(request.getMode(), ErrorCode.CompleteOk,
r66code.name());
setResultFromLCR(lcr, resulttest);
} else {
// Transfer is not running
// but maybe need action on database
int test = stopOrCancelRunner(request.getTid(), request.getDestuid(), request.getFromuid(), r66code);
if (test > 0) {
resulttest = new R66Result(request.getMode(), ErrorCode.CompleteOk,
r66code.name());
} else if (test == 0) {
resulttest = new R66Result(request.getMode(), ErrorCode.TransferOk,
r66code.name());
} else {
resulttest = new R66Result(request.getMode(), ErrorCode.CommandNotFound,
"Error: cannot accomplished task on transfer");
}
}
return resulttest;
}
private R66Result restart(R66Request request, LocalChannelReference lcr) {
// Try to validate a restarting transfer
// validLimit on requested side
if (Configuration.configuration.getConstraintLimitHandler().checkConstraints()) {
logger.warn("Limit exceeded {} while asking to relaunch a task "
+ request.toString(), Configuration.configuration.getConstraintLimitHandler().lastAlert);
return new R66Result(request.getMode(), ErrorCode.ServerOverloaded,
"Limit exceeded while asking to relaunch a task");
}
// Try to validate a restarting transfer
// header = ?; middle = requested+blank+requester+blank+specialId
DbTaskRunner taskRunner = null;
try {
taskRunner = new DbTaskRunner(DbConstant.admin.getSession(), null,
null, request.getTid(), request.getFromuid(), request.getDestuid());
org.waarp.openr66.context.R66Result resulttest = TransferUtils.restartTransfer(taskRunner, lcr);
return new R66Result(request.getMode(), ErrorCode.valueOf(resulttest.getCode().name()),
resulttest.getMessage());
} catch (WaarpDatabaseException e1) {
logger.warn("Exception while trying to restart transfer", e1);
return new R66Result(request.getMode(), ErrorCode.Internal,
"Exception while trying to restart transfer");
}
}
public R66Result infoTransferQuery(R66Request request) throws TException {
RequestMode mode = request.getMode();
if (mode != RequestMode.INFOREQUEST) {
// error
logger.warn("Mode is uncompatible with infoTransferQuery");
return new R66Result(request.getMode(), ErrorCode.Unimplemented,
"Mode is uncompatible with infoTransferQuery");
}
// now check if enough arguments are provided
if ((!request.isSetTid()) || (!request.isSetDestuid() && !request.isSetFromuid()) ||
(!request.isSetAction())) {
// error
logger.warn("Not enough arguments");
return new R66Result(request.getMode(), ErrorCode.RemoteError,
"Not enough arguments");
}
// requested+blank+requester+blank+specialId
LocalChannelReference lcr =
Configuration.configuration.getLocalTransaction().
getFromRequest(request.getDestuid() + " " + request.getFromuid() + " " + request.getTid());
org.waarp.openr66.context.ErrorCode r66code;
switch (request.getAction()) {
case Detail: {
R66Result result = new R66Result(request.getMode(), ErrorCode.CompleteOk,
"Existence test OK");
result.setAction(Action.Exist);
result.setDestuid(request.getDestuid());
result.setFromuid(request.getFromuid());
result.setTid(request.getTid());
if (lcr != null) {
setResultFromLCR(lcr, result);
} else {
try {
DbTaskRunner runner = new DbTaskRunner(DbConstant.admin.getSession(), null,
null, request.getTid(), request.getFromuid(),
request.getDestuid());
if (runner != null) {
setResultFromRunner(runner, result);
}
} catch (WaarpDatabaseException e) {
result.setCode(ErrorCode.FileNotFound);
}
}
return result;
}
case Restart:
return restart(request, lcr);
case Cancel:
r66code = org.waarp.openr66.context.ErrorCode.CanceledTransfer;
return stopOrCancel(request, lcr, r66code);
case Stop:
r66code = org.waarp.openr66.context.ErrorCode.StoppedTransfer;
return stopOrCancel(request, lcr, r66code);
default:
logger.warn("Uncompatible with " + request.getAction().name());
return new R66Result(request.getMode(), ErrorCode.Unimplemented,
"Uncompatible with " + request.getAction().name());
}
}
public boolean isStillRunning(String fromuid, String touid, long tid) throws TException {
// now check if enough arguments are provided
if (fromuid == null || touid == null || tid == DbConstant.ILLEGALVALUE) {
// error
logger.warn("Not enough arguments");
return false;
}
// header = ?; middle = requested+blank+requester+blank+specialId
LocalChannelReference lcr =
Configuration.configuration.getLocalTransaction().
getFromRequest(touid + " " + fromuid + " " + tid);
return (lcr != null);
}
public List<String> infoListQuery(R66Request request) throws TException {
List<String> list = new ArrayList<String>();
RequestMode mode = request.getMode();
if (mode != RequestMode.INFOFILE) {
// error
logger.warn("Not correct mode for infoListQuery");
list.add("Not correct mode for infoListQuery");
return list;
}
// now check if enough arguments are provided
if ((!request.isSetRule()) || (!request.isSetAction())) {
// error
logger.warn("Not enough arguments");
list.add("Not enough arguments");
return list;
}
R66Session session = new R66Session();
session.getAuth().specialNoSessionAuth(false, Configuration.configuration.getHOST_ID());
DbRule rule;
try {
rule = new DbRule(DbConstant.admin.getSession(), request.getRule());
} catch (WaarpDatabaseException e) {
logger.warn("Rule is unknown: " + request.getRule());
list.add("Rule is unknown: " + request.getRule());
return list;
}
try {
if (RequestPacket.isRecvMode(rule.getMode())) {
session.getDir().changeDirectory(rule.getWorkPath());
} else {
session.getDir().changeDirectory(rule.getSendPath());
}
if (request.getAction() == Action.List ||
request.getAction() == Action.Mlsx) {
// ls or mls from current directory
if (request.getAction() == Action.List) {
list = session.getDir().list(request.getFile());
} else {
list = session.getDir().listFull(request.getFile(), false);
}
return list;
} else {
// ls pr mls from current directory and filename
if (!request.isSetFile()) {
logger.warn("File missing");
list.add("File missing");
return list;
}
R66File file = (R66File) session.getDir().setFile(request.getFile(), false);
String sresult = null;
if (request.getAction() == Action.Exist) {
sresult = "" + file.exists();
list.add(sresult);
} else if (request.getAction() == Action.Detail) {
sresult = session.getDir().fileFull(request.getFile(), false);
String[] slist = sresult.split("\n");
sresult = slist[1];
list.add(sresult);
}
return list;
}
} catch (CommandAbstractException e) {
logger.warn("Error occurs during: " + request.toString(), e);
list.add("Error occurs during: " + request.toString());
return list;
}
}
}