/**
* 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.protocol.localhandler;
import static org.waarp.openr66.context.R66FiniteDualStates.DATAR;
import static org.waarp.openr66.context.R66FiniteDualStates.ERROR;
import static org.waarp.openr66.context.R66FiniteDualStates.INFORMATION;
import static org.waarp.openr66.context.R66FiniteDualStates.SHUTDOWN;
import static org.waarp.openr66.context.R66FiniteDualStates.TEST;
import io.netty.channel.ChannelFutureListener;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import io.netty.channel.local.LocalChannel;
import io.netty.util.concurrent.Future;
import io.netty.util.concurrent.GenericFutureListener;
import org.waarp.common.logging.WaarpLogger;
import org.waarp.common.logging.WaarpLoggerFactory;
import org.waarp.openr66.context.ErrorCode;
import org.waarp.openr66.context.R66FiniteDualStates;
import org.waarp.openr66.context.R66Result;
import org.waarp.openr66.context.task.exception.OpenR66RunnerErrorException;
import org.waarp.openr66.context.task.exception.OpenR66RunnerException;
import org.waarp.openr66.database.data.DbTaskRunner;
import org.waarp.openr66.protocol.configuration.Configuration;
import org.waarp.openr66.protocol.configuration.Messages;
import org.waarp.openr66.protocol.configuration.PartnerConfiguration;
import org.waarp.openr66.protocol.exception.OpenR66Exception;
import org.waarp.openr66.protocol.exception.OpenR66ExceptionTrappedFactory;
import org.waarp.openr66.protocol.exception.OpenR66ProtocolBusinessCancelException;
import org.waarp.openr66.protocol.exception.OpenR66ProtocolBusinessNoWriteBackException;
import org.waarp.openr66.protocol.exception.OpenR66ProtocolBusinessQueryAlreadyFinishedException;
import org.waarp.openr66.protocol.exception.OpenR66ProtocolBusinessQueryStillRunningException;
import org.waarp.openr66.protocol.exception.OpenR66ProtocolBusinessRemoteFileNotFoundException;
import org.waarp.openr66.protocol.exception.OpenR66ProtocolBusinessStopException;
import org.waarp.openr66.protocol.exception.OpenR66ProtocolNetworkException;
import org.waarp.openr66.protocol.exception.OpenR66ProtocolNoConnectionException;
import org.waarp.openr66.protocol.exception.OpenR66ProtocolNotAuthenticatedException;
import org.waarp.openr66.protocol.exception.OpenR66ProtocolPacketException;
import org.waarp.openr66.protocol.exception.OpenR66ProtocolRemoteShutdownException;
import org.waarp.openr66.protocol.exception.OpenR66ProtocolShutdownException;
import org.waarp.openr66.protocol.exception.OpenR66ProtocolSystemException;
import org.waarp.openr66.protocol.localhandler.packet.AbstractLocalPacket;
import org.waarp.openr66.protocol.localhandler.packet.AuthentPacket;
import org.waarp.openr66.protocol.localhandler.packet.BlockRequestPacket;
import org.waarp.openr66.protocol.localhandler.packet.BusinessRequestPacket;
import org.waarp.openr66.protocol.localhandler.packet.ConnectionErrorPacket;
import org.waarp.openr66.protocol.localhandler.packet.DataPacket;
import org.waarp.openr66.protocol.localhandler.packet.EndRequestPacket;
import org.waarp.openr66.protocol.localhandler.packet.EndTransferPacket;
import org.waarp.openr66.protocol.localhandler.packet.ErrorPacket;
import org.waarp.openr66.protocol.localhandler.packet.InformationPacket;
import org.waarp.openr66.protocol.localhandler.packet.JsonCommandPacket;
import org.waarp.openr66.protocol.localhandler.packet.LocalPacketFactory;
import org.waarp.openr66.protocol.localhandler.packet.RequestPacket;
import org.waarp.openr66.protocol.localhandler.packet.ShutdownPacket;
import org.waarp.openr66.protocol.localhandler.packet.StartupPacket;
import org.waarp.openr66.protocol.localhandler.packet.TestPacket;
import org.waarp.openr66.protocol.localhandler.packet.ValidPacket;
import org.waarp.openr66.protocol.localhandler.packet.json.JsonPacket;
import org.waarp.openr66.protocol.localhandler.packet.json.RequestJsonPacket;
import org.waarp.openr66.protocol.utils.ChannelCloseTimer;
import org.waarp.openr66.protocol.utils.ChannelUtils;
import org.waarp.openr66.protocol.utils.R66ShutdownHook;
/**
* The local server handler handles real end file operations.
*
* @author frederic bregier
*/
class LocalServerHandler extends SimpleChannelInboundHandler<AbstractLocalPacket> {
/**
* Internal Logger
*/
private static final WaarpLogger logger = WaarpLoggerFactory.getLogger(LocalServerHandler.class);
/**
* Server Actions handler
*/
private TransferActions serverHandler = new TransferActions();
@Override
public void channelInactive(ChannelHandlerContext ctx) throws Exception {
serverHandler.channelClosed(ctx);
}
@Override
public void channelActive(ChannelHandlerContext ctx) throws Exception {
serverHandler.newSession();
}
@Override
protected void channelRead0(final ChannelHandlerContext ctx, AbstractLocalPacket msg) throws Exception {
// action as requested and answer if necessary
final AbstractLocalPacket packet = msg;
if (packet.getType() == LocalPacketFactory.STARTUPPACKET) {
serverHandler.startup(ctx.channel(), (StartupPacket) packet);
} else {
if (serverHandler.getLocalChannelReference() == null) {
logger.error("No LocalChannelReference at " +
packet.getClass().getName());
serverHandler.getSession().newState(ERROR);
final ErrorPacket errorPacket = new ErrorPacket(
"No LocalChannelReference at " +
packet.getClass().getName(),
ErrorCode.ConnectionImpossible.getCode(),
ErrorPacket.FORWARDCLOSECODE);
ctx.channel().writeAndFlush(errorPacket).addListener(ChannelFutureListener.CLOSE);
if (Configuration.configuration.getR66Mib() != null) {
Configuration.configuration.getR66Mib().notifyWarning(
"No LocalChannelReference", packet.getClass().getSimpleName());
}
packet.clear();
return;
}
switch (packet.getType()) {
case LocalPacketFactory.AUTHENTPACKET: {
serverHandler.authent(ctx.channel(), (AuthentPacket) packet);
break;
}
// Already done case LocalPacketFactory.STARTUPPACKET:
case LocalPacketFactory.DATAPACKET: {
if (((DataPacket) packet).getPacketRank() % 100 == 1
|| serverHandler.getSession().getState() != R66FiniteDualStates.DATAR) {
serverHandler.getSession().newState(DATAR);
logger.debug("DATA RANK: " + ((DataPacket) packet).getPacketRank() + " : " +
serverHandler.getSession().getRunner().getRank());
}
serverHandler.data(ctx.channel(), (DataPacket) packet);
break;
}
case LocalPacketFactory.VALIDPACKET: {
// SHUTDOWNPACKET does not need authentication
if (((ValidPacket) packet).getTypeValid() != LocalPacketFactory.SHUTDOWNPACKET &&
(!serverHandler.getSession().isAuthenticated())) {
logger.warn("Valid packet received while not authenticated: {} {}", packet,
serverHandler.getSession());
serverHandler.getSession().newState(ERROR);
packet.clear();
throw new OpenR66ProtocolNotAuthenticatedException(
"Not authenticated while Valid received");
}
if (((ValidPacket) packet).getTypeValid() == LocalPacketFactory.REQUESTPACKET) {
String[] fields = ((ValidPacket) packet).getSmiddle().split(
PartnerConfiguration.BAR_SEPARATOR_FIELD);
String newfilename = fields[0];
// potential file size changed
long newSize = -1;
String newFileInfo = null;
if (fields.length > 1) {
try {
newSize = Long.parseLong(fields[1]);
// potential fileInfo changed
if (fields.length > 2) {
newFileInfo = fields[2];
}
} catch (NumberFormatException e2) {
newfilename += PartnerConfiguration.BAR_SEPARATOR_FIELD + fields[1];
newSize = -1;
}
}
if (newFileInfo != null && ! newFileInfo.equals(serverHandler.session.getRunner().getFileInformation())) {
serverHandler.requestChangeFileInfo(ctx.channel(), newFileInfo);
}
serverHandler.requestChangeNameSize(ctx.channel(), newfilename, newSize);
packet.clear();
} else {
serverHandler.valid(ctx.channel(), (ValidPacket) packet);
}
break;
}
case LocalPacketFactory.ERRORPACKET: {
serverHandler.getSession().newState(ERROR);
serverHandler.errorMesg(ctx.channel(), (ErrorPacket) packet);
break;
}
case LocalPacketFactory.CONNECTERRORPACKET: {
serverHandler.connectionError(ctx.channel(),
(ConnectionErrorPacket) packet);
break;
}
case LocalPacketFactory.REQUESTPACKET: {
serverHandler.request((LocalChannel) ctx.channel(), (RequestPacket) packet);
break;
}
case LocalPacketFactory.SHUTDOWNPACKET: {
serverHandler.getSession().newState(SHUTDOWN);
serverHandler.shutdown(ctx.channel(), (ShutdownPacket) packet);
break;
}
case LocalPacketFactory.STOPPACKET:
case LocalPacketFactory.CANCELPACKET:
case LocalPacketFactory.CONFIMPORTPACKET:
case LocalPacketFactory.CONFEXPORTPACKET:
case LocalPacketFactory.BANDWIDTHPACKET: {
logger.error("Unimplemented Mesg: " +
packet.getClass().getName());
serverHandler.getSession().newState(ERROR);
serverHandler.getLocalChannelReference().invalidateRequest(new R66Result(
new OpenR66ProtocolSystemException(
"Not implemented"), serverHandler.getSession(), true,
ErrorCode.Unimplemented, null));
final ErrorPacket errorPacket = new ErrorPacket(
"Unimplemented Mesg: " +
packet.getClass().getName(),
ErrorCode.Unimplemented.getCode(),
ErrorPacket.FORWARDCLOSECODE);
ChannelUtils.writeAbstractLocalPacket(serverHandler.getLocalChannelReference(), errorPacket, true)
.addListener(
new GenericFutureListener<Future<? super Void>>() {
public void operationComplete(Future<? super Void> future) throws Exception {
ctx.close();
}
});
packet.clear();
break;
}
case LocalPacketFactory.TESTPACKET: {
serverHandler.getSession().newState(TEST);
serverHandler.test(ctx.channel(), (TestPacket) packet);
break;
}
case LocalPacketFactory.ENDTRANSFERPACKET: {
serverHandler.endTransfer(ctx.channel(), (EndTransferPacket) packet);
break;
}
case LocalPacketFactory.INFORMATIONPACKET: {
serverHandler.getSession().newState(INFORMATION);
serverHandler.information(ctx.channel(), (InformationPacket) packet);
break;
}
case LocalPacketFactory.ENDREQUESTPACKET: {
serverHandler.endRequest(ctx.channel(), (EndRequestPacket) packet);
break;
}
case LocalPacketFactory.BUSINESSREQUESTPACKET: {
serverHandler.businessRequest(ctx.channel(), (BusinessRequestPacket) packet);
break;
}
case LocalPacketFactory.BLOCKREQUESTPACKET: {
serverHandler.blockRequest(ctx.channel(), (BlockRequestPacket) packet);
break;
}
case LocalPacketFactory.JSONREQUESTPACKET: {
if (!serverHandler.getSession().isAuthenticated()) {
logger.warn("JsonCommand packet received while not authenticated: {} {}", packet,
serverHandler.getSession());
serverHandler.getSession().newState(ERROR);
throw new OpenR66ProtocolNotAuthenticatedException(
"Not authenticated while Valid received");
}
JsonPacket json = ((JsonCommandPacket) packet).getJsonRequest();
if (json == null) {
ErrorCode code = ErrorCode.CommandNotFound;
R66Result resulttest = new R66Result(serverHandler.getSession(), true,
code, serverHandler.getSession().getRunner());
json = new JsonPacket();
json.setComment("Invalid command");
json.setRequestUserPacket(((JsonCommandPacket) packet).getTypeValid());
JsonCommandPacket valid = new JsonCommandPacket(json, resulttest.getCode().getCode(),
LocalPacketFactory.REQUESTUSERPACKET);
resulttest.setOther(packet);
serverHandler.getLocalChannelReference().validateRequest(resulttest);
try {
ChannelUtils.writeAbstractLocalPacket(serverHandler.getLocalChannelReference(),
valid, true);
} catch (OpenR66ProtocolPacketException e2) {
}
serverHandler.getSession().setStatus(99);
ctx.channel().close();
return;
}
json.setRequestUserPacket(((JsonCommandPacket) packet).getTypeValid());
if (((JsonCommandPacket) packet).getTypeValid() == LocalPacketFactory.REQUESTPACKET) {
RequestJsonPacket node = (RequestJsonPacket) json;
String newfilename = node.getFilename();
if (newfilename == null) {
// error so ignore
return;
}
long newSize = node.getFilesize();
String newFileInfo = node.getFileInfo();
logger.debug("NewSize " + newSize + " NewName " + newfilename);
// potential fileInfo changed
if (newFileInfo != null && ! newFileInfo.equals(serverHandler.session.getRunner().getFileInformation())) {
logger.debug("NewSize " + newSize + " NewName " + newfilename + " newFileInfo: " + newFileInfo);
serverHandler.requestChangeFileInfo(ctx.channel(), newFileInfo);
}
// potential file size changed
serverHandler.requestChangeNameSize(ctx.channel(), newfilename, newSize);
} else {
serverHandler.jsonCommand(ctx.channel(), (JsonCommandPacket) packet);
}
break;
}
default: {
logger
.error("Unknown Mesg: " +
packet.getClass().getName());
serverHandler.getSession().newState(ERROR);
serverHandler.getLocalChannelReference().invalidateRequest(new R66Result(
new OpenR66ProtocolSystemException(
"Unknown Message"), serverHandler.getSession(), true,
ErrorCode.Unimplemented, null));
final ErrorPacket errorPacket = new ErrorPacket(
"Unkown Mesg: " + packet.getClass().getName(),
ErrorCode.Unimplemented.getCode(), ErrorPacket.FORWARDCLOSECODE);
ChannelUtils.writeAbstractLocalPacket(serverHandler.getLocalChannelReference(), errorPacket, true)
.addListener(
new GenericFutureListener<Future<? super Void>>() {
public void operationComplete(Future<? super Void> future) throws Exception {
ctx.close();
}
});
packet.clear();
}
}
}
}
@Override
public void exceptionCaught(ChannelHandlerContext ctx, Throwable cause) {
// inform clients
logger.debug("Exception and isFinished: "
+
(serverHandler.getLocalChannelReference() != null && serverHandler.getLocalChannelReference()
.getFutureRequest().isDone()), cause);
if (serverHandler.getLocalChannelReference() != null
&& serverHandler.getLocalChannelReference().getFutureRequest().isDone()) {
ctx.channel().close();
return;
}
OpenR66Exception exception = OpenR66ExceptionTrappedFactory
.getExceptionFromTrappedException(ctx.channel(), cause);
ErrorCode code = null;
if (exception != null) {
serverHandler.getSession().newState(ERROR);
boolean isAnswered = false;
if (exception instanceof OpenR66ProtocolShutdownException) {
R66ShutdownHook.shutdownWillStart();
logger.warn(Messages.getString("LocalServerHandler.0") + //$NON-NLS-1$
serverHandler.getSession().getAuth().getUser());
if (serverHandler.getLocalChannelReference() != null) {
R66Result finalValue = new R66Result(exception, serverHandler.getSession(), true,
ErrorCode.Shutdown, serverHandler.getSession().getRunner());
try {
serverHandler.tryFinalizeRequest(finalValue);
} catch (OpenR66RunnerErrorException e2) {
} catch (OpenR66ProtocolSystemException e2) {
}
if (!serverHandler.getLocalChannelReference().getFutureRequest().isDone()) {
try {
serverHandler.getSession().setFinalizeTransfer(false, finalValue);
} catch (OpenR66RunnerErrorException e1) {
serverHandler.getLocalChannelReference().invalidateRequest(finalValue);
} catch (OpenR66ProtocolSystemException e1) {
serverHandler.getLocalChannelReference().invalidateRequest(finalValue);
}
}
}
// dont'close, thread will do
ChannelUtils.startShutdown();
// set global shutdown info and before close, send a valid
// shutdown to all
serverHandler.getSession().setStatus(54);
return;
} else {
if (serverHandler.getLocalChannelReference() != null
&& serverHandler.getLocalChannelReference().getFutureRequest() != null) {
if (serverHandler.getLocalChannelReference().getFutureRequest().isDone()) {
R66Result result = serverHandler.getLocalChannelReference().getFutureRequest()
.getResult();
if (result != null) {
isAnswered = result.isAnswered();
}
}
}
if (exception instanceof OpenR66ProtocolNoConnectionException) {
code = ErrorCode.ConnectionImpossible;
DbTaskRunner runner = serverHandler.getSession().getRunner();
if (runner != null) {
runner.stopOrCancelRunner(code);
}
} else if (exception instanceof OpenR66ProtocolBusinessCancelException) {
code = ErrorCode.CanceledTransfer;
DbTaskRunner runner = serverHandler.getSession().getRunner();
if (runner != null) {
runner.stopOrCancelRunner(code);
}
} else if (exception instanceof OpenR66ProtocolBusinessStopException) {
code = ErrorCode.StoppedTransfer;
DbTaskRunner runner = serverHandler.getSession().getRunner();
if (runner != null) {
runner.stopOrCancelRunner(code);
}
} else if (exception instanceof OpenR66ProtocolBusinessQueryAlreadyFinishedException) {
code = ErrorCode.QueryAlreadyFinished;
try {
serverHandler.tryFinalizeRequest(new R66Result(serverHandler.getSession(), true, code,
serverHandler.getSession().getRunner()));
ChannelCloseTimer.closeFutureChannel(ctx.channel());
return;
} catch (OpenR66RunnerErrorException e1) {
} catch (OpenR66ProtocolSystemException e1) {
}
} else if (exception instanceof OpenR66ProtocolBusinessQueryStillRunningException) {
code = ErrorCode.QueryStillRunning;
// nothing is to be done
logger.error("Will close channel since ", exception);
ctx.channel().close();
serverHandler.getSession().setStatus(56);
return;
} else if (exception instanceof OpenR66ProtocolBusinessRemoteFileNotFoundException) {
code = ErrorCode.FileNotFound;
} else if (exception instanceof OpenR66RunnerException) {
code = ErrorCode.ExternalOp;
} else if (exception instanceof OpenR66RunnerErrorException) {
code = ErrorCode.ExternalOp;
} else if (exception instanceof OpenR66ProtocolNotAuthenticatedException) {
code = ErrorCode.BadAuthent;
} else if (exception instanceof OpenR66ProtocolNetworkException) {
code = ErrorCode.Disconnection;
DbTaskRunner runner = serverHandler.getSession().getRunner();
if (runner != null) {
R66Result finalValue = new R66Result(
new OpenR66ProtocolSystemException(
Messages.getString("LocalServerHandler.2")), //$NON-NLS-1$
serverHandler.getSession(), true, code, serverHandler.getSession().getRunner());
try {
serverHandler.tryFinalizeRequest(finalValue);
} catch (OpenR66Exception e2) {
}
}
} else if (exception instanceof OpenR66ProtocolRemoteShutdownException) {
code = ErrorCode.RemoteShutdown;
DbTaskRunner runner = serverHandler.getSession().getRunner();
if (runner != null) {
runner.stopOrCancelRunner(code);
}
} else {
DbTaskRunner runner = serverHandler.getSession().getRunner();
if (runner != null) {
switch (runner.getErrorInfo()) {
case InitOk:
case PostProcessingOk:
case PreProcessingOk:
case Running:
case TransferOk:
code = ErrorCode.Internal;
break;
default:
code = runner.getErrorInfo();
}
} else {
code = ErrorCode.Internal;
}
}
if ((!isAnswered) &&
(!(exception instanceof OpenR66ProtocolBusinessNoWriteBackException)) &&
(!(exception instanceof OpenR66ProtocolNoConnectionException))) {
if (code == null || code == ErrorCode.Internal) {
code = ErrorCode.RemoteError;
}
final ErrorPacket errorPacket = new ErrorPacket(exception
.getMessage(),
code.getCode(), ErrorPacket.FORWARDCLOSECODE);
try {
if (serverHandler.getLocalChannelReference() != null) {
ChannelUtils.writeAbstractLocalPacket(serverHandler.getLocalChannelReference(),
errorPacket, true);
}
} catch (OpenR66ProtocolPacketException e1) {
// should not be
}
}
R66Result finalValue =
new R66Result(
exception, serverHandler.getSession(), true, code, serverHandler.getSession()
.getRunner());
try {
serverHandler.getSession().setFinalizeTransfer(false, finalValue);
if (serverHandler.getLocalChannelReference() != null) {
serverHandler.getLocalChannelReference().invalidateRequest(finalValue);
}
} catch (OpenR66RunnerErrorException e1) {
if (serverHandler.getLocalChannelReference() != null)
serverHandler.getLocalChannelReference().invalidateRequest(finalValue);
} catch (OpenR66ProtocolSystemException e1) {
if (serverHandler.getLocalChannelReference() != null)
serverHandler.getLocalChannelReference().invalidateRequest(finalValue);
}
}
if (exception instanceof OpenR66ProtocolBusinessNoWriteBackException) {
logger.error("Will close channel {}", exception.getMessage());
ctx.channel().close();
serverHandler.getSession().setStatus(56);
return;
} else if (exception instanceof OpenR66ProtocolNoConnectionException) {
logger.error("Will close channel {}", exception.getMessage());
ctx.channel().close();
serverHandler.getSession().setStatus(57);
return;
}
serverHandler.getSession().setStatus(58);
ChannelCloseTimer.closeFutureChannel(ctx.channel());
} else {
// Nothing to do
serverHandler.getSession().setStatus(59);
return;
}
}
}