LocalServerHandler.java
/*
* This file is part of Waarp Project (named also Waarp or GG).
*
* Copyright (c) 2019, Waarp SAS, 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 org.waarp.common.logging.WaarpLogger;
import org.waarp.common.logging.WaarpLoggerFactory;
import org.waarp.common.utility.WaarpShutdownHook;
import org.waarp.openr66.context.ErrorCode;
import org.waarp.openr66.context.R66Result;
import org.waarp.openr66.context.R66Session;
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.OpenR66ProtocolNoCorrectAuthenticationException;
import org.waarp.openr66.protocol.exception.OpenR66ProtocolNoDataException;
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.LocalPacketCodec;
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.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.networkhandler.packet.NetworkPacket;
import org.waarp.openr66.protocol.utils.ChannelCloseTimer;
import org.waarp.openr66.protocol.utils.ChannelUtils;
import org.waarp.openr66.protocol.utils.R66Future;
import static org.waarp.openr66.context.R66FiniteDualStates.*;
/**
* The local server handler handles real end file operations.
*/
public final class LocalServerHandler {
/**
* Internal Logger
*/
private static final WaarpLogger logger =
WaarpLoggerFactory.getLogger(LocalServerHandler.class);
private LocalServerHandler() {
}
public static void channelInactive(final TransferActions serverHandler) {
serverHandler.channelClosed();
}
public static void channelActive(final TransferActions serverHandler) {
serverHandler.newSession();
}
/**
* Replacement for local channels
*
* @param localChannelReference
* @param networkPacket
*/
public static void channelRead0(
final LocalChannelReference localChannelReference,
final NetworkPacket networkPacket) {
try {
final AbstractLocalPacket packet =
LocalPacketCodec.decodeNetworkPacket(networkPacket.getBuffer());
channelRead1(localChannelReference, packet);
} catch (final OpenR66ProtocolShutdownException e) {
logger.error(e.getMessage());
exceptionCaught(localChannelReference.getServerHandler(), e);
} catch (final Exception e) {
exceptionCaught(localChannelReference.getServerHandler(), e);
} finally {
networkPacket.clear();
}
}
public static void channelRead0(
final LocalChannelReference localChannelReference,
final AbstractLocalPacket msg) {
try {
channelRead1(localChannelReference, msg);
} catch (final Exception e) {
exceptionCaught(localChannelReference.getServerHandler(), e);
}
}
public static void channelRead1(
final LocalChannelReference localChannelReference,
final AbstractLocalPacket packet) throws Exception {
// action as requested and answer if necessary
final TransferActions serverHandler =
localChannelReference.getServerHandler();
if (packet.getType() == LocalPacketFactory.STARTUPPACKET) {
logger.warn("Error in the protocol: {}", packet.toString());
} 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);
ChannelUtils.writeAbstractLocalPacket(localChannelReference,
errorPacket, false);
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((AuthentPacket) packet,
localChannelReference.getNetworkChannelObject()
.isSSL());
break;
}
// Already done case LocalPacketFactory.STARTUPPACKET:
case LocalPacketFactory.DATAPACKET: {
if (((DataPacket) packet).getPacketRank() % 100 == 1 ||
serverHandler.getSession().getState() != DATAR) {
serverHandler.getSession().newState(DATAR);
logger.debug("DATA RANK: {} : {}",
((DataPacket) packet).getPacketRank(),
serverHandler.getSession().getRunner().getRank());
}
((DataPacket) packet).createByteBufFromRecv(
serverHandler.getSession());
logger.debug("DATA RANK: {} : {} for {} bytes",
((DataPacket) packet).getPacketRank(),
serverHandler.getSession().getRunner().getRank(),
((DataPacket) packet).getLengthPacket());
if (localChannelReference.getSession().isCompressionEnabled()) {
R66Session.getCodec().uncompress(((DataPacket) packet),
serverHandler.getSession());
}
serverHandler.data((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) {
final 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 (final NumberFormatException e2) {
newfilename +=
PartnerConfiguration.BAR_SEPARATOR_FIELD + fields[1];
newSize = -1;
}
}
if (newFileInfo != null && !newFileInfo.equals(
serverHandler.getSession().getRunner().getFileInformation())) {
serverHandler.requestChangeFileInfo(newFileInfo);
}
serverHandler.requestChangeNameSize(newfilename, newSize);
serverHandler.saveAfterChangingFileInfo();
packet.clear();
} else {
serverHandler.valid((ValidPacket) packet);
}
break;
}
case LocalPacketFactory.ERRORPACKET: {
serverHandler.getSession().newState(ERROR);
serverHandler.errorMesg((ErrorPacket) packet);
break;
}
case LocalPacketFactory.CONNECTERRORPACKET: {
serverHandler.connectionError((ConnectionErrorPacket) packet);
break;
}
case LocalPacketFactory.REQUESTPACKET: {
serverHandler.request((RequestPacket) packet);
break;
}
case LocalPacketFactory.SHUTDOWNPACKET: {
serverHandler.getSession().newState(SHUTDOWN);
serverHandler.shutdown((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, false);
packet.clear();
break;
}
case LocalPacketFactory.TESTPACKET: {
serverHandler.getSession().newState(TEST);
serverHandler.test((TestPacket) packet);
break;
}
case LocalPacketFactory.ENDTRANSFERPACKET: {
serverHandler.endTransfer((EndTransferPacket) packet);
break;
}
case LocalPacketFactory.INFORMATIONPACKET: {
serverHandler.getSession().newState(INFORMATION);
serverHandler.information((InformationPacket) packet);
break;
}
case LocalPacketFactory.ENDREQUESTPACKET: {
serverHandler.endRequest((EndRequestPacket) packet);
break;
}
case LocalPacketFactory.BUSINESSREQUESTPACKET: {
serverHandler.businessRequest((BusinessRequestPacket) packet);
break;
}
case LocalPacketFactory.BLOCKREQUESTPACKET: {
serverHandler.blockRequest((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) {
final ErrorCode code = ErrorCode.CommandNotFound;
final R66Result resulttest =
new R66Result(serverHandler.getSession(), true, code,
serverHandler.getSession().getRunner());
json = new JsonPacket();
json.setComment("Invalid command");
json.setRequestUserPacket(
((JsonCommandPacket) packet).getTypeValid());
final JsonCommandPacket valid =
new JsonCommandPacket(json, resulttest.getCode().getCode(),
LocalPacketFactory.REQUESTUSERPACKET);
resulttest.setOther(packet);
serverHandler.getLocalChannelReference()
.validateRequest(resulttest);
try {
ChannelUtils.writeAbstractLocalPacket(
serverHandler.getLocalChannelReference(), valid, false);
} catch (final OpenR66ProtocolPacketException ignored) {
// ignore
}
serverHandler.getSession().setStatus(99);
localChannelReference.close();
return;
}
json.setRequestUserPacket(
((JsonCommandPacket) packet).getTypeValid());
if (((JsonCommandPacket) packet).getTypeValid() ==
LocalPacketFactory.REQUESTPACKET) {
final RequestJsonPacket node = (RequestJsonPacket) json;
final String newfilename = node.getFilename();
if (newfilename == null) {
// error so ignore
return;
}
final long newSize = node.getFilesize();
final String newFileInfo = node.getFileInfo();
logger.debug("NewSize {} NewName {}", newSize, newfilename);
// potential fileInfo changed
if (newFileInfo != null && !newFileInfo.equals(
serverHandler.getSession().getRunner().getFileInformation())) {
logger.debug("NewSize {} NewName {} newFileInfo {}", newSize,
newfilename, newFileInfo);
serverHandler.requestChangeFileInfo(newFileInfo);
}
// potential file size changed
serverHandler.requestChangeNameSize(newfilename, newSize);
serverHandler.saveAfterChangingFileInfo();
} else {
serverHandler.jsonCommand((JsonCommandPacket) packet, json);
}
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, false);
packet.clear();
}
}
}
}
public static void exceptionCaught(final TransferActions serverHandler,
final Throwable cause) {
// inform clients
final R66Future futureRequest =
serverHandler.getLocalChannelReference() != null?
serverHandler.getLocalChannelReference().getFutureRequest() : null;
logger.debug("Exception and isFinished: {}",
(futureRequest != null && futureRequest.isDone()), cause);
if (futureRequest != null && futureRequest.isDone()) {
ChannelCloseTimer.closeFutureTransaction(serverHandler);
return;
}
final OpenR66Exception exception =
OpenR66ExceptionTrappedFactory.getExceptionFromTrappedException(
serverHandler.getLocalChannelReference() != null?
serverHandler.getLocalChannelReference().getNetworkChannel() :
null, cause);
ErrorCode code;
if (exception != null) {
serverHandler.getSession().newState(ERROR);
boolean isAnswered = false;
if (exception instanceof OpenR66ProtocolShutdownException) {
shutdownFromException(serverHandler, exception);
return;
} else {
if (futureRequest != null) {
if (futureRequest.isDone()) {
final R66Result result = futureRequest.getResult();
if (result != null) {
isAnswered = result.isAnswered();
}
}
}
final DbTaskRunner runner = serverHandler.getSession().getRunner();
if (exception instanceof OpenR66ProtocolNoConnectionException) {
code = ErrorCode.ConnectionImpossible;
if (runner != null) {
runner.stopOrCancelRunner(code);
}
} else if (exception instanceof OpenR66ProtocolBusinessCancelException) {
code = ErrorCode.CanceledTransfer;
if (runner != null) {
runner.stopOrCancelRunner(code);
}
} else if (exception instanceof OpenR66ProtocolBusinessStopException) {
code = ErrorCode.StoppedTransfer;
if (runner != null) {
runner.stopOrCancelRunner(code);
}
} else if (exception instanceof OpenR66ProtocolBusinessQueryAlreadyFinishedException) {
code = ErrorCode.QueryAlreadyFinished;
try {
serverHandler.tryFinalizeRequest(
new R66Result(serverHandler.getSession(), true, code, runner));
ChannelCloseTimer.closeFutureTransaction(serverHandler);
return;
} catch (final OpenR66RunnerErrorException ignored) {
// nothing
} catch (final OpenR66ProtocolSystemException ignored) {
// nothing
}
} else if (exception instanceof OpenR66ProtocolBusinessQueryStillRunningException) {
code = ErrorCode.QueryStillRunning;
// nothing is to be done
logger.error("Will close channel since ", exception);
serverHandler.getLocalChannelReference().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;
isAnswered = true;
} else if (exception instanceof OpenR66ProtocolNoCorrectAuthenticationException) {
code = ErrorCode.BadAuthent;
} else if (exception instanceof OpenR66ProtocolNetworkException) {
code = ErrorCode.Disconnection;
if (runner != null) {
final R66Result finalValue = new R66Result(
new OpenR66ProtocolSystemException(
Messages.getString("LocalServerHandler.2")),
//$NON-NLS-1$
serverHandler.getSession(), true, code, runner);
try {
serverHandler.tryFinalizeRequest(finalValue);
} catch (final OpenR66Exception ignored) {
// nothing
}
}
} else if (exception instanceof OpenR66ProtocolRemoteShutdownException) {
code = ErrorCode.RemoteShutdown;
if (runner != null) {
runner.stopOrCancelRunner(code);
}
} else if (exception instanceof OpenR66ProtocolNoDataException) {
code = ErrorCode.FileNotFound;
} else {
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, false);
}
} catch (final OpenR66ProtocolPacketException e1) {
// should not be
}
}
if (Configuration.configuration.getR66Mib() != null) {
Configuration.configuration.getR66Mib().notifyError(
"Transfer in error since " + exception.getMessage(),
code != null? code.getMesg() : "Unknown Error");
}
final R66Result finalValue =
new R66Result(exception, serverHandler.getSession(), true, code,
runner);
try {
serverHandler.getSession().setFinalizeTransfer(false, finalValue);
if (serverHandler.getLocalChannelReference() != null) {
serverHandler.getLocalChannelReference()
.invalidateRequest(finalValue);
}
} catch (final OpenR66RunnerErrorException e1) {
if (serverHandler.getLocalChannelReference() != null) {
serverHandler.getLocalChannelReference()
.invalidateRequest(finalValue);
}
} catch (final OpenR66ProtocolSystemException e1) {
if (serverHandler.getLocalChannelReference() != null) {
serverHandler.getLocalChannelReference()
.invalidateRequest(finalValue);
}
}
}
if (exception instanceof OpenR66ProtocolBusinessNoWriteBackException) {
logger.error("Will close channel {}", exception.getMessage());
ChannelCloseTimer.closeFutureTransaction(serverHandler);
serverHandler.getSession().setStatus(56);
return;
} else if (exception instanceof OpenR66ProtocolNoConnectionException) {
logger.error("Will close channel {}", exception.getMessage());
ChannelCloseTimer.closeFutureTransaction(serverHandler);
serverHandler.getSession().setStatus(57);
return;
}
serverHandler.getSession().setStatus(58);
ChannelCloseTimer.closeFutureTransaction(serverHandler);
} else {
// Nothing to do
serverHandler.getSession().setStatus(59);
}
}
private static void shutdownFromException(final TransferActions serverHandler,
final OpenR66Exception exception) {
WaarpShutdownHook.shutdownWillStart();
logger.warn(Messages.getString("LocalServerHandler.0") +
//$NON-NLS-1$
serverHandler.getSession().getAuth().getUser());
if (serverHandler.getLocalChannelReference() != null) {
final R66Result finalValue =
new R66Result(exception, serverHandler.getSession(), true,
ErrorCode.Shutdown,
serverHandler.getSession().getRunner());
try {
serverHandler.tryFinalizeRequest(finalValue);
} catch (final OpenR66RunnerErrorException ignored) {
// ignore
} catch (final OpenR66ProtocolSystemException ignored) {
// ignore
}
if (!serverHandler.getLocalChannelReference().getFutureRequest()
.isDone()) {
try {
serverHandler.getSession().setFinalizeTransfer(false, finalValue);
} catch (final OpenR66RunnerErrorException e1) {
serverHandler.getLocalChannelReference()
.invalidateRequest(finalValue);
} catch (final 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);
}
}