001/*
002 * #%L
003 * Netarchivesuite - deploy
004 * %%
005 * Copyright (C) 2005 - 2018 The Royal Danish Library, 
006 *             the National Library of France and the Austrian National Library.
007 * %%
008 * This program is free software: you can redistribute it and/or modify
009 * it under the terms of the GNU Lesser General Public License as
010 * published by the Free Software Foundation, either version 2.1 of the
011 * License, or (at your option) any later version.
012 * 
013 * This program is distributed in the hope that it will be useful,
014 * but WITHOUT ANY WARRANTY; without even the implied warranty of
015 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
016 * GNU General Lesser Public License for more details.
017 * 
018 * You should have received a copy of the GNU General Lesser Public
019 * License along with this program.  If not, see
020 * <http://www.gnu.org/licenses/lgpl-2.1.html>.
021 * #L%
022 */
023package dk.netarkivet.deploy;
024
025import java.io.File;
026import java.io.IOException;
027import java.io.PrintWriter;
028import java.util.HashMap;
029import java.util.Iterator;
030import java.util.LinkedHashMap;
031import java.util.Map;
032import java.util.Map.Entry;
033
034import org.dom4j.Element;
035
036import dk.netarkivet.common.exceptions.IOFailure;
037
038/**
039 * A LinuxMachine is the instance of the abstract machine class, which runs the operating system Linux or another Unix
040 * dependent operation system. This class only contains the operating system specific functions.
041 */
042public class LinuxMachine extends Machine {
043
044        public static final String HERITRIX_1_CLASSNAME = "org.archive.crawler.Heritrix";
045
046        protected LinkedHashMap<String, String> bundles = new LinkedHashMap<>();
047        protected LinkedHashMap<String, String> certificates = new LinkedHashMap<String, String>();
048
049        /**
050     * The constructor. Starts by initialising the parent abstract class, then sets the operating system dependent
051     * variables.
052     *
053     * @param subTreeRoot The XML root element.
054     * @param parentSettings The Settings to be inherited from the PhysicalLocation, where this machine is placed.
055     * @param param The machine parameters to be inherited from the PhysicalLocation.
056     * @param netarchiveSuiteSource The name of the NetarchiveSuite package file. Must end with '.zip'.
057     * @param securityPolicy The security policy file, to be copied into machine directory.
058     * @param dbFile The name of the database file.
059     * @param arcdbFile The name of the archive file.
060     * @param resetDir Whether the temporary directory should be reset.
061     * @param externalJarFolder The folder containing the external jar library files.
062     * @param logoFile user specific logo png file.
063     * @param menulogoFile user specific menulogo png file.
064     * @param deployConfiguration The general deployment configuration.
065     */
066    public LinuxMachine(Element subTreeRoot, XmlStructure parentSettings, Parameters param,
067            String netarchiveSuiteSource, File slf4JConfig, File securityPolicy, File dbFile,
068            File arcdbFile, boolean resetDir, File externalJarFolder, File logoFile, File menulogoFile,
069            DeployConfiguration deployConfiguration) {
070        super(subTreeRoot, parentSettings, param, netarchiveSuiteSource, slf4JConfig, securityPolicy, dbFile,
071                arcdbFile, resetDir, externalJarFolder, logoFile, menulogoFile);
072        // set operating system
073        operatingSystem = Constants.OPERATING_SYSTEM_LINUX_ATTRIBUTE;
074        scriptExtension = Constants.SCRIPT_EXTENSION_LINUX;
075
076        String[] bundlesArr;
077        String[] certificatesArr;
078        String srcStr;
079        String dstStr;
080        int idx;
081        for (Application app : applications) {
082            if (app.isBundledHarvester()) {
083                bundlesArr = app.getSettingsValues(Constants.SETTINGS_HARVEST_HERITRIX3_BUNDLE_LEAF);
084                if ((bundlesArr == null || bundlesArr.length == 0)
085                        && deployConfiguration.getDefaultBundlerZip() != null) {
086                    bundlesArr = new String[] { deployConfiguration.getDefaultBundlerZip().getAbsolutePath() };
087                } else if ((bundlesArr == null || bundlesArr.length == 0 || bundlesArr[0].length()==0)
088                        && deployConfiguration.getDefaultBundlerZip() == null) {
089                    throw new IllegalArgumentException("A Heritrix bundler needs to be defined for H3 controllers, "
090                            + "either directly in the deploy configuration or from the command line with the -B option.");
091                }
092                certificatesArr = app.getSettingsValues(Constants.SETTINGS_HARVEST_HERITRIX3_CERTIFICATE_LEAF);
093                if (bundlesArr != null && bundlesArr.length > 0 && certificatesArr != null) {
094                    for (int i = 0; i < bundlesArr.length; ++i) {
095                        srcStr = bundlesArr[i];
096                        if (!bundles.containsKey(srcStr)) {
097                            idx = srcStr.lastIndexOf('/');
098                            if (idx != -1) {
099                                dstStr = srcStr.substring(idx + 1);
100                            } else {
101                                dstStr = srcStr;
102                            }
103                            dstStr = machineParameters.getInstallDirValue() + "/" + getEnvironmentName() + "/" + dstStr;
104                            bundles.put(srcStr, dstStr);
105                            System.out.println(srcStr + " -> " + dstStr);
106                        }
107                    }
108                    for (int i = 0; i < certificatesArr.length; ++i) {
109                        srcStr = certificatesArr[i];
110                        if (!certificates.containsKey(srcStr)) {
111                            idx = srcStr.lastIndexOf('/');
112                            if (idx != -1) {
113                                dstStr = srcStr.substring(idx + 1);
114                            } else {
115                                dstStr = srcStr;
116                            }
117                            dstStr = machineParameters.getInstallDirValue() + "/" + getEnvironmentName() + "/" + dstStr;
118                            certificates.put(srcStr, dstStr);
119                            System.out.println(srcStr + " -> " + dstStr);
120                        }
121                    }
122                    XmlStructure appSettings = app.getSettings();
123                    Element heritrixBundleElement =
124                            appSettings.getSubChild(Constants.SETTINGS_HARVEST_HERITRIX3_BUNDLE_LEAF);
125                    if (heritrixBundleElement == null) {
126                        appSettings.getSubChild(Constants.SETTINGS_HERITRIX3_BRANCH).addElement("bundle");
127                        heritrixBundleElement =
128                                appSettings.getSubChild(Constants.SETTINGS_HARVEST_HERITRIX3_BUNDLE_LEAF);
129                        heritrixBundleElement.setText((String)bundles.values().toArray()[0]);
130                    } else {
131                        heritrixBundleElement.setText(bundles.get(heritrixBundleElement.getText()));
132                    }
133                    Element h3KeystoreElement = appSettings
134                            .getSubChild(Constants.SETTINGS_HARVEST_HERITRIX3_CERTIFICATE_LEAF);
135                    if (h3KeystoreElement != null) {
136                        String h3KeystoreName = certificates.get(h3KeystoreElement.getText());
137                        if (h3KeystoreName != null) {
138                            h3KeystoreElement.setText(h3KeystoreName);
139                        }
140                    }
141                }
142            }
143        }
144    }
145
146    protected static final class osInstallScriptTpl {
147        protected static final String[] mainScript = {
148            // echo copying null.zip to:kb-test-adm-001.kb.dk
149            "echo copying ${netarchiveSuiteFileName} to:${name}",
150            // scp null.zip dev@kb-test-adm-001.kb.dk:/home/dev
151            "scp ${netarchiveSuiteFileName} ${machineUserLogin}:${installDirValue}",
152            // echo deleting dev@kb-test-adm-001.kb.dk:/home/dev/TEST/lib
153            "echo deleting ${machineUserLogin}:${installDirValue}/${environmentName}/lib",
154            // ssh dev@kb-test-adm-001.kb.dk rm -rf /home/dev/TEST/lib
155            "ssh ${machineUserLogin} \"rm -rf ${installDirValue}/${environmentName}/lib\"",
156            // echo unzipping null.zip at:kb-test-adm-001.kb.dk
157            "echo unzipping ${netarchiveSuiteFileName} at:${name}",
158            // ssh dev@kb-test-adm-001.kb.dk unzip -q -o /home/dev/null.zip -d /home/dev/TEST
159            "ssh ${machineUserLogin} \"unzip -q -o ${installDirValue}/${netarchiveSuiteFileName} -d ${installDirValue}/${environmentName}\"",
160            // update Logos.
161            "${osUpdateLogos}",
162            // create other directories.
163            "${osInstallScriptCreateDir}",
164            // echo preparing for copying of settings and scripts
165            "echo preparing for copying of settings and scripts",
166            // For overriding jmxremote.password give user all rights.
167            // ssh machine: "if [ -e conf/jmxremote.password ];
168            // then chmod u+rwx conf/jmxremote.password; fi; "
169            "ssh ${machineUserLogin} \" cd ~; if [ -e ${installDirValue}/${environmentName}/conf/jmxremote.password ]; then chmod u+rwx ${installDirValue}/${environmentName}/conf/jmxremote.password; fi; \"",
170            // For overriding jmxremote.access give user all rights.
171            // ssh machine: "if [ -e conf/jmxremote.access ];
172            // then chmod u+rwx conf/jmxremote.access; fi; "
173            "ssh ${machineUserLogin} \" cd ~; if [ -e ${installDirValue}/${environmentName}/conf/jmxremote.access ]; then chmod u+rwx ${installDirValue}/${environmentName}/conf/jmxremote.access; fi; \"",
174            // echo copying settings and scripts
175            "echo copying settings and scripts",
176            // scp -r kb-test-adm-001.kb.dk/* dev@kb-test-adm-001.kb.dk:/home/dev/TEST/conf/
177            "scp -r ${name}/* ${machineUserLogin}:${installDirValue}/${environmentName}/conf/",
178            // INSTALL EXTERNAL JAR FILES.
179            "${osInstallExternalJarFiles}",
180            // APPLY HARVEST DEFINITION DATABASE!
181            "${osInstallDatabase}",
182            // APPLY ARCHIVE DATABASE!
183            "${osInstallArchiveDatabase}",
184            // echo make scripts executable
185            "echo make scripts executable",
186            // Allow only user to be able to deal with these files
187            // (go=-rwx,u=+rwx) = 700.
188            // ssh dev@kb-test-adm-001.kb.dk "chmod 700 /home/dev/TEST/conf/*.sh "
189            "ssh ${machineUserLogin} \"chmod 700 ${installDirValue}/${environmentName}/conf/*.sh \"",
190            // HANDLE JMXREMOTE PASSWORD AND ACCESS FILE.
191            "${JMXremoteFilesCommand}",
192            // END OF SCRIPT
193            "${heritrix3Files}"
194        };
195        protected static final String scpFile = "scp ${srcFileName} ${machineUserLogin}:${dstFileName}";
196    }
197
198    @Override
199    protected String osInstallScript() {
200        Map<String, String> env = new HashMap<String, String>();
201        StringBuilder sb = new StringBuilder();
202        Iterator<Entry<String, String>> iter;
203        String tmpStr;
204        env.put("machineUserLogin", machineUserLogin());
205        iter = bundles.entrySet().iterator();
206        Entry<String, String> entry;
207        while (iter.hasNext()) {
208                entry = iter.next();
209                env.put("srcFileName", entry.getKey());
210            env.put("dstFileName", entry.getValue());
211            tmpStr = Template.untemplate(osInstallScriptTpl.scpFile, env, true);
212            if (sb.length() > 0) {
213                sb.append("\n");
214            }
215            sb.append(tmpStr);
216        }
217        iter = certificates.entrySet().iterator();
218        while (iter.hasNext()) {
219                entry = iter.next();
220                env.put("srcFileName", entry.getKey());
221            env.put("dstFileName", entry.getValue());
222            tmpStr = Template.untemplate(osInstallScriptTpl.scpFile, env, true);
223            if (sb.length() > 0) {
224                sb.append("\n");
225            }
226            sb.append(tmpStr);
227        }
228
229        env.clear();
230        env.put("netarchiveSuiteFileName", netarchiveSuiteFileName);
231        env.put("name", hostname);
232        env.put("machineUserLogin", machineUserLogin());
233        env.put("installDirValue", machineParameters.getInstallDirValue());
234        env.put("environmentName", getEnvironmentName());
235        env.put("osUpdateLogos", osUpdateLogos());
236        env.put("osInstallScriptCreateDir", osInstallScriptCreateDir());
237        env.put("osInstallExternalJarFiles", osInstallExternalJarFiles());
238        env.put("osInstallDatabase", osInstallDatabase());
239        env.put("osInstallArchiveDatabase", osInstallArchiveDatabase());
240        env.put("JMXremoteFilesCommand", getJMXremoteFilesCommand());
241        env.put("heritrix3Files", sb.toString());
242        String str = Template.untemplate(osInstallScriptTpl.mainScript, env, true, "\n");
243        return str;
244    }
245
246    protected static final class osKillScriptTpl {
247        protected static final String[] mainScript = {
248            "ssh ${machineUserLogin} \". /etc/profile; ${installDirValue}/${environmentName}/conf/killall.sh\";"
249        };
250    }
251
252    @Override
253    protected String osKillScript() {
254        Map<String, String> env = new HashMap<String, String>();
255        env.put("machineUserLogin", machineUserLogin());
256        env.put("environmentName", getEnvironmentName());
257        env.put("installDirValue", machineParameters.getInstallDirValue());
258        String str = Template.untemplate(osKillScriptTpl.mainScript, env, true, "\n");
259        return str;
260    }
261
262    protected static final class osStartScriptTpl {
263        protected static final String[] mainScript = {
264            "ssh ${machineUserLogin} \". /etc/profile;. ~/.bash_profile; ${installDirValue}/${environmentName}/conf/startall.sh; sleep 5; cat ${installDirValue}/${environmentName}/*.log\""
265        };
266    }
267
268    /**
269     * Creates the operation system specific starting script for this machine.
270     * <p>
271     * pseudo code: - ssh maclogin ". /etc/profile; conf/startall.sh; sleep 5; cat install/*.log"
272     * <p>
273     * where: maclogin = login for machine (username@machine). conf = path to /conf directory. install = path to install
274     * directory.
275     *
276     * @return Operation system specific part of the startscript.
277     */
278    @Override
279    protected String osStartScript() {
280        Map<String, String> env = new HashMap<String, String>();
281        env.put("machineUserLogin", machineUserLogin());
282        env.put("environmentName", getEnvironmentName());
283        env.put("installDirValue", machineParameters.getInstallDirValue());
284        String str = Template.untemplate(osStartScriptTpl.mainScript, env, true, "\n");
285        return str;
286    }
287
288    @Override
289    protected String getInstallDirPath() {
290        return machineParameters.getInstallDirValue() + Constants.SLASH + getEnvironmentName();
291    }
292
293    @Override
294    protected String getConfDirPath() {
295        return getInstallDirPath() + Constants.CONF_DIR_LINUX;
296    }
297
298    /**
299     * Creates the local path to the lib dir.
300     *
301     * @return The path to the lib dir for ssh.
302     */
303    protected String getLocalLibDirPath() {
304        return Constants.LIB_DIR_LINUX;
305    }
306
307    /**
308     * This function creates the script to kill all applications on this machine. The scripts calls all the kill script
309     * for each application. It also runs the script for killing any external database.
310     * <p>
311     * pseudo code: - echo Killing all applications at machine: mac - if [ -e ./kill_app.sh ] - ./kill_app.sh - fi - ...
312     * <p>
313     * where: mac = machine name. app = application name. ... = the same for other applications.
314     *
315     * @param directory The directory for this machine (use global variable?).
316     * @throws IOFailure If an error occurred during the creation of the local killall script.
317     */
318    @Override
319    protected void createOSLocalKillAllScript(File directory) throws IOFailure {
320        // create the kill all script file
321        File killAllScript = new File(directory, Constants.SCRIPT_NAME_KILL_ALL + scriptExtension);
322        try {
323            // Initialise script
324            PrintWriter killPrinter = new PrintWriter(killAllScript, getTargetEncoding());
325            try {
326                killPrinter.println(ScriptConstants.ECHO_KILL_ALL_APPS + Constants.COLON + Constants.SPACE
327                        + Constants.APOSTROPHE + hostname + Constants.APOSTROPHE);
328                killPrinter.println(ScriptConstants.BIN_BASH_COMMENT);
329                killPrinter.println(ScriptConstants.CD + Constants.SPACE + getConfDirPath());
330                // insert path to kill script for all applications
331                for (Application app : applications) {
332                    // Constructing filename
333                    String appScript = Constants.DOT + Constants.SLASH + Constants.SCRIPT_NAME_LOCAL_KILL
334                            + app.getIdentification() + scriptExtension;
335                    // check if file exists
336                    killPrinter.println(ScriptConstants.LINUX_IF_EXIST + Constants.SPACE + appScript + Constants.SPACE
337                            + ScriptConstants.LINUX_THEN + Constants.SPACE);
338                    killPrinter.println(ScriptConstants.MULTI_SPACE_6 + appScript);
339                    killPrinter.println(ScriptConstants.FI);
340                }
341
342                // kill the harvest database, if any, after the applications
343                killPrinter.print(callKillHarvestDatabase());
344                // kill the admin database, if any, after the applications
345                killPrinter.print(callKillArchiveDatabase());
346            } finally {
347                // close script
348                killPrinter.close();
349            }
350        } catch (IOException e) {
351            String msg = "Problems creating local kill all script. ";
352            log.error(msg, e);
353            throw new IOFailure(msg, e);
354        }
355    }
356
357    /**
358     * This function creates the script to start all applications on this machine. The scripts calls all the start
359     * script for each application. It also runs the script for starting any external database.
360     * <p>
361     * pseudo code: - echo Starting all applications at machine: mac - if [ -e ./start_app.sh ] - ./start_app.sh - fi -
362     * ...
363     * <p>
364     * where: mac = machine name. app = application name. ... = the same for other applications.
365     *
366     * @param directory The directory for this machine (use global variable?).
367     * @throws IOFailure If an error occurred during the creation of the local startall script.
368     */
369    @Override
370    protected void createOSLocalStartAllScript(File directory) throws IOFailure {
371        // create the start all script file
372        File startAllScript = new File(directory, Constants.SCRIPT_NAME_START_ALL + scriptExtension);
373        try {
374            // Initialise script
375            PrintWriter startPrinter = new PrintWriter(startAllScript, getTargetEncoding());
376            try {
377                startPrinter.println(ScriptConstants.BIN_BASH_COMMENT);
378                startPrinter.println(ScriptConstants.CD + Constants.SPACE + getConfDirPath());
379
380                // start the harvest database, if any, before the applications.
381                startPrinter.print(callStartHarvestDatabase());
382                // start the admin database, if any, before the applications.
383                startPrinter.print(callStartArchiveDatabase());
384
385                startPrinter.println(ScriptConstants.ECHO_START_ALL_APPS + Constants.COLON + Constants.SPACE
386                        + Constants.APOSTROPHE + hostname + Constants.APOSTROPHE);
387
388                // insert path to start script for each applications
389                for (Application app : applications) {
390                    // make name of file
391                    String appScript = Constants.DOT + Constants.SLASH + Constants.SCRIPT_NAME_LOCAL_START
392                            + app.getIdentification() + scriptExtension;
393                    // check if file exists
394                    startPrinter.println(ScriptConstants.LINUX_IF_EXIST + Constants.SPACE + appScript + Constants.SPACE
395                            + ScriptConstants.LINUX_THEN + Constants.SPACE);
396                    startPrinter.println(ScriptConstants.MULTI_SPACE_6 + appScript);
397                    startPrinter.println(ScriptConstants.FI);
398                }
399            } finally {
400                // close script
401                startPrinter.close();
402            }
403        } catch (IOException e) {
404            String msg = "Problems creating local start all script. ";
405            log.trace(msg, e);
406            throw new IOFailure(msg, e);
407        }
408    }
409
410    /**
411     * Creates the kill scripts for all the applications.
412     * <p>
413     * The script starts by finding all running processes of the application. If it finds any processes, it kills them.
414     * <p>
415     * The kill_app.sh should have the following structure:
416     * <p>
417     * - echo Killing linux application. - #!/bin/bash - PIDS = $(ps -wwfe | grep fullapp | grep -v grep | grep
418     * path\settings_app.xml | awk "{print \\$2}") - if [ -n "$PIDS" ]; then - kill -9 $PIDS; - fi
419     * <p>
420     * Also, if a heritrix process is started, the following is added: - PIDS = $(ps -wwfe | grep heritrix | grep -v
421     * grep | grep path\settings_app.xml | awk "{print \\$2}") - if [ -n "$PIDS" ]; then - kill -9 $PIDS; - fi
422     * <p>
423     * where: path = the path to the ./conf directory. fullapp = the full application name with class path. app = the id
424     * of the application (name + instanceId). heritrix = the heritrix class path.
425     *
426     * @param directory The directory for this machine (use global variable?).
427     * @throws IOFailure If an error occured during the creation of the kill application script file.
428     */
429    @Override
430    protected void createApplicationKillScripts(File directory) throws IOFailure {
431        // go through all applications and create their kill script
432        for (Application app : applications) {
433            File appKillScript = new File(directory, Constants.SCRIPT_NAME_LOCAL_KILL + app.getIdentification()
434                    + scriptExtension);
435            try {
436                // make print writer for writing to file
437                PrintWriter appPrint = new PrintWriter(appKillScript, getTargetEncoding());
438                try {
439                    // echo Killing linux application.
440                    appPrint.println(ScriptConstants.ECHO_KILL_LINUX_APPLICATION + Constants.COLON + Constants.SPACE
441                            + app.getIdentification());
442                    // #!/bin/bash
443                    appPrint.println(ScriptConstants.BIN_BASH_COMMENT);
444
445                    // First try an ordinary kill, wait 2 seconds. Then test,
446                    // if process is still around. If it is make a hard kill
447                    // (-9)
448
449                    // PIDS = $(ps -wwfe | grep fullapp | grep -v grep | grep
450                    // path\settings_app.xml | awk "{print \\$2}")
451                    appPrint.println(ScriptConstants.getLinuxPIDS(app.getTotalName(), getConfDirPath(),
452                            app.getIdentification()));
453                    // if [ -n "$PIDS" ]; then
454                    appPrint.println(ScriptConstants.LINUX_IF_N_EXIST + Constants.SPACE + Constants.QUOTE_MARK
455                            + ScriptConstants.PIDS + Constants.QUOTE_MARK + Constants.SPACE
456                            + ScriptConstants.LINUX_N_THEN);
457
458                    appPrint.println(ScriptConstants.KILL_PIDS + Constants.SEMICOLON);
459                    // fi
460                    appPrint.println(ScriptConstants.FI);
461                    appPrint.println();
462                    appPrint.println(ScriptConstants.SLEEP_2);
463
464                    appPrint.println();
465                    // Set PIDS
466                    appPrint.println(ScriptConstants.getLinuxPIDS(app.getTotalName(), getConfDirPath(),
467                            app.getIdentification()));
468                    // IF
469                    appPrint.println(ScriptConstants.LINUX_IF_N_EXIST + Constants.SPACE + Constants.QUOTE_MARK
470                            + ScriptConstants.PIDS + Constants.QUOTE_MARK + Constants.SPACE
471                            + ScriptConstants.LINUX_N_THEN);
472
473                    // kill -9 $PIDS;
474                    appPrint.println(ScriptConstants.KILL_9_PIDS + Constants.SEMICOLON);
475                    // fi
476                    appPrint.println(ScriptConstants.FI);
477
478                    // If the application contains a heritrix instance,
479                    // then make script for killing the heritrix process.
480                    String[] heritrixJmxPort = app.getSettingsValues(Constants.SETTINGS_HARVEST_HERITRIX_JMX_PORT);
481                    if (heritrixJmxPort != null && heritrixJmxPort.length > 0) {
482                        // log if more than one jmx port defined for heritrix.
483                        if (heritrixJmxPort.length > 1) {
484                            log.trace(heritrixJmxPort.length + " number of jmx-ports for a heritrix " + "harvester.");
485                        }
486                        appPrint.println();
487                        // - PIDS = $(ps -wwfe | grep heritrix | grep -v grep
488                        // | grep path\settings_app.xml | awk "{print \\$2}")
489                        appPrint.println(ScriptConstants.getLinuxPIDS(HERITRIX_1_CLASSNAME, getConfDirPath(),
490                                app.getIdentification()));
491                        // - if [ -n "$PIDS" ]; then
492                        appPrint.println(ScriptConstants.LINUX_IF_N_EXIST + Constants.SPACE + Constants.QUOTE_MARK
493                                + ScriptConstants.PIDS + Constants.QUOTE_MARK + Constants.SPACE
494                                + ScriptConstants.LINUX_N_THEN);
495                        // first make a ordinary kill, wait 2 seconds, then make a
496                        // hard kill -9
497                        appPrint.println(ScriptConstants.KILL_PIDS + Constants.SEMICOLON);
498                        // - fi
499                        appPrint.println(ScriptConstants.FI);
500                        appPrint.println();
501                        // wait 2 seconds
502                        appPrint.println(ScriptConstants.SLEEP_2);
503                        appPrint.println();
504                        // See if Process is still around
505                        appPrint.println(ScriptConstants.getLinuxPIDS(HERITRIX_1_CLASSNAME, getConfDirPath(),
506                                app.getIdentification()));
507                        // if still around
508                        appPrint.println(ScriptConstants.LINUX_IF_N_EXIST + Constants.SPACE + Constants.QUOTE_MARK
509                                + ScriptConstants.PIDS + Constants.QUOTE_MARK + Constants.SPACE
510                                + ScriptConstants.LINUX_N_THEN);
511                        // - kill -9 $PIDS;
512                        appPrint.println(ScriptConstants.KILL_9_PIDS + Constants.SEMICOLON);
513                        // - fi
514                        appPrint.println(ScriptConstants.FI);
515                    }
516                } finally {
517                    // close file
518                    appPrint.close();
519                }
520            } catch (IOException e) {
521                String msg = "Problems creating application kill script: ";
522                log.error(msg, e);
523                throw new IOFailure(msg, e);
524            }
525        }
526    }
527
528    /**
529     * Creates the start scripts for all the applications.
530     * <p>
531     * The application should only be started, if it is not running already. The script starts by finding all running
532     * processes of the application. If any processes are found, a new application should not be started. Otherwise
533     * start the application.
534     * <p>
535     * The start_app.sh should have the following structure:
536     * <p>
537     * - echo Starting linux application: app - cd path - #!/bin/bash - PIDS = $(ps -wwfe | grep fullapp | grep -v grep
538     * | grep path\settings_app.xml | awk "{print \\$2}") - if [ -n "$PIDS" ]; then - echo Application already running.
539     * - else - export CLASSPATH = cp:$CLASSPATH; - JAVA - fi
540     * <p>
541     * where: path = the path to the install directory. fullapp = the full name application with java path. app = the
542     * name of the application. cp = the classpaths for the application. JAVA = the command to run the java application.
543     *
544     * @param directory The directory for this machine (use global variable?).
545     * @throws IOFailure If an error occurred during the creation of the start application script file.
546     */
547    @Override
548    protected void createApplicationStartScripts(File directory) throws IOFailure {
549        // go through all applications and create their start script
550        for (Application app : applications) {
551            if (app.getTotalName().contains("GUI")) {
552                 createHarvestDatabaseUpdateScript(directory, true);
553            }
554            File appStartScript = new File(directory, Constants.SCRIPT_NAME_LOCAL_START + app.getIdentification()
555                    + scriptExtension);
556            try {
557                // make print writer for writing to file
558                PrintWriter appPrint = new PrintWriter(appStartScript, getTargetEncoding());
559                try {
560                    // #!/bin/bash
561                    appPrint.println(ScriptConstants.ECHO_START_LINUX_APP + Constants.COLON + Constants.SPACE
562                            + app.getIdentification());
563                    // cd path
564                    appPrint.println(ScriptConstants.CD + Constants.SPACE + app.installPathLinux());
565                    // PIDS = $(ps -wwfe | grep fullapp | grep -v grep | grep
566                    // path\settings_app.xml | awk "{print \\$2}")
567                    appPrint.println(ScriptConstants.getLinuxPIDS(app.getTotalName(), getConfDirPath(),
568                            app.getIdentification()));
569                    // if [ -n "$PIDS" ]; then
570                    appPrint.println(ScriptConstants.LINUX_IF_N_EXIST + Constants.SPACE + Constants.QUOTE_MARK
571                            + ScriptConstants.PIDS + Constants.QUOTE_MARK + Constants.SPACE
572                            + ScriptConstants.LINUX_N_THEN);
573                    // echo Application already running.
574                    appPrint.println(ScriptConstants.ECHO_APP_ALREADY_RUNNING);
575                    // else
576                    appPrint.println(ScriptConstants.ELSE);
577                    // export CLASSPATH = cp;
578                    appPrint.println(ScriptConstants.MULTI_SPACE_4 + ScriptConstants.EXPORT_CLASSPATH
579                            + osGetClassPath(app) + ScriptConstants.VALUE_OF_CLASSPATH + Constants.SEMICOLON);
580                    // JAVA
581                    String securityManagement = "";
582                    if (app.getTotalName().contains(ScriptConstants.BITARCHIVE_APPLICATION_NAME)) {
583                        securityManagement = Constants.SPACE + Constants.DASH + ScriptConstants.OPTION_SECURITY_MANAGER
584                                + Constants.SPACE + Constants.DASH + ScriptConstants.OPTION_SECURITY_POLICY
585                                + getConfDirPath() + Constants.SECURITY_POLICY_FILE_NAME;
586                    }
587                    appPrint.println(ScriptConstants.MULTI_SPACE_4
588                            + ScriptConstants.JAVA
589                            + Constants.SPACE
590                            + app.getMachineParameters().writeJavaOptions()
591                            + Constants.SPACE
592                            + Constants.DASH
593                            + ScriptConstants.OPTION_SETTINGS
594                            + getConfDirPath()
595                            + Constants.PREFIX_SETTINGS
596                            + app.getIdentification()
597                            + Constants.EXTENSION_XML_FILES
598
599                            // TODO check to see if inheritedSlf4jConfigFile is not null
600                            + Constants.SPACE + Constants.DASH + ScriptConstants.OPTION_LOGBACK_CONFIG
601                            + getConfDirPath() + Constants.LOGBACK_PREFIX + app.getIdentification()
602                            + Constants.EXTENSION_XML_FILES
603
604                            + securityManagement
605
606                            + Constants.SPACE + app.getTotalName() + Constants.SPACE + ScriptConstants.LINUX_DEV_NULL
607                            + Constants.SPACE + Constants.SCRIPT_NAME_LOCAL_START + app.getIdentification()
608                            + Constants.EXTENSION_LOG_FILES + Constants.SPACE
609                            + ScriptConstants.LINUX_ERROR_MESSAGE_TO_1);
610                    // fi
611                    appPrint.println(ScriptConstants.FI);
612                } finally {
613                    // close file
614                    appPrint.close();
615                }
616            } catch (IOException e) {
617                String msg = "Problems creating application start script. ";
618                log.trace(msg, e);
619                throw new IOFailure(msg, e);
620            }
621        }
622    }
623
624    @Override
625    protected String osGetClassPath(Application app) {
626        StringBuilder res = new StringBuilder();
627        // get all the classpaths
628        for (Element cp : app.getMachineParameters().getClassPaths()) {
629            res.append(getInstallDirPath() + Constants.SLASH + cp.getText().trim() + Constants.COLON);
630        }
631        return res.toString();
632    }
633
634    @Override
635    protected String osInstallDatabase() {
636        StringBuilder res = new StringBuilder();
637
638        String databaseDir = machineParameters.getHarvestDatabaseDirValue();
639        // Do not install if no proper database directory.
640        if (databaseDir == null || databaseDir.isEmpty()) {
641            return Constants.EMPTY;
642        }
643
644        // copy to final destination if database argument.
645        if (databaseFile != null) {
646            // echo Copying database
647            res.append(ScriptConstants.ECHO_COPYING_DATABASE);
648            res.append(Constants.NEWLINE);
649            // scp database.jar user@machine:dbDir/db
650            res.append(ScriptConstants.SCP + Constants.SPACE);
651            res.append(databaseFile.getPath());
652            res.append(Constants.SPACE);
653            res.append(machineUserLogin());
654            res.append(Constants.COLON);
655            res.append(getInstallDirPath());
656            res.append(Constants.SLASH);
657            res.append(Constants.HARVEST_DATABASE_BASE_PATH);
658            res.append(Constants.NEWLINE);
659        }
660        // unzip database.
661        res.append(ScriptConstants.ECHO_UNZIPPING_DATABASE);
662        res.append(Constants.NEWLINE);
663        // ssh user@machine "
664        // cd dir; if [ -d databaseDir ]; then echo ;
665        // else mkdir databaseDir; fi; if [ $(ls -A databaseDir) ];
666        // then echo ERROR MESSAGE: DIR NOT EMPTY;
667        // else unzip -q -o dbDir/db -d databaseDir/.; fi; exit;
668        // "
669        res.append(ScriptConstants.SSH + Constants.SPACE);
670        res.append(machineUserLogin());
671        res.append(Constants.SPACE + Constants.QUOTE_MARK + ScriptConstants.CD + Constants.SPACE);
672        res.append(getInstallDirPath());
673        res.append(Constants.SEMICOLON + Constants.SPACE + ScriptConstants.LINUX_IF_DIR_EXIST + Constants.SPACE);
674        res.append(databaseDir);
675        res.append(Constants.SPACE + ScriptConstants.LINUX_THEN + Constants.SPACE + ScriptConstants.ECHO
676                + Constants.SPACE);
677        res.append(ScriptConstants.DATABASE_ERROR_PROMPT_DIR_NOT_EMPTY);
678        res.append(Constants.SEMICOLON + Constants.SPACE + ScriptConstants.ELSE + Constants.SPACE
679                + ScriptConstants.LINUX_UNZIP_COMMAND + Constants.SPACE);
680        res.append(Constants.HARVEST_DATABASE_BASE_PATH);
681        res.append(Constants.SPACE + ScriptConstants.SCRIPT_DIR + Constants.SPACE);
682        res.append(databaseDir);
683        res.append(Constants.SEMICOLON + Constants.SPACE + ScriptConstants.FI + Constants.SEMICOLON + Constants.SPACE
684                + ScriptConstants.EXIT + Constants.SEMICOLON + Constants.SPACE + Constants.QUOTE_MARK);
685        res.append(Constants.NEWLINE);
686
687        return res.toString();
688    }
689
690    @Override
691    protected String osInstallExternalJarFiles() {
692        if (jarFolder == null) {
693            return Constants.EMPTY;
694        }
695
696        StringBuilder res = new StringBuilder();
697
698        // Comment about copying files.
699        res.append(ScriptConstants.ECHO_INSTALLING_EXTERNAL_JAR_FILES);
700        res.append(Constants.NEWLINE);
701        // if [ -d folder ]; then scp folder machine:installdir/external; fi;
702        res.append(ScriptConstants.LINUX_IF_DIR_EXIST + Constants.SPACE);
703        res.append(jarFolder.getPath());
704        res.append(Constants.SPACE + ScriptConstants.LINUX_THEN + Constants.SPACE + ScriptConstants.SCP
705                + Constants.SPACE + ScriptConstants.DASH_R + Constants.SPACE);
706        res.append(jarFolder.getPath());
707        res.append(Constants.SPACE);
708        res.append(machineUserLogin());
709        res.append(Constants.COLON);
710        res.append(getInstallDirPath());
711        res.append(Constants.SLASH + Constants.EXTERNAL_JAR_DIRECTORY + Constants.SEMICOLON + Constants.SPACE
712                + ScriptConstants.FI + Constants.SEMICOLON);
713        res.append(Constants.NEWLINE);
714
715        return res.toString();
716    }
717
718    @Override
719    protected String osInstallArchiveDatabase() {
720        String adminDatabaseDir = machineParameters.getArchiveDatabaseDirValue();
721        // Do not install if no proper archive database directory.
722        if (adminDatabaseDir == null || adminDatabaseDir.isEmpty()) {
723            return Constants.EMPTY;
724        }
725
726        // Initialise the StringBuilder containing the resulting script.
727        StringBuilder res = new StringBuilder();
728
729        // copy to final destination if database argument.
730        if (arcDatabaseFile != null) {
731            // echo Copying database
732            res.append(ScriptConstants.ECHO_COPYING_ARCHIVE_DATABASE);
733            res.append(Constants.NEWLINE);
734            // scp database.jar user@machine:dbDir/bpdb
735            res.append(ScriptConstants.SCP + Constants.SPACE);
736            res.append(arcDatabaseFile.getPath());
737            res.append(Constants.SPACE);
738            res.append(machineUserLogin());
739            res.append(Constants.COLON);
740            res.append(getInstallDirPath());
741            res.append(Constants.SLASH);
742            // Now the two databases are in different directories
743            res.append(Constants.ARCHIVE_DATABASE_BASE_PATH);
744            res.append(Constants.NEWLINE);
745        }
746        // unzip database.
747        res.append(ScriptConstants.ECHO_UNZIPPING_ARCHIVE_DATABASE);
748        res.append(Constants.NEWLINE);
749        // ssh user@machine "
750        // cd dir; if [ -d bpDatabaseDir ]; then echo ;
751        // else mkdir bpDatabaseDir; fi; if [ $(ls -A bpDatabaseDir) ];
752        // then echo ERROR MESSAGE: DIR NOT EMPTY;
753        // else unzip -q -o dbDir/bpdb -d databaseDir/.; fi; exit;
754        // "
755        res.append(ScriptConstants.SSH + Constants.SPACE);
756        res.append(machineUserLogin());
757        res.append(Constants.SPACE + Constants.QUOTE_MARK + ScriptConstants.CD + Constants.SPACE);
758        res.append(getInstallDirPath());
759        res.append(Constants.SEMICOLON + Constants.SPACE + ScriptConstants.LINUX_IF_DIR_EXIST + Constants.SPACE);
760        res.append(adminDatabaseDir);
761        res.append(Constants.SPACE + ScriptConstants.LINUX_THEN + Constants.SPACE + ScriptConstants.ECHO
762                + Constants.SPACE);
763        res.append(ScriptConstants.DATABASE_ERROR_PROMPT_DIR_NOT_EMPTY);
764        res.append(Constants.SEMICOLON + Constants.SPACE + ScriptConstants.ELSE + Constants.SPACE
765                + ScriptConstants.LINUX_UNZIP_COMMAND + Constants.SPACE);
766        res.append(Constants.ARCHIVE_DATABASE_BASE_PATH);
767        res.append(Constants.SPACE + ScriptConstants.SCRIPT_DIR + Constants.SPACE);
768        res.append(adminDatabaseDir);
769        res.append(Constants.SEMICOLON + Constants.SPACE + ScriptConstants.FI + Constants.SEMICOLON + Constants.SPACE
770                + ScriptConstants.EXIT + Constants.SEMICOLON + Constants.SPACE + Constants.QUOTE_MARK);
771        res.append(Constants.NEWLINE);
772
773        return res.toString();
774    }
775
776    /**
777     * Creates the specified directories in the deploy-configuration file.
778     * <p>
779     * Structure - ssh login cd path; DIRS; CLEANDIR; exit;
780     * <p>
781     * where: login = username@machine. path = path to install directory. DIRS = the way to create directories. CLEANDIR
782     * = the command to clean the tempDir (if chosen as optional)
783     * <p>
784     * The install creation of DIR has the following structure for directory dir: if [ ! -d dir ]; then mkdir dir; fi;
785     *
786     * @return The script for creating the directories.
787     */
788    @Override
789    protected String osInstallScriptCreateDir() {
790        StringBuilder res = new StringBuilder();
791        res.append(ScriptConstants.ECHO_CREATING_DIRECTORIES);
792        res.append(Constants.NEWLINE);
793        res.append(ScriptConstants.SSH + Constants.SPACE);
794        res.append(machineUserLogin());
795        res.append(Constants.SPACE + Constants.QUOTE_MARK + ScriptConstants.CD + Constants.SPACE);
796        res.append(getInstallDirPath());
797        res.append(Constants.SEMICOLON + Constants.SPACE);
798
799        // go through all directories.
800        String dir;
801
802        // get archive.bitpresevation.baseDir directory.
803        dir = settings.getLeafValue(Constants.SETTINGS_ARCHIVE_BP_BASEDIR_LEAF);
804        if (dir != null && !dir.isEmpty() && !dir.equalsIgnoreCase(Constants.DOT)) {
805            res.append(createPathToDir(dir));
806            res.append(scriptCreateDir(dir, false));
807        }
808
809        // get archive.arcrepository.baseDir directory.
810        dir = settings.getLeafValue(Constants.SETTINGS_ARCHIVE_ARC_BASEDIR_LEAF);
811        if (dir != null && !dir.isEmpty() && !dir.equalsIgnoreCase(Constants.DOT)) {
812            res.append(scriptCreateDir(dir, false));
813        }
814
815        // get tempDir directory.
816        dir = settings.getLeafValue(Constants.SETTINGS_TEMPDIR_LEAF);
817        if (dir != null && !dir.isEmpty() && !dir.equalsIgnoreCase(Constants.DOT)) {
818            res.append(createPathToDir(dir));
819            res.append(scriptCreateDir(dir, resetTempDir));
820        }
821
822        // get the application specific directories.
823        res.append(getAppDirectories());
824
825        res.append(ScriptConstants.EXIT + Constants.SEMICOLON + Constants.SPACE + Constants.QUOTE_MARK
826                + Constants.NEWLINE);
827
828        return res.toString();
829    }
830
831    @Override
832    protected String scriptCreateDir(String dir, boolean clean) {
833        StringBuilder res = new StringBuilder();
834        res.append(ScriptConstants.LINUX_IF_NOT_DIR_EXIST + Constants.SPACE);
835        res.append(dir);
836        res.append(Constants.SPACE + ScriptConstants.LINUX_THEN + Constants.SPACE + ScriptConstants.MKDIR
837                + Constants.SPACE);
838        res.append(dir);
839        if (clean) {
840            res.append(Constants.SEMICOLON + Constants.SPACE + ScriptConstants.ELSE_REMOVE + Constants.SPACE);
841            res.append(dir);
842            res.append(Constants.SEMICOLON + Constants.SPACE + ScriptConstants.MKDIR + Constants.SPACE);
843            res.append(dir);
844        }
845        res.append(Constants.SEMICOLON + Constants.SPACE + ScriptConstants.FI + Constants.SEMICOLON + Constants.SPACE);
846
847        return res.toString();
848    }
849
850    /**
851     * Function for creating the directories along the path until the end directory. Does not create the end directory.
852     *
853     * @param dir The path to the directory.
854     * @return The script for creating the directory.
855     */
856    protected String createPathToDir(String dir) {
857        StringBuilder res = new StringBuilder();
858
859        String[] pathDirs = dir.split(Constants.REGEX_SLASH_CHARACTER);
860        StringBuilder path = new StringBuilder();
861
862        // only make directories along path to last directory,
863        // don't create end directory.
864        for (int i = 0; i < pathDirs.length - 1; i++) {
865            // don't make directory of empty path.
866            if (!pathDirs[i].isEmpty()) {
867                path.append(pathDirs[i]);
868                res.append(scriptCreateDir(path.toString(), false));
869            }
870            path.append(Constants.SLASH);
871        }
872
873        return res.toString();
874    }
875
876    @Override
877    protected String getAppDirectories() {
878        StringBuilder res = new StringBuilder();
879        String[] dirs;
880
881        for (Application app : applications) {
882            // get archive.fileDir directories.
883            dirs = app.getSettingsValues(Constants.SETTINGS_BITARCHIVE_BASEFILEDIR_LEAF);
884            if (dirs != null && dirs.length > 0) {
885                for (String dir : dirs) {
886                    res.append(createPathToDir(dir));
887                    res.append(scriptCreateDir(dir, false));
888                    for (String subdir : Constants.BASEFILEDIR_SUBDIRECTORIES) {
889                        res.append(scriptCreateDir(dir + Constants.SLASH + subdir, false));
890                    }
891                }
892            }
893
894            // get harvester.harvesting.serverDir directories.
895            dirs = app.getSettingsValues(Constants.SETTINGS_HARVEST_SERVERDIR_LEAF);
896            if (dirs != null && dirs.length > 0) {
897                for (String dir : dirs) {
898                    res.append(createPathToDir(dir));
899                    res.append(scriptCreateDir(dir, false));
900                }
901            }
902
903            // get the viewerproxy.baseDir directories.
904            dirs = app.getSettingsValues(Constants.SETTINGS_VIEWERPROXY_BASEDIR_LEAF);
905            if (dirs != null && dirs.length > 0) {
906                for (String dir : dirs) {
907                    res.append(createPathToDir(dir));
908                    res.append(scriptCreateDir(dir, false));
909                }
910            }
911
912            // get the common.tempDir directories. But only those,
913            // which are not the same as the machine common.tempDir.
914            dirs = app.getSettingsValues(Constants.SETTINGS_TEMPDIR_LEAF);
915            if (dirs != null && dirs.length > 0) {
916                String machineDir = settings.getLeafValue(Constants.SETTINGS_TEMPDIR_LEAF);
917                for (String dir : dirs) {
918                    // Don't make machine temp dir twice.
919                    if (!dir.equals(machineDir)) {
920                        res.append(createPathToDir(dir));
921                        res.append(scriptCreateDir(dir, resetTempDir));
922                    }
923                }
924            }
925        }
926
927        return res.toString();
928    }
929
930    /**
931     * Dummy function on linux machine. This is only used for windows machines!
932     *
933     * @param dir The directory to put the file.
934     */
935    @Override
936    protected void createInstallDirScript(File dir) {
937        // Do nothing. Dummy function on linux machine.
938    }
939
940    @Override
941    protected String changeFileDirPathForSecurity(String path) {
942        path += Constants.SLASH + Constants.SECURITY_FILE_DIR_TAG + Constants.SLASH;
943        return path.replace(Constants.SLASH, ScriptConstants.SECURITY_DIR_SEPARATOR);
944    }
945
946    @Override
947    protected String getJMXremoteFilesCommand() {
948        String accessFilePath;
949        String passwordFilePath;
950        String[] options;
951
952        // retrieve the access file path.
953        options = settings.getLeafValues(Constants.SETTINGS_COMMON_JMX_ACCESSFILE);
954
955        // extract the path, if any. Else set default.
956        if (options.length == 0) {
957            accessFilePath = Constants.JMX_ACCESS_FILE_PATH_DEFAULT;
958        } else {
959            accessFilePath = options[0];
960            // warn if more than one access file is defined.
961            if (options.length > 1) {
962                log.debug(Constants.MSG_WARN_TOO_MANY_JMXREMOTE_FILE_PATHS);
963            }
964        }
965
966        // retrieve the password file path.
967        options = settings.getLeafValues(Constants.SETTINGS_COMMON_JMX_PASSWORDFILE);
968
969        // extract the path, if any. Else set default.
970        if (options.length == 0) {
971            passwordFilePath = Constants.JMX_PASSWORD_FILE_PATH_DEFAULT;
972        } else {
973            passwordFilePath = options[0];
974            // warn if more than one access file is defined.
975            if (options.length > 1) {
976                log.debug(Constants.MSG_WARN_TOO_MANY_JMXREMOTE_FILE_PATHS);
977            }
978        }
979
980        // initialise the resulting command string.
981        StringBuilder res = new StringBuilder();
982
983        // echo make password files readonly
984        res.append(ScriptConstants.ECHO_MAKE_PASSWORD_FILES);
985        res.append(Constants.NEWLINE);
986
987        // IF NOT DEFAULT PATHS, THEN MAKE SCRIPT TO MOVE THE FILES.
988        if (!accessFilePath.equals(Constants.JMX_ACCESS_FILE_PATH_DEFAULT)) {
989            // ssh dev@kb-test-adm-001.kb.dk "mv -f
990            // installpath/conf/jmxremote.access installpath/accessFilePath"
991            res.append(ScriptConstants.SSH + Constants.SPACE);
992            res.append(machineUserLogin());
993            res.append(Constants.SPACE + Constants.QUOTE_MARK);
994            res.append(ScriptConstants.LINUX_FORCE_MOVE);
995            res.append(Constants.SPACE);
996            res.append(getInstallDirPath());
997            res.append(Constants.SLASH);
998            res.append(Constants.JMX_ACCESS_FILE_PATH_DEFAULT);
999            res.append(Constants.SPACE);
1000            res.append(getInstallDirPath());
1001            res.append(Constants.SLASH);
1002            res.append(accessFilePath);
1003            res.append(Constants.QUOTE_MARK);
1004            res.append(Constants.NEWLINE);
1005        }
1006
1007        if (!passwordFilePath.equals(Constants.JMX_PASSWORD_FILE_PATH_DEFAULT)) {
1008            // ssh dev@kb-test-adm-001.kb.dk "mv -f
1009            // installpath/conf/jmxremote.access installpath/accessFilePath"
1010            res.append(ScriptConstants.SSH + Constants.SPACE);
1011            res.append(machineUserLogin());
1012            res.append(Constants.SPACE + Constants.QUOTE_MARK);
1013            res.append(ScriptConstants.LINUX_FORCE_MOVE);
1014            res.append(Constants.SPACE);
1015            res.append(getInstallDirPath());
1016            res.append(Constants.SLASH);
1017            res.append(Constants.JMX_PASSWORD_FILE_PATH_DEFAULT);
1018            res.append(Constants.SPACE);
1019            res.append(getInstallDirPath());
1020            res.append(Constants.SLASH);
1021            res.append(passwordFilePath);
1022            res.append(Constants.QUOTE_MARK);
1023            res.append(Constants.NEWLINE);
1024        }
1025
1026        // Allow only user to be able to only read jmxremote.password
1027        // (a=-rwx,u=+r) = 400.
1028        // ssh dev@kb-test-adm-001.kb.dk "chmod 400
1029        // /home/dev/TEST/conf/jmxremote.password"
1030        res.append(ScriptConstants.SSH + Constants.SPACE);
1031        res.append(machineUserLogin());
1032        res.append(Constants.SPACE + Constants.QUOTE_MARK + ScriptConstants.LINUX_USER_400 + Constants.SPACE);
1033        res.append(getInstallDirPath());
1034        res.append(Constants.SLASH);
1035        res.append(passwordFilePath);
1036        res.append(Constants.QUOTE_MARK);
1037        res.append(Constants.NEWLINE);
1038        // ssh dev@kb-test-adm-001.kb.dk "chmod 400
1039        // /home/dev/TEST/conf/jmxremote.access"
1040        res.append(ScriptConstants.SSH + Constants.SPACE);
1041        res.append(machineUserLogin());
1042        res.append(Constants.SPACE + Constants.QUOTE_MARK + ScriptConstants.LINUX_USER_400 + Constants.SPACE);
1043        res.append(getInstallDirPath());
1044        res.append(Constants.SLASH);
1045        res.append(accessFilePath);
1046        res.append(Constants.QUOTE_MARK);
1047        res.append(Constants.NEWLINE);
1048
1049        return res.toString();
1050    }
1051
1052    /**
1053     * Creates script for restarting all the applications on a machine. This script should start by killing all the
1054     * existing processes, and then starting them again.
1055     * <p>
1056     * First the killall scripts is called, then wait for 5 seconds for the applications to be fully terminated, and
1057     * finally the startall script is called.
1058     *
1059     * @param dir The directory where the script file will be placed.
1060     * @throws IOFailure If the restart script cannot be created.
1061     */
1062    @Override
1063    protected void createRestartScript(File dir) throws IOFailure {
1064        try {
1065            // initialise the script file.
1066            File restartScript = new File(dir, Constants.SCRIPT_NAME_RESTART + scriptExtension);
1067
1068            // make print writer for writing to file
1069            PrintWriter restartPrint = new PrintWriter(restartScript, getTargetEncoding());
1070            try {
1071                // init, go to directory
1072                restartPrint.println(ScriptConstants.BIN_BASH_COMMENT);
1073                restartPrint.println(ScriptConstants.CD + Constants.SPACE + getConfDirPath());
1074
1075                // call killall script.
1076                restartPrint.print(Constants.DOT + Constants.SLASH + Constants.SCRIPT_NAME_KILL_ALL + scriptExtension);
1077                restartPrint.print(Constants.NEWLINE);
1078
1079                // call wait script.
1080                restartPrint.print(ScriptConstants.SLEEP);
1081                restartPrint.print(Constants.SPACE);
1082                restartPrint.print(Constants.WAIT_TIME_DURING_RESTART);
1083                restartPrint.print(Constants.NEWLINE);
1084
1085                // call startall script.
1086                restartPrint.print(Constants.DOT + Constants.SLASH + Constants.SCRIPT_NAME_START_ALL + scriptExtension);
1087                restartPrint.print(Constants.NEWLINE);
1088            } finally {
1089                // close file
1090                restartPrint.close();
1091            }
1092        } catch (IOException e) {
1093            // Log the error and throw an IOFailure.
1094            log.trace(Constants.MSG_ERROR_RESTART_FILE, e);
1095            throw new IOFailure(Constants.MSG_ERROR_RESTART_FILE, e);
1096        }
1097    }
1098
1099    /**
1100     * Creates a script for starting the archive database on a given machine. This is only created if the
1101     * &lt;globalArchiveDatabaseDir&gt; parameter is defined on the machine level.
1102     * <p>
1103     * <br/>
1104     * &gt; #!/bin/bash <br/>
1105     * &gt; cd InstallDir <br/>
1106     * &gt; java -cp 'DB-CLASSPATH' org.apache.derby.drda.NetworkServerControl start < /dev/null >
1107     * start_external_database.log 2>&1 &
1108     *
1109     * @param dir The directory where the script will be placed.
1110     * @throws IOFailure If the script cannot be written.
1111     */
1112    @Override
1113    protected void createArchiveDatabaseStartScript(File dir) throws IOFailure {
1114
1115        // Ignore if no archive database directory has been defined.
1116        String dbDir = machineParameters.getArchiveDatabaseDirValue();
1117        if (dbDir.isEmpty()) {
1118            return;
1119        }
1120
1121        try {
1122            // initialise the script file.
1123            File startArcDBScript = new File(dir, Constants.SCRIPT_NAME_ADMIN_DB_START + scriptExtension);
1124
1125            // retrieve the port
1126            String port = settings.getLeafValue(Constants.SETTINGS_ARCHIVE_DATABASE_PORT);
1127
1128            // make print writer for writing to file
1129            PrintWriter startDBPrint = new PrintWriter(startArcDBScript, getTargetEncoding());
1130            try {
1131                // - #!/bin/bash
1132                startDBPrint.println(ScriptConstants.BIN_BASH_COMMENT);
1133                // - cd InstallDir
1134                startDBPrint.print(ScriptConstants.CD + Constants.SPACE);
1135                startDBPrint.println(getInstallDirPath());
1136                // - java -Dderby.system.home=$INSTALLDIR/archivedatabasedir
1137                // -cp 'DB-CLASSPATH'
1138                // org.apache.derby.drda.NetworkServerControl start
1139                // < /dev/null > start_external_database.log 2>&1 &
1140                startDBPrint.print(ScriptConstants.JAVA + Constants.SPACE);
1141                // FIXME: Incomplete implementation of NAS-2030
1142                // startDBPrint.print("-Dderby.system.home="
1143                // + getInstallDirPath() + Constants.SLASH
1144                // + dbDir
1145                // + Constants.SPACE);
1146
1147                startDBPrint.print(machineParameters.writeJavaOptions());
1148                startDBPrint.print(Constants.SPACE);
1149                startDBPrint.print(ScriptConstants.JAVA_CLASSPATH);
1150                startDBPrint.print(Constants.SPACE + getDbClasspaths());
1151                startDBPrint.print(ScriptConstants.DERBY_ACCESS_METHOD);
1152                // insert the PORT if any specified.
1153                if (port != null && !port.isEmpty()) {
1154                    startDBPrint.print(Constants.SPACE);
1155                    startDBPrint.print(ScriptConstants.DATABASE_PORT_ARGUMENT);
1156                    startDBPrint.print(Constants.SPACE);
1157                    startDBPrint.print(port);
1158                }
1159                startDBPrint.print(Constants.SPACE);
1160                startDBPrint.print(ScriptConstants.DERBY_COMMAND_START);
1161                startDBPrint.print(Constants.SPACE);
1162                startDBPrint.print(ScriptConstants.LINUX_DEV_NULL);
1163                startDBPrint.print(Constants.SPACE);
1164                startDBPrint.print(Constants.SCRIPT_NAME_ADMIN_DB_START);
1165                startDBPrint.print(Constants.EXTENSION_LOG_FILES);
1166                startDBPrint.print(Constants.SPACE);
1167                startDBPrint.println(ScriptConstants.LINUX_ERROR_MESSAGE_TO_1);
1168            } finally {
1169                // close file
1170                startDBPrint.close();
1171            }
1172        } catch (IOException e) {
1173            // Log the error and throw an IOFailure.
1174            log.trace(Constants.MSG_ERROR_DB_START_FILE, e);
1175            throw new IOFailure(Constants.MSG_ERROR_DB_START_FILE, e);
1176        }
1177    }
1178
1179    /**
1180     * Method for generating the command for running the external_admin_database_start script. This should be called
1181     * before the application on the machines have been started.
1182     * <p>
1183     * <br/>
1184     * &gt; echo Starting external database <br/>
1185     * &gt; if [ -e ./start_external_admin_database.sh ]; then <br/>
1186     * &gt; ./start_external_admin_database.sh & <br/>
1187     * &gt; sleep 5 <br/>
1188     * &gt; fi
1189     *
1190     * @return The command for running external_admin_database_start script.
1191     */
1192    protected String callStartArchiveDatabase() {
1193        // Ignore if no archive database directory has been defined.
1194        String dbDir = machineParameters.getArchiveDatabaseDirValue();
1195        if (dbDir.isEmpty()) {
1196            return "";
1197        }
1198
1199        // Constructing filename
1200        String appScript = Constants.DOT + Constants.SLASH + Constants.SCRIPT_NAME_ADMIN_DB_START + scriptExtension;
1201
1202        StringBuilder res = new StringBuilder();
1203        // echo Starting external database
1204        res.append(ScriptConstants.ECHO_START_EXTERNAL_ADMIN_DATABASE);
1205        res.append(Constants.NEWLINE);
1206        // if [ -e ./start_external_database.sh ]; then
1207        res.append(ScriptConstants.LINUX_IF_EXIST + Constants.SPACE);
1208        res.append(appScript + Constants.SPACE + ScriptConstants.LINUX_THEN);
1209        res.append(Constants.NEWLINE);
1210        // ./start_external_database.sh
1211        res.append(ScriptConstants.MULTI_SPACE_6 + appScript);
1212        res.append(ScriptConstants.LINUX_RUN_BACKGROUND + Constants.NEWLINE);
1213        // sleep 5
1214        res.append(ScriptConstants.MULTI_SPACE_6 + ScriptConstants.SLEEP_5);
1215        res.append(Constants.NEWLINE);
1216        // fi
1217        res.append(ScriptConstants.FI + Constants.NEWLINE);
1218
1219        return res.toString();
1220    }
1221
1222    /**
1223     * Creates a script for killing the archive database on a given machine. This is only created if the
1224     * &lt;globalArchiveDatabaseDir&gt; parameter is defined on the machine level.
1225     * <p>
1226     * The output is appended to the log, thus the '>>' instead of the standard '>' when redirecting the output.
1227     * <p>
1228     * <br/>
1229     * &gt; #!/bin/bash <br/>
1230     * &gt; cd InstallDir <br/>
1231     * &gt; java -cp 'DB-CLASSPATH' org.apache.derby.drda.NetworkServerControl shutdown < /dev/null >>
1232     * start_external_database.log 2>&1 &
1233     * <p>
1234     * <br/>
1235     * where 'PORT' is in the setting: settings.archive.admin.database.port
1236     *
1237     * @param dir The directory where the script will be placed.
1238     * @throws IOFailure If the script cannot be created.
1239     */
1240    @Override
1241    protected void createArchiveDatabaseKillScript(File dir) throws IOFailure {
1242        // Ignore if no archive database directory has been defined.
1243        String dbDir = machineParameters.getArchiveDatabaseDirValue();
1244        if (dbDir.isEmpty()) {
1245            return;
1246        }
1247
1248        try {
1249            // initialise the script file.
1250            File killArcDBScript = new File(dir, Constants.SCRIPT_NAME_ADMIN_DB_KILL + scriptExtension);
1251
1252            // retrieve the port for the database.
1253            String port = settings.getLeafValue(Constants.SETTINGS_ARCHIVE_DATABASE_PORT);
1254
1255            // make print writer for writing to file
1256            PrintWriter killDBPrint = new PrintWriter(killArcDBScript, getTargetEncoding());
1257            try {
1258                // - #!/bin/bash
1259                killDBPrint.println(ScriptConstants.BIN_BASH_COMMENT);
1260
1261                // - cd InstallDir
1262                killDBPrint.print(ScriptConstants.CD + Constants.SPACE);
1263                killDBPrint.println(getInstallDirPath());
1264                // - java -cp 'DB-CLASSPATH'
1265                // org.apache.derby.drda.NetworkServerControl shutdown
1266                // < /dev/null >> start_external_database.log 2>&1 &
1267                killDBPrint.print(ScriptConstants.JAVA + Constants.SPACE);
1268                killDBPrint.print(ScriptConstants.JAVA_CLASSPATH);
1269                killDBPrint.print(Constants.SPACE + getDbClasspaths());
1270                killDBPrint.print(ScriptConstants.DERBY_ACCESS_METHOD);
1271                // insert the PORT if any specified.
1272                if (port != null && !port.isEmpty()) {
1273                    killDBPrint.print(Constants.SPACE);
1274                    killDBPrint.print(ScriptConstants.DATABASE_PORT_ARGUMENT);
1275                    killDBPrint.print(Constants.SPACE);
1276                    killDBPrint.print(port);
1277                }
1278                killDBPrint.print(Constants.SPACE);
1279                killDBPrint.print(ScriptConstants.DERBY_COMMAND_KILL);
1280                killDBPrint.print(Constants.SPACE);
1281                killDBPrint.print(ScriptConstants.LINUX_DEV_NULL);
1282                killDBPrint.print(Constants.GREATER_THAN);
1283                killDBPrint.print(Constants.SPACE);
1284                killDBPrint.print(Constants.SCRIPT_NAME_ADMIN_DB_START);
1285                killDBPrint.print(Constants.EXTENSION_LOG_FILES);
1286                killDBPrint.print(Constants.SPACE);
1287                killDBPrint.println(ScriptConstants.LINUX_ERROR_MESSAGE_TO_1);
1288            } finally {
1289                // close file
1290                killDBPrint.close();
1291            }
1292        } catch (IOException e) {
1293            // Log the error and throw an IOFailure.
1294            log.trace(Constants.MSG_ERROR_DB_KILL_FILE, e);
1295            throw new IOFailure(Constants.MSG_ERROR_DB_KILL_FILE, e);
1296        }
1297    }
1298
1299    /**
1300     * Method for generating the command for running the external_database_kill script. This should be called when the
1301     * application on the machines have been killed.
1302     * <p>
1303     * <br/>
1304     * &gt; echo Killing external database <br/>
1305     * &gt; if [ -e ./kill_external_database.sh ]; then <br/>
1306     * &gt; ./kill_external_database.sh <br/>
1307     * &gt; fi
1308     *
1309     * @return The command for running external_database_kill script.
1310     */
1311    protected String callKillArchiveDatabase() {
1312        // Ignore if no archive database directory has been defined.
1313        String dbDir = machineParameters.getArchiveDatabaseDirValue();
1314        if (dbDir.isEmpty()) {
1315            return "";
1316        }
1317
1318        // Constructing filename
1319        String appScript = Constants.DOT + Constants.SLASH + Constants.SCRIPT_NAME_ADMIN_DB_KILL + scriptExtension;
1320
1321        StringBuilder res = new StringBuilder();
1322        // echo Killing external database
1323        res.append(ScriptConstants.ECHO_KILL_EXTERNAL_ADMIN_DATABASE);
1324        res.append(Constants.NEWLINE);
1325        // if [ -e ./kill_external_database.sh ]; then
1326        res.append(ScriptConstants.LINUX_IF_EXIST + Constants.SPACE);
1327        res.append(appScript + Constants.SPACE + ScriptConstants.LINUX_THEN);
1328        res.append(Constants.NEWLINE);
1329        // ./kill_external_database.sh
1330        res.append(ScriptConstants.MULTI_SPACE_6 + appScript);
1331        res.append(Constants.NEWLINE);
1332        // fi
1333        res.append(ScriptConstants.FI + Constants.NEWLINE);
1334
1335        return res.toString();
1336    }
1337
1338    /**
1339     * Creates a script for starting the harvest database on a given machine. This is only created if the
1340     * &lt;deployHarvestDatabaseDir&gt; parameter is defined on the machine level.
1341     * <p>
1342     * <br/>
1343     * &gt; #!/bin/bash <br/>
1344     * &gt; cd InstallDir <br/>
1345     * &gt; java -cp 'DB-CLASSPATH' org.apache.derby.drda.NetworkServerControl start < /dev/null >
1346     * start_external_harvest_database.log 2>&1 &
1347     *
1348     * @param dir The directory where the script will be placed.
1349     * @throws IOFailure If the script cannot be written.
1350     */
1351    @Override
1352    protected void createHarvestDatabaseStartScript(File dir) throws IOFailure {
1353        // Ignore if no harvest database directory has been defined.
1354        String dbDir = machineParameters.getHarvestDatabaseDirValue();
1355        if (dbDir.isEmpty()) {
1356            return;
1357        }
1358
1359        try {
1360            // initialise the script file.
1361            File startHarvestDBScript = new File(dir, Constants.SCRIPT_NAME_HARVEST_DB_START + scriptExtension);
1362
1363            // retrieve the port
1364            String port = settings.getLeafValue(Constants.SETTINGS_HARVEST_DATABASE_PORT);
1365
1366            // make print writer for writing to file
1367            PrintWriter startDBPrint = new PrintWriter(startHarvestDBScript, getTargetEncoding());
1368            try {
1369                // - #!/bin/bash
1370                startDBPrint.println(ScriptConstants.BIN_BASH_COMMENT);
1371                // - cd InstallDir
1372                startDBPrint.print(ScriptConstants.CD + Constants.SPACE);
1373                startDBPrint.println(getInstallDirPath());
1374                // - java -cp 'DB-CLASSPATH'
1375                // org.apache.derby.drda.NetworkServerControl start
1376                // < /dev/null > start_external_harvest_database.log 2>&1 &
1377                startDBPrint.print(ScriptConstants.JAVA + Constants.SPACE);
1378                // FIXME: Incomplete implementation of NAS-2030
1379                // startDBPrint.print("-Dderby.system.home="
1380                // + getInstallDirPath() + Constants.SLASH
1381                // + dbDir
1382                // + Constants.SPACE);
1383
1384                startDBPrint.print(machineParameters.writeJavaOptions());
1385                startDBPrint.print(Constants.SPACE);
1386                startDBPrint.print(ScriptConstants.JAVA_CLASSPATH);
1387                startDBPrint.print(Constants.SPACE + getDbClasspaths());
1388                startDBPrint.print(ScriptConstants.DERBY_ACCESS_METHOD);
1389                // insert the PORT if any specified.
1390                if (port != null && !port.isEmpty()) {
1391                    startDBPrint.print(Constants.SPACE);
1392                    startDBPrint.print(ScriptConstants.DATABASE_PORT_ARGUMENT);
1393                    startDBPrint.print(Constants.SPACE);
1394                    startDBPrint.print(port);
1395                }
1396                startDBPrint.print(Constants.SPACE);
1397                startDBPrint.print(ScriptConstants.DERBY_COMMAND_START);
1398                startDBPrint.print(Constants.SPACE);
1399                startDBPrint.print(ScriptConstants.LINUX_DEV_NULL);
1400                startDBPrint.print(Constants.SPACE);
1401                startDBPrint.print(Constants.SCRIPT_NAME_HARVEST_DB_START);
1402                startDBPrint.print(Constants.EXTENSION_LOG_FILES);
1403                startDBPrint.print(Constants.SPACE);
1404                startDBPrint.println(ScriptConstants.LINUX_ERROR_MESSAGE_TO_1);
1405            } finally {
1406                // close file
1407                startDBPrint.close();
1408            }
1409        } catch (IOException e) {
1410            // Log the error and throw an IOFailure.
1411            log.trace(Constants.MSG_ERROR_DB_START_FILE, e);
1412            throw new IOFailure(Constants.MSG_ERROR_DB_START_FILE, e);
1413        }
1414    }
1415
1416    /**
1417     * Method for generating the command for running the external_harvest_database_start script. This should be called
1418     * before the application on the machines have been started.
1419     * <p>
1420     * <br/>
1421     * &gt; echo Starting external harvest database <br/>
1422     * &gt; if [ -e ./start_external_harvest_database.sh ]; then <br/>
1423     * &gt; ./start_external_harvest_database.sh & <br/>
1424     * &gt; sleep 5 <br/>
1425     * &gt; fi
1426     *
1427     * @return The command for running external_harvest_database_start script.
1428     */
1429    protected String callStartHarvestDatabase() {
1430        // Ignore if no archive database directory has been defined.
1431        String dbDir = machineParameters.getHarvestDatabaseDirValue();
1432        if (dbDir.isEmpty()) {
1433            return "";
1434        }
1435
1436        // Constructing filename
1437        String appScript = Constants.DOT + Constants.SLASH + Constants.SCRIPT_NAME_HARVEST_DB_START + scriptExtension;
1438
1439        //String app2Script = Constants.DOT + Constants.SLASH + Constants.SCRIPT_NAME_HARVEST_DB_UPDATE + scriptExtension;
1440        ;
1441
1442        StringBuilder res = new StringBuilder();
1443        // echo Starting external harvest database
1444        res.append(ScriptConstants.ECHO_START_EXTERNAL_HARVEST_DATABASE);
1445        res.append(Constants.NEWLINE);
1446        // if [ -e ./start_external_harvest_database.sh ]; then
1447        res.append(ScriptConstants.LINUX_IF_EXIST + Constants.SPACE);
1448        res.append(appScript + Constants.SPACE + ScriptConstants.LINUX_THEN);
1449        res.append(Constants.NEWLINE);
1450        // ./start_external_harvest_database.sh
1451        res.append(ScriptConstants.MULTI_SPACE_6 + appScript);
1452        res.append(ScriptConstants.LINUX_RUN_BACKGROUND + Constants.NEWLINE);
1453        // sleep 5
1454        res.append(ScriptConstants.MULTI_SPACE_6 + ScriptConstants.SLEEP_5);
1455        // fi
1456        res.append(Constants.NEWLINE + ScriptConstants.FI);
1457        res.append(Constants.NEWLINE);
1458        // echo Updating external harvest database
1459        //res.append(ScriptConstants.ECHO_UPDATE_EXTERNAL_HARVEST_DATABASE);
1460        //res.append(Constants.NEWLINE);
1461        // if [ -e ./start_external_harvest_database.sh ]; then
1462        //res.append(ScriptConstants.LINUX_IF_EXIST + Constants.SPACE);
1463        //res.append(app2Script + Constants.SPACE + ScriptConstants.LINUX_THEN);
1464        //res.append(Constants.NEWLINE);
1465        //res.append(ScriptConstants.MULTI_SPACE_6 + app2Script);
1466        //res.append(Constants.NEWLINE);
1467        //fi
1468        //res.append(ScriptConstants.FI + Constants.NEWLINE);
1469
1470        return res.toString();
1471    }
1472
1473    /**
1474     * Creates a script for killing the harvest database on a given machine. This is only created if the
1475     * &lt;globalHarvestDatabaseDir&gt; parameter is defined on the machine level.
1476     * <p>
1477     * The output is appended to the log, thus the '>>' instead of the standard '>' when redirecting the output.
1478     * <p>
1479     * <br/>
1480     * &gt; #!/bin/bash <br/>
1481     * &gt; cd InstallDir <br/>
1482     * &gt; java -cp 'DB-CLASSPATH' org.apache.derby.drda.NetworkServerControl shutdown < /dev/null >>
1483     * start_external_harvest_database.log 2>&1 &
1484     * <p>
1485     * <br/>
1486     * where 'PORT' is in the setting: settings.common.database.port
1487     *
1488     * @param dir The directory where the script will be placed.
1489     * @throws IOFailure If the script cannot be created.
1490     */
1491    @Override
1492    protected void createHarvestDatabaseKillScript(File dir) throws IOFailure {
1493        // Ignore if no harvest database directory has been defined.
1494        String dbDir = machineParameters.getHarvestDatabaseDirValue();
1495        if (dbDir.isEmpty()) {
1496            return;
1497        }
1498
1499        try {
1500            // initialise the script file.
1501            File killHarvestDBScript = new File(dir, Constants.SCRIPT_NAME_HARVEST_DB_KILL + scriptExtension);
1502
1503            // retrieve the port for the database.
1504            String port = settings.getLeafValue(Constants.SETTINGS_HARVEST_DATABASE_PORT);
1505
1506            // make print writer for writing to file
1507            PrintWriter killDBPrint = new PrintWriter(killHarvestDBScript, getTargetEncoding());
1508            try {
1509                // - #!/bin/bash
1510                killDBPrint.println(ScriptConstants.BIN_BASH_COMMENT);
1511
1512                // - cd InstallDir
1513                killDBPrint.print(ScriptConstants.CD + Constants.SPACE);
1514                killDBPrint.println(getInstallDirPath());
1515                // - java -cp 'DB-CLASSPATH'
1516                // org.apache.derby.drda.NetworkServerControl shutdown
1517                // < /dev/null >> start_external_harvest_database.log 2>&1 &
1518                killDBPrint.print(ScriptConstants.JAVA + Constants.SPACE);
1519                killDBPrint.print(ScriptConstants.JAVA_CLASSPATH);
1520                killDBPrint.print(Constants.SPACE + getDbClasspaths());
1521                killDBPrint.print(ScriptConstants.DERBY_ACCESS_METHOD);
1522                // insert the PORT if any specified.
1523                if (port != null && !port.isEmpty()) {
1524                    killDBPrint.print(Constants.SPACE);
1525                    killDBPrint.print(ScriptConstants.DATABASE_PORT_ARGUMENT);
1526                    killDBPrint.print(Constants.SPACE);
1527                    killDBPrint.print(port);
1528                }
1529                killDBPrint.print(Constants.SPACE);
1530                killDBPrint.print(ScriptConstants.DERBY_COMMAND_KILL);
1531                killDBPrint.print(Constants.SPACE);
1532                killDBPrint.print(ScriptConstants.LINUX_DEV_NULL);
1533                killDBPrint.print(Constants.GREATER_THAN);
1534                killDBPrint.print(Constants.SPACE);
1535                killDBPrint.print(Constants.SCRIPT_NAME_HARVEST_DB_START);
1536                killDBPrint.print(Constants.EXTENSION_LOG_FILES);
1537                killDBPrint.print(Constants.SPACE);
1538                killDBPrint.println(ScriptConstants.LINUX_ERROR_MESSAGE_TO_1);
1539            } finally {
1540                // close file
1541                killDBPrint.close();
1542            }
1543        } catch (IOException e) {
1544            // Log the error and throw an IOFailure.
1545            log.trace(Constants.MSG_ERROR_DB_KILL_FILE, e);
1546            throw new IOFailure(Constants.MSG_ERROR_DB_KILL_FILE, e);
1547        }
1548    }
1549
1550    /**
1551     * Method for generating the command for running the external_database_kill script. This should be called when the
1552     * application on the machines have been killed.
1553     * <p>
1554     * <br/>
1555     * &gt; echo Killing external harvest database <br/>
1556     * &gt; if [ -e ./kill_external_harvest_database.sh ]; then <br/>
1557     * &gt; ./kill_external_harvest_database.sh <br/>
1558     * &gt; fi
1559     *
1560     * @return The command for running external_harvest_database_kill script.
1561     */
1562    protected String callKillHarvestDatabase() {
1563        // Ignore if no harvest database directory has been defined.
1564        String dbDir = machineParameters.getHarvestDatabaseDirValue();
1565        if (dbDir.isEmpty()) {
1566            return "";
1567        }
1568
1569        // Constructing filename
1570        String appScript = Constants.DOT + Constants.SLASH + Constants.SCRIPT_NAME_HARVEST_DB_KILL + scriptExtension;
1571
1572        StringBuilder res = new StringBuilder();
1573        // echo Killing external harvest database
1574        res.append(ScriptConstants.ECHO_KILL_EXTERNAL_HARVEST_DATABASE);
1575        res.append(Constants.NEWLINE);
1576        // if [ -e ./kill_external_harvest_database.sh ]; then
1577        res.append(ScriptConstants.LINUX_IF_EXIST + Constants.SPACE);
1578        res.append(appScript + Constants.SPACE + ScriptConstants.LINUX_THEN);
1579        res.append(Constants.NEWLINE);
1580        // ./kill_external_harvest_database.sh
1581        res.append(ScriptConstants.MULTI_SPACE_6 + appScript);
1582        res.append(Constants.NEWLINE);
1583        // fi
1584        res.append(ScriptConstants.FI + Constants.NEWLINE);
1585
1586        return res.toString();
1587    }
1588
1589    /**
1590     * Method for combining the classpaths for the database access. <br/>
1591     * E.g. /home/test/NAS/lib/db/derby.jar:/home/test/NAS/lib/db/derbynet.jar
1592     *
1593     * @return The combined classpaths for accessing the database.
1594     */
1595    private String getDbClasspaths() {
1596        StringBuilder res = new StringBuilder();
1597
1598        for (int i = 0; i < ScriptConstants.DERBY_ACCESS_CLASSPATH.length; i++) {
1599            // ignore colon at the first classpath.
1600            if (i != 0) {
1601                res.append(Constants.COLON);
1602            }
1603            res.append(getInstallDirPath() + Constants.SLASH);
1604            res.append(ScriptConstants.DERBY_ACCESS_CLASSPATH[i]);
1605        }
1606        res.append(Constants.SPACE);
1607        return res.toString();
1608    }
1609
1610    @Override
1611    protected void createHarvestDatabaseUpdateScript(File dir, boolean forceCreate) {
1612        // Ignore if no harvest database directory has been defined or this isn't a harvest server app.
1613        String dbDir = machineParameters.getHarvestDatabaseDirValue();
1614        if (dbDir.isEmpty() && !forceCreate) {
1615            return;
1616        }
1617
1618        try {
1619            // initialise the script file.
1620            File updateHarvestDBScript = new File(dir, Constants.SCRIPT_NAME_HARVEST_DB_UPDATE + scriptExtension);
1621
1622            File updateHarvestDBSettingsFile = new File(dir, Constants.SETTINGS_PREFIX
1623                    + Constants.SCRIPT_NAME_HARVEST_DB_UPDATE + Constants.EXTENSION_XML_FILES);
1624            PrintWriter updateDBSettings = new PrintWriter(updateHarvestDBSettingsFile, getTargetEncoding());
1625            updateDBSettings.println(settings.getXML());
1626            updateDBSettings.close();
1627
1628            // make print writer for writing to file
1629            PrintWriter updateDBPrint = new PrintWriter(updateHarvestDBScript, getTargetEncoding());
1630            try {
1631                // - #!/bin/bash
1632                updateDBPrint.println(ScriptConstants.BIN_BASH_COMMENT);
1633
1634                // - cd InstallDir
1635                updateDBPrint.print(ScriptConstants.CD + Constants.SPACE);
1636                updateDBPrint.println(getInstallDirPath());
1637
1638                // - java -cp
1639                // org.apache.derby.drda.NetworkServerControl shutdown
1640                // < /dev/null >> start_external_harvest_database.log 2>&1 &
1641
1642                updateDBPrint.print(ScriptConstants.EXPORT_CLASSPATH);
1643                updateDBPrint.print(getHarvestServerClasspath() + getHarvesterCoreClasspath() + ScriptConstants.NEWLINE);
1644
1645                updateDBPrint.print(ScriptConstants.JAVA + Constants.SPACE + "-" + ScriptConstants.OPTION_SETTINGS
1646                        + getConfDirPath() + updateHarvestDBSettingsFile.getName() + Constants.SPACE);
1647                updateDBPrint.print(ScriptConstants.HARVEST_DATABASE_UPDATE_APP);
1648
1649                updateDBPrint.print(Constants.SPACE);
1650                updateDBPrint.print(ScriptConstants.LINUX_DEV_NULL);
1651                updateDBPrint.print(Constants.GREATER_THAN);
1652                updateDBPrint.print(Constants.SPACE);
1653                updateDBPrint.print(Constants.SCRIPT_NAME_HARVEST_DB_UPDATE);
1654                updateDBPrint.print(Constants.EXTENSION_LOG_FILES);
1655                updateDBPrint.print(Constants.SPACE);
1656                updateDBPrint.println(ScriptConstants.LINUX_ERROR_MESSAGE_TO_1);
1657            } finally {
1658                // close file
1659                updateDBPrint.close();
1660            }
1661        } catch (IOException e) {
1662            // Log the error and throw an IOFailure.
1663            log.trace(Constants.MSG_ERROR_DB_KILL_FILE, e);
1664            throw new IOFailure(Constants.MSG_ERROR_DB_KILL_FILE, e);
1665        }
1666    }
1667
1668    private String getDefaultMachineClasspath() {
1669        StringBuilder res = new StringBuilder();
1670        // get all the classpaths
1671        for (Element cp : machineParameters.getClassPaths()) {
1672            res.append(getInstallDirPath() + Constants.SLASH + cp.getText().trim() + Constants.COLON);
1673        }
1674        return res.toString();
1675    }
1676
1677    private String getHarvestServerClasspath() {
1678        return getDefaultMachineClasspath() +
1679                getInstallDirPath() + Constants.SLASH + "lib/netarchivesuite-harvest-scheduler.jar" + Constants.COLON;
1680    }
1681
1682    private String getHarvesterCoreClasspath() {
1683        return getDefaultMachineClasspath() +
1684                getInstallDirPath() + Constants.SLASH + "lib/netarchivesuite-harvester-core.jar" + Constants.COLON;
1685    }
1686
1687
1688    @Override
1689    protected String getLibDirPath() {
1690        return getInstallDirPath() + Constants.LIB_DIR_LINUX;
1691    }
1692
1693        @Override
1694        protected String osUpdateLogos() {
1695                if (logoFile == null && menulogoFile == null) {
1696                        return "";
1697                }
1698                
1699                StringBuilder res = new StringBuilder();
1700                
1701        res.append(ScriptConstants.ECHO_CHANGING_LOGOS);
1702        res.append(Constants.NEWLINE);
1703
1704        if (logoFile != null) {
1705                res = updateLogofileInWarFiles(res, logoFile, Constants.DEFAULT_LOGO_FILENAME);         
1706        }
1707        
1708        if (menulogoFile != null) {
1709                res = updateLogofileInWarFiles(res, menulogoFile, Constants.DEFAULT_MENULOGO_FILENAME);         
1710        }
1711        
1712        return res.toString();
1713        }
1714
1715}