View Javadoc

1   /**
2    * Copyright 2009, Frederic Bregier, and individual contributors by the @author
3    * tags. See the COPYRIGHT.txt in the distribution for a full listing of
4    * individual contributors.
5    *
6    * This is free software; you can redistribute it and/or modify it under the
7    * terms of the GNU Lesser General Public License as published by the Free
8    * Software Foundation; either version 3.0 of the License, or (at your option)
9    * any later version.
10   *
11   * This software is distributed in the hope that it will be useful, but WITHOUT
12   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
13   * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
14   * details.
15   *
16   * You should have received a copy of the GNU Lesser General Public License
17   * along with this software; if not, write to the Free Software Foundation,
18   * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA, or see the FSF
19   * site: http://www.fsf.org.
20   */
21  package goldengate.ftp.exec.config;
22  
23  import goldengate.common.crypto.Des;
24  import goldengate.common.crypto.ssl.GgSecureKeyStore;
25  import goldengate.common.crypto.ssl.GgSslContextFactory;
26  import goldengate.common.database.DbAdmin;
27  import goldengate.common.database.DbPreparedStatement;
28  import goldengate.common.database.exception.GoldenGateDatabaseNoConnectionException;
29  import goldengate.common.database.exception.GoldenGateDatabaseSqlException;
30  import goldengate.common.digest.FilesystemBasedDigest;
31  import goldengate.common.exception.CryptoException;
32  import goldengate.common.file.DirInterface;
33  import goldengate.common.file.FileParameterInterface;
34  import goldengate.common.file.filesystembased.FilesystemBasedDirImpl;
35  import goldengate.common.file.filesystembased.FilesystemBasedFileParameterImpl;
36  import goldengate.common.file.filesystembased.specific.FilesystemBasedDirJdk5;
37  import goldengate.common.file.filesystembased.specific.FilesystemBasedDirJdk6;
38  import goldengate.common.file.filesystembased.specific.FilesystemBasedDirJdkAbstract;
39  import goldengate.common.logging.GgInternalLogger;
40  import goldengate.common.logging.GgInternalLoggerFactory;
41  import goldengate.common.utility.GgThreadFactory;
42  import goldengate.common.xml.XmlDecl;
43  import goldengate.common.xml.XmlHash;
44  import goldengate.common.xml.XmlType;
45  import goldengate.common.xml.XmlUtil;
46  import goldengate.common.xml.XmlValue;
47  import goldengate.ftp.core.config.FtpConfiguration;
48  import goldengate.ftp.core.control.BusinessHandler;
49  import goldengate.ftp.core.data.handler.DataBusinessHandler;
50  import goldengate.ftp.core.exception.FtpNoConnectionException;
51  import goldengate.ftp.core.exception.FtpUnknownFieldException;
52  import goldengate.ftp.exec.adminssl.HttpSslPipelineFactory;
53  import goldengate.ftp.exec.control.FtpConstraintLimitHandler;
54  import goldengate.ftp.exec.database.DbConstant;
55  import goldengate.ftp.exec.database.data.DbTransferLog;
56  import goldengate.ftp.exec.database.model.DbModelFactory;
57  import goldengate.ftp.exec.exec.AbstractExecutor;
58  import goldengate.ftp.exec.exec.LocalExecClient;
59  import goldengate.ftp.exec.file.FileBasedDir;
60  import goldengate.ftp.exec.file.SimpleAuth;
61  import goldengate.ftp.exec.snmp.FtpMonitoring;
62  import goldengate.ftp.exec.snmp.FtpPrivateMib;
63  import goldengate.ftp.exec.snmp.FtpVariableFactory;
64  import goldengate.snmp.GgMOFactory;
65  import goldengate.snmp.GgSnmpAgent;
66  import goldengate.snmp.SnmpConfiguration;
67  
68  import java.io.File;
69  import java.io.IOException;
70  import java.io.InvalidObjectException;
71  import java.net.InetAddress;
72  import java.net.InetSocketAddress;
73  import java.net.UnknownHostException;
74  import java.util.Arrays;
75  import java.util.Enumeration;
76  import java.util.Iterator;
77  import java.util.List;
78  import java.util.concurrent.ConcurrentHashMap;
79  import java.util.concurrent.Executors;
80  import java.util.concurrent.TimeUnit;
81  
82  import org.dom4j.Document;
83  import org.dom4j.DocumentException;
84  import org.dom4j.io.SAXReader;
85  import org.jboss.netty.bootstrap.ServerBootstrap;
86  import org.jboss.netty.channel.ChannelFactory;
87  import org.jboss.netty.channel.group.ChannelGroup;
88  import org.jboss.netty.channel.group.ChannelGroupFuture;
89  import org.jboss.netty.channel.group.ChannelGroupFutureListener;
90  import org.jboss.netty.channel.group.DefaultChannelGroup;
91  import org.jboss.netty.channel.socket.nio.NioServerSocketChannelFactory;
92  import org.jboss.netty.handler.execution.OrderedMemoryAwareThreadPoolExecutor;
93  import org.jboss.netty.handler.traffic.AbstractTrafficShapingHandler;
94  
95  /**
96   * FtpConfiguration based on a XML file
97   *
98   * @author Frederic Bregier
99   *
100  */
101 public class FileBasedConfiguration extends FtpConfiguration {
102     /**
103      * Internal Logger
104      */
105     private static final GgInternalLogger logger = GgInternalLoggerFactory
106             .getLogger(FileBasedConfiguration.class);
107 
108     /**
109      * SERVER HOSTID
110      */
111     private static final String XML_SERVER_HOSTID = "hostid";
112     /**
113      * Authentication
114      */
115     private static final String XML_AUTHENTIFICATION_FILE = "authentfile";
116     /**
117      * SERVER CRYPTO for Password
118      */
119     private static final String XML_PATH_CRYPTOKEY = "cryptokey";
120 
121     /**
122      * Structure of the Configuration file
123      *
124      */
125     private static final XmlDecl [] configIdentityDecls = {
126         // identity
127         new XmlDecl(XmlType.STRING, XML_SERVER_HOSTID), 
128         new XmlDecl(XmlType.STRING, XML_PATH_CRYPTOKEY),
129         new XmlDecl(XmlType.STRING, XML_AUTHENTIFICATION_FILE)
130     };
131     /**
132      * Use HTTP compression for R66 HTTP connection
133      */
134     private static final String XML_USEHTTPCOMP = "usehttpcomp";
135     /**
136      * Use external GoldenGate Local Exec for ExecTask and ExecMoveTask
137      */
138     private static final String XML_USELOCALEXEC = "uselocalexec";
139 
140     /**
141      * Address of GoldenGate Local Exec for ExecTask and ExecMoveTask
142      */
143     private static final String XML_LEXECADDR = "lexecaddr";
144 
145     /**
146      * Port of GoldenGate Local Exec for ExecTask and ExecMoveTask
147      */
148     private static final String XML_LEXECPORT = "lexecport";
149     /**
150      * ADMINISTRATOR SERVER NAME (shutdown)
151      */
152     private static final String XML_SERVER_ADMIN = "serveradmin";
153     /**
154      * SERVER PASSWORD (shutdown)
155      */
156     private static final String XML_SERVER_PASSWD = "serverpasswd";
157     /**
158      * SERVER SSL STOREKEY PATH ADMIN
159      */
160     private static final String XML_PATH_ADMIN_KEYPATH = "admkeypath";
161 
162     /**
163      * SERVER SSL KEY PASS ADMIN
164      */
165     private static final String XML_PATH_ADMIN_KEYPASS = "admkeypass";
166 
167     /**
168      * SERVER SSL STOREKEY PASS ADMIN
169      */
170     private static final String XML_PATH_ADMIN_KEYSTOREPASS = "admkeystorepass";
171     /**
172      * HTTP Admin Directory
173      */
174     private static final String XML_HTTPADMINPATH = "httpadmin";
175     /**
176      * Monitoring: snmp configuration file (if empty, no snmp support)
177      */
178     private static final String XML_MONITOR_SNMP_CONFIG= "snmpconfig";
179 
180     /**
181      * Structure of the Configuration file
182      *
183      */
184     private static final XmlDecl [] configServerParamDecls = {
185         // server
186         new XmlDecl(XmlType.BOOLEAN, XML_USELOCALEXEC), 
187         new XmlDecl(XmlType.STRING, XML_LEXECADDR), 
188         new XmlDecl(XmlType.INTEGER, XML_LEXECPORT),
189         new XmlDecl(XmlType.STRING, XML_SERVER_ADMIN), 
190         new XmlDecl(XmlType.STRING, XML_SERVER_PASSWD),
191         new XmlDecl(XmlType.BOOLEAN, XML_USEHTTPCOMP),
192         new XmlDecl(XmlType.STRING, XML_HTTPADMINPATH),
193         new XmlDecl(XmlType.STRING, XML_PATH_ADMIN_KEYPATH), 
194         new XmlDecl(XmlType.STRING, XML_PATH_ADMIN_KEYSTOREPASS), 
195         new XmlDecl(XmlType.STRING, XML_PATH_ADMIN_KEYPASS),
196         new XmlDecl(XmlType.STRING, XML_MONITOR_SNMP_CONFIG)
197     };
198     /**
199      * SERVER PORT
200      */
201     private static final String XML_SERVER_PORT = "serverport";
202     /**
203      * SERVER ADDRESS if any
204      */
205     private static final String XML_SERVER_ADDRESS = "serveraddress";
206     /**
207      * RANGE of PORT for Passive Mode
208      */
209     private static final String XML_RANGE_PORT_MIN = "portmin";
210 
211     /**
212      * RANGE of PORT for Passive Mode
213      */
214     private static final String XML_RANGE_PORT_MAX = "portmax";
215     /**
216      * SERVER HTTP PORT MONITORING
217      */
218     private static final String XML_SERVER_HTTP_PORT = "serverhttpport";
219     /**
220      * SERVER HTTPS PORT ADMINISTRATION
221      */
222     private static final String XML_SERVER_HTTPS_PORT = "serverhttpsport";
223 
224     /**
225      * Structure of the Configuration file
226      *
227      */
228     private static final XmlDecl [] configNetworkServerDecls = {
229         // network
230         new XmlDecl(XmlType.INTEGER, XML_SERVER_PORT),
231         new XmlDecl(XmlType.STRING, XML_SERVER_ADDRESS),
232         new XmlDecl(XmlType.INTEGER, XML_RANGE_PORT_MIN),
233         new XmlDecl(XmlType.INTEGER, XML_RANGE_PORT_MAX),
234         new XmlDecl(XmlType.INTEGER, XML_SERVER_HTTP_PORT),
235         new XmlDecl(XmlType.INTEGER, XML_SERVER_HTTPS_PORT)
236     };
237     /**
238      * Database Driver as of oracle, mysql, postgresql, h2
239      */
240     private static final String XML_DBDRIVER = "dbdriver";
241 
242     /**
243      * Database Server connection string as of
244      * jdbc:type://[host:port],[failoverhost:port]
245      * .../[database][?propertyName1][
246      * =propertyValue1][&propertyName2][=propertyValue2]...
247      */
248     private static final String XML_DBSERVER = "dbserver";
249 
250     /**
251      * Database User
252      */
253     private static final String XML_DBUSER = "dbuser";
254 
255     /**
256      * Database Password
257      */
258     private static final String XML_DBPASSWD = "dbpasswd";
259     /**
260      * Structure of the Configuration file
261      *
262      */
263     private static final XmlDecl [] configDbDecls = {
264         //db
265         new XmlDecl(XmlType.STRING, XML_DBDRIVER), 
266         new XmlDecl(XmlType.STRING, XML_DBSERVER),
267         new XmlDecl(XmlType.STRING, XML_DBUSER), 
268         new XmlDecl(XmlType.STRING, XML_DBPASSWD)
269     };
270     /**
271      * Should a file be deleted when a Store like command is aborted
272      */
273     private static final String XML_DELETEONABORT = "deleteonabort";
274     /**
275      * Default number of threads in pool for Server.
276      */
277     private static final String XML_SERVER_THREAD = "serverthread";
278 
279     /**
280      * Default number of threads in pool for Client.
281      */
282     private static final String XML_CLIENT_THREAD = "clientthread";
283     /**
284      * Memory Limit to use.
285      */
286     private static final String XML_MEMORY_LIMIT = "memorylimit";
287 
288     /**
289      * Limit for Session
290      */
291     private static final String XML_LIMITSESSION = "sessionlimit";
292 
293     /**
294      * Limit for Global
295      */
296     private static final String XML_LIMITGLOBAL = "globallimit";
297     /**
298      * Delay between two checks for Limit
299      */
300     private static final String XML_LIMITDELAY = "delaylimit";
301     /**
302      * Nb of milliseconds after connection is in timeout
303      */
304     private static final String XML_TIMEOUTCON = "timeoutcon";
305     /**
306      * Size by default of block size for receive/sending files. Should be a
307      * multiple of 8192 (maximum = 64K due to block limitation to 2 bytes)
308      */
309     private static final String XML_BLOCKSIZE = "blocksize";
310     /**
311      * Should a file MD5 SHA1 be computed using NIO
312      */
313     private static final String XML_USENIO = "usenio";
314 
315     /**
316      * Should a file MD5 be computed using FastMD5
317      */
318     private static final String XML_USEFASTMD5 = "usefastmd5";
319 
320     /**
321      * If using Fast MD5, should we used the binary JNI library, empty meaning
322      * no
323      */
324     private static final String XML_FASTMD5 = "fastmd5";
325     /**
326      * Usage of CPU Limit
327      */
328     private static final String XML_CSTRT_USECPULIMIT = "usecpulimit";
329 
330     /**
331      * Usage of JDK CPU Limit (True) or SysMon CPU Limit
332      */
333     private static final String XML_CSTRT_USECPUJDKLIMIT = "usejdkcpulimit";
334 
335     /**
336      * CPU LIMIT between 0 and 1, where 1 stands for no limit
337      */
338     private static final String XML_CSTRT_CPULIMIT = "cpulimit";
339     /**
340      * Connection limit where 0 stands for no limit
341      */
342     private static final String XML_CSTRT_CONNLIMIT = "connlimit";
343     /**
344      * CPU LOW limit to apply increase of throttle
345      */
346     private static final String XML_CSTRT_LOWCPULIMIT = "lowcpulimit";
347     /**
348      * CPU HIGH limit to apply decrease of throttle, 0 meaning no throttle activated
349      */
350     private static final String XML_CSTRT_HIGHCPULIMIT = "highcpulimit";
351     /**
352      * PERCENTAGE DECREASE of Bandwidth
353      */
354     private static final String XML_CSTRT_PERCENTDECREASE = "percentdecrease";
355     /**
356      * Delay between 2 checks of throttle test
357      */
358     private static final String XML_CSTRT_DELAYTHROTTLE = "delaythrottle";
359     /**
360      * Bandwidth low limit to not got below
361      */
362     private static final String XML_CSTRT_LIMITLOWBANDWIDTH = "limitlowbandwidth";
363     /**
364      * Structure of the Configuration file
365      *
366      */
367     private static final XmlDecl [] configLimitDecls = {
368         // limit
369         new XmlDecl(XmlType.BOOLEAN, XML_DELETEONABORT),
370         new XmlDecl(XmlType.LONG, XML_LIMITSESSION), 
371         new XmlDecl(XmlType.LONG, XML_LIMITGLOBAL), 
372         new XmlDecl(XmlType.LONG, XML_LIMITDELAY),
373         new XmlDecl(XmlType.INTEGER, XML_SERVER_THREAD), 
374         new XmlDecl(XmlType.INTEGER, XML_CLIENT_THREAD), 
375         new XmlDecl(XmlType.LONG, XML_MEMORY_LIMIT), 
376         new XmlDecl(XmlType.BOOLEAN, XML_CSTRT_USECPULIMIT),
377         new XmlDecl(XmlType.BOOLEAN, XML_CSTRT_USECPUJDKLIMIT),
378         new XmlDecl(XmlType.DOUBLE, XML_CSTRT_CPULIMIT),
379         new XmlDecl(XmlType.INTEGER, XML_CSTRT_CONNLIMIT),
380         new XmlDecl(XmlType.DOUBLE, XML_CSTRT_LOWCPULIMIT),
381         new XmlDecl(XmlType.DOUBLE, XML_CSTRT_HIGHCPULIMIT),
382         new XmlDecl(XmlType.DOUBLE, XML_CSTRT_PERCENTDECREASE),
383         new XmlDecl(XmlType.LONG, XML_CSTRT_LIMITLOWBANDWIDTH),
384         new XmlDecl(XmlType.LONG, XML_CSTRT_DELAYTHROTTLE),
385         new XmlDecl(XmlType.LONG, XML_TIMEOUTCON),
386         new XmlDecl(XmlType.BOOLEAN, XML_USENIO),
387         new XmlDecl(XmlType.BOOLEAN, XML_USEFASTMD5), 
388         new XmlDecl(XmlType.STRING, XML_FASTMD5), 
389         new XmlDecl(XmlType.INTEGER, XML_BLOCKSIZE)
390     };
391     
392     /**
393      * RETRIEVE COMMAND
394      */
395     public static final String XML_RETRIEVE_COMMAND = "retrievecmd";
396 
397     /**
398      * STORE COMMAND
399      */
400     public static final String XML_STORE_COMMAND = "storecmd";
401 
402     /**
403      * DELAY RETRIEVE COMMAND
404      */
405     public static final String XML_DELAYRETRIEVE_COMMAND = "retrievedelay";
406 
407     /**
408      * DELAY STORE COMMAND
409      */
410     public static final String XML_DELAYSTORE_COMMAND = "storedelay";
411     /**
412      * Structure of the Configuration file
413      *
414      */
415     private static final XmlDecl [] configExecDecls = {
416         // Exec
417         new XmlDecl(XmlType.STRING, XML_RETRIEVE_COMMAND),
418         new XmlDecl(XmlType.LONG, XML_DELAYRETRIEVE_COMMAND), 
419         new XmlDecl(XmlType.STRING, XML_STORE_COMMAND), 
420         new XmlDecl(XmlType.LONG, XML_DELAYSTORE_COMMAND)
421     };
422     /**
423      * Base Directory
424      */
425     private static final String XML_SERVER_HOME = "serverhome";
426     /**
427      * Structure of the Configuration file
428      *
429      */
430     private static final XmlDecl [] configDirectoryDecls = {
431         // directory
432         new XmlDecl(XmlType.STRING, XML_SERVER_HOME)
433     };
434     /**
435      * Overall structure of the Configuration file
436      */
437     private static final String XML_ROOT = "/config/";
438     private static final String XML_IDENTITY = "identity";
439     private static final String XML_SERVER = "server";
440     private static final String XML_DIRECTORY = "directory";
441     private static final String XML_LIMIT = "limit";
442     private static final String XML_NETWORK = "network";
443     private static final String XML_EXEC = "exec";
444     private static final String XML_DB = "db";
445     /**
446      * Global Structure for Server Configuration
447      */
448     private static final XmlDecl[] configServer = {
449         new XmlDecl(XML_IDENTITY, XmlType.XVAL, XML_ROOT+XML_IDENTITY, configIdentityDecls, false),
450         new XmlDecl(XML_SERVER, XmlType.XVAL, XML_ROOT+XML_SERVER, configServerParamDecls, false),
451         new XmlDecl(XML_NETWORK, XmlType.XVAL, XML_ROOT+XML_NETWORK, configNetworkServerDecls, false),
452         new XmlDecl(XML_EXEC, XmlType.XVAL, XML_ROOT+XML_EXEC, configExecDecls, false),
453         new XmlDecl(XML_DIRECTORY, XmlType.XVAL, XML_ROOT+XML_DIRECTORY, configDirectoryDecls, false),
454         new XmlDecl(XML_LIMIT, XmlType.XVAL, XML_ROOT+XML_LIMIT, configLimitDecls, false),
455         new XmlDecl(XML_DB, XmlType.XVAL, XML_ROOT+XML_DB, configDbDecls, false)
456     };
457 
458     /**
459      * Authentication Fields
460      */
461     private static final String XML_AUTHENTIFICATION_ROOT = "authent";
462     /**
463      * Authentication Fields
464      */
465     private static final String XML_AUTHENTIFICATION_ENTRY = "entry";
466     /**
467      * Authentication Fields
468      */
469     private static final String XML_AUTHENTIFICATION_BASED = "/"+
470         XML_AUTHENTIFICATION_ROOT+"/"+XML_AUTHENTIFICATION_ENTRY;
471 
472     /**
473      * Authentication Fields
474      */
475     private static final String XML_AUTHENTICATION_USER = "user";
476 
477     /**
478      * Authentication Fields
479      */
480     private static final String XML_AUTHENTICATION_PASSWD = "passwd";
481     /**
482      * Authentication Fields
483      */
484     private static final String XML_AUTHENTICATION_PASSWDFILE = "passwdfile";
485 
486     /**
487      * Authentication Fields
488      */
489     private static final String XML_AUTHENTICATION_ACCOUNT = "account";
490 
491     /**
492      * Authentication Fields
493      */
494     private static final String XML_AUTHENTICATION_ADMIN = "admin";
495     /**
496      * Structure of the Configuration file
497      *
498      */
499     private static final XmlDecl [] configAuthenticationDecls = {
500         // identity
501         new XmlDecl(XmlType.STRING, XML_AUTHENTICATION_USER), 
502         new XmlDecl(XmlType.STRING, XML_AUTHENTICATION_PASSWDFILE),
503         new XmlDecl(XmlType.STRING, XML_AUTHENTICATION_PASSWD),
504         new XmlDecl(XML_AUTHENTICATION_ACCOUNT, XmlType.STRING, XML_AUTHENTICATION_ACCOUNT, true),
505         new XmlDecl(XmlType.BOOLEAN, XML_AUTHENTICATION_ADMIN),
506         // Exec
507         new XmlDecl(XmlType.STRING, XML_RETRIEVE_COMMAND),
508         new XmlDecl(XmlType.LONG, XML_DELAYRETRIEVE_COMMAND), 
509         new XmlDecl(XmlType.STRING, XML_STORE_COMMAND), 
510         new XmlDecl(XmlType.LONG, XML_DELAYSTORE_COMMAND)
511     };
512     /**
513      * Global Structure for Server Configuration
514      */
515     private static final XmlDecl[] authentElements = {
516         new XmlDecl(XML_AUTHENTIFICATION_ENTRY, XmlType.XVAL, XML_AUTHENTIFICATION_BASED, 
517                 configAuthenticationDecls, true)
518     };
519 
520     /**
521      * RANGE of PORT for Passive Mode
522      */
523     private static final String RANGE_PORT = "FTP_RANGE_PORT";
524     /**
525      * Use to access directly the configuration
526      */
527     public static FileBasedConfiguration fileBasedConfiguration;
528     /**
529      * All authentications
530      */
531     private ConcurrentHashMap<String, SimpleAuth> authentications = new ConcurrentHashMap<String, SimpleAuth>();
532 
533     /**
534      * File containing the authentications
535      */
536     public String authenticationFile;
537     /**
538      * Default HTTP server port
539      */
540     public int SERVER_HTTPPORT = 8066;
541 
542     /**
543      * Default HTTP server port
544      */
545     public int SERVER_HTTPSPORT = 8067;
546     /**
547      * Max global memory limit: default is 4GB
548      */
549     public long maxGlobalMemory = 0x100000000L;
550     /**
551      * Http Admin base
552      */
553     public String httpBasePath = "src/main/admin/";
554     /**
555      * Delay in ms between two checks
556      */
557     public long delayLimit = 10000;
558     /**
559      * Does this server will try to compress HTTP connections
560      */
561     public boolean useHttpCompression = false;
562 
563     /**
564      * Does this server will use GoldenGate LocalExec Daemon for Execute
565      */
566     public boolean useLocalExec = false;
567 
568     /**
569      * Crypto Key
570      */
571     public Des cryptoKey = null;
572     /**
573      * Server Administration Key
574      */
575     private byte[] SERVERADMINKEY = null;
576     /**
577      * FTP server ID
578      */
579     public String HOST_ID = "noId";
580     /**
581      * Admin name Id
582      */
583     public String ADMINNAME = "noAdmin";
584     /**
585      * Limit on CPU and Connection
586      */
587     public FtpConstraintLimitHandler constraintLimitHandler = null;
588     
589     /**
590      * List of all Http Channels to enable the close call on them using Netty
591      * ChannelGroup
592      */
593     private ChannelGroup httpChannelGroup = null;
594     /**
595      * Bootstrap for Https server
596      */
597     private ServerBootstrap httpsBootstrap = null;
598     /**
599      * ChannelFactory for HttpsServer part
600      */
601     private ChannelFactory httpsChannelFactory = null;
602     /**
603      * ThreadPoolExecutor for Http and Https Server
604      */
605     private volatile OrderedMemoryAwareThreadPoolExecutor httpPipelineExecutor;
606     /**
607      * Monitoring: snmp configuration file (empty means no snmp support)
608      */
609     public String snmpConfig = null;
610     /**
611      * SNMP Agent (if any)
612      */
613     public GgSnmpAgent agentSnmp = null;
614     /**
615      * Associated MIB
616      */
617     public FtpPrivateMib ftpMib = null;
618     /**
619      * Monitoring object
620      */
621     public FtpMonitoring monitoring = null;
622 
623     
624     /**
625      * @param classtype
626      * @param businessHandler
627      *            class that will be used for BusinessHandler
628      * @param dataBusinessHandler
629      *            class that will be used for DataBusinessHandler
630      * @param fileParameter
631      *            the FileParameter to use
632      */
633     public FileBasedConfiguration(Class<?> classtype,
634             Class<? extends BusinessHandler> businessHandler,
635             Class<? extends DataBusinessHandler> dataBusinessHandler,
636             FileParameterInterface fileParameter) {
637         super(classtype, businessHandler, dataBusinessHandler, fileParameter);
638         computeNbThreads();
639     }
640 
641     private static XmlValue[] configuration = null;
642     private static XmlHash hashConfig = null; 
643     
644     private boolean loadIdentity() {
645         XmlValue value = hashConfig.get(XML_SERVER_HOSTID);
646         if (value != null && (!value.isEmpty())) {
647             HOST_ID = value.getString();
648         } else {
649             logger.error("Unable to find Host ID in Config file");
650             return false;
651         }
652         return setCryptoKey();
653     }
654     
655     private boolean loadAuthentication() {
656             // if no database, must load authentication from file
657             XmlValue value = hashConfig.get(XML_AUTHENTIFICATION_FILE);
658             if (value != null && (!value.isEmpty())) {
659                 authenticationFile = value.getString();
660                 if (!initializeAuthent(authenticationFile, false)) {
661                     return false;
662                 }
663             } else {
664                 logger.warn("Unable to find Authentication file in Config file");
665                 return false;
666             }
667         return true;
668     }
669     
670     private boolean loadServerParam() {
671         XmlValue value = hashConfig.get(XML_USEHTTPCOMP);
672         if (value != null && (!value.isEmpty())) {
673             useHttpCompression = value.getBoolean();
674         }
675         value = hashConfig.get(XML_USELOCALEXEC);
676         if (value != null && (!value.isEmpty())) {
677             useLocalExec = value.getBoolean();
678             if (useLocalExec) {
679                 value = hashConfig.get(XML_LEXECADDR);
680                 String saddr;
681                 InetAddress addr;
682                 if (value != null && (!value.isEmpty())) {
683                     saddr = value.getString();
684                     try {
685                         addr = InetAddress.getByName(saddr);
686                     } catch (UnknownHostException e) {
687                         logger.error("Unable to find LocalExec Address in Config file");
688                         return false;
689                     }
690                 } else {
691                     logger.warn("Unable to find LocalExec Address in Config file");
692                     try {
693                         addr = InetAddress.getByAddress(new byte[]{127,0,0,1});
694                     } catch (UnknownHostException e) {
695                         logger.error("Unable to find LocalExec Address in Config file");
696                         return false;
697                     }
698                 }
699                 value = hashConfig.get(XML_LEXECPORT);
700                 int port;
701                 if (value != null && (!value.isEmpty())) {
702                     port = value.getInteger();
703                 } else {
704                     port = 9999;
705                 }
706                 LocalExecClient.address = new InetSocketAddress(addr, port);
707             }
708         }
709         value = hashConfig.get(XML_SERVER_ADMIN);
710         if (value != null && (!value.isEmpty())) {
711             ADMINNAME = value.getString();
712         } else {
713             logger.error("Unable to find Administrator name in Config file");
714             return false;
715         }
716         if (cryptoKey == null) {
717             if (! setCryptoKey()) {
718                 logger.error("Unable to find Crypto Key in Config file");
719                 return false;
720             }
721         }
722         String passwd;
723         value = hashConfig.get(XML_SERVER_PASSWD);
724         if (value != null && (!value.isEmpty())) {
725             passwd = value.getString();
726         } else {
727             logger.error("Unable to find Password in Config file");
728             return false;
729         }
730         byte[] decodedByteKeys = null;
731         try {
732             decodedByteKeys =
733                 cryptoKey.decryptHexInBytes(passwd);
734         } catch (Exception e) {
735             logger.error(
736                     "Unable to Decrypt Server Password in Config file from: " +
737                             passwd, e);
738             return false;
739         }
740         setSERVERKEY(decodedByteKeys);
741         value = hashConfig.get(XML_HTTPADMINPATH);
742         if (value == null || (value.isEmpty())) {
743             logger.error("Unable to find Http Admin Base in Config file");
744             return false;
745         }
746         String path = value.getString();
747         if (path == null || path.length() == 0) {
748             logger.warn("Unable to set correct Http Admin Base in Config file. No HTTPS support will be used.");
749             httpBasePath = null;
750         } else {
751             File file = new File(path);
752             if (!file.isDirectory()) {
753                 logger.error("Http Admin is not a directory in Config file");
754                 return false;
755             }
756             try {
757                 httpBasePath =
758                     FilesystemBasedDirImpl.normalizePath(file.getCanonicalPath())+ 
759                     DirInterface.SEPARATOR;
760             } catch (IOException e1) {
761                 logger.error("Unable to set Http Admin Path in Config file");
762                 return false;
763             }
764         }
765         httpChannelGroup = new DefaultChannelGroup("HttpOpenR66");
766         if (httpBasePath != null) {
767             // Key for HTTPS
768             value = hashConfig.get(XML_PATH_ADMIN_KEYPATH);
769             if (value != null && (!value.isEmpty())) {
770                 String keypath = value.getString();
771                 if ((keypath == null) || (keypath.length() == 0)) {
772                     logger.error("Bad Key Path");
773                     return false;
774                 }
775                 value = hashConfig.get(XML_PATH_ADMIN_KEYSTOREPASS);
776                 if (value == null || (value.isEmpty())) {
777                     logger.error("Unable to find KeyStore Passwd");
778                     return false;
779                 }
780                 String keystorepass = value.getString();
781                 if ((keystorepass == null) || (keystorepass.length() == 0)) {
782                     logger.error("Bad KeyStore Passwd");
783                     return false;
784                 }
785                 value = hashConfig.get(XML_PATH_ADMIN_KEYPASS);
786                 if (value == null || (value.isEmpty())) {
787                     logger.error("Unable to find Key Passwd");
788                     return false;
789                 }
790                 String keypass = value.getString();
791                 if ((keypass == null) || (keypass.length() == 0)) {
792                     logger.error("Bad Key Passwd");
793                     return false;
794                 }
795                 try {
796                     HttpSslPipelineFactory.ggSecureKeyStore =
797                         new GgSecureKeyStore(keypath, keystorepass,
798                                 keypass);
799                 } catch (CryptoException e) {
800                     logger.error("Bad SecureKeyStore construction for AdminSsl");
801                     return false;
802                 }
803                 // No client authentication
804                 HttpSslPipelineFactory.ggSecureKeyStore.initEmptyTrustStore();
805                 HttpSslPipelineFactory.ggSslContextFactory =
806                     new GgSslContextFactory(
807                             HttpSslPipelineFactory.ggSecureKeyStore, true);
808             }
809         }
810         value = hashConfig.get(XML_MONITOR_SNMP_CONFIG);
811         if (value != null && (!value.isEmpty())) {
812             snmpConfig = value.getString();
813             logger.warn("SNMP configuration file: "+snmpConfig);
814             File snmpfile = new File(snmpConfig);
815             if (snmpfile.canRead()) {
816                 if (!SnmpConfiguration.setConfigurationFromXml(snmpfile)) {
817                     logger.warn("Bad SNMP configuration file: "+snmpConfig);
818                     snmpConfig = null;
819                 }
820             } else {
821                 logger.warn("Cannot read SNMP configuration file: "+snmpConfig);
822                 snmpConfig = null;
823             }
824         } else {
825             logger.warn("NO SNMP configuration file");
826         }
827         return true;
828     }
829     private boolean loadDirectory() {
830         XmlValue value = hashConfig.get(XML_SERVER_HOME);
831         if (value == null || (value.isEmpty())) {
832             logger.error("Unable to find Home in Config file");
833             return false;
834         }
835         String path = value.getString();
836         File file = new File(path);
837         if (!file.isDirectory()) {
838             logger.error("Home is not a directory in Config file");
839             return false;
840         }
841         try {
842             setBaseDirectory(FilesystemBasedDirImpl.normalizePath(file
843                     .getCanonicalPath()));
844         } catch (IOException e1) {
845             logger.error("Unable to set Home in Config file: " + path);
846             return false;
847         }
848         return true;
849     }
850     private boolean loadLimit(boolean updateLimit) {
851         XmlValue value = hashConfig.get(XML_LIMITGLOBAL);
852         if (value != null && (!value.isEmpty())) {
853             serverGlobalReadLimit = value.getLong();
854             if (serverGlobalReadLimit <= 0) {
855                 serverGlobalReadLimit = 0;
856             }
857             serverGlobalWriteLimit = serverGlobalReadLimit;
858             logger.info("Global Limit: {}",
859                     serverGlobalReadLimit);
860         }
861         value = hashConfig.get(XML_LIMITSESSION);
862         if (value != null && (!value.isEmpty())) {
863             serverChannelReadLimit = value.getLong();
864             if (serverChannelReadLimit <= 0) {
865                 serverChannelReadLimit = 0;
866             }
867             serverChannelWriteLimit = serverChannelReadLimit;
868             logger.info("SessionInterface Limit: {}",
869                     serverChannelReadLimit);
870         }
871         delayLimit = AbstractTrafficShapingHandler.DEFAULT_CHECK_INTERVAL;
872         value = hashConfig.get(XML_LIMITDELAY);
873         if (value != null && (!value.isEmpty())) {
874             delayLimit = (value.getLong()/10)*10;
875             if (delayLimit <= 0) {
876                 delayLimit = 0;
877             }
878             logger.info("Delay Limit: {}",
879                     delayLimit);
880         }
881         boolean useCpuLimit = false;
882         boolean useCpuLimitJDK = false; 
883         double cpulimit = 1.0;
884         value = hashConfig.get(XML_CSTRT_USECPULIMIT);
885         if (value != null && (!value.isEmpty())) {
886             useCpuLimit = value.getBoolean();
887             value = hashConfig.get(XML_CSTRT_USECPUJDKLIMIT);
888             if (value != null && (!value.isEmpty())) {
889                 useCpuLimitJDK = value.getBoolean();
890             }
891             value = hashConfig.get(XML_CSTRT_CPULIMIT);
892             if (value != null && (!value.isEmpty())) {
893                 cpulimit = value.getDouble();
894             }
895         }
896         int connlimit = 0;
897         value = hashConfig.get(XML_CSTRT_CONNLIMIT);
898         if (value != null && (!value.isEmpty())) {
899             connlimit = value.getInteger();
900         }
901         double lowcpuLimit = 0;
902         double highcpuLimit = 0;
903         double percentageDecrease = 0;
904         long delay = 1000000;
905         long limitLowBandwidth = 4096;
906         value = hashConfig.get(XML_CSTRT_LOWCPULIMIT);
907         if (value != null && (!value.isEmpty())) {
908             lowcpuLimit = value.getDouble();
909         }
910         value = hashConfig.get(XML_CSTRT_HIGHCPULIMIT);
911         if (value != null && (!value.isEmpty())) {
912             highcpuLimit = value.getDouble();
913         }
914         value = hashConfig.get(XML_CSTRT_PERCENTDECREASE);
915         if (value != null && (!value.isEmpty())) {
916             percentageDecrease = value.getDouble();
917         }
918         value = hashConfig.get(XML_CSTRT_DELAYTHROTTLE);
919         if (value != null && (!value.isEmpty())) {
920             delay = (value.getLong()/10)*10;
921         }
922         value = hashConfig.get(XML_CSTRT_LIMITLOWBANDWIDTH);
923         if (value != null && (!value.isEmpty())) {
924             limitLowBandwidth = value.getLong();
925         }
926         value = hashConfig.get(XML_TIMEOUTCON);
927         if (value != null && (!value.isEmpty())) {
928             TIMEOUTCON = (value.getLong()/10)*10;
929         }
930         if (highcpuLimit > 0) {
931             constraintLimitHandler =
932                 new FtpConstraintLimitHandler(TIMEOUTCON, useCpuLimit, useCpuLimitJDK, cpulimit, connlimit,
933                         lowcpuLimit, highcpuLimit, percentageDecrease, null, delay, limitLowBandwidth);
934         } else {
935             constraintLimitHandler =
936                 new FtpConstraintLimitHandler(TIMEOUTCON, useCpuLimit, useCpuLimitJDK, cpulimit, connlimit);
937         }
938         value = hashConfig.get(XML_SERVER_THREAD);
939         if (value != null && (!value.isEmpty())) {
940             SERVER_THREAD = value.getInteger();
941         }
942         value = hashConfig.get(XML_CLIENT_THREAD);
943         if (value != null && (!value.isEmpty())) {
944             CLIENT_THREAD = value.getInteger();
945         }
946         value = hashConfig.get(XML_MEMORY_LIMIT);
947         if (value != null && (!value.isEmpty())) {
948             maxGlobalMemory = value.getLong();
949         }
950         ((FilesystemBasedFileParameterImpl)getFileParameter()).deleteOnAbort = false;
951         value = hashConfig.get(XML_USENIO);
952         if (value != null && (!value.isEmpty())) {
953             FilesystemBasedFileParameterImpl.useNio = value.getBoolean();
954         }
955         value = hashConfig.get(XML_USEFASTMD5);
956         if (value != null && (!value.isEmpty())) {
957             FilesystemBasedDigest.useFastMd5 = value.getBoolean();
958             if (FilesystemBasedDigest.useFastMd5) {
959                 value = hashConfig.get(XML_FASTMD5);
960                 if (value != null && (!value.isEmpty())) {
961                     FilesystemBasedDigest.fastMd5Path = value.getString();
962                     if (FilesystemBasedDigest.fastMd5Path == null ||
963                             FilesystemBasedDigest.fastMd5Path.length() == 0) {
964                         logger.info("FastMD5 init lib to null");
965                         FilesystemBasedDigest.initializeMd5(false, null);
966                     } else {
967                         logger.info("FastMD5 init lib to {}",
968                                 FilesystemBasedDigest.fastMd5Path);
969                         FilesystemBasedDigest.initializeMd5(true,
970                                 FilesystemBasedDigest.fastMd5Path);
971                     }
972                 }
973             } else {
974                 FilesystemBasedDigest.initializeMd5(false, null);
975             }
976         } else {
977             FilesystemBasedDigest.initializeMd5(false, null);
978         }
979         value = hashConfig.get(XML_BLOCKSIZE);
980         if (value != null && (!value.isEmpty())) {
981             BLOCKSIZE = value.getInteger();
982         }
983         value = hashConfig.get(XML_DELETEONABORT);
984         if (value != null && (!value.isEmpty())) {
985             deleteOnAbort = value.getBoolean();
986         }
987         // We use Apache Commons IO
988         FilesystemBasedDirJdkAbstract.ueApacheCommonsIo = true;
989         if (USEJDK6) {
990             FileBasedDir.initJdkDependent(new FilesystemBasedDirJdk6());
991         } else {
992             FileBasedDir.initJdkDependent(new FilesystemBasedDirJdk5());
993         }
994         return true;
995     }
996     private boolean loadNetworkServer() {
997         XmlValue value = hashConfig.get(XML_SERVER_PORT);
998         int port = 21;
999         if (value != null && (!value.isEmpty())) {
1000             port = value.getInteger();
1001         } else {
1002             port = 21;
1003         }
1004         setServerPort(port);
1005         value = hashConfig.get(XML_SERVER_ADDRESS);
1006         String address = null;
1007         if (value != null && (!value.isEmpty())) {
1008             address = value.getString();
1009         }
1010         setServerAddress(address);
1011         int min = 100;
1012         int max = 65535;
1013         value = hashConfig.get(XML_RANGE_PORT_MIN);
1014         if (value != null && (!value.isEmpty())) {
1015             min = value.getInteger();
1016         }
1017         value = hashConfig.get(XML_RANGE_PORT_MAX);
1018         if (value != null && (!value.isEmpty())) {
1019             max = value.getInteger();
1020         }
1021         logger.warn("Passive Port range Min: "+min+" Max: "+max);
1022         CircularIntValue rangePort = new CircularIntValue(min, max);
1023         setRangePort(rangePort);
1024         value = hashConfig.get(XML_SERVER_HTTP_PORT);
1025         int httpport = 8066;
1026         if (value != null && (!value.isEmpty())) {
1027             httpport = value.getInteger();
1028         }
1029         SERVER_HTTPPORT = httpport;
1030         value = hashConfig.get(XML_SERVER_HTTPS_PORT);
1031         int httpsport = 8067;
1032         if (value != null && (!value.isEmpty())) {
1033             httpsport = value.getInteger();
1034         }
1035         SERVER_HTTPSPORT = httpsport;
1036         return true;
1037     }
1038     /**
1039      * Set the Crypto Key from the Document
1040      * @param document
1041      * @return True if OK
1042      */
1043     private boolean setCryptoKey() {
1044         XmlValue value = hashConfig.get(XML_PATH_CRYPTOKEY);
1045         if (value == null || (value.isEmpty())) {
1046             logger.error("Unable to find CryptoKey in Config file");
1047             return false;
1048         }
1049         String filename = value.getString();
1050         File key = new File(filename);
1051         Des des = new Des();
1052         try {
1053             des.setSecretKey(key);
1054         } catch (CryptoException e) {
1055             logger.error("Unable to load CryptoKey from Config file");
1056             return false;
1057         } catch (IOException e) {
1058             logger.error("Unable to load CryptoKey from Config file");
1059             return false;
1060         }
1061         cryptoKey = des;
1062         return true;
1063     }
1064     /**
1065      * 
1066      * @return True if the global Exec parameters are correctly loaded
1067      */
1068     private boolean loadExec() {
1069         // Specific Exec command options
1070         XmlValue value = hashConfig.get(XML_RETRIEVE_COMMAND);
1071         if (value == null || (value.isEmpty())) {
1072             logger.error("Unable to find Retrieve Command in Config file");
1073             return false;
1074         }
1075         String retrieve = value.getString();
1076         value = hashConfig.get(XML_DELAYRETRIEVE_COMMAND);
1077         long retrievedelay = 0;
1078         if (value != null && (!value.isEmpty())) {
1079             retrievedelay = (value.getLong()/10)*10;
1080         }
1081         value = hashConfig.get(XML_STORE_COMMAND);
1082         if (value == null || (value.isEmpty())) {
1083             logger.error("Unable to find Store Command in Config file");
1084             return false;
1085         }
1086         String store = value.getString();
1087         value = hashConfig.get(XML_DELAYSTORE_COMMAND);
1088         long storedelay = 0;
1089         if (value != null && (!value.isEmpty())) {
1090             storedelay = (value.getLong()/10)*10;
1091         }
1092         AbstractExecutor.initializeExecutor(retrieve, retrievedelay, store, storedelay);
1093         return true;
1094     }
1095     /**
1096      * Load database parameter
1097      *
1098      * @param document
1099      * @return True if OK
1100      */
1101     private boolean loadDatabase() {
1102         XmlValue value = hashConfig.get(XML_DBDRIVER);
1103         if (value == null || (value.isEmpty())) {
1104             logger.error("Unable to find DBDriver in Config file");
1105             DbConstant.admin = new DbAdmin(); // no database support
1106         } else {
1107             String dbdriver = value.getString();
1108             value = hashConfig.get(XML_DBSERVER);
1109             if (value == null || (value.isEmpty())) {
1110                 logger.error("Unable to find DBServer in Config file");
1111                 return false;
1112             }
1113             String dbserver = value.getString();
1114             value = hashConfig.get(XML_DBUSER);
1115             if (value == null || (value.isEmpty())) {
1116                 logger.error("Unable to find DBUser in Config file");
1117                 return false;
1118             }
1119             String dbuser = value.getString();
1120             value = hashConfig.get(XML_DBPASSWD);
1121             if (value == null || (value.isEmpty())) {
1122                 logger.error("Unable to find DBPassword in Config file");
1123                 return false;
1124             }
1125             String dbpasswd = value.getString();
1126             if (dbdriver == null || dbserver == null || dbuser == null ||
1127                     dbpasswd == null || dbdriver.length() == 0 ||
1128                     dbserver.length() == 0 || dbuser.length() == 0 ||
1129                     dbpasswd.length() == 0) {
1130                 logger.error("Unable to find Correct DB data in Config file");
1131                 return false;
1132             }
1133             try {
1134                 DbConstant.admin = 
1135                     DbModelFactory.initialize(dbdriver, dbserver, dbuser, dbpasswd,
1136                         true);
1137             } catch (GoldenGateDatabaseNoConnectionException e2) {
1138                 logger.error("Unable to Connect to DB", e2);
1139                 return false;
1140             }
1141             AbstractExecutor.useDatabase = true;
1142         }
1143         return true;
1144     }
1145    /**
1146     * Initiate the configuration from the xml file for server
1147     *
1148     * @param filename
1149     * @return True if OK
1150     */
1151    public boolean setConfigurationServerFromXml(String filename) {
1152        Document document = null;
1153        // Open config file
1154        try {
1155            document = new SAXReader().read(filename);
1156        } catch (DocumentException e) {
1157            logger.error("Unable to read the XML Config file: " + filename, e);
1158            return false;
1159        }
1160        if (document == null) {
1161            logger.error("Unable to read the XML Config file: " + filename);
1162            return false;
1163        }
1164        configuration = XmlUtil.read(document, configServer);
1165        hashConfig = new XmlHash(configuration);
1166        // Now read the configuration
1167        if (! loadIdentity()) {
1168            logger.error("Cannot load Identity");
1169            return false;
1170        }
1171        if (!loadDatabase()) {
1172            logger.error("Cannot load Database configuration");
1173            return false;
1174        }
1175        if (! loadServerParam()) {
1176            logger.error("Cannot load Server Parameters");
1177            return false;
1178        }
1179        if (! loadDirectory()) {
1180            logger.error("Cannot load Directory configuration");
1181            return false;
1182        }
1183        if (! loadLimit(false)) {
1184            logger.error("Cannot load Limit configuration");
1185            return false;
1186        }
1187        if (! loadNetworkServer()) {
1188            logger.error("Cannot load Network configuration");
1189            return false;
1190        }
1191        if (!loadExec()) {
1192            logger.error("Cannot load Exec configuration");
1193            return false;
1194        }
1195        //if (!DbConstant.admin.isConnected) {
1196            // if no database, must load authentication from file
1197            if (! loadAuthentication()) {
1198                logger.error("Cannot load Authentication configuration");
1199                return false;
1200            }
1201        //}
1202        hashConfig.clear();
1203        hashConfig = null;
1204        configuration = null;
1205        return true;
1206    }
1207 
1208    /**
1209     * Configure HTTPS
1210     */
1211    public void configureHttps() {
1212        // Now start the HTTPS support
1213        // Configure the server.
1214        httpPipelineExecutor = new OrderedMemoryAwareThreadPoolExecutor(
1215                CLIENT_THREAD, maxGlobalMemory / 10, maxGlobalMemory, 1000,
1216                TimeUnit.MILLISECONDS, getFtpInternalConfiguration().getObjectSizeEstimator(), 
1217                new GgThreadFactory("HttpExecutor"));
1218        httpsChannelFactory = new NioServerSocketChannelFactory(
1219                Executors.newCachedThreadPool(),
1220                Executors.newCachedThreadPool(),
1221                SERVER_THREAD);
1222        httpsBootstrap = new ServerBootstrap(
1223                httpsChannelFactory);
1224        // Set up the event pipeline factory.
1225        httpsBootstrap.setPipelineFactory(new HttpSslPipelineFactory(useHttpCompression,
1226                false, getHttpPipelineExecutor()));
1227        httpsBootstrap.setOption("child.tcpNoDelay", true);
1228        httpsBootstrap.setOption("child.keepAlive", true);
1229        httpsBootstrap.setOption("child.reuseAddress", true);
1230        httpsBootstrap.setOption("child.connectTimeoutMillis", TIMEOUTCON);
1231        httpsBootstrap.setOption("tcpNoDelay", true);
1232        httpsBootstrap.setOption("reuseAddress", true);
1233        httpsBootstrap.setOption("connectTimeoutMillis", TIMEOUTCON);
1234        // Bind and start to accept incoming connections.
1235        logger.warn("Start Https Support on port: "+SERVER_HTTPSPORT);
1236        httpChannelGroup.add(httpsBootstrap.bind(new InetSocketAddress(SERVER_HTTPSPORT)));
1237    }
1238    /**
1239     * Configure ConstraintLimitHandler
1240     */
1241    public void configureConstraint() {
1242        constraintLimitHandler.setHandler(
1243                this.getFtpInternalConfiguration().getGlobalTrafficShapingHandler());
1244    }
1245    /**
1246     * Configure LocalExec
1247     */
1248    public void configureLExec() {
1249        if (useLocalExec) {
1250            LocalExecClient.initialize(this);
1251        }
1252    }
1253    /**
1254     * Configure the SNMP support if needed
1255     * @throws FtpNoConnectionException
1256     */
1257    public void configureSnmp() throws FtpNoConnectionException {
1258        monitoring = new FtpMonitoring(null);
1259        if (snmpConfig != null) {
1260            int snmpPortShow =  getServerPort();
1261            ftpMib = 
1262                new FtpPrivateMib(snmpPortShow);
1263            GgMOFactory.factory = new FtpVariableFactory();
1264            agentSnmp = new GgSnmpAgent(new File(snmpConfig), monitoring, ftpMib);
1265            try {
1266                agentSnmp.start();
1267                logger.debug("SNMP configured");
1268            } catch (IOException e) {
1269                monitoring.releaseResources();
1270                monitoring = null;
1271                ftpMib = null;
1272                agentSnmp = null;
1273                throw new FtpNoConnectionException("AgentSnmp Error while starting", e);
1274            }
1275        }
1276    }
1277     /**
1278      * @param serverkey
1279      *            the SERVERADMINKEY to set
1280      */
1281     public void setSERVERKEY(byte[] serverkey) {
1282         SERVERADMINKEY = serverkey;
1283     }
1284     /**
1285      * Check the password for Shutdown
1286      *
1287      * @param password
1288      * @return True if the password is OK
1289      */
1290     public boolean checkPassword(String password) {
1291         if (password == null) {
1292             return false;
1293         }
1294         return Arrays.equals(SERVERADMINKEY, password.getBytes());
1295     }
1296     /**
1297      * Initialize Authentication from current authenticationFile
1298      * @param filename the filename from which authentication will be loaded
1299      * @param purge if True, the current authentications are totally replaced by the new ones
1300      * @return True if OK
1301      */
1302     @SuppressWarnings("unchecked")
1303     public boolean initializeAuthent(String filename, boolean purge) {
1304         Document document = null;
1305         try {
1306             document = new SAXReader().read(filename);
1307         } catch (DocumentException e) {
1308             logger.error("Unable to read the XML Authentication file: " +
1309                     filename, e);
1310             return false;
1311         }
1312         if (document == null) {
1313             logger.error("Unable to read the XML Authentication file: " +
1314                     filename);
1315             return false;
1316         }
1317         XmlValue[] configuration = XmlUtil.read(document, authentElements);
1318         XmlHash hashConfig = new XmlHash(configuration);
1319 
1320         XmlValue value = hashConfig.get(XML_AUTHENTIFICATION_ENTRY);
1321         List<XmlValue []> list = (List<XmlValue []>)value.getList();
1322         ConcurrentHashMap<String, SimpleAuth> newAuthents =
1323             new ConcurrentHashMap<String, SimpleAuth>();
1324         for (XmlValue[] xmlValues: list) {
1325             hashConfig = new XmlHash(xmlValues);
1326             value = hashConfig.get(XML_AUTHENTICATION_USER);
1327             if (value == null || (value.isEmpty())) {
1328                 logger.error("Unable to find a User in Config file");
1329                 continue;
1330             }
1331             String user = value.getString();
1332             value = hashConfig.get(XML_AUTHENTICATION_ACCOUNT);
1333             if (value == null || (value.isEmpty())) {
1334                 logger.error("Unable to find a Account in Config file: "+user);
1335                 continue;
1336             }
1337             String[] account = null;
1338             List<String> listaccount = (List<String>) value.getList();
1339             if (!listaccount.isEmpty()) {
1340                 account = new String[listaccount.size()];
1341                 int i = 0;
1342                 Iterator<String> iteratoraccount = listaccount.iterator();
1343                 while (iteratoraccount.hasNext()) {
1344                     account[i] = iteratoraccount.next();
1345                     // logger.debug("User: {} Acct: {}", user, account[i]);
1346                     File directory = new File(getBaseDirectory()+"/"+user+"/"+account[i]);
1347                     directory.mkdirs();
1348                     i ++;
1349                 }
1350             } else {
1351                 logger.error("Unable to find a Account in Config file: "+user);
1352                 continue;
1353             }
1354             value = hashConfig.get(XML_AUTHENTICATION_ADMIN);
1355             boolean isAdmin = false;
1356             if (value != null && (!value.isEmpty())) {
1357                 isAdmin = value.getBoolean();
1358             }
1359             String retrcmd = null;
1360             long retrdelay = 0;
1361             String storcmd = null;
1362             long stordelay = 0;
1363             value = hashConfig.get(XML_RETRIEVE_COMMAND);
1364             if (value != null && (!value.isEmpty())) {
1365                 retrcmd = value.getString();
1366             }
1367             value = hashConfig.get(XML_DELAYRETRIEVE_COMMAND);
1368             if (value != null && (!value.isEmpty())) {
1369                 retrdelay = (value.getLong()/10)*10;
1370             }
1371             value = hashConfig.get(XML_STORE_COMMAND);
1372             if (value != null && (!value.isEmpty())) {
1373                 storcmd = value.getString();
1374             }
1375             value = hashConfig.get(XML_DELAYSTORE_COMMAND);
1376             if (value != null && (!value.isEmpty())) {
1377                 stordelay = (value.getLong()/10)*10;
1378             }
1379             String passwd;
1380             value = hashConfig.get(XML_AUTHENTICATION_PASSWDFILE);
1381             if (value != null && (!value.isEmpty())) {
1382                 // load key from file
1383                 File key = new File(value.getString());
1384                 if (!key.canRead()) {
1385                     logger.error("Cannot read key for user " + user+":"+key.getName());
1386                     continue;
1387                 }
1388                 try {
1389                     byte [] byteKeys = cryptoKey.decryptHexFile(key);
1390                     passwd = new String(byteKeys);
1391                 } catch (Exception e2) {
1392                     logger.error("Cannot read key for user " + user, e2);
1393                     continue;
1394                 }
1395             } else {
1396                 value = hashConfig.get(XML_AUTHENTICATION_PASSWD);
1397                 if (value != null && (!value.isEmpty())) {
1398                     String encrypted = value.getString();
1399                     byte[] byteKeys = null;
1400                     try {
1401                         byteKeys =
1402                             cryptoKey.decryptHexInBytes(encrypted);
1403                         passwd = new String(byteKeys);
1404                     } catch (Exception e) {
1405                         logger.error(
1406                                 "Unable to Decrypt Key for user " + user, e);
1407                         continue;
1408                     }
1409                 } else {
1410                     logger.error("Unable to find Password in Config file");
1411                     // DO NOT Allow empty key
1412                     continue;
1413                 }
1414             }
1415             SimpleAuth auth = new SimpleAuth(user, passwd, account, 
1416                     storcmd, stordelay, retrcmd, retrdelay);
1417             auth.setAdmin(isAdmin);
1418             newAuthents.put(user, auth);
1419             hashConfig.clear();
1420         }
1421         hashConfig.clear();
1422         configuration = null;
1423         if (purge) {
1424             ConcurrentHashMap<String, SimpleAuth> previousOne = authentications;
1425             authentications = newAuthents;
1426             previousOne.clear();
1427         } else {
1428             authentications.putAll(newAuthents);
1429             newAuthents.clear();
1430         }
1431         document = null;
1432         return true;
1433     }
1434     /**
1435      * Export the Authentication to the original files
1436      * @param filename the filename where the authentication will be exported
1437      * @return True if successful
1438      */
1439     public boolean saveAuthenticationFile(String filename) {
1440         Document document = XmlUtil.createEmptyDocument();
1441         XmlValue [] roots = new XmlValue[1];
1442         XmlValue root = new XmlValue(authentElements[0]);
1443         roots[0] = root;
1444         Enumeration<SimpleAuth> auths = authentications.elements();
1445         while (auths.hasMoreElements()) {
1446             SimpleAuth auth = auths.nextElement();
1447             XmlValue []values = new XmlValue[configAuthenticationDecls.length];
1448             for (int i = 0; i < configAuthenticationDecls.length; i++) {
1449                 values[i] = new XmlValue(configAuthenticationDecls[i]);
1450             }
1451             values[0].setFromString(auth.user);
1452             //PasswdFile: none values[1].setFromString();
1453             values[2].setFromString(auth.password);
1454             // Accounts
1455             String []accts = auth.accounts;
1456             for (String string: accts) {
1457                 try {
1458                     values[3].addFromString(string);
1459                 } catch (InvalidObjectException e) {
1460                     logger.error("Error during Write Authentication file", e);
1461                     return false;
1462                 }
1463             }
1464             try {
1465                 values[4].setValue(auth.isAdmin);
1466             } catch (InvalidObjectException e) {
1467                 logger.error("Error during Write Authentication file", e);
1468                 return false;
1469             }
1470             values[5].setFromString(auth.retrCmd);
1471             try {
1472                 values[6].setValue(auth.retrDelay);
1473             } catch (InvalidObjectException e) {
1474                 logger.error("Error during Write Authentication file", e);
1475                 return false;
1476             }
1477             values[7].setFromString(auth.storCmd);
1478             try {
1479                 values[8].setValue(auth.storDelay);
1480             } catch (InvalidObjectException e) {
1481                 logger.error("Error during Write Authentication file", e);
1482                 return false;
1483             }
1484             try {
1485                 root.addValue(values);
1486             } catch (InvalidObjectException e) {
1487                 logger.error("Error during Write Authentication file", e);
1488                 return false;
1489             }
1490         }
1491         XmlUtil.write(document, roots);
1492         try {
1493             XmlUtil.saveDocument(filename, document);
1494         } catch (IOException e1) {
1495             logger.error("Cannot write to file: "+filename+" since {}", e1.getMessage());
1496             return false;
1497         }
1498         return true;
1499     }
1500     /**
1501      * @param user
1502      * @return the SimpleAuth if any for this user
1503      */
1504     public SimpleAuth getSimpleAuth(String user) {
1505         return authentications.get(user);
1506     }
1507     /**
1508      * @param format Format in HTML to use as ouput format
1509      * @return the Html String containing the table of all Authentication entries
1510      */
1511     public String getHtmlAuth(String format) {
1512         String result;
1513         StringBuilder builder = new StringBuilder();
1514         /*
1515             XXXUSERXXX XXXPWDXXX XXXACTSXXX XXXADMXXX XXXSTCXXX XXXSTDXXX XXXRTCXXX XXXRTDXXX
1516          */
1517         Enumeration<SimpleAuth> simpleAuths = authentications.elements();
1518         SimpleAuth auth = null;
1519         while (simpleAuths.hasMoreElements()) {
1520             auth = simpleAuths.nextElement();
1521             String newElt = format.replace("XXXUSERXXX", auth.user);
1522             newElt = newElt.replace("XXXPWDXXX", auth.password);
1523             if (auth.storCmd != null)
1524                 newElt = newElt.replace("XXXSTCXXX", auth.storCmd);
1525             else
1526                 newElt = newElt.replace("XXXSTCXXX", "");
1527             if (auth.retrCmd != null)
1528                 newElt = newElt.replace("XXXRTCXXX", auth.retrCmd);
1529             else
1530                 newElt = newElt.replace("XXXRTCXXX", "");
1531             newElt = newElt.replace("XXXSTDXXX", Long.toString(auth.storDelay));
1532             newElt = newElt.replace("XXXRTDXXX", Long.toString(auth.retrDelay));
1533             newElt = newElt.replace("XXXADMXXX", Boolean.toString(auth.isAdmin));
1534             if (auth.accounts != null) {
1535                 StringBuilder accts = new StringBuilder();
1536                 for (int i = 0; i < auth.accounts.length-1; i++) {
1537                     accts.append(auth.accounts[i]);
1538                     accts.append(", ");
1539                 }
1540                 accts.append(auth.accounts[auth.accounts.length-1]);
1541                 newElt = newElt.replace("XXXACTSXXX", accts.toString());
1542             } else {
1543                 newElt = newElt.replace("XXXACTSXXX", "No Account");
1544             }
1545             builder.append(newElt);
1546         }
1547         result = builder.toString();
1548         return result;
1549     }
1550     /**
1551      * Only available with Database support for GoldenGate
1552      * @param format Format in HTML to use as ouput format
1553      * @param limit number of TransferLog to populate
1554      * @return the Html String containing the table of all Transfer entries
1555      */
1556     public String getHtmlTransfer(String format, int limit) {
1557         String result;
1558         StringBuilder builder = new StringBuilder();
1559         /*
1560             XXXIDXXX XXXUSERXXX XXXACCTXXX XXXFILEXXX XXXMODEXXX XXXSTATUSXXX XXXINFOXXX 
1561             XXXUPINFXXX XXXSTARTXXX XXXSTOPXXX
1562          */
1563         if (! DbConstant.admin.isConnected) {
1564             return "";
1565         }
1566         DbPreparedStatement preparedStatement = null;
1567         try {
1568             try {
1569                 preparedStatement = 
1570                     DbTransferLog.getStatusPrepareStament(DbConstant.admin.session, null, limit);
1571                 preparedStatement.executeQuery();
1572             } catch (GoldenGateDatabaseNoConnectionException e) {
1573                 return "";
1574             } catch (GoldenGateDatabaseSqlException e) {
1575                 return "";
1576             }
1577             try {
1578                 while (preparedStatement.getNext()) {
1579                     DbTransferLog log = DbTransferLog.getFromStatement(preparedStatement);
1580                     String newElt = format.replaceAll("XXXIDXXX", Long.toString(log.getSpecialId()));
1581                     newElt = newElt.replaceAll("XXXUSERXXX", log.getUser());
1582                     newElt = newElt.replaceAll("XXXACCTXXX", log.getAccount());
1583                     newElt = newElt.replace("XXXFILEXXX", log.getFilename());
1584                     newElt = newElt.replace("XXXMODEXXX", log.getMode());
1585                     newElt = newElt.replace("XXXSTATUSXXX", log.getErrorInfo().getMesg());
1586                     newElt = newElt.replace("XXXINFOXXX", log.getInfotransf());
1587                     newElt = newElt.replace("XXXUPINFXXX", log.getUpdatedInfo().name());
1588                     newElt = newElt.replace("XXXSTARTXXX", log.getStart().toString());
1589                     newElt = newElt.replace("XXXSTOPXXX", log.getStop().toString());
1590                     builder.append(newElt);
1591                 }
1592             } catch (GoldenGateDatabaseNoConnectionException e) {
1593                 return "";
1594             } catch (GoldenGateDatabaseSqlException e) {
1595                 return "";
1596             }
1597             result = builder.toString();
1598             return result;
1599         } finally {
1600             if (preparedStatement != null) {
1601                 preparedStatement.realClose();
1602             }
1603         }
1604     }
1605     /**
1606      * @see goldengate.ftp.core.config.FtpConfiguration#getNextRangePort()
1607      */
1608     @Override
1609     public int getNextRangePort() {
1610         try {
1611             return ((CircularIntValue) getProperty(RANGE_PORT)).getNext();
1612         } catch (FtpUnknownFieldException e) {
1613             return -1;
1614         }
1615     }
1616 
1617     /**
1618      *
1619      * @param rangePort
1620      *            the range of available ports for Passive connections
1621      */
1622     private void setRangePort(CircularIntValue rangePort) {
1623         setProperty(RANGE_PORT, rangePort);
1624     }
1625 
1626     /**
1627      * @return the httpPipelineExecutor
1628      */
1629     public OrderedMemoryAwareThreadPoolExecutor getHttpPipelineExecutor() {
1630         return httpPipelineExecutor;
1631     }
1632     /**
1633      * @return the httpChannelGroup
1634      */
1635     public ChannelGroup getHttpChannelGroup() {
1636         return httpChannelGroup;
1637     }
1638     /**
1639      * Finalize resources attached to handlers
1640      *
1641      * @author Frederic Bregier
1642      */
1643     private static class GgChannelGroupFutureListener implements
1644             ChannelGroupFutureListener {
1645         OrderedMemoryAwareThreadPoolExecutor pool;
1646         String name;
1647         ChannelFactory channelFactory;
1648 
1649         public GgChannelGroupFutureListener(
1650                 String name,
1651                 OrderedMemoryAwareThreadPoolExecutor pool,
1652                 ChannelFactory channelFactory) {
1653             this.name = name;
1654             this.pool = pool;
1655             this.channelFactory = channelFactory;
1656         }
1657 
1658         public void operationComplete(ChannelGroupFuture future)
1659                 throws Exception {
1660             if (pool != null) {
1661                 pool.shutdownNow();
1662             }
1663             if (channelFactory != null) {
1664                 channelFactory.releaseExternalResources();
1665             }
1666             logger.info("Done with shutdown "+name);
1667         }
1668     }
1669     @Override
1670     public void releaseResources() {
1671         super.releaseResources();
1672         final int result = getHttpChannelGroup().size();
1673         logger.debug("HttpChannelGroup: " + result);
1674         getHttpChannelGroup().close().addListener(
1675                 new GgChannelGroupFutureListener(
1676                         "HttpChannelGroup",
1677                         httpPipelineExecutor,
1678                         httpsChannelFactory));
1679         if (useLocalExec) {
1680             LocalExecClient.releaseResources();
1681         }
1682         this.constraintLimitHandler.release();
1683         agentSnmp.stop();
1684         DbAdmin.closeAllConnection();
1685     }
1686 
1687     /* (non-Javadoc)
1688      * @see goldengate.ftp.core.config.FtpConfiguration#inShutdownProcess()
1689      */
1690     @Override
1691     public void inShutdownProcess() {
1692         if (ftpMib != null) {
1693             ftpMib.notifyStartStop("Shutdown in progress for "+HOST_ID, "Gives extra seconds: "+TIMEOUTCON);
1694         }
1695     }
1696 }