View Javadoc
1   /*
2    * This file is part of Waarp Project (named also Waarp or GG).
3    *
4    *  Copyright (c) 2019, Waarp SAS, and individual contributors by the @author
5    *  tags. See the COPYRIGHT.txt in the distribution for a full listing of
6    * individual contributors.
7    *
8    *  All Waarp Project is free software: you can redistribute it and/or
9    * modify it under the terms of the GNU General Public License as published by
10   * the Free Software Foundation, either version 3 of the License, or (at your
11   * option) any later version.
12   *
13   * Waarp is distributed in the hope that it will be useful, but WITHOUT ANY
14   * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR
15   * A PARTICULAR PURPOSE. See the GNU General Public License for more details.
16   *
17   *  You should have received a copy of the GNU General Public License along with
18   * Waarp . If not, see <http://www.gnu.org/licenses/>.
19   */
20  package org.waarp.openr66.protocol.localhandler;
21  
22  import com.fasterxml.jackson.databind.node.ArrayNode;
23  import com.fasterxml.jackson.databind.node.ObjectNode;
24  import org.waarp.common.command.exception.CommandAbstractException;
25  import org.waarp.common.database.DbPreparedStatement;
26  import org.waarp.common.database.DbSession;
27  import org.waarp.common.database.data.AbstractDbData;
28  import org.waarp.common.database.exception.WaarpDatabaseException;
29  import org.waarp.common.database.exception.WaarpDatabaseNoConnectionException;
30  import org.waarp.common.database.exception.WaarpDatabaseNoDataException;
31  import org.waarp.common.database.exception.WaarpDatabaseSqlException;
32  import org.waarp.common.exception.FileTransferException;
33  import org.waarp.common.file.DirInterface;
34  import org.waarp.common.file.FileUtils;
35  import org.waarp.common.json.JsonHandler;
36  import org.waarp.common.logging.SysErrLogger;
37  import org.waarp.common.logging.WaarpLogger;
38  import org.waarp.common.logging.WaarpLoggerFactory;
39  import org.waarp.common.role.RoleDefault.ROLE;
40  import org.waarp.common.utility.ParametersChecker;
41  import org.waarp.common.utility.WaarpShutdownHook;
42  import org.waarp.common.utility.WaarpStringUtils;
43  import org.waarp.openr66.client.AbstractTransfer;
44  import org.waarp.openr66.configuration.AuthenticationFileBasedConfiguration;
45  import org.waarp.openr66.configuration.RuleFileBasedConfiguration;
46  import org.waarp.openr66.context.ErrorCode;
47  import org.waarp.openr66.context.R66Result;
48  import org.waarp.openr66.context.filesystem.R66File;
49  import org.waarp.openr66.context.task.ExecJavaTask;
50  import org.waarp.openr66.context.task.exception.OpenR66RunnerErrorException;
51  import org.waarp.openr66.database.data.DbHostAuth;
52  import org.waarp.openr66.database.data.DbHostConfiguration;
53  import org.waarp.openr66.database.data.DbRule;
54  import org.waarp.openr66.database.data.DbTaskRunner;
55  import org.waarp.openr66.pojo.Transfer;
56  import org.waarp.openr66.pojo.UpdatedInfo;
57  import org.waarp.openr66.protocol.configuration.Configuration;
58  import org.waarp.openr66.protocol.configuration.Messages;
59  import org.waarp.openr66.protocol.configuration.PartnerConfiguration;
60  import org.waarp.openr66.protocol.exception.OpenR66DatabaseGlobalException;
61  import org.waarp.openr66.protocol.exception.OpenR66ProtocolBusinessException;
62  import org.waarp.openr66.protocol.exception.OpenR66ProtocolBusinessRemoteFileNotFoundException;
63  import org.waarp.openr66.protocol.exception.OpenR66ProtocolNoCorrectAuthenticationException;
64  import org.waarp.openr66.protocol.exception.OpenR66ProtocolNoDataException;
65  import org.waarp.openr66.protocol.exception.OpenR66ProtocolNoSslException;
66  import org.waarp.openr66.protocol.exception.OpenR66ProtocolNotAuthenticatedException;
67  import org.waarp.openr66.protocol.exception.OpenR66ProtocolPacketException;
68  import org.waarp.openr66.protocol.exception.OpenR66ProtocolShutdownException;
69  import org.waarp.openr66.protocol.exception.OpenR66ProtocolSystemException;
70  import org.waarp.openr66.protocol.localhandler.packet.BlockRequestPacket;
71  import org.waarp.openr66.protocol.localhandler.packet.BusinessRequestPacket;
72  import org.waarp.openr66.protocol.localhandler.packet.ErrorPacket;
73  import org.waarp.openr66.protocol.localhandler.packet.InformationPacket;
74  import org.waarp.openr66.protocol.localhandler.packet.JsonCommandPacket;
75  import org.waarp.openr66.protocol.localhandler.packet.LocalPacketFactory;
76  import org.waarp.openr66.protocol.localhandler.packet.RequestPacket;
77  import org.waarp.openr66.protocol.localhandler.packet.ShutdownPacket;
78  import org.waarp.openr66.protocol.localhandler.packet.TestPacket;
79  import org.waarp.openr66.protocol.localhandler.packet.ValidPacket;
80  import org.waarp.openr66.protocol.localhandler.packet.json.BandwidthJsonPacket;
81  import org.waarp.openr66.protocol.localhandler.packet.json.BusinessRequestJsonPacket;
82  import org.waarp.openr66.protocol.localhandler.packet.json.ConfigExportJsonPacket;
83  import org.waarp.openr66.protocol.localhandler.packet.json.ConfigExportResponseJsonPacket;
84  import org.waarp.openr66.protocol.localhandler.packet.json.ConfigImportJsonPacket;
85  import org.waarp.openr66.protocol.localhandler.packet.json.ConfigImportResponseJsonPacket;
86  import org.waarp.openr66.protocol.localhandler.packet.json.InformationJsonPacket;
87  import org.waarp.openr66.protocol.localhandler.packet.json.JsonPacket;
88  import org.waarp.openr66.protocol.localhandler.packet.json.LogJsonPacket;
89  import org.waarp.openr66.protocol.localhandler.packet.json.LogResponseJsonPacket;
90  import org.waarp.openr66.protocol.localhandler.packet.json.RestartTransferJsonPacket;
91  import org.waarp.openr66.protocol.localhandler.packet.json.ShutdownOrBlockJsonPacket;
92  import org.waarp.openr66.protocol.localhandler.packet.json.ShutdownRequestJsonPacket;
93  import org.waarp.openr66.protocol.localhandler.packet.json.StopOrCancelJsonPacket;
94  import org.waarp.openr66.protocol.localhandler.packet.json.TransferRequestJsonPacket;
95  import org.waarp.openr66.protocol.networkhandler.NetworkChannelReference;
96  import org.waarp.openr66.protocol.networkhandler.NetworkTransaction;
97  import org.waarp.openr66.protocol.utils.ChannelCloseTimer;
98  import org.waarp.openr66.protocol.utils.ChannelUtils;
99  import org.waarp.openr66.protocol.utils.NbAndSpecialId;
100 import org.waarp.openr66.protocol.utils.R66Future;
101 import org.waarp.openr66.protocol.utils.TransferUtils;
102 
103 import java.io.File;
104 import java.io.FileOutputStream;
105 import java.io.IOException;
106 import java.sql.Timestamp;
107 import java.text.ParseException;
108 import java.text.SimpleDateFormat;
109 import java.util.Date;
110 import java.util.List;
111 
112 import static org.waarp.common.database.DbConstant.*;
113 import static org.waarp.openr66.client.RequestInformation.*;
114 import static org.waarp.openr66.context.R66FiniteDualStates.*;
115 
116 /**
117  * Class to implement actions related to extra server actions: shutdown,
118  * bandwidth control, configuration
119  * import/export, log purge, request restart/stop/cancel, business request,
120  * block new request control,
121  * information request and transfer request.
122  * <p>
123  * Can be used in both standard mode (original packet), or in JSON mode.
124  */
125 public class ServerActions extends ConnectionActions {
126   private static final String FILE_IS_NOT_FOUND = "File is not found: ";
127   private static final String RUNNER_TASK_IS_NOT_FOUND =
128       "RunnerTask is not found: ";
129   private static final String
130       NOT_CORRECTLY_AUTHENTICATED_SINCE_SSL_IS_NOT_SUPPORTED =
131       "Not correctly authenticated since SSL is not supported";
132   private static final String NOT_CORRECTLY_AUTHENTICATED =
133       "Not correctly authenticated";
134   /**
135    * Internal Logger
136    */
137   private static final WaarpLogger logger =
138       WaarpLoggerFactory.getLogger(ServerActions.class);
139 
140   public ServerActions() {
141     // nothing
142   }
143 
144   /**
145    * Test reception
146    *
147    * @param packet
148    *
149    * @throws OpenR66ProtocolNotAuthenticatedException
150    * @throws OpenR66ProtocolPacketException
151    */
152   public final void test(final TestPacket packet)
153       throws OpenR66ProtocolNotAuthenticatedException,
154              OpenR66ProtocolPacketException {
155     if (!session.isAuthenticated()) {
156       throw new OpenR66ProtocolNotAuthenticatedException(
157           "Not authenticated while Test received");
158     }
159     // simply write back after+1
160     packet.update();
161     if (packet.getType() == LocalPacketFactory.VALIDPACKET) {
162       final ValidPacket validPacket = new ValidPacket(packet.toString(), null,
163                                                       LocalPacketFactory.TESTPACKET);
164       final R66Result result =
165           new R66Result(session, true, ErrorCode.CompleteOk, null);
166       result.setOther(validPacket);
167       session.newState(VALIDOTHER);
168       localChannelReference.validateRequest(result);
169       ChannelUtils.writeAbstractLocalPacket(localChannelReference, validPacket,
170                                             false);
171       logger.warn(
172           "Valid TEST MESSAGE from " + session.getAuth().getUser() + " [" +
173           localChannelReference.getNetworkChannel().remoteAddress() + "] Msg=" +
174           packet);
175       ChannelCloseTimer.closeFutureTransaction(
176           localChannelReference.getServerHandler());
177       packet.clear();
178     } else {
179       ChannelUtils.writeAbstractLocalPacket(localChannelReference, packet,
180                                             false);
181     }
182   }
183 
184   /**
185    * Receive a request of information
186    *
187    * @param packet
188    *
189    * @throws CommandAbstractException
190    * @throws OpenR66ProtocolNotAuthenticatedException
191    * @throws OpenR66ProtocolNoDataException
192    * @throws OpenR66ProtocolPacketException
193    */
194   public final void information(final InformationPacket packet)
195       throws OpenR66ProtocolNotAuthenticatedException,
196              OpenR66ProtocolNoDataException, OpenR66ProtocolPacketException {
197     final byte request = packet.getRequest();
198     final String rulename = packet.getRulename();
199     final String filename = packet.getFilename();
200     packet.clear();
201     long id = ILLEGALVALUE;
202     if (request == REQUEST_CHECK) {
203       try {
204         id = Long.parseLong(rulename);
205       } catch (final NumberFormatException e) {
206         logger.error("Incorrect Transfer ID: {}", e.getMessage());
207         throw new OpenR66ProtocolNoDataException("Incorrect Transfer ID", e);
208       }
209     }
210     final boolean isTo = "1".equals(filename);
211     final ValidPacket validPacket;
212     if (request == REQUEST_CHECK) {
213       validPacket = informationRequest(id, isTo, rulename, false);
214     } else {
215       validPacket = informationFile(request, rulename, filename, false);
216     }
217     if (validPacket != null) {
218       ChannelUtils.writeAbstractLocalPacket(localChannelReference, validPacket,
219                                             false);
220       localChannelReference.close();
221     } else {
222       session.newState(ERROR);
223       final ErrorPacket error =
224           new ErrorPacket("Error while Request " + request,
225                           ErrorCode.Internal.getCode(),
226                           ErrorPacket.FORWARDCLOSECODE);
227       ChannelUtils.writeAbstractLocalPacket(localChannelReference, error,
228                                             false);
229       ChannelCloseTimer.closeFutureTransaction(
230           localChannelReference.getServerHandler());
231     }
232   }
233 
234   /**
235    * Receive a validation or a special request
236    *
237    * @param packet
238    *
239    * @throws OpenR66ProtocolNotAuthenticatedException
240    * @throws OpenR66RunnerErrorException
241    * @throws OpenR66ProtocolSystemException
242    * @throws OpenR66ProtocolBusinessException
243    */
244   public final void valid(final ValidPacket packet)
245       throws OpenR66ProtocolNotAuthenticatedException,
246              OpenR66RunnerErrorException, OpenR66ProtocolSystemException,
247              OpenR66ProtocolBusinessException {
248     // SHUTDOWNPACKET does not need authentication
249     if (packet.getTypeValid() != LocalPacketFactory.SHUTDOWNPACKET &&
250         !session.isAuthenticated()) {
251       logger.warn("Valid packet received while not authenticated: {} {}",
252                   packet, session);
253       session.newState(ERROR);
254       packet.clear();
255       throw new OpenR66ProtocolNotAuthenticatedException(
256           "Not authenticated while Valid received");
257     }
258     switch (packet.getTypeValid()) {
259       case LocalPacketFactory.SHUTDOWNPACKET: {
260         shutdownPacket(packet);
261         break;
262       }
263       case LocalPacketFactory.STOPPACKET:
264       case LocalPacketFactory.CANCELPACKET: {
265         stopOrCancelPacket(packet);
266         break;
267       }
268       case LocalPacketFactory.VALIDPACKET: {
269         validPacket(packet);
270         break;
271       }
272       case LocalPacketFactory.REQUESTUSERPACKET: {
273         requestUserPacket(packet);
274         break;
275       }
276       case LocalPacketFactory.LOGPACKET:
277       case LocalPacketFactory.LOGPURGEPACKET: {
278         logPacket(packet);
279         break;
280       }
281       case LocalPacketFactory.CONFEXPORTPACKET: {
282         configExportPacket(packet);
283         break;
284       }
285       case LocalPacketFactory.CONFIMPORTPACKET: {
286         configImportPacket(packet);
287         break;
288       }
289       case LocalPacketFactory.INFORMATIONPACKET: {
290         session.newState(VALIDOTHER);
291         // Validate user request
292         final R66Result resulttest =
293             new R66Result(session, true, ErrorCode.CompleteOk, null);
294         resulttest.setOther(packet);
295         localChannelReference.validateRequest(resulttest);
296         localChannelReference.close();
297         break;
298       }
299       case LocalPacketFactory.BANDWIDTHPACKET: {
300         bandwidthPacket(packet);
301         break;
302       }
303       case LocalPacketFactory.TESTPACKET: {
304         session.newState(VALIDOTHER);
305         logger.info("Valid TEST MESSAGE: {}", packet);
306         final R66Result resulttest =
307             new R66Result(session, true, ErrorCode.CompleteOk, null);
308         resulttest.setOther(packet);
309         localChannelReference.validateRequest(resulttest);
310         localChannelReference.close();
311         break;
312       }
313       default:
314         logger.info("Validation is ignored: {}", packet.getTypeValid());
315         packet.clear();
316     }
317   }
318 
319   private void bandwidthPacket(final ValidPacket packet)
320       throws OpenR66ProtocolNotAuthenticatedException,
321              OpenR66ProtocolNoCorrectAuthenticationException {
322     final String[] splitglobal = packet.getSheader().split(" ");
323     final String[] splitsession = packet.getSmiddle().split(" ");
324     packet.clear();
325     final R66Result result =
326         new R66Result(session, true, ErrorCode.CompleteOk, null);
327     final ValidPacket valid;
328     if (splitglobal.length < 2 || splitsession.length < 2) {
329       // request of current values
330       session.newState(VALIDOTHER);
331       final long[] lresult = bandwidth(false, 0, 0, 0, 0);
332       // Now answer
333       valid = new ValidPacket(
334           lresult[0] + " " + lresult[1] + ' ' + lresult[2] + ' ' + lresult[3],
335           result.getCode().getCode(), LocalPacketFactory.REQUESTUSERPACKET);
336     } else {
337       session.newState(VALIDOTHER);
338       bandwidth(true, Long.parseLong(splitglobal[0]),
339                 Long.parseLong(splitglobal[1]), Long.parseLong(splitsession[0]),
340                 Long.parseLong(splitsession[1]));
341       // Now answer
342       valid = new ValidPacket("Bandwidth changed", result.getCode().getCode(),
343                               LocalPacketFactory.REQUESTUSERPACKET);
344     }
345     localChannelReference.validateRequest(result);
346     try {
347       ChannelUtils.writeAbstractLocalPacket(localChannelReference, valid,
348                                             false);
349     } catch (final OpenR66ProtocolPacketException ignored) {
350       // nothing
351     }
352     localChannelReference.close();
353   }
354 
355   private void configImportPacket(final ValidPacket packet)
356       throws OpenR66ProtocolNotAuthenticatedException,
357              OpenR66ProtocolNoCorrectAuthenticationException,
358              OpenR66ProtocolSystemException {
359     session.newState(VALIDOTHER);
360     // Authentication must be the local server or CONFIGADMIN authorization
361     try {
362       if (!session.getAuth().getUser().equals(
363           Configuration.configuration.getHostId(session.getAuth().isSsl())) &&
364           !session.getAuth().isValidRole(ROLE.CONFIGADMIN)) {
365         throw new OpenR66ProtocolNoCorrectAuthenticationException(
366             NOT_CORRECTLY_AUTHENTICATED);
367       }
368     } catch (final OpenR66ProtocolNoSslException e1) {
369       throw new OpenR66ProtocolNotAuthenticatedException(
370           NOT_CORRECTLY_AUTHENTICATED_SINCE_SSL_IS_NOT_SUPPORTED, e1);
371     }
372     if (Configuration.configuration.getR66Mib() != null) {
373       Configuration.configuration.getR66Mib().notifyWarning(
374           "Import Configuration Order received", session.getAuth().getUser());
375     }
376     String shost = packet.getSheader();
377     String srule = packet.getSmiddle();
378     final boolean bhostPurge = shost.startsWith("1 ");
379     shost = shost.substring(2);
380     final boolean brulePurge = srule.startsWith("1 ");
381     srule = srule.substring(2);
382     boolean bhost = !shost.isEmpty();
383     boolean brule = !srule.isEmpty();
384     packet.clear();
385     if (bhost) {
386       DbHostAuth[] oldHosts = null;
387       if (bhostPurge) {
388         // Need to first delete all entries
389         try {
390           oldHosts = DbHostAuth.deleteAll();
391         } catch (final WaarpDatabaseException e) {
392           // ignore
393         }
394       }
395       final String filename = shost;
396       if (AuthenticationFileBasedConfiguration.loadAuthentication(
397           Configuration.configuration, filename)) {
398         shost = "Host:OK";
399       } else {
400         logger.error("Error in Load Hosts");
401         shost = "Host:KO";
402         bhost = false;
403       }
404       if (!bhost && oldHosts != null) {
405         for (final DbHostAuth dbHost : oldHosts) {
406           try {
407             if (!dbHost.exist()) {
408               dbHost.insert();
409             }
410           } catch (final WaarpDatabaseException e1) {
411             // ignore
412           }
413         }
414       }
415     }
416     if (brule) {
417       DbRule[] oldRules = null;
418       if (brulePurge) {
419         // Need to first delete all entries
420         try {
421           oldRules = DbRule.deleteAll();
422         } catch (final WaarpDatabaseException e) {
423           // ignore
424         }
425       }
426       final File file = new File(srule);
427       try {
428         RuleFileBasedConfiguration.getMultipleFromFile(file);
429         srule = "Rule:OK";
430         brule = true;
431       } catch (final WaarpDatabaseNoConnectionException e) {
432         logger.error("Error: {}", e.getMessage());
433         srule = "Rule:KO";
434         brule = false;
435       } catch (final WaarpDatabaseSqlException e) {
436         logger.error("Error", e);
437         srule = "Rule:KO";
438         brule = false;
439       } catch (final WaarpDatabaseNoDataException e) {
440         logger.error("Error", e);
441         srule = "Rule:KO";
442         brule = false;
443       } catch (final WaarpDatabaseException e) {
444         logger.error("Error", e);
445         srule = "Rule:KO";
446         brule = false;
447       }
448       if (!brule && oldRules != null) {
449         for (final DbRule dbRule : oldRules) {
450           try {
451             if (!dbRule.exist()) {
452               dbRule.insert();
453             }
454           } catch (final WaarpDatabaseException e1) {
455             // ignore
456           }
457         }
458       }
459     }
460     final R66Result result;
461     if (brule || bhost) {
462       result = new R66Result(session, true, ErrorCode.CompleteOk, null);
463     } else {
464       result = new R66Result(session, true, ErrorCode.TransferError, null);
465     }
466     // Now answer
467     final ValidPacket valid =
468         new ValidPacket(shost + ' ' + srule, result.getCode().getCode(),
469                         LocalPacketFactory.REQUESTUSERPACKET);
470     localChannelReference.validateRequest(result);
471     try {
472       ChannelUtils.writeAbstractLocalPacket(localChannelReference, valid,
473                                             false);
474     } catch (final OpenR66ProtocolPacketException ignored) {
475       // nothing
476     }
477     localChannelReference.close();
478   }
479 
480   private void configExportPacket(final ValidPacket packet)
481       throws OpenR66ProtocolNotAuthenticatedException,
482              OpenR66ProtocolNoCorrectAuthenticationException {
483     final String shost = packet.getSheader();
484     final String srule = packet.getSmiddle();
485     final boolean bhost = Boolean.parseBoolean(shost);
486     final boolean brule = Boolean.parseBoolean(srule);
487     packet.clear();
488     session.newState(VALIDOTHER);
489     final String[] sresult = configExport(bhost, brule, false, false, false);
490     final R66Result result;
491     if (sresult[0] != null || sresult[1] != null) {
492       result = new R66Result(session, true, ErrorCode.CompleteOk, null);
493     } else {
494       result = new R66Result(session, true, ErrorCode.TransferError, null);
495     }
496     // Now answer
497     final ValidPacket valid =
498         new ValidPacket(shost + ' ' + srule, result.getCode().getCode(),
499                         LocalPacketFactory.REQUESTUSERPACKET);
500     localChannelReference.validateRequest(result);
501     try {
502       ChannelUtils.writeAbstractLocalPacket(localChannelReference, valid,
503                                             false);
504     } catch (final OpenR66ProtocolPacketException ignored) {
505       // ignore
506     }
507     localChannelReference.close();
508   }
509 
510   private void logPacket(final ValidPacket packet)
511       throws OpenR66ProtocolBusinessException {
512     session.newState(VALIDOTHER);
513     // should be from the local server or from an authorized hosts: LOGCONTROL
514     try {
515       if (!session.getAuth().getUser().equals(
516           Configuration.configuration.getHostId(session.getAuth().isSsl())) &&
517           !session.getAuth().isValidRole(ROLE.LOGCONTROL)) {
518         throw new OpenR66ProtocolNoCorrectAuthenticationException(
519             NOT_CORRECTLY_AUTHENTICATED);
520       }
521     } catch (final OpenR66ProtocolNoSslException e1) {
522       throw new OpenR66ProtocolNotAuthenticatedException(
523           NOT_CORRECTLY_AUTHENTICATED_SINCE_SSL_IS_NOT_SUPPORTED, e1);
524     }
525     final String sstart = packet.getSheader();
526     final String sstop = packet.getSmiddle();
527     final boolean isPurge =
528         packet.getTypeValid() == LocalPacketFactory.LOGPURGEPACKET;
529     final Timestamp start =
530         ParametersChecker.isEmpty(sstart)? null : Timestamp.valueOf(sstart);
531     final Timestamp stop =
532         ParametersChecker.isEmpty(sstop)? null : Timestamp.valueOf(sstop);
533     packet.clear();
534     // create export of log and optionally purge them from database
535     final String filename = Configuration.configuration.getBaseDirectory() +
536                             Configuration.configuration.getArchivePath() +
537                             DirInterface.SEPARATOR +
538                             Configuration.configuration.getHostId() + '_' +
539                             System.currentTimeMillis() + "_runners.xml";
540     DbPreparedStatement statement = null;
541     try {
542       statement = DbTaskRunner.getLogPrepareStatement(
543           localChannelReference.getDbSession(), start, stop);
544       DbTaskRunner.writeXMLWriter(statement, filename);
545     } catch (final WaarpDatabaseNoConnectionException e) {
546       throw new OpenR66ProtocolBusinessException(e);
547     } catch (final WaarpDatabaseSqlException e) {
548       throw new OpenR66ProtocolBusinessException(e);
549     } finally {
550       if (statement != null) {
551         statement.realClose();
552       }
553     }
554     // in case of purge
555     int nb = 0;
556     if (isPurge) {
557       // purge in same interval all runners with globallaststep
558       // as ALLDONETASK or ERRORTASK
559       if (Configuration.configuration.getR66Mib() != null) {
560         Configuration.configuration.getR66Mib()
561                                    .notifyWarning("Purge Log Order received",
562                                                   session.getAuth().getUser());
563       }
564       try {
565         nb = DbTaskRunner.purgeLogPrepareStatement(
566             localChannelReference.getDbSession(), start, stop);
567       } catch (final WaarpDatabaseNoConnectionException e) {
568         throw new OpenR66ProtocolBusinessException(e);
569       } catch (final WaarpDatabaseSqlException e) {
570         throw new OpenR66ProtocolBusinessException(e);
571       }
572     }
573     final R66Result result =
574         new R66Result(session, true, ErrorCode.CompleteOk, null);
575     // Now answer
576     final ValidPacket valid =
577         new ValidPacket(filename + ' ' + nb, result.getCode().getCode(),
578                         LocalPacketFactory.REQUESTUSERPACKET);
579     localChannelReference.validateRequest(result);
580     try {
581       ChannelUtils.writeAbstractLocalPacket(localChannelReference, valid,
582                                             false);
583     } catch (final OpenR66ProtocolPacketException ignored) {
584       // ignore
585     }
586     localChannelReference.close();
587   }
588 
589   private void requestUserPacket(final ValidPacket packet) {
590     session.newState(VALIDOTHER);
591     // Validate user request
592     final R66Result resulttest =
593         new R66Result(session, true, ErrorCode.getFromCode(packet.getSmiddle()),
594                       null);
595     resulttest.setOther(packet);
596     switch (resulttest.getCode()) {
597       case CompleteOk:
598       case InitOk:
599       case PostProcessingOk:
600       case PreProcessingOk:
601       case QueryAlreadyFinished:
602       case QueryStillRunning:
603       case Running:
604       case TransferOk:
605         break;
606       default:
607         localChannelReference.invalidateRequest(resulttest);
608         session.setStatus(102);
609         localChannelReference.close();
610         return;
611     }
612     localChannelReference.validateRequest(resulttest);
613     session.setStatus(28);
614     localChannelReference.close();
615   }
616 
617   private void validPacket(final ValidPacket packet)
618       throws OpenR66ProtocolNotAuthenticatedException,
619              OpenR66ProtocolNoCorrectAuthenticationException {
620     // header = ?; middle = requested+blank+requester+blank+specialId
621     // note: might contains one more argument = time to reschedule in yyyyMMddHHmmss format
622     final String[] keys = packet.getSmiddle().split(" ");
623     final ValidPacket valid;
624     if (keys.length < 3) {
625       // not enough args
626       valid = new ValidPacket(packet.getSmiddle(),
627                               ErrorCode.IncorrectCommand.getCode(),
628                               LocalPacketFactory.REQUESTUSERPACKET);
629       final R66Result resulttest = new R66Result(
630           new OpenR66ProtocolBusinessRemoteFileNotFoundException(
631               "Not enough arguments"), session, true,
632           ErrorCode.IncorrectCommand, null);
633       resulttest.setOther(packet);
634       localChannelReference.invalidateRequest(resulttest);
635     } else {
636       final long id = Long.parseLong(keys[2]);
637       Date date = null;
638       if (keys.length > 3) {
639         // time to reschedule in yyyyMMddHHmmss format
640         logger.debug("Debug: restart with {}", keys[3]);
641         final SimpleDateFormat dateFormat =
642             new SimpleDateFormat(AbstractTransfer.TIMESTAMP_FORMAT);
643         try {
644           date = dateFormat.parse(keys[3]);
645         } catch (final ParseException ignored) {
646           // ignore
647         }
648       }
649       session.newState(VALIDOTHER);
650       final R66Result result = requestRestart(keys[0], keys[1], id, date);
651       valid = new ValidPacket(packet.getSmiddle(), result.getCode().getCode(),
652                               LocalPacketFactory.REQUESTUSERPACKET);
653       result.setOther(packet);
654       if (isCodeValid(result.getCode())) {
655         localChannelReference.validateRequest(result);
656       } else {
657         localChannelReference.invalidateRequest(result);
658       }
659     }
660     // inform back the requester
661     try {
662       ChannelUtils.writeAbstractLocalPacket(localChannelReference, valid,
663                                             false);
664     } catch (final OpenR66ProtocolPacketException ignored) {
665       // ignore
666     }
667     localChannelReference.close();
668   }
669 
670   private void stopOrCancelPacket(final ValidPacket packet)
671       throws OpenR66ProtocolNotAuthenticatedException,
672              OpenR66ProtocolNoCorrectAuthenticationException {
673     final String[] keys = packet.getSmiddle().split(" ");
674     final long id = Long.parseLong(keys[2]);
675     session.newState(VALIDOTHER);
676     final R66Result resulttest =
677         stopOrCancel(packet.getTypeValid(), keys[0], keys[1], id);
678     // inform back the requester
679     final ValidPacket valid =
680         new ValidPacket(packet.getSmiddle(), resulttest.getCode().getCode(),
681                         LocalPacketFactory.REQUESTUSERPACKET);
682     resulttest.setOther(packet);
683     localChannelReference.validateRequest(resulttest);
684     try {
685       ChannelUtils.writeAbstractLocalPacket(localChannelReference, valid,
686                                             false);
687     } catch (final OpenR66ProtocolPacketException ignored) {
688       // ignore
689     }
690     session.setStatus(27);
691     localChannelReference.close();
692   }
693 
694   private void shutdownPacket(final ValidPacket packet)
695       throws OpenR66RunnerErrorException, OpenR66ProtocolSystemException {
696     int rank = -1;
697     if (session.getRunner() != null && session.getRunner().isInTransfer()) {
698       final String srank = packet.getSmiddle();
699       if (ParametersChecker.isNotEmpty(srank)) {
700         // Save last rank from remote point of view
701         try {
702           rank = Integer.parseInt(srank);
703         } catch (final NumberFormatException e) {
704           // ignore
705         }
706       }
707     }
708     final R66Result result =
709         new R66Result(new OpenR66ProtocolShutdownException(), session, true,
710                       ErrorCode.Shutdown, session.getRunner());
711     result.setOther(packet);
712     rank = shutdownRequest(result, rank);
713     if (rank >= 0) {
714       packet.setSmiddle(Integer.toString(rank));
715       try {
716         ChannelUtils.writeAbstractLocalPacket(localChannelReference, packet,
717                                               false);
718       } catch (final OpenR66ProtocolPacketException ignored) {
719         // ignore
720       }
721     }
722     shutdownLocalChannel();
723   }
724 
725   /**
726    * Receive a json request
727    *
728    * @param packet
729    * @param json
730    *
731    * @throws OpenR66ProtocolNotAuthenticatedException
732    * @throws OpenR66RunnerErrorException
733    * @throws OpenR66ProtocolSystemException
734    * @throws OpenR66ProtocolBusinessException
735    * @throws OpenR66ProtocolShutdownException
736    * @throws OpenR66ProtocolPacketException
737    * @throws OpenR66ProtocolNoDataException
738    */
739   public final void jsonCommand(final JsonCommandPacket packet,
740                                 final JsonPacket json)
741       throws OpenR66ProtocolNotAuthenticatedException,
742              OpenR66RunnerErrorException, OpenR66ProtocolSystemException,
743              OpenR66ProtocolBusinessException, OpenR66ProtocolShutdownException,
744              OpenR66ProtocolPacketException, OpenR66ProtocolNoDataException {
745     // SHUTDOWNPACKET does not need authentication
746     if (packet.getTypeValid() != LocalPacketFactory.SHUTDOWNPACKET &&
747         !session.isAuthenticated()) {
748       logger.warn("JsonCommand packet received while not authenticated: {} {}",
749                   packet, session);
750       session.newState(ERROR);
751       throw new OpenR66ProtocolNotAuthenticatedException(
752           "Not authenticated while Valid received");
753     }
754     if (json == null) {
755       jsonCommandEmptyJson(packet);
756       return;
757     }
758     switch (json.getRequestUserPacket()) {
759       case LocalPacketFactory.SHUTDOWNPACKET: {
760         jsonCommandShutdown(packet, (ShutdownRequestJsonPacket) json);
761         break;
762       }
763       case LocalPacketFactory.BLOCKREQUESTPACKET: {
764         jsonCommandBlockRequest(json);
765         break;
766       }
767       case LocalPacketFactory.BUSINESSREQUESTPACKET: {
768         jsonCommandBusinessCommand((BusinessRequestJsonPacket) json);
769         break;
770       }
771       case LocalPacketFactory.INFORMATIONPACKET: {
772         jsonCommandInformation((InformationJsonPacket) json);
773         break;
774       }
775       case LocalPacketFactory.REQUESTPACKET: {
776         jsonCommandRequest(packet, json);
777         break;
778       }
779       case LocalPacketFactory.STOPPACKET:
780       case LocalPacketFactory.CANCELPACKET: {
781         jsonCommandStopOrCancel(packet, json);
782         break;
783       }
784       case LocalPacketFactory.VALIDPACKET: {
785         jsonCommandValid(packet, (RestartTransferJsonPacket) json);
786         break;
787       }
788       case LocalPacketFactory.REQUESTUSERPACKET: {
789         jsonCommandRequestUser(packet);
790         break;
791       }
792       case LocalPacketFactory.LOGPACKET:
793       case LocalPacketFactory.LOGPURGEPACKET: {
794         jsonCommandLog(packet, (LogJsonPacket) json);
795         break;
796       }
797       case LocalPacketFactory.CONFEXPORTPACKET: {
798         jsonCommandConfigExport((ConfigExportJsonPacket) json);
799         break;
800       }
801       case LocalPacketFactory.CONFIMPORTPACKET: {
802         jsonCommandConfigImport((ConfigImportJsonPacket) json);
803         break;
804       }
805       case LocalPacketFactory.BANDWIDTHPACKET: {
806         jsonCommandBandwidth((BandwidthJsonPacket) json);
807         break;
808       }
809       case LocalPacketFactory.TESTPACKET: {
810         jsonCommandTest(packet, json);
811         break;
812       }
813       default:
814         logger.warn("Validation is ignored: " + packet.getTypeValid());
815     }
816   }
817 
818   private void jsonCommandTest(final JsonCommandPacket packet,
819                                final JsonPacket json) {
820     session.newState(VALIDOTHER);
821     logger.info("Valid TEST MESSAGE: {}", packet);
822     final R66Result resulttest =
823         new R66Result(session, true, ErrorCode.CompleteOk, null);
824     resulttest.setOther(packet);
825     final JsonCommandPacket valid =
826         new JsonCommandPacket(json, resulttest.getCode().getCode(),
827                               LocalPacketFactory.REQUESTUSERPACKET);
828     localChannelReference.validateRequest(resulttest);
829     try {
830       ChannelUtils.writeAbstractLocalPacket(localChannelReference, valid,
831                                             false);
832     } catch (final OpenR66ProtocolPacketException ignored) {
833       // ignore
834     }
835     localChannelReference.close();
836   }
837 
838   private void jsonCommandBandwidth(final BandwidthJsonPacket json)
839       throws OpenR66ProtocolNotAuthenticatedException,
840              OpenR66ProtocolNoCorrectAuthenticationException {
841     // setter, writeglobal, readglobal, writesession, readsession
842     final boolean setter = json.isSetter();
843     // request of current values or set new values
844     session.newState(VALIDOTHER);
845     final long[] lresult =
846         bandwidth(setter, json.getWriteglobal(), json.getReadglobal(),
847                   json.getWritesession(), json.getReadsession());
848     // Now answer
849     json.setWriteglobal(lresult[0]);
850     json.setReadglobal(lresult[1]);
851     json.setWritesession(lresult[2]);
852     json.setReadsession(lresult[3]);
853     final R66Result result =
854         new R66Result(session, true, ErrorCode.CompleteOk, null);
855     final JsonCommandPacket valid =
856         new JsonCommandPacket(json, result.getCode().getCode(),
857                               LocalPacketFactory.REQUESTUSERPACKET);
858     localChannelReference.validateRequest(result);
859     try {
860       ChannelUtils.writeAbstractLocalPacket(localChannelReference, valid,
861                                             false);
862     } catch (final OpenR66ProtocolPacketException ignored) {
863       // ignore
864     }
865     localChannelReference.close();
866   }
867 
868   private void jsonCommandConfigImport(final ConfigImportJsonPacket json)
869       throws OpenR66ProtocolNotAuthenticatedException,
870              OpenR66ProtocolSystemException,
871              OpenR66ProtocolNoCorrectAuthenticationException {
872     final ConfigImportResponseJsonPacket resp = configImport(json);
873     final R66Result result;
874     if (resp.isImportedhost() || resp.isImportedrule() ||
875         resp.isImportedbusiness() || resp.isImportedalias() ||
876         resp.isImportedroles()) {
877       result = new R66Result(session, true, ErrorCode.CompleteOk, null);
878     } else {
879       result = new R66Result(session, true, ErrorCode.TransferError, null);
880     }
881     final JsonCommandPacket valid =
882         new JsonCommandPacket(resp, result.getCode().getCode(),
883                               LocalPacketFactory.REQUESTUSERPACKET);
884     logger.debug(valid.getRequest());
885     localChannelReference.validateRequest(result);
886     try {
887       ChannelUtils.writeAbstractLocalPacket(localChannelReference, valid,
888                                             false);
889     } catch (final OpenR66ProtocolPacketException ignored) {
890       // ignore
891     }
892     localChannelReference.close();
893   }
894 
895   private void jsonCommandConfigExport(final ConfigExportJsonPacket json)
896       throws OpenR66ProtocolNotAuthenticatedException,
897              OpenR66ProtocolNoCorrectAuthenticationException {
898     // host, rule, business, alias, roles
899     final boolean bhost = json.isHost();
900     final boolean brule = json.isRule();
901     final boolean bbusiness = json.isBusiness();
902     final boolean balias = json.isAlias();
903     final boolean broles = json.isRoles();
904     session.newState(VALIDOTHER);
905     final String[] sresult =
906         configExport(bhost, brule, bbusiness, balias, broles);
907     // Now answer
908     final ConfigExportResponseJsonPacket resp =
909         new ConfigExportResponseJsonPacket();
910     resp.fromJson(json);
911     resp.setFilehost(sresult[0]);
912     resp.setFilerule(sresult[1]);
913     resp.setFilebusiness(sresult[2]);
914     resp.setFilealias(sresult[3]);
915     resp.setFileroles(sresult[4]);
916     final R66Result result;
917     if (resp.getFilerule() != null || resp.getFilehost() != null ||
918         resp.getFilebusiness() != null || resp.getFilealias() != null ||
919         resp.getFileroles() != null) {
920       result = new R66Result(session, true, ErrorCode.CompleteOk, null);
921     } else {
922       result = new R66Result(session, true, ErrorCode.TransferError, null);
923     }
924     final JsonCommandPacket valid =
925         new JsonCommandPacket(resp, result.getCode().getCode(),
926                               LocalPacketFactory.REQUESTUSERPACKET);
927     localChannelReference.validateRequest(result);
928     try {
929       ChannelUtils.writeAbstractLocalPacket(localChannelReference, valid,
930                                             false);
931     } catch (final OpenR66ProtocolPacketException ignored) {
932       // ignore
933     }
934     localChannelReference.close();
935   }
936 
937   private void jsonCommandLog(final JsonCommandPacket packet,
938                               final LogJsonPacket json)
939       throws OpenR66ProtocolBusinessException {
940     final boolean purge = json.isPurge();
941     final boolean clean = json.isClean();
942     final Timestamp start = json.getStart() == null? null :
943         new Timestamp(json.getStart().getTime());
944     final Timestamp stop =
945         json.getStop() == null? null : new Timestamp(json.getStop().getTime());
946     final String startid = json.getStartid();
947     final String stopid = json.getStopid();
948     final String rule = json.getRule();
949     final String request = json.getRequest();
950     final boolean pending = json.isStatuspending();
951     final boolean transfer = json.isStatustransfer();
952     final boolean done = json.isStatusdone();
953     final boolean error = json.isStatuserror();
954     final boolean isPurge =
955         packet.getTypeValid() == LocalPacketFactory.LOGPURGEPACKET || purge;
956     session.newState(VALIDOTHER);
957     final String[] sresult =
958         logPurge(purge, clean, start, stop, startid, stopid, rule, request,
959                  pending, transfer, done, error, isPurge);
960     final LogResponseJsonPacket newjson = new LogResponseJsonPacket();
961     newjson.fromJson(json);
962     // Now answer
963     newjson.setCommand(packet.getTypeValid());
964     newjson.setFilename(sresult[0]);
965     newjson.setExported(Long.parseLong(sresult[1]));
966     newjson.setPurged(Long.parseLong(sresult[2]));
967     final R66Result result =
968         new R66Result(session, true, ErrorCode.CompleteOk, null);
969     final JsonCommandPacket valid =
970         new JsonCommandPacket(newjson, result.getCode().getCode(),
971                               LocalPacketFactory.REQUESTUSERPACKET);
972     localChannelReference.validateRequest(result);
973     try {
974       ChannelUtils.writeAbstractLocalPacket(localChannelReference, valid,
975                                             false);
976     } catch (final OpenR66ProtocolPacketException ignored) {
977       // ignore
978     }
979     localChannelReference.close();
980   }
981 
982   private void jsonCommandRequestUser(final JsonCommandPacket packet) {
983     session.newState(VALIDOTHER);
984     // Validate user request
985     final R66Result resulttest =
986         new R66Result(session, true, ErrorCode.getFromCode(packet.getResult()),
987                       null);
988     resulttest.setOther(packet);
989     switch (resulttest.getCode()) {
990       case CompleteOk:
991       case InitOk:
992       case PostProcessingOk:
993       case PreProcessingOk:
994       case QueryAlreadyFinished:
995       case QueryStillRunning:
996       case Running:
997       case TransferOk:
998         break;
999       default:
1000         localChannelReference.invalidateRequest(resulttest);
1001         session.setStatus(102);
1002         localChannelReference.close();
1003         return;
1004     }
1005     localChannelReference.validateRequest(resulttest);
1006     session.setStatus(28);
1007     localChannelReference.close();
1008   }
1009 
1010   private void jsonCommandValid(final JsonCommandPacket packet,
1011                                 final RestartTransferJsonPacket json)
1012       throws OpenR66ProtocolNotAuthenticatedException,
1013              OpenR66ProtocolNoCorrectAuthenticationException {
1014     session.newState(VALIDOTHER);
1015     final R66Result result =
1016         requestRestart(json.getRequested(), json.getRequester(),
1017                        json.getSpecialid(), json.getRestarttime());
1018     result.setOther(packet);
1019     final JsonCommandPacket valid =
1020         new JsonCommandPacket(json, result.getCode().getCode(),
1021                               LocalPacketFactory.REQUESTUSERPACKET);
1022     if (isCodeValid(result.getCode())) {
1023       localChannelReference.validateRequest(result);
1024     } else {
1025       localChannelReference.invalidateRequest(result);
1026     }
1027     // inform back the requester
1028     try {
1029       ChannelUtils.writeAbstractLocalPacket(localChannelReference, valid,
1030                                             false);
1031     } catch (final OpenR66ProtocolPacketException ignored) {
1032       // ignore
1033     }
1034     localChannelReference.close();
1035   }
1036 
1037   private void jsonCommandStopOrCancel(final JsonCommandPacket packet,
1038                                        final JsonPacket json)
1039       throws OpenR66ProtocolNotAuthenticatedException,
1040              OpenR66ProtocolNoCorrectAuthenticationException {
1041     final StopOrCancelJsonPacket node = (StopOrCancelJsonPacket) json;
1042     final R66Result resulttest;
1043     if (node.getRequested() == null || node.getRequester() == null ||
1044         node.getSpecialid() == ILLEGALVALUE) {
1045       final ErrorCode code = ErrorCode.CommandNotFound;
1046       resulttest = new R66Result(session, true, code, session.getRunner());
1047     } else {
1048       final String reqd = node.getRequested();
1049       final String reqr = node.getRequester();
1050       final long id = node.getSpecialid();
1051       session.newState(VALIDOTHER);
1052       resulttest = stopOrCancel(packet.getTypeValid(), reqd, reqr, id);
1053     }
1054     // inform back the requester
1055     final JsonCommandPacket valid =
1056         new JsonCommandPacket(json, resulttest.getCode().getCode(),
1057                               LocalPacketFactory.REQUESTUSERPACKET);
1058     resulttest.setOther(packet);
1059     localChannelReference.validateRequest(resulttest);
1060     try {
1061       ChannelUtils.writeAbstractLocalPacket(localChannelReference, valid,
1062                                             false);
1063     } catch (final OpenR66ProtocolPacketException ignored) {
1064       // ignore
1065     }
1066     session.setStatus(27);
1067     localChannelReference.close();
1068   }
1069 
1070   private void jsonCommandRequest(final JsonCommandPacket packet,
1071                                   final JsonPacket json)
1072       throws OpenR66ProtocolPacketException {
1073     final TransferRequestJsonPacket node = (TransferRequestJsonPacket) json;
1074     final R66Result result = transferRequest(node);
1075     if (isCodeValid(result.getCode())) {
1076       final JsonCommandPacket valid =
1077           new JsonCommandPacket(json, result.getCode().getCode(),
1078                                 LocalPacketFactory.REQUESTUSERPACKET);
1079       result.setOther(packet);
1080       localChannelReference.validateRequest(result);
1081       try {
1082         ChannelUtils.writeAbstractLocalPacket(localChannelReference, valid,
1083                                               false);
1084       } catch (final OpenR66ProtocolPacketException ignored) {
1085         // ignore
1086       }
1087       session.setStatus(27);
1088       localChannelReference.close();
1089     } else {
1090       result.setOther(packet);
1091       localChannelReference.invalidateRequest(result);
1092       final ErrorPacket error = new ErrorPacket(
1093           "TransferRequest in error: for " + node + " since " +
1094           result.getMessage(), result.getCode().getCode(),
1095           ErrorPacket.FORWARDCLOSECODE);
1096       ChannelUtils.writeAbstractLocalPacket(localChannelReference, error,
1097                                             false);
1098       ChannelCloseTimer.closeFutureTransaction(
1099           localChannelReference.getServerHandler());
1100     }
1101   }
1102 
1103   private void jsonCommandInformation(final InformationJsonPacket json)
1104       throws OpenR66ProtocolNotAuthenticatedException,
1105              OpenR66ProtocolNoDataException, OpenR66ProtocolPacketException {
1106     final ValidPacket validPacket;
1107     if (json.isIdRequest()) {
1108       validPacket =
1109           informationRequest(json.getId(), json.isTo(), json.getRulename(),
1110                              false);
1111     } else {
1112       validPacket = informationFile(json.getRequest(), json.getRulename(),
1113                                     json.getFilename(), false);
1114     }
1115     if (validPacket != null) {
1116       ChannelUtils.writeAbstractLocalPacket(localChannelReference, validPacket,
1117                                             false);
1118       localChannelReference.close();
1119     } else {
1120       session.newState(ERROR);
1121       final ErrorPacket error = new ErrorPacket("Error while Request " + json,
1122                                                 ErrorCode.Internal.getCode(),
1123                                                 ErrorPacket.FORWARDCLOSECODE);
1124       ChannelUtils.writeAbstractLocalPacket(localChannelReference, error,
1125                                             false);
1126       ChannelCloseTimer.closeFutureTransaction(
1127           localChannelReference.getServerHandler());
1128     }
1129   }
1130 
1131   private void jsonCommandBusinessCommand(final BusinessRequestJsonPacket json)
1132       throws OpenR66ProtocolNotAuthenticatedException,
1133              OpenR66ProtocolPacketException,
1134              OpenR66ProtocolNoCorrectAuthenticationException {
1135     if (json.isToApplied()) {
1136       session.newState(BUSINESSD);
1137     }
1138     final R66Future future =
1139         businessRequest(json.isToApplied(), json.getClassName(),
1140                         json.getArguments(), json.getExtraArguments(),
1141                         json.getDelay());
1142     if (future != null && !future.isSuccess()) {
1143       R66Result result = future.getResult();
1144       if (result == null) {
1145         result = new R66Result(session, false, ErrorCode.ExternalOp,
1146                                session.getRunner());
1147       }
1148       wrongResult(json, result);
1149     } else if (future == null) {
1150       final R66Result result =
1151           new R66Result(session, false, ErrorCode.ExternalOp,
1152                         session.getRunner());
1153       wrongResult(json, result);
1154     } else {
1155       logger.debug("BusinessRequest part 2");
1156       final R66Result result = future.getResult();
1157       final JsonCommandPacket valid =
1158           new JsonCommandPacket(json, result.getCode().getCode(),
1159                                 LocalPacketFactory.REQUESTUSERPACKET);
1160       if (isCodeValid(result.getCode())) {
1161         localChannelReference.validateRequest(result);
1162       } else {
1163         localChannelReference.invalidateRequest(result);
1164       }
1165       // inform back the requester
1166       try {
1167         ChannelUtils.writeAbstractLocalPacket(localChannelReference, valid,
1168                                               false);
1169       } catch (final OpenR66ProtocolPacketException ignored) {
1170         // ignore
1171       }
1172       localChannelReference.close();
1173     }
1174   }
1175 
1176   private void wrongResult(final BusinessRequestJsonPacket node,
1177                            final R66Result result)
1178       throws OpenR66ProtocolPacketException {
1179     logger.info("Task in Error: {} {}", node.getClassName(), result);
1180     if (!result.isAnswered()) {
1181       node.setValidated(false);
1182       session.newState(ERROR);
1183       final ErrorPacket error = new ErrorPacket(
1184           "BusinessRequest in error: for " + node + " since " +
1185           result.getMessage(), result.getCode().getCode(),
1186           ErrorPacket.FORWARDCLOSECODE);
1187       ChannelUtils.writeAbstractLocalPacket(localChannelReference, error,
1188                                             false);
1189       session.setStatus(203);
1190     }
1191     session.setStatus(204);
1192   }
1193 
1194   private void jsonCommandBlockRequest(final JsonPacket json)
1195       throws OpenR66ProtocolShutdownException,
1196              OpenR66ProtocolBusinessException {
1197     final ShutdownOrBlockJsonPacket node = (ShutdownOrBlockJsonPacket) json;
1198     final byte[] key = node.getKey();
1199     if (node.isShutdownOrBlock()) {
1200       // Shutdown
1201       session.newState(SHUTDOWN);
1202       shutdown(key, node.isRestartOrBlock());
1203     } else {
1204       // Block
1205       final R66Result result = blockRequest(key, node.isRestartOrBlock());
1206       node.setComment(
1207           (node.isRestartOrBlock()? "Block" : "Unblock") + " new request");
1208       final JsonCommandPacket valid =
1209           new JsonCommandPacket(json, result.getCode().getCode(),
1210                                 LocalPacketFactory.REQUESTUSERPACKET);
1211       try {
1212         ChannelUtils.writeAbstractLocalPacket(localChannelReference, valid,
1213                                               false);
1214       } catch (final OpenR66ProtocolPacketException ignored) {
1215         // ignore
1216       }
1217       localChannelReference.close();
1218     }
1219   }
1220 
1221   private void jsonCommandShutdown(final JsonCommandPacket packet,
1222                                    final ShutdownRequestJsonPacket json)
1223       throws OpenR66RunnerErrorException, OpenR66ProtocolSystemException {
1224     int rank = -1;
1225     if (session.getRunner() != null && session.getRunner().isInTransfer()) {
1226       rank = json.getRank();
1227     }
1228     final R66Result result =
1229         new R66Result(new OpenR66ProtocolShutdownException(), session, true,
1230                       ErrorCode.Shutdown, session.getRunner());
1231     result.setOther(packet);
1232     rank = shutdownRequest(result, rank);
1233     if (rank >= 0) {
1234       json.setRank(rank);
1235       final JsonCommandPacket valid =
1236           new JsonCommandPacket(json, result.getCode().getCode(),
1237                                 LocalPacketFactory.SHUTDOWNPACKET);
1238       try {
1239         ChannelUtils.writeAbstractLocalPacket(localChannelReference, valid,
1240                                               false);
1241       } catch (final OpenR66ProtocolPacketException ignored) {
1242         // ignore
1243       }
1244     }
1245     shutdownLocalChannel();
1246   }
1247 
1248   private void jsonCommandEmptyJson(final JsonCommandPacket packet) {
1249     final JsonPacket json;
1250     final ErrorCode code = ErrorCode.CommandNotFound;
1251     final R66Result resulttest =
1252         new R66Result(session, true, code, session.getRunner());
1253     json = new JsonPacket();
1254     json.setComment("Invalid command");
1255     json.setRequestUserPacket(packet.getTypeValid());
1256     final JsonCommandPacket valid =
1257         new JsonCommandPacket(json, resulttest.getCode().getCode(),
1258                               LocalPacketFactory.REQUESTUSERPACKET);
1259     resulttest.setOther(packet);
1260     localChannelReference.validateRequest(resulttest);
1261     try {
1262       ChannelUtils.writeAbstractLocalPacket(localChannelReference, valid,
1263                                             false);
1264     } catch (final OpenR66ProtocolPacketException ignored) {
1265       // ignore
1266     }
1267     session.setStatus(99);
1268     localChannelReference.close();
1269   }
1270 
1271   /**
1272    * Shutdown Local Channel after the request is shutdown
1273    */
1274   private void shutdownLocalChannel() {
1275     session.setStatus(26);
1276     logger.warn(
1277         "Will Close Local from Network Channel since Remote shutdown received");
1278     ChannelCloseTimer.closeFutureTransaction(
1279         localChannelReference.getServerHandler());
1280     try {
1281       Thread.sleep(Configuration.WAITFORNETOP);
1282     } catch (final InterruptedException e) {//NOSONAR
1283       SysErrLogger.FAKE_LOGGER.ignoreLog(e);
1284       Thread.currentThread().interrupt();
1285     }
1286     final NetworkChannelReference ncr =
1287         localChannelReference.getNetworkChannelObject();
1288     ncr.lockNetwork();
1289     try {
1290       final long time = ncr.shutdownAllowed();
1291       if (time == 0) {
1292         logger.info("Will close networkChannel {}", ncr.nbLocalChannels());
1293         NetworkTransaction.shuttingDownNetworkChannel(ncr);
1294         NetworkTransaction.shuttingdownNetworkChannelsPerHostID(
1295             ncr.getHostId());
1296       }
1297     } finally {
1298       ncr.unlockNetwork();
1299     }
1300   }
1301 
1302   /**
1303    * Shutdown the current request with an optional rank to set for future
1304    * restart
1305    *
1306    * @param result the result to be associated in finalization
1307    * @param rank the future rank to set if restart (<0 if none)
1308    *
1309    * @return the rank to set for future restart if any (< 0 if none)
1310    *
1311    * @throws OpenR66RunnerErrorException
1312    * @throws OpenR66ProtocolSystemException
1313    */
1314   private int shutdownRequest(final R66Result result, final int rank)
1315       throws OpenR66RunnerErrorException, OpenR66ProtocolSystemException {
1316     session.newState(SHUTDOWN);
1317     logger.warn(
1318         "Shutdown received so Will close channel" + localChannelReference);
1319     if (session.getRunner() != null && session.getRunner().isInTransfer()) {
1320       final DbTaskRunner runner = session.getRunner();
1321       if (rank >= 0) {
1322         // Save last rank from remote point of view
1323         runner.setRankAtStartup(rank);
1324         session.setFinalizeTransfer(false, result);
1325       } else if (!session.isSender()) {
1326         // is receiver so informs back for the rank to use next time
1327         final int newrank = runner.getRank();
1328         try {
1329           runner.saveStatus();
1330         } catch (final OpenR66RunnerErrorException ignored) {
1331           // ignore
1332         }
1333         session.setFinalizeTransfer(false, result);
1334         return newrank;
1335       } else {
1336         session.setFinalizeTransfer(false, result);
1337       }
1338     } else {
1339       session.setFinalizeTransfer(false, result);
1340     }
1341     return -1;
1342   }
1343 
1344   /**
1345    * Get or Set the bandwidth configuration
1346    *
1347    * @param setter
1348    * @param writeglobal
1349    * @param readglobal
1350    * @param writesession
1351    * @param readsession
1352    *
1353    * @return the 4 current values for the bandwidth (in the same order)
1354    *
1355    * @throws OpenR66ProtocolNotAuthenticatedException
1356    */
1357   public final long[] bandwidth(final boolean setter, final long writeglobal,
1358                                 final long readglobal, final long writesession,
1359                                 final long readsession)
1360       throws OpenR66ProtocolNotAuthenticatedException,
1361              OpenR66ProtocolNoCorrectAuthenticationException {
1362     // Authentication must be the local server or LIMIT authorization
1363     try {
1364       if (!session.getAuth().getUser().equals(
1365           Configuration.configuration.getHostId(session.getAuth().isSsl())) &&
1366           !session.getAuth().isValidRole(ROLE.LIMIT)) {
1367         throw new OpenR66ProtocolNoCorrectAuthenticationException(
1368             NOT_CORRECTLY_AUTHENTICATED);
1369       }
1370     } catch (final OpenR66ProtocolNoSslException e1) {
1371       throw new OpenR66ProtocolNotAuthenticatedException(
1372           NOT_CORRECTLY_AUTHENTICATED_SINCE_SSL_IS_NOT_SUPPORTED, e1);
1373     }
1374     if (!setter) {
1375       // request of current values
1376       // Now answer
1377     } else {
1378       long wgl = (writeglobal / 10) * 10;
1379       long rgl = (readglobal / 10) * 10;
1380       long wsl = (writesession / 10) * 10;
1381       long rsl = (readsession / 10) * 10;
1382       if (wgl < 0) {
1383         wgl = Configuration.configuration.getServerGlobalWriteLimit();
1384       }
1385       if (rgl < 0) {
1386         rgl = Configuration.configuration.getServerGlobalReadLimit();
1387       }
1388       if (wsl < 0) {
1389         wsl = Configuration.configuration.getServerChannelWriteLimit();
1390       }
1391       if (rsl < 0) {
1392         rsl = Configuration.configuration.getServerChannelReadLimit();
1393       }
1394       if (Configuration.configuration.getR66Mib() != null) {
1395         Configuration.configuration.getR66Mib().notifyWarning(
1396             "Change Bandwidth Limit Order received: Global " + wgl + ':' + rgl +
1397             " (W:R) Local " + wsl + ':' + rsl + " (W:R)",
1398             session.getAuth().getUser());
1399       }
1400       Configuration.configuration.changeNetworkLimit(wgl, rgl, wsl, rsl,
1401                                                      Configuration.configuration.getDelayLimit());
1402       // Now answer
1403     }
1404     return new long[] {
1405         Configuration.configuration.getServerGlobalWriteLimit(),
1406         Configuration.configuration.getServerGlobalReadLimit(),
1407         Configuration.configuration.getServerChannelWriteLimit(),
1408         Configuration.configuration.getServerChannelReadLimit()
1409     };
1410   }
1411 
1412   /**
1413    * Import configuration from files as parameter
1414    *
1415    * @param json
1416    *
1417    * @return the packet to answer
1418    *
1419    * @throws OpenR66ProtocolNotAuthenticatedException
1420    * @throws OpenR66ProtocolSystemException
1421    */
1422   public final ConfigImportResponseJsonPacket configImport(
1423       final ConfigImportJsonPacket json)
1424       throws OpenR66ProtocolNotAuthenticatedException,
1425              OpenR66ProtocolNoCorrectAuthenticationException,
1426              OpenR66ProtocolSystemException {
1427     session.newState(VALIDOTHER);
1428     // Authentication must be the local server or CONFIGADMIN authorization
1429     try {
1430       if (!session.getAuth().getUser().equals(
1431           Configuration.configuration.getHostId(session.getAuth().isSsl())) &&
1432           !session.getAuth().isValidRole(ROLE.CONFIGADMIN)) {
1433         throw new OpenR66ProtocolNoCorrectAuthenticationException(
1434             NOT_CORRECTLY_AUTHENTICATED);
1435       }
1436     } catch (final OpenR66ProtocolNoSslException e1) {
1437       throw new OpenR66ProtocolNotAuthenticatedException(
1438           NOT_CORRECTLY_AUTHENTICATED_SINCE_SSL_IS_NOT_SUPPORTED, e1);
1439     }
1440     if (Configuration.configuration.getR66Mib() != null) {
1441       Configuration.configuration.getR66Mib().notifyWarning(
1442           "Import Configuration Order received", session.getAuth().getUser());
1443     }
1444     // purgehost, purgerule, purgebusiness, purgealias, purgeroles, host, rule, business, alias, roles
1445     final boolean bhostPurge = json.isPurgehost();
1446     final boolean brulePurge = json.isPurgerule();
1447     final boolean bbusinessPurge = json.isPurgebusiness();
1448     final boolean baliasPurge = json.isPurgealias();
1449     final boolean brolesPurge = json.isPurgeroles();
1450     boolean importedhost = false;
1451     boolean importedrule = false;
1452     boolean importedbusiness = false;
1453     boolean importedalias = false;
1454     boolean importedroles = false;
1455     String shost = json.getHost();
1456     String srule = json.getRule();
1457     String sbusiness = json.getBusiness();
1458     String salias = json.getAlias();
1459     String sroles = json.getRoles();
1460     final long hostid = json.getHostid();
1461     final long ruleid = json.getRuleid();
1462     final long businessid = json.getBusinessid();
1463     final long aliasid = json.getAliasid();
1464     final long roleid = json.getRolesid();
1465 
1466     localChannelReference.getDbSession();
1467 
1468     final String remote = session.getAuth().getUser();
1469     String local = null;
1470     try {
1471       local = Configuration.configuration.getHostId(session.getAuth().isSsl());
1472     } catch (final OpenR66ProtocolNoSslException e1) {
1473       logger.warn("Local Ssl Host is unknown" + " : {}", e1.getMessage());
1474     }
1475     if (shost != null || hostid != ILLEGALVALUE && local != null) {
1476       DbHostAuth[] oldHosts = null;
1477       final DbTaskRunner runner;
1478       if (hostid != ILLEGALVALUE && local != null) {
1479         // need to find the local filename
1480         try {
1481           runner = new DbTaskRunner(session, null, hostid, remote, local);
1482           shost = runner.getFullFilePath();
1483         } catch (final WaarpDatabaseException e) {
1484           logger.error(RUNNER_TASK_IS_NOT_FOUND + hostid, e);
1485           shost = null;
1486         } catch (final CommandAbstractException e) {
1487           logger.error(FILE_IS_NOT_FOUND + hostid, e);
1488           shost = null;
1489         }
1490       }
1491       if (shost != null) {
1492         if (bhostPurge) {
1493           // Need to first delete all entries
1494           try {
1495             oldHosts = DbHostAuth.deleteAll();
1496           } catch (final WaarpDatabaseException e) {
1497             // ignore
1498           }
1499         }
1500         if (AuthenticationFileBasedConfiguration.loadAuthentication(
1501             Configuration.configuration, shost)) {
1502           importedhost = true;
1503           logger.debug("Host configuration imported from {}", shost);
1504         } else {
1505           logger.error("Error in Load Hosts");
1506           importedhost = false;
1507         }
1508         if (!importedhost && bhostPurge && oldHosts != null) {
1509           for (final DbHostAuth dbHost : oldHosts) {
1510             try {
1511               if (!dbHost.exist()) {
1512                 dbHost.insert();
1513               }
1514             } catch (final WaarpDatabaseException e1) {
1515               // ignore
1516             }
1517           }
1518         }
1519       }
1520     }
1521     if (srule != null || ruleid != ILLEGALVALUE && local != null) {
1522       DbRule[] oldRules = null;
1523       final DbTaskRunner runner;
1524       if (ruleid != ILLEGALVALUE && local != null) {
1525         // need to find the local filename
1526         try {
1527           runner = new DbTaskRunner(session, null, ruleid, remote, local);
1528           srule = runner.getFullFilePath();
1529         } catch (final WaarpDatabaseException e) {
1530           logger.error(RUNNER_TASK_IS_NOT_FOUND + ruleid, e);
1531           srule = null;
1532         } catch (final CommandAbstractException e) {
1533           logger.error(FILE_IS_NOT_FOUND + hostid, e);
1534           srule = null;
1535         }
1536       }
1537       if (srule != null) {
1538         if (brulePurge) {
1539           // Need to first delete all entries
1540           try {
1541             oldRules = DbRule.deleteAll();
1542           } catch (final WaarpDatabaseException e) {
1543             // ignore
1544           }
1545         }
1546         final File file = new File(srule);
1547         try {
1548           RuleFileBasedConfiguration.getMultipleFromFile(file);
1549           importedrule = true;
1550           logger.debug("Rule configuration imported from {}", srule);
1551         } catch (final WaarpDatabaseNoConnectionException e) {
1552           logger.error("Error: {}", e.getMessage());
1553           importedrule = false;
1554         } catch (final WaarpDatabaseSqlException e) {
1555           logger.error("Error", e);
1556           importedrule = false;
1557         } catch (final WaarpDatabaseNoDataException e) {
1558           logger.error("Error", e);
1559           importedrule = false;
1560         } catch (final WaarpDatabaseException e) {
1561           logger.error("Error", e);
1562           importedrule = false;
1563         }
1564         if (!importedrule && brulePurge && oldRules != null) {
1565           for (final DbRule dbRule : oldRules) {
1566             try {
1567               if (!dbRule.exist()) {
1568                 dbRule.insert();
1569               }
1570             } catch (final WaarpDatabaseException e1) {
1571               // ignore
1572             }
1573           }
1574         }
1575       }
1576     }
1577     // load from file ! not from filename ! Moreover: filename might be incorrect => Must get the remote filename
1578     // (recv)
1579     if (sbusiness != null || salias != null || sroles != null ||
1580         bbusinessPurge || baliasPurge || brolesPurge ||
1581         (businessid != ILLEGALVALUE || aliasid != ILLEGALVALUE ||
1582          roleid != ILLEGALVALUE) && local != null) {
1583       final DbHostConfiguration host;
1584       try {
1585         host = new DbHostConfiguration(Configuration.configuration.getHostId());
1586         DbTaskRunner runner;
1587         if (businessid != ILLEGALVALUE && local != null) {
1588           // need to find the local filename
1589           try {
1590             runner = new DbTaskRunner(session, null, businessid, remote, local);
1591             sbusiness = runner.getFullFilePath();
1592           } catch (final WaarpDatabaseException e) {
1593             logger.error(RUNNER_TASK_IS_NOT_FOUND + businessid, e);
1594             sbusiness = null;
1595           } catch (final CommandAbstractException e) {
1596             logger.error(FILE_IS_NOT_FOUND + hostid, e);
1597             sbusiness = null;
1598           }
1599         }
1600         if (sbusiness != null) {
1601           try {
1602             final String content =
1603                 WaarpStringUtils.readFileException(sbusiness);
1604             importedbusiness =
1605                 host.updateBusiness(Configuration.configuration, content,
1606                                     bbusinessPurge);
1607             logger.debug("Business configuration imported from {}({})",
1608                          sbusiness, importedbusiness);
1609           } catch (final FileTransferException e) {
1610             logger.error("Error", e);
1611             importedbusiness = false;
1612           }
1613         }
1614         if (aliasid != ILLEGALVALUE && local != null) {
1615           // need to find the local filename
1616           try {
1617             runner = new DbTaskRunner(session, null, aliasid, remote, local);
1618             salias = runner.getFullFilePath();
1619           } catch (final WaarpDatabaseException e) {
1620             logger.error(RUNNER_TASK_IS_NOT_FOUND + aliasid, e);
1621             salias = null;
1622           } catch (final CommandAbstractException e) {
1623             logger.error(FILE_IS_NOT_FOUND + hostid, e);
1624             salias = null;
1625           }
1626         }
1627         if (salias != null) {
1628           try {
1629             final String content = WaarpStringUtils.readFileException(salias);
1630             importedalias =
1631                 host.updateAlias(Configuration.configuration, content,
1632                                  baliasPurge);
1633             logger.debug("Alias configuration imported from {}({})", salias,
1634                          importedalias);
1635           } catch (final FileTransferException e) {
1636             logger.error("Error", e);
1637             importedalias = false;
1638           }
1639         }
1640         if (roleid != ILLEGALVALUE && local != null) {
1641           // need to find the local filename
1642           try {
1643             runner = new DbTaskRunner(session, null, roleid, remote, local);
1644             sroles = runner.getFullFilePath();
1645           } catch (final WaarpDatabaseException e) {
1646             logger.error(RUNNER_TASK_IS_NOT_FOUND + roleid, e);
1647             sroles = null;
1648           } catch (final CommandAbstractException e) {
1649             logger.error(FILE_IS_NOT_FOUND + hostid, e);
1650             sroles = null;
1651           }
1652         }
1653         if (sroles != null) {
1654           try {
1655             final String content = WaarpStringUtils.readFileException(sroles);
1656             importedroles =
1657                 host.updateRoles(Configuration.configuration, content,
1658                                  brolesPurge);
1659             logger.debug("Roles configuration imported from {}({})", sroles,
1660                          importedroles);
1661           } catch (final FileTransferException e) {
1662             logger.error("Error", e);
1663             importedroles = false;
1664           }
1665         }
1666       } catch (final WaarpDatabaseException e1) {
1667         logger.error("Error while trying to open: " + sbusiness, e1);
1668         importedbusiness = false;
1669         importedalias = false;
1670         importedroles = false;
1671       }
1672     }
1673     // Now answer
1674     final ConfigImportResponseJsonPacket resp =
1675         new ConfigImportResponseJsonPacket();
1676     resp.fromJson(json);
1677     if (bhostPurge || shost != null) {
1678       resp.setPurgedhost(bhostPurge);
1679       resp.setImportedhost(importedhost);
1680     }
1681     if (brulePurge || srule != null) {
1682       resp.setPurgedrule(brulePurge);
1683       resp.setImportedrule(importedrule);
1684     }
1685     if (bbusinessPurge || sbusiness != null) {
1686       resp.setPurgedbusiness(bbusinessPurge);
1687       resp.setImportedbusiness(importedbusiness);
1688     }
1689     if (baliasPurge || salias != null) {
1690       resp.setPurgedalias(baliasPurge);
1691       resp.setImportedalias(importedalias);
1692     }
1693     if (brolesPurge || sroles != null) {
1694       resp.setPurgedroles(brolesPurge);
1695       resp.setImportedroles(importedroles);
1696     }
1697     return resp;
1698   }
1699 
1700   /**
1701    * Export configuration and return filenames in order
1702    *
1703    * @param bhost
1704    * @param brule
1705    * @param bbusiness
1706    * @param balias
1707    * @param broles
1708    *
1709    * @return filenames in order
1710    *
1711    * @throws OpenR66ProtocolNotAuthenticatedException
1712    */
1713   public final String[] configExport(final boolean bhost, final boolean brule,
1714                                      final boolean bbusiness,
1715                                      final boolean balias, final boolean broles)
1716       throws OpenR66ProtocolNotAuthenticatedException,
1717              OpenR66ProtocolNoCorrectAuthenticationException {
1718     // Authentication must be the local server or CONFIGADMIN authorization
1719     try {
1720       if (!session.getAuth().getUser().equals(
1721           Configuration.configuration.getHostId(session.getAuth().isSsl())) &&
1722           !session.getAuth().isValidRole(ROLE.CONFIGADMIN)) {
1723         throw new OpenR66ProtocolNoCorrectAuthenticationException(
1724             NOT_CORRECTLY_AUTHENTICATED);
1725       }
1726     } catch (final OpenR66ProtocolNoSslException e1) {
1727       throw new OpenR66ProtocolNotAuthenticatedException(
1728           NOT_CORRECTLY_AUTHENTICATED_SINCE_SSL_IS_NOT_SUPPORTED, e1);
1729     }
1730     if (Configuration.configuration.getR66Mib() != null) {
1731       Configuration.configuration.getR66Mib().notifyWarning(
1732           "Export Configuration Order received", session.getAuth().getUser());
1733     }
1734     final String dir = Configuration.configuration.getBaseDirectory() +
1735                        Configuration.configuration.getArchivePath();
1736     return staticConfigExport(dir, bhost, brule, bbusiness, balias, broles);
1737   }
1738 
1739   /**
1740    * Export configuration and return filenames in order
1741    *
1742    * @param dir
1743    * @param bhost
1744    * @param brule
1745    * @param bbusiness
1746    * @param balias
1747    * @param broles
1748    *
1749    * @return filenames in order
1750    */
1751   public static String[] staticConfigExport(final String dir, boolean bhost,
1752                                             boolean brule, boolean bbusiness,
1753                                             boolean balias, boolean broles) {
1754     String shost = null;
1755     String srule = null;
1756     String sbusiness = null;
1757     String salias = null;
1758     String sroles = null;
1759     final String hostname = Configuration.configuration.getHostId();
1760     if (bhost) {
1761       final String filename =
1762           dir + File.separator + hostname + "_Authentications.xml";
1763       try {
1764         AuthenticationFileBasedConfiguration.writeXML(
1765             Configuration.configuration, filename);
1766         shost = filename;
1767       } catch (final WaarpDatabaseNoConnectionException e) {
1768         logger.error("Error", e);
1769         shost = null;
1770         bhost = false;
1771       } catch (final OpenR66ProtocolSystemException e) {
1772         logger.error("Error", e);
1773         shost = null;
1774         bhost = false;
1775       }
1776     }
1777     if (brule) {
1778       try {
1779         srule = RuleFileBasedConfiguration.writeOneXml(dir, hostname);
1780       } catch (final WaarpDatabaseNoConnectionException e1) {
1781         logger.error("Error", e1);
1782         srule = null;
1783         brule = false;
1784       } catch (final OpenR66ProtocolSystemException e1) {
1785         logger.error("Error", e1);
1786         srule = null;
1787         brule = false;
1788       }
1789     }
1790     if (bbusiness || balias || broles) {
1791       try {
1792         final DbHostConfiguration host =
1793             new DbHostConfiguration(Configuration.configuration.getHostId());
1794         if (bbusiness) {
1795           sbusiness = host.getBusiness();
1796           if (sbusiness != null) {
1797             final String filename =
1798                 dir + File.separator + hostname + "_Business.xml";
1799             FileOutputStream outputStream = null;
1800             try {
1801               outputStream = new FileOutputStream(filename);
1802               outputStream.write(sbusiness.getBytes(WaarpStringUtils.UTF8));
1803             } finally {
1804               FileUtils.close(outputStream);
1805             }
1806             sbusiness = filename;
1807           }
1808           bbusiness = sbusiness != null;
1809         }
1810         if (balias) {
1811           salias = host.getAliases();
1812           if (salias != null) {
1813             final String filename =
1814                 dir + File.separator + hostname + "_Aliases.xml";
1815             FileOutputStream outputStream = null;
1816             try {
1817               outputStream = new FileOutputStream(filename);
1818               outputStream.write(salias.getBytes(WaarpStringUtils.UTF8));
1819             } finally {
1820               FileUtils.close(outputStream);
1821             }
1822             salias = filename;
1823           }
1824           balias = salias != null;
1825         }
1826         if (broles) {
1827           sroles = host.getRoles();
1828           if (sroles != null) {
1829             final String filename =
1830                 dir + File.separator + hostname + "_Roles.xml";
1831             FileOutputStream outputStream = null;
1832             try {
1833               outputStream = new FileOutputStream(filename);
1834               outputStream.write(sroles.getBytes(WaarpStringUtils.UTF8));
1835             } finally {
1836               FileUtils.close(outputStream);
1837             }
1838             sroles = filename;
1839           }
1840           broles = sroles != null;
1841         }
1842       } catch (final WaarpDatabaseNoConnectionException e1) {
1843         logger.error("Error", e1);
1844       } catch (final WaarpDatabaseSqlException e1) {
1845         logger.error("Error", e1);
1846       } catch (final WaarpDatabaseException e) {
1847         logger.error("Error", e);
1848       } catch (final IOException e) {
1849         logger.error("Error", e);
1850       }
1851     }
1852     // Now answer
1853     return new String[] { shost, srule, sbusiness, salias, sroles };
1854   }
1855 
1856   /**
1857    * Request to restart a transfer
1858    *
1859    * @param reqd requested
1860    * @param reqr requester
1861    * @param id id of the Transfer
1862    * @param date time start if any
1863    *
1864    * @return the Result including the error code to use in return
1865    *
1866    * @throws OpenR66ProtocolNotAuthenticatedException
1867    */
1868   public final R66Result requestRestart(final String reqd, final String reqr,
1869                                         final long id, final Date date)
1870       throws OpenR66ProtocolNotAuthenticatedException,
1871              OpenR66ProtocolNoCorrectAuthenticationException {
1872     ErrorCode returnCode = ErrorCode.Internal;
1873     R66Result resulttest;
1874     // should be from the local server or from an authorized hosts: TRANSFER
1875     try {
1876       if (!session.getAuth().getUser().equals(
1877           Configuration.configuration.getHostId(session.getAuth().isSsl())) &&
1878           !session.getAuth().isValidRole(ROLE.TRANSFER)) {
1879         throw new OpenR66ProtocolNoCorrectAuthenticationException(
1880             NOT_CORRECTLY_AUTHENTICATED);
1881       }
1882     } catch (final OpenR66ProtocolNoSslException e1) {
1883       throw new OpenR66ProtocolNotAuthenticatedException(
1884           NOT_CORRECTLY_AUTHENTICATED_SINCE_SSL_IS_NOT_SUPPORTED, e1);
1885     }
1886     // Try to validate a restarting transfer
1887     // validLimit on requested side
1888     if (Configuration.configuration.getConstraintLimitHandler()
1889                                    .checkConstraints()) {
1890       logger.error(
1891           "Limit exceeded {} while asking to relaunch a task" + reqd + ':' +
1892           reqr + ':' + id,
1893           Configuration.configuration.getConstraintLimitHandler().lastAlert);
1894       session.setStatus(100);
1895       returnCode = ErrorCode.ServerOverloaded;
1896       resulttest = new R66Result(null, session, true, returnCode, null);
1897     } else {
1898       // Try to validate a restarting transfer
1899       // header = ?; middle = requested+blank+requester+blank+specialId
1900       // note: might contains one more argument = time to reschedule in yyyyMMddHHmmss format
1901       if (reqd == null || reqr == null || id == ILLEGALVALUE) {
1902         // not enough args
1903         returnCode = ErrorCode.IncorrectCommand;
1904         resulttest = new R66Result(
1905             new OpenR66ProtocolBusinessRemoteFileNotFoundException(
1906                 "Not enough arguments"), session, true, returnCode, null);
1907       } else {
1908         DbTaskRunner taskRunner = null;
1909         try {
1910           localChannelReference.getDbSession();
1911           taskRunner = new DbTaskRunner(session, null, id, reqr, reqd);
1912           final Timestamp timestart;
1913           if (date != null) {
1914             // time to reschedule in yyyyMMddHHmmss format
1915             logger.debug("Debug: restart with {}", date);
1916             timestart = new Timestamp(date.getTime());
1917             taskRunner.setStart(timestart);
1918           }
1919           final LocalChannelReference lcr =
1920               Configuration.configuration.getLocalTransaction().getFromRequest(
1921                   reqd + ' ' + reqr + ' ' + id);
1922           // since it comes from a request transfer, cannot redo it
1923           if (logger.isInfoEnabled()) {
1924             logger.info("Will try to restart: {}", taskRunner.toShortString());
1925           }
1926           resulttest = TransferUtils.restartTransfer(taskRunner, lcr);
1927           returnCode = resulttest.getCode();
1928         } catch (final WaarpDatabaseException e1) {
1929           returnCode = ErrorCode.Internal;
1930           resulttest =
1931               new R66Result(new OpenR66DatabaseGlobalException(e1), session,
1932                             true, returnCode, taskRunner);
1933         }
1934       }
1935     }
1936     return resulttest;
1937   }
1938 
1939   /**
1940    * @param code
1941    *
1942    * @return True if the code is an OK code and not an error
1943    */
1944   public final boolean isCodeValid(final ErrorCode code) {
1945     switch (code) {
1946       case CompleteOk:
1947       case InitOk:
1948       case PostProcessingOk:
1949       case PreProcessingOk:
1950       case QueryAlreadyFinished:
1951       case QueryStillRunning:
1952       case Running:
1953       case TransferOk:
1954         return true;
1955       case BadAuthent:
1956       case CanceledTransfer:
1957       case CommandNotFound:
1958       case ConnectionImpossible:
1959       case Disconnection:
1960       case ExternalOp:
1961       case FileNotAllowed:
1962       case FileNotFound:
1963       case FinalOp:
1964       case IncorrectCommand:
1965       case Internal:
1966       case LoopSelfRequestedHost:
1967       case MD5Error:
1968       case NotKnownHost:
1969       case PassThroughMode:
1970       case QueryRemotelyUnknown:
1971       case RemoteError:
1972       case RemoteShutdown:
1973       case ServerOverloaded:
1974       case Shutdown:
1975       case SizeNotAllowed:
1976       case StoppedTransfer:
1977       case TransferError:
1978       case Unimplemented:
1979       case Unknown:
1980       case Warning:
1981       default:
1982         return false;
1983     }
1984   }
1985 
1986   /**
1987    * Purge the logs as required
1988    *
1989    * @param purge
1990    * @param clean
1991    * @param start
1992    * @param stop
1993    * @param startid
1994    * @param stopid
1995    * @param rule
1996    * @param request
1997    * @param pending
1998    * @param transfer
1999    * @param done
2000    * @param error
2001    * @param isPurge
2002    *
2003    * @return an array of Strings as: filename, nb of exported, nb of purged
2004    *
2005    * @throws OpenR66ProtocolNotAuthenticatedException
2006    * @throws OpenR66ProtocolBusinessException
2007    */
2008   public final String[] logPurge(final boolean purge, final boolean clean,
2009                                  final Timestamp start, final Timestamp stop,
2010                                  final String startid, String stopid,
2011                                  final String rule, final String request,
2012                                  final boolean pending, final boolean transfer,
2013                                  final boolean done, final boolean error,
2014                                  final boolean isPurge)
2015       throws OpenR66ProtocolNotAuthenticatedException,
2016              OpenR66ProtocolBusinessException {
2017     // should be from the local server or from an authorized hosts: LOGCONTROL
2018     try {
2019       if (!session.getAuth().getUser().equals(
2020           Configuration.configuration.getHostId(session.getAuth().isSsl())) &&
2021           !session.getAuth().isValidRole(ROLE.LOGCONTROL)) {
2022         throw new OpenR66ProtocolNoCorrectAuthenticationException(
2023             NOT_CORRECTLY_AUTHENTICATED);
2024       }
2025     } catch (final OpenR66ProtocolNoSslException e1) {
2026       throw new OpenR66ProtocolNotAuthenticatedException(
2027           NOT_CORRECTLY_AUTHENTICATED_SINCE_SSL_IS_NOT_SUPPORTED, e1);
2028     }
2029     final DbSession dbSession =
2030         localChannelReference != null? localChannelReference.getDbSession() :
2031             admin.getSession();
2032     // first clean if ask
2033     if (clean) {
2034       // Update all UpdatedInfo to DONE
2035       // where GlobalLastStep = ALLDONETASK and status = CompleteOk
2036       try {
2037         DbTaskRunner.changeFinishedToDone();
2038       } catch (final WaarpDatabaseNoConnectionException e) {
2039         logger.warn("Clean cannot be done {}", e.getMessage());
2040       }
2041     }
2042     // create export of log and optionally purge them from database
2043     final String filename = Configuration.configuration.getBaseDirectory() +
2044                             Configuration.configuration.getArchivePath() +
2045                             DirInterface.SEPARATOR +
2046                             Configuration.configuration.getHostId() + '_' +
2047                             System.currentTimeMillis() + "_runners.xml";
2048     NbAndSpecialId nb;
2049     DbPreparedStatement getValid = null;
2050     try {
2051       getValid = DbTaskRunner.getFilterPrepareStatement(dbSession, 0,
2052                                                         // 0 means no limit
2053                                                         true, startid, stopid,
2054                                                         start, stop, rule,
2055                                                         request, pending,
2056                                                         transfer, error, done,
2057                                                         false);
2058       nb = DbTaskRunner.writeXMLWriter(getValid, filename);
2059     } catch (final WaarpDatabaseNoConnectionException e1) {
2060       throw new OpenR66ProtocolBusinessException(e1);
2061     } catch (final WaarpDatabaseSqlException e1) {
2062       throw new OpenR66ProtocolBusinessException(e1);
2063     } finally {
2064       if (getValid != null) {
2065         getValid.realClose();
2066       }
2067     }
2068 
2069     // in case of purge
2070     int npurge = 0;
2071     if (nb != null && nb.nb > 0 && (purge || isPurge)) {
2072       // purge in same interval all runners with globallaststep
2073       // as ALLDONETASK or ERRORTASK
2074       if (Configuration.configuration.getR66Mib() != null) {
2075         Configuration.configuration.getR66Mib()
2076                                    .notifyWarning("Purge Log Order received",
2077                                                   session.getAuth().getUser());
2078       }
2079       try {
2080         if (stopid != null) {
2081           final long newstopid = Long.parseLong(stopid);
2082           if (nb.higherSpecialId < newstopid) {
2083             stopid = Long.toString(nb.higherSpecialId);
2084           }
2085         } else {
2086           stopid = Long.toString(nb.higherSpecialId);
2087         }
2088         // not pending or in transfer
2089         npurge =
2090             DbTaskRunner.purgeLogPrepareStatement(dbSession, startid, stopid,
2091                                                   start, stop, rule, request,
2092                                                   false, false, error, done,
2093                                                   false);
2094       } catch (final WaarpDatabaseNoConnectionException e) {
2095         throw new OpenR66ProtocolBusinessException(e);
2096       } catch (final WaarpDatabaseSqlException e) {
2097         throw new OpenR66ProtocolBusinessException(e);
2098       }
2099     }
2100     return new String[] {
2101         filename, nb != null? Long.toString(nb.nb) : "0", Long.toString(npurge)
2102     };
2103   }
2104 
2105   /**
2106    * Stop or Cancel a transfer.
2107    *
2108    * Warning use stopTransfer or cancelTransfer instead.
2109    *
2110    * @param type
2111    * @param reqd
2112    * @param reqr
2113    * @param id
2114    *
2115    * @return the Result to answer
2116    *
2117    * @throws OpenR66ProtocolNotAuthenticatedException
2118    */
2119   public final R66Result stopOrCancel(final byte type, final String reqd,
2120                                       final String reqr, final long id)
2121       throws OpenR66ProtocolNotAuthenticatedException,
2122              OpenR66ProtocolNoCorrectAuthenticationException {
2123     // should be from the local server or from an authorized hosts: SYSTEM
2124     try {
2125       if (!session.getAuth().getUser().equals(
2126           Configuration.configuration.getHostId(session.getAuth().isSsl())) &&
2127           !session.getAuth().isValidRole(ROLE.SYSTEM)) {
2128         throw new OpenR66ProtocolNoCorrectAuthenticationException(
2129             NOT_CORRECTLY_AUTHENTICATED);
2130       }
2131     } catch (final OpenR66ProtocolNoSslException e1) {
2132       throw new OpenR66ProtocolNotAuthenticatedException(
2133           NOT_CORRECTLY_AUTHENTICATED_SINCE_SSL_IS_NOT_SUPPORTED, e1);
2134     }
2135     final R66Result resulttest;
2136     final String key = reqd + ' ' + reqr + ' ' + id;
2137     // header = ?; middle = requested+blank+requester+blank+specialId
2138     final LocalChannelReference lcr =
2139         Configuration.configuration.getLocalTransaction().getFromRequest(key);
2140     // stop the current transfer
2141     final ErrorCode code =
2142         type == LocalPacketFactory.STOPPACKET? ErrorCode.StoppedTransfer :
2143             ErrorCode.CanceledTransfer;
2144     if (lcr != null) {
2145       int rank = 0;
2146       if (code == ErrorCode.StoppedTransfer && lcr.getSession() != null) {
2147         final DbTaskRunner taskRunner = lcr.getSession().getRunner();
2148         if (taskRunner != null) {
2149           rank = taskRunner.getRank();
2150         }
2151       }
2152       session.newState(ERROR);
2153       final ErrorPacket error =
2154           new ErrorPacket(code.name() + ' ' + rank, code.getCode(),
2155                           ErrorPacket.FORWARDCLOSECODE);
2156       try {
2157         // inform local instead of remote
2158         LocalServerHandler.channelRead0(lcr, error);
2159       } catch (final Exception e) {
2160         logger.warn("Write local packet error" + " : {}", e.getMessage());
2161       }
2162       resulttest = new R66Result(session, true, ErrorCode.CompleteOk,
2163                                  session.getRunner());
2164     } else {
2165       // Transfer is not running
2166       // but maybe need action on database
2167       if (stopOrCancelRunner(id, reqd, reqr, code)) {
2168         resulttest = new R66Result(session, true, ErrorCode.CompleteOk,
2169                                    session.getRunner());
2170       } else {
2171         resulttest = new R66Result(session, true, ErrorCode.TransferOk,
2172                                    session.getRunner());
2173       }
2174     }
2175     return resulttest;
2176   }
2177 
2178   private final LocalChannelReference getLocalChannelReference(
2179       final Transfer transfer) {
2180     final String key =
2181         transfer.getRequested() + ' ' + transfer.getRequester() + ' ' +
2182         transfer.getId();
2183     return Configuration.configuration.getLocalTransaction()
2184                                       .getFromRequest(key);
2185   }
2186 
2187   /**
2188    * @param transfer the transfer to stop
2189    *
2190    * @return
2191    */
2192   public final R66Result stopTransfer(final Transfer transfer) {
2193     final ErrorCode code = ErrorCode.StoppedTransfer;
2194     final LocalChannelReference lcr = getLocalChannelReference(transfer);
2195     if (lcr == null) {
2196       // Transfer is not running
2197       transfer.setUpdatedInfo(UpdatedInfo.INERROR);
2198       transfer.setTransferInfo(code.getCode());
2199       return new R66Result(session, true, ErrorCode.CompleteOk,
2200                            session.getRunner());
2201     }
2202     final ErrorPacket error =
2203         new ErrorPacket(code.name() + ' ' + transfer.getRank(), code.getCode(),
2204                         ErrorPacket.FORWARDCLOSECODE);
2205     try {
2206       LocalServerHandler.channelRead0(lcr, error);
2207     } catch (final Exception e) {
2208       logger.error("Cannot stop transfer (" + transfer + ')', e);
2209       return new R66Result(session, true, ErrorCode.TransferOk,
2210                            session.getRunner());
2211     }
2212     // Update session and transfer status
2213     session.setErrorState();
2214     transfer.setTransferInfo(code.getCode());
2215     return new R66Result(session, true, ErrorCode.CompleteOk,
2216                          session.getRunner());
2217   }
2218 
2219   /**
2220    * @param transfer the transfer to stop
2221    *
2222    * @return
2223    */
2224   public final R66Result cancelTransfer(final Transfer transfer) {
2225     final ErrorCode code = ErrorCode.CanceledTransfer;
2226     final LocalChannelReference lcr = getLocalChannelReference(transfer);
2227     if (lcr == null) {
2228       // Transfer is not running
2229       transfer.setUpdatedInfo(UpdatedInfo.INERROR);
2230       transfer.setTransferInfo(code.getCode());
2231       return new R66Result(session, true, ErrorCode.CompleteOk,
2232                            session.getRunner());
2233     }
2234     final ErrorPacket error =
2235         new ErrorPacket(code.name() + ' ' + transfer.getRank(), code.getCode(),
2236                         ErrorPacket.FORWARDCLOSECODE);
2237     try {
2238       LocalServerHandler.channelRead0(lcr, error);
2239     } catch (final Exception e) {
2240       logger.error("Cannot cancel transfer (" + transfer + ')', e);
2241       return new R66Result(session, true, ErrorCode.TransferOk,
2242                            session.getRunner());
2243     }
2244     // Update session and transfer status
2245     session.setErrorState();
2246     transfer.setTransferInfo(code.getCode());
2247     return new R66Result(session, true, ErrorCode.CompleteOk,
2248                          session.getRunner());
2249   }
2250 
2251   /**
2252    * Stop or Cancel a Runner
2253    *
2254    * @param id
2255    * @param reqd
2256    * @param reqr
2257    * @param code
2258    *
2259    * @return True if correctly stopped or canceled
2260    */
2261   private boolean stopOrCancelRunner(final long id, final String reqd,
2262                                      final String reqr, final ErrorCode code) {
2263     try {
2264       localChannelReference.getDbSession();
2265       final DbTaskRunner taskRunner =
2266           new DbTaskRunner(session, null, id, reqr, reqd);
2267       return taskRunner.stopOrCancelRunner(code);
2268     } catch (final WaarpDatabaseException ignored) {
2269       // ignore
2270     }
2271     return false;
2272   }
2273 
2274   /**
2275    * Receive a Shutdown request
2276    *
2277    * @param packet
2278    *
2279    * @throws OpenR66ProtocolShutdownException
2280    * @throws OpenR66ProtocolNotAuthenticatedException
2281    * @throws OpenR66ProtocolBusinessException
2282    */
2283   public final void shutdown(final ShutdownPacket packet)
2284       throws OpenR66ProtocolShutdownException,
2285              OpenR66ProtocolNotAuthenticatedException,
2286              OpenR66ProtocolBusinessException {
2287     session.newState(SHUTDOWN);
2288     shutdown(packet.getKey(), packet.isRestart());
2289     packet.clear();
2290   }
2291 
2292   /**
2293    * Receive a Shutdown request
2294    *
2295    * @param key
2296    * @param isRestart
2297    *
2298    * @throws OpenR66ProtocolShutdownException
2299    * @throws OpenR66ProtocolNotAuthenticatedException
2300    * @throws OpenR66ProtocolBusinessException
2301    */
2302   public final void shutdown(final byte[] key, final boolean isRestart)
2303       throws OpenR66ProtocolShutdownException,
2304              OpenR66ProtocolNotAuthenticatedException,
2305              OpenR66ProtocolBusinessException {
2306     if (!session.isAuthenticated()) {
2307       throw new OpenR66ProtocolNotAuthenticatedException(
2308           "Not authenticated while Shutdown received");
2309     }
2310     // SYSTEM authorization
2311     final boolean isAdmin = session.getAuth().isValidRole(ROLE.SYSTEM);
2312     final boolean isKeyValid = Configuration.configuration.isKeyValid(key);
2313     if (isAdmin && isKeyValid) {
2314       if (Configuration.configuration.getR66Mib() != null) {
2315         Configuration.configuration.getR66Mib().notifyStartStop(
2316             "Shutdown Order received effective in " +
2317             Configuration.configuration.getTimeoutCon() + " ms",
2318             session.getAuth().getUser());
2319       }
2320       if (Configuration.configuration.getShutdownConfiguration().serviceFuture !=
2321           null) {
2322         logger.warn(
2323             "R66 started as a service, Windows Services might not shown it as stopped");
2324       }
2325       if (isRestart) {
2326         WaarpShutdownHook.setRestart(true);
2327         logger.warn("Server will shutdown and restart");
2328       }
2329       throw new OpenR66ProtocolShutdownException("Shutdown Type received");
2330     }
2331     logger.error(
2332         "Invalid Shutdown command: from " + session.getAuth().getUser() +
2333         " AdmValid: " + isAdmin + " KeyValid: " + isKeyValid);
2334     throw new OpenR66ProtocolBusinessException("Invalid Shutdown comand");
2335   }
2336 
2337   /**
2338    * Business Request (channel should stay open)
2339    * <p>
2340    * Note: the thread called should manage all writeback informations, as well
2341    * as status, channel closing if
2342    * needed or not.
2343    *
2344    * @param packet
2345    *
2346    * @throws OpenR66ProtocolNotAuthenticatedException
2347    * @throws OpenR66ProtocolPacketException
2348    */
2349   public final void businessRequest(final BusinessRequestPacket packet)
2350       throws OpenR66ProtocolNotAuthenticatedException,
2351              OpenR66ProtocolPacketException,
2352              OpenR66ProtocolNoCorrectAuthenticationException {
2353     final String argRule = packet.getSheader();
2354     if (packet.isToValidate()) {
2355       session.newState(BUSINESSD);
2356     }
2357     final R66Future future =
2358         businessRequest(packet.isToValidate(), argRule, null, null,
2359                         packet.getDelay());
2360     if (future != null && !future.isSuccess()) {
2361       R66Result result = future.getResult();
2362       if (result == null) {
2363         result = new R66Result(session, false, ErrorCode.ExternalOp,
2364                                session.getRunner());
2365       }
2366       wrongResult(packet, argRule, result);
2367     } else if (future == null) {
2368       final R66Result result =
2369           new R66Result(session, false, ErrorCode.ExternalOp,
2370                         session.getRunner());
2371       wrongResult(packet, argRule, result);
2372     } else {
2373       logger.debug("BusinessRequest part 2");
2374       final R66Result result = future.getResult();
2375       final LocalChannelReference localChannelReference =
2376           session.getLocalChannelReference();
2377       if (localChannelReference != null) {
2378         localChannelReference.validateRequest(result);
2379         try {
2380           ChannelUtils.writeAbstractLocalPacket(localChannelReference, packet,
2381                                                 false);
2382         } catch (final OpenR66ProtocolPacketException ignored) {
2383           // ignore
2384         }
2385         localChannelReference.close();
2386       }
2387     }
2388   }
2389 
2390   private void wrongResult(final BusinessRequestPacket packet,
2391                            final String argRule, final R66Result result)
2392       throws OpenR66ProtocolPacketException {
2393     logger.info("Task in Error: {} {}", argRule, result);
2394     if (!result.isAnswered()) {
2395       packet.invalidate();
2396       session.newState(ERROR);
2397       final ErrorPacket error = new ErrorPacket(
2398           "BusinessRequest in error: for " + packet + " since " +
2399           result.getMessage(), result.getCode().getCode(),
2400           ErrorPacket.FORWARDCLOSECODE);
2401       ChannelUtils.writeAbstractLocalPacket(localChannelReference, error,
2402                                             false);
2403       session.setStatus(203);
2404     }
2405     session.setStatus(204);
2406     packet.clear();
2407   }
2408 
2409   /**
2410    * Business Request (channel should stay open)
2411    * <p>
2412    * Note: the thread called should manage all writeback informations, as well
2413    * as status, channel closing if
2414    * needed or not.
2415    *
2416    * @param isToApplied True means this is an action request, False it
2417    *     is
2418    *     the feedback
2419    * @param className
2420    * @param arguments
2421    * @param extraArguments
2422    * @param delay
2423    *
2424    * @return future of the execution
2425    *
2426    * @throws OpenR66ProtocolNotAuthenticatedException
2427    */
2428   public final R66Future businessRequest(final boolean isToApplied,
2429                                          final String className,
2430                                          final String arguments,
2431                                          final String extraArguments,
2432                                          final int delay)
2433       throws OpenR66ProtocolNotAuthenticatedException,
2434              OpenR66ProtocolNoCorrectAuthenticationException {
2435     if (!session.isAuthenticated()) {
2436       throw new OpenR66ProtocolNotAuthenticatedException(
2437           "Not authenticated while BusinessRequest received");
2438     }
2439     if (isToApplied && !Configuration.configuration.getBusinessWhiteSet()
2440                                                    .contains(session.getAuth()
2441                                                                     .getUser())) {
2442       logger.warn("Not allow to execute a BusinessRequest: " +
2443                   session.getAuth().getUser());
2444       throw new OpenR66ProtocolNoCorrectAuthenticationException(
2445           "Not allow to execute a BusinessRequest");
2446     }
2447     session.setStatus(200);
2448     String argRule = className;
2449     if (arguments != null) {
2450       argRule += ' ' + arguments;
2451     }
2452     final ExecJavaTask task =
2453         new ExecJavaTask(argRule + ' ' + isToApplied, delay, extraArguments,
2454                          session);
2455     task.setBusinessRequest(true);
2456     task.run();
2457     session.setStatus(201);
2458     if (task.isSuccess()) {
2459       session.setStatus(202);
2460       logger.info("Task done: " + className.split(" ")[0]);
2461     }
2462     return task.getFutureCompletion();
2463   }
2464 
2465   /**
2466    * Block/Unblock Request
2467    *
2468    * @param packet
2469    *
2470    * @throws OpenR66ProtocolBusinessException
2471    */
2472   public final void blockRequest(final BlockRequestPacket packet)
2473       throws OpenR66ProtocolBusinessException {
2474     final R66Result result = blockRequest(packet.getKey(), packet.getBlock());
2475     final ValidPacket valid = new ValidPacket(
2476         (packet.getBlock()? "Block" : "Unblock") + " new request",
2477         result.getCode().getCode(), LocalPacketFactory.REQUESTUSERPACKET);
2478     try {
2479       ChannelUtils.writeAbstractLocalPacket(localChannelReference, valid,
2480                                             false);
2481     } catch (final OpenR66ProtocolPacketException ignored) {
2482       // ignore
2483     }
2484     localChannelReference.close();
2485     packet.clear();
2486   }
2487 
2488   /**
2489    * Block/Unblock Request
2490    *
2491    * @param key
2492    * @param isBlocking
2493    *
2494    * @return The result
2495    *
2496    * @throws OpenR66ProtocolPacketException
2497    * @throws OpenR66ProtocolBusinessException
2498    */
2499   public final R66Result blockRequest(final byte[] key,
2500                                       final boolean isBlocking)
2501       throws OpenR66ProtocolBusinessException {
2502     if (!session.isAuthenticated()) {
2503       throw new OpenR66ProtocolNotAuthenticatedException(
2504           "Not authenticated while BlockRequest received");
2505     }
2506     // SYSTEM authorization
2507     final boolean isAdmin = session.getAuth().isValidRole(ROLE.SYSTEM);
2508     final boolean isKeyValid = Configuration.configuration.isKeyValid(key);
2509     if (isAdmin && isKeyValid) {
2510       if (Configuration.configuration.getR66Mib() != null) {
2511         Configuration.configuration.getR66Mib().notifyWarning(
2512             (isBlocking? "Block" : "Unblock") + " Order received",
2513             session.getAuth().getUser());
2514       }
2515       logger.debug((isBlocking? "Block" : "Unblock") + " Order received");
2516       Configuration.configuration.setShutdown(isBlocking);
2517       // inform back the requester
2518       // request of current values
2519       final R66Result result =
2520           new R66Result(session, true, ErrorCode.CompleteOk, null);
2521       if (localChannelReference != null) {
2522         localChannelReference.validateRequest(result);
2523       }
2524       return result;
2525     }
2526     logger.error("Invalid Block command: from " + session.getAuth().getUser() +
2527                  " AdmValid: " + isAdmin + " KeyValid: " + isKeyValid);
2528     throw new OpenR66ProtocolBusinessException("Invalid Block comand");
2529   }
2530 
2531   /**
2532    * Receive a request of information (Transfer information or File listing)
2533    *
2534    * @param request InformationPacket.ASKENUM ordinal
2535    * @param rulename rulename for file path
2536    * @param filename partial name (including wildcard)
2537    * @param jsonOutput ValidPacket will contain Json format ?
2538    *
2539    * @return the ValidPacket to answer containing: File Listing as Header and
2540    *     Number of entries as Middle
2541    *
2542    * @throws OpenR66ProtocolNotAuthenticatedException
2543    * @throws OpenR66ProtocolNoDataException
2544    */
2545   public final ValidPacket informationFile(final byte request,
2546                                            final String rulename,
2547                                            final String filename,
2548                                            final boolean jsonOutput)
2549       throws OpenR66ProtocolNotAuthenticatedException,
2550              OpenR66ProtocolNoDataException {
2551     if (!session.isAuthenticated()) {
2552       throw new OpenR66ProtocolNotAuthenticatedException(
2553           "Not authenticated while Information received");
2554     }
2555     localChannelReference.getDbSession();
2556     final DbRule rule;
2557     try {
2558       rule = new DbRule(rulename);
2559     } catch (final WaarpDatabaseException e) {
2560       logger.error("Rule is unknown: " + rulename, e);
2561       throw new OpenR66ProtocolNoDataException(e);
2562     }
2563     try {
2564       session.getDir().changeDirectory(rule.getSendPath());
2565 
2566       if (request == InformationPacket.ASKENUM.ASKLIST.ordinal() ||
2567           request == InformationPacket.ASKENUM.ASKMLSLIST.ordinal()) {
2568         // ls or mls from current directory
2569         final List<String> list;
2570         if (request == InformationPacket.ASKENUM.ASKLIST.ordinal()) {
2571           list = session.getDir().list(filename);
2572         } else {
2573           list = session.getDir().listFull(filename, false);
2574         }
2575 
2576         final StringBuilder builder = new StringBuilder();
2577         if (jsonOutput) {
2578           final ObjectNode node = JsonHandler.createObjectNode();
2579           final String asked =
2580               request == InformationPacket.ASKENUM.ASKLIST.ordinal()? "ls" :
2581                   "mls";
2582           final ArrayNode array = node.putArray(asked);
2583           for (final String elt : list) {
2584             array.add(elt);
2585           }
2586           builder.append(JsonHandler.writeAsString(node));
2587         } else {
2588           for (final String elt : list) {
2589             builder.append(elt).append('\n');
2590           }
2591         }
2592         if (!jsonOutput) {
2593           session.newState(VALIDOTHER);
2594         }
2595         final ValidPacket validPacket =
2596             new ValidPacket(builder.toString(), String.valueOf(list.size()),
2597                             LocalPacketFactory.INFORMATIONPACKET);
2598         final R66Result result =
2599             new R66Result(session, true, ErrorCode.CompleteOk, null);
2600         result.setOther(validPacket);
2601         if (localChannelReference != null) {
2602           localChannelReference.validateEndTransfer(result);
2603           localChannelReference.validateRequest(result);
2604         }
2605         return validPacket;
2606       } else {
2607         // exists or ls or mls from current directory and filename
2608         final R66File file =
2609             (R66File) session.getDir().setFile(filename, false);
2610         String sresult;
2611         if (request == InformationPacket.ASKENUM.ASKEXIST.ordinal()) {
2612           if (jsonOutput) {
2613             final ObjectNode node = JsonHandler.createObjectNode();
2614             node.put("exist", file.exists());
2615             sresult = JsonHandler.writeAsString(node);
2616           } else {
2617             sresult = String.valueOf(file.exists());
2618           }
2619         } else if (request ==
2620                    InformationPacket.ASKENUM.ASKMLSDETAIL.ordinal()) {
2621           sresult = session.getDir().fileFull(filename, false);
2622           final String[] list = sresult.split("\n");
2623           sresult = list[1];
2624           if (jsonOutput) {
2625             final ObjectNode node = JsonHandler.createObjectNode();
2626             node.put("mls", sresult);
2627             sresult = JsonHandler.writeAsString(node);
2628           }
2629         } else {
2630           session.newState(ERROR);
2631           logger.warn("Unknown Request " + request);
2632           return null;
2633         }
2634         if (!jsonOutput) {
2635           session.newState(VALIDOTHER);
2636         }
2637         final ValidPacket validPacket =
2638             new ValidPacket(sresult, "1", LocalPacketFactory.INFORMATIONPACKET);
2639         final R66Result result =
2640             new R66Result(session, true, ErrorCode.CompleteOk, null);
2641         result.setOther(validPacket);
2642         if (localChannelReference != null) {
2643           localChannelReference.validateEndTransfer(result);
2644           localChannelReference.validateRequest(result);
2645         }
2646         return validPacket;
2647       }
2648     } catch (final CommandAbstractException e) {
2649       session.newState(ERROR);
2650       logger.warn("Error while Request " + request + ' ' + e.getMessage());
2651       return null;
2652     }
2653   }
2654 
2655   /**
2656    * Receive a request of information (Transfer information or File listing)
2657    *
2658    * @param id Id of request
2659    * @param isTo True for remote host is requester, False for
2660    *     requested
2661    *     (default)
2662    * @param remoteHost requester/requested for transfer if jsonOutput
2663    *     is
2664    *     True, else (jsonOutput False)
2665    *     remoteHost is from current Authenticated user
2666    * @param jsonOutput ValidPacket will contain Json format ?
2667    *
2668    * @return the ValidPacket to answer containing: Transfer Information as
2669    *     Header
2670    *
2671    * @throws OpenR66ProtocolNotAuthenticatedException
2672    * @throws OpenR66ProtocolNoDataException
2673    */
2674   public final ValidPacket informationRequest(final long id, final boolean isTo,
2675                                               final String remoteHost,
2676                                               final boolean jsonOutput)
2677       throws OpenR66ProtocolNotAuthenticatedException,
2678              OpenR66ProtocolNoDataException {
2679     if (!session.isAuthenticated()) {
2680       throw new OpenR66ProtocolNotAuthenticatedException(
2681           "Not authenticated while Information received");
2682     }
2683     String remote = session.getAuth().getUser();
2684     if (jsonOutput && ParametersChecker.isNotEmpty(remoteHost)) {
2685       remote = remoteHost;
2686     }
2687     final String local;
2688     try {
2689       local = Configuration.configuration.getHostId(remote);
2690     } catch (final WaarpDatabaseException e1) {
2691       logger.error("Remote Host is unknown", e1);
2692       throw new OpenR66ProtocolNoDataException("Remote Host is unknown", e1);
2693     }
2694     final DbTaskRunner runner;
2695     if (isTo) {
2696       logger.info("{} {} {}", id, remote, local);
2697       try {
2698         runner = new DbTaskRunner(session, null, id, remote, local);
2699       } catch (final WaarpDatabaseException e) {
2700         logger.error(
2701             Messages.getString("LocalServerHandler.21") + id); //$NON-NLS-1$
2702         logger.debug(RUNNER_TASK_IS_NOT_FOUND + id + ':' + remote + ':' + local,
2703                      e);
2704         throw new OpenR66ProtocolNoDataException(
2705             Messages.getString("LocalServerHandler.22") + id, e); //$NON-NLS-1$
2706       }
2707     } else {
2708       try {
2709         runner = new DbTaskRunner(session, null, id, local, remote);
2710       } catch (final WaarpDatabaseException e) {
2711         logger.debug(RUNNER_TASK_IS_NOT_FOUND + id + ':' + local + ':' + remote,
2712                      e);
2713         logger.error(Messages.getString("LocalServerHandler.21") + id);
2714         throw new OpenR66ProtocolNoDataException(
2715             "(Local) " + Messages.getString("LocalServerHandler.21") + id, e);
2716       }
2717     }
2718     if (!jsonOutput) {
2719       session.newState(VALIDOTHER);
2720     }
2721     final ValidPacket validPacket =
2722         new ValidPacket(jsonOutput? runner.asJson() : runner.asXML(), "",
2723                         LocalPacketFactory.INFORMATIONPACKET);
2724     final R66Result result =
2725         new R66Result(session, true, ErrorCode.CompleteOk, null);
2726     result.setOther(validPacket);
2727     if (localChannelReference != null) {
2728       localChannelReference.validateEndTransfer(result);
2729       localChannelReference.validateRequest(result);
2730     }
2731     return validPacket;
2732   }
2733 
2734   /**
2735    * Receive a TransferRequest in JSON mode: just setting it to be scheduled
2736    *
2737    * @param request
2738    *
2739    * @return the result associated with the new transfer request
2740    */
2741   public final R66Result transferRequest(
2742       final TransferRequestJsonPacket request) {
2743     final DbTaskRunner runner = initTransferRequest(request);
2744     if (runner != null) {
2745       runner.changeUpdatedInfo(AbstractDbData.UpdatedInfo.TOSUBMIT);
2746       final boolean isSender = runner.isSender();
2747       if (!runner.forceSaveStatus()) {
2748         logger.warn("Cannot prepare task");
2749         return new R66Result(session, false, ErrorCode.CommandNotFound, runner);
2750       }
2751       final R66Result result =
2752           new R66Result(session, false, ErrorCode.InitOk, runner);
2753       try {
2754         runner.select();
2755       } catch (final WaarpDatabaseException ignored) {
2756         // ignore
2757       }
2758       runner.setSender(isSender);
2759       request.setFromDbTaskRunner(runner);
2760       request.validate();
2761       return result;
2762     } else {
2763       logger.warn("ERROR: Transfer NOT scheduled");
2764       return new R66Result(session, false, ErrorCode.Internal, null);
2765     }
2766   }
2767 
2768   /**
2769    * initialize a new Transfer Request
2770    *
2771    * @param request
2772    *
2773    * @return the associated DbTaskRunner
2774    */
2775   private DbTaskRunner initTransferRequest(
2776       final TransferRequestJsonPacket request) {
2777     Timestamp ttimestart = null;
2778     final Date date = request.getStart();
2779     if (date != null) {
2780       ttimestart = new Timestamp(date.getTime());
2781     } else if (request.getDelay() > 0) {
2782       if (request.isAdditionalDelay()) {
2783         ttimestart =
2784             new Timestamp(System.currentTimeMillis() + request.getDelay());
2785       } else {
2786         ttimestart = new Timestamp(request.getDelay());
2787       }
2788     }
2789     final DbRule rule;
2790     try {
2791       rule = new DbRule(request.getRulename());
2792     } catch (final WaarpDatabaseException e) {
2793       logger.warn("Cannot get Rule: " + request.getRulename() + " : {}",
2794                   e.getMessage());
2795       return null;
2796     }
2797     int mode = rule.getMode();
2798     if (RequestPacket.isMD5Mode(request.getMode())) {
2799       mode = RequestPacket.getModeMD5(mode);
2800     }
2801     final DbTaskRunner taskRunner;
2802     long tid = ILLEGALVALUE;
2803     if (request.getSpecialId() != 0 || request.getSpecialId() == ILLEGALVALUE) {
2804       tid = request.getSpecialId();
2805     }
2806     if (tid != ILLEGALVALUE) {
2807       try {
2808         taskRunner = new DbTaskRunner(tid, request.getRequested());
2809         // requested
2810         taskRunner.setSenderByRequestToValidate(true);
2811       } catch (final WaarpDatabaseException e) {
2812         logger.warn("Cannot get task" + " : {}", e.getMessage());
2813         return null;
2814       }
2815     } else {
2816       final String sep =
2817           PartnerConfiguration.getSeparator(request.getRequested());
2818       final RequestPacket requestPacket =
2819           new RequestPacket(request.getRulename(), mode, request.getFilename(),
2820                             request.getBlocksize(), 0, tid,
2821                             request.getFileInformation(), -1, sep);
2822       // Not isRecv since it is the requester, so send => isRetrieve is true
2823       final boolean isRetrieve =
2824           !RequestPacket.isRecvMode(requestPacket.getMode());
2825       try {
2826         taskRunner = new DbTaskRunner(rule, isRetrieve, requestPacket,
2827                                       request.getRequested(), ttimestart);
2828       } catch (final WaarpDatabaseException e) {
2829         logger.warn("Cannot get task" + " : {}", e.getMessage());
2830         return null;
2831       }
2832     }
2833     return taskRunner;
2834   }
2835 }