001/*
002 * #%L
003 * Netarchivesuite - deploy
004 * %%
005 * Copyright (C) 2005 - 2014 The Royal Danish Library, the Danish State and University 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.ArrayList;
029import java.util.List;
030
031import org.dom4j.Attribute;
032import org.dom4j.Element;
033import org.slf4j.Logger;
034import org.slf4j.LoggerFactory;
035
036import dk.netarkivet.common.exceptions.ArgumentNotValid;
037import dk.netarkivet.common.exceptions.IOFailure;
038import dk.netarkivet.common.exceptions.IllegalState;
039import dk.netarkivet.common.utils.FileUtils;
040
041/**
042 * Machine defines an abstract representation of a physical computer at a physical location. The actual instances are
043 * depending on the operation system: LinuxMachine and WindowsMachine. All non-OS specific methods are implemented this
044 * machine class.
045 */
046public abstract class Machine {
047
048    /** the log, for logging stuff instead of displaying them directly. */
049    protected static final Logger log = LoggerFactory.getLogger(Machine.class);
050    /** The root-branch for this machine in the XML tree. */
051    protected Element machineRoot;
052    /** The settings, inherited from parent and overwritten. */
053    protected XmlStructure settings;
054    /** The machine parameters. */
055    protected Parameters machineParameters;
056    /** The list of the application on this machine. */
057    protected List<Application> applications;
058    /** The name of this machine. */
059    protected String hostname;
060    /** The operating system on this machine: 'windows' or 'linux'. */
061    protected String operatingSystem;
062    /** The extension on the script files (specified by operating system). */
063    protected String scriptExtension;
064    /** The name of the NetarchiveSuite.zip file. */
065    protected String netarchiveSuiteFileName;
066    /** The inherited SLF4J config file. */
067    protected File inheritedSlf4jConfigFile;
068    /** The inherited security.policy file. */
069    protected File inheritedSecurityPolicyFile;
070    /** The inherited database file name. */
071    protected File databaseFile;
072    /** The inherited archive database file name. */
073    protected File arcDatabaseFile;
074    /** The directory for this machine. */
075    protected File machineDirectory;
076    /** Whether the temp dir should be cleaned. */
077    protected boolean resetTempDir;
078    /** The folder containing the external jar library files. */
079    protected File jarFolder;
080    /** The encoding to use when writing files. */
081    protected String targetEncoding;
082
083    /**
084     * A machine is referring to an actual computer at a physical location, which can have independent applications from
085     * the other machines at the same location.
086     *
087     * @param subTreeRoot The root of this instance in the XML document.
088     * @param parentSettings The setting inherited by the parent.
089     * @param param The machine parameters inherited by the parent.
090     * @param netarchiveSuiteSource The name of the NetarchiveSuite package file.
091     * @param securityPolicy The security policy file.
092     * @param dbFileName The name of the database file.
093     * @param archiveDbFileName The name of the archive database file.
094     * @param resetDir Whether the temporary directory should be reset.
095     * @param externalJarFolder The folder containing the external jar library files.
096     * @throws ArgumentNotValid If one of the following arguments are null: subTreeRoot, parentSettings, param,
097     * netarchiveSuiteSource, logProp, securityPolicy.
098     */
099    public Machine(Element subTreeRoot, XmlStructure parentSettings, Parameters param, String netarchiveSuiteSource,
100            File slf4JConfig, File securityPolicy, File dbFileName, File archiveDbFileName,
101            boolean resetDir, File externalJarFolder) throws ArgumentNotValid {
102        ArgumentNotValid.checkNotNull(subTreeRoot, "Element subTreeRoot");
103        ArgumentNotValid.checkNotNull(parentSettings, "XmlStructure parentSettings");
104        ArgumentNotValid.checkNotNull(param, "Parameters param");
105        ArgumentNotValid.checkNotNull(netarchiveSuiteSource, "String netarchiveSuiteSource");
106        ArgumentNotValid.checkNotNull(slf4JConfig, "File slf4JConfig");
107        ArgumentNotValid.checkNotNull(securityPolicy, "File securityPolicy");
108
109        settings = new XmlStructure(parentSettings.getRoot());
110        machineRoot = subTreeRoot;
111        machineParameters = new Parameters(param);
112        netarchiveSuiteFileName = netarchiveSuiteSource;
113        inheritedSlf4jConfigFile = slf4JConfig;
114        inheritedSecurityPolicyFile = securityPolicy;
115        databaseFile = dbFileName;
116        arcDatabaseFile = archiveDbFileName;
117        resetTempDir = resetDir;
118        jarFolder = externalJarFolder;
119
120        // Retrieve machine encoding
121        targetEncoding = machineRoot.attributeValue(Constants.MACHINE_ENCODING_ATTRIBUTE);
122        String msgTail = "";
123        if (targetEncoding == null || targetEncoding.isEmpty()) {
124            targetEncoding = Constants.MACHINE_ENCODING_DEFAULT;
125            msgTail = " (defaulted)";
126        }
127        System.out.println("Machine '" + machineRoot.attributeValue(Constants.MACHINE_NAME_ATTRIBUTE)
128                + "' configured with encoding '" + targetEncoding + "'" + msgTail);
129
130        // retrieve the specific settings for this instance
131        Element tmpSet = machineRoot.element(Constants.COMPLETE_SETTINGS_BRANCH);
132        // Generate the specific settings by combining the general settings
133        // and the specific, (only if this instance has specific settings)
134        if (tmpSet != null) {
135            settings.overWrite(tmpSet);
136        }
137
138        // check if new machine parameters
139        machineParameters.newParameters(machineRoot);
140        // Retrieve the variables for this instance.
141        extractVariables();
142        // generate the machines on this instance
143        extractApplications();
144    }
145
146    /**
147     * Extract the local variables from the root. Currently, this is the name and the operating system.
148     */
149    private void extractVariables() {
150        // retrieve name
151        Attribute at = machineRoot.attribute(Constants.MACHINE_NAME_ATTRIBUTE);
152        if (at != null) {
153            hostname = at.getText().trim();
154        } else {
155            throw new IllegalState("A Machine instance has no name!");
156        }
157    }
158
159    /**
160     * Extracts the XML for the applications from the root, creates the applications and puts them into the list.
161     */
162    @SuppressWarnings("unchecked")
163    private void extractApplications() {
164        applications = new ArrayList<Application>();
165        List<Element> le = machineRoot.elements(Constants.DEPLOY_APPLICATION_NAME);
166        for (Element e : le) {
167            applications.add(new Application(e, settings, machineParameters, targetEncoding));
168        }
169    }
170
171    /**
172     * Create the directory for the specific configurations of this machine and call the functions for creating all the
173     * scripts in this directory.
174     *
175     * @param parentDirectory The directory where to write the files.
176     * @throws ArgumentNotValid If the parenteDirectory is null.
177     */
178    public void write(File parentDirectory) throws ArgumentNotValid {
179        ArgumentNotValid.checkNotNull(parentDirectory, "File parentDirectory");
180
181        // create the directory for this machine
182        machineDirectory = new File(parentDirectory, hostname);
183        FileUtils.createDir(machineDirectory);
184
185        //
186        // create the content in the directory
187        //
188
189        // Create kill scripts
190        createApplicationKillScripts(machineDirectory);
191        createOSLocalKillAllScript(machineDirectory);
192        createHarvestDatabaseKillScript(machineDirectory);
193        createArchiveDatabaseKillScript(machineDirectory);
194        // create start scripts
195        createApplicationStartScripts(machineDirectory);
196        createOSLocalStartAllScript(machineDirectory);
197        createHarvestDatabaseStartScript(machineDirectory);
198        createArchiveDatabaseStartScript(machineDirectory);
199        createHarvestDatabaseUpdateScript(machineDirectory);
200        // create restart script
201        createRestartScript(machineDirectory);
202        // copy the security policy file
203        createSecurityPolicyFile(machineDirectory);
204        // create the SLF4J property files
205        createSlf4jConfigFiles(machineDirectory);
206        // create the jmx remote files
207        createJmxRemotePasswordFile(machineDirectory);
208        createJmxRemoteAccessFile(machineDirectory);
209        // create the installCreateDir script
210        createInstallDirScript(parentDirectory);
211
212        // write the settings for all application at this machine
213        for (Application app : applications) {
214            app.createSettingsFile(machineDirectory);
215        }
216    }
217
218    /**
219     * Make the script for killing this machine. This is put into the entire kill all script for the physical location.
220     *
221     * @return The script to kill this machine.
222     */
223    public String writeToGlobalKillScript() {
224        StringBuilder res = new StringBuilder();
225        res.append(ScriptConstants.writeKillMachineHeader(machineUserLogin()));
226        // write the operating system dependent part of the kill script
227        res.append(osKillScript());
228        return res.toString();
229    }
230
231    /**
232     * Make the script for installing this machine. This is put into the entire install script for the physical
233     * location.
234     *
235     * @return The script to make the installation on this machine
236     */
237    public String writeToGlobalInstallScript() {
238        StringBuilder res = new StringBuilder();
239        res.append(ScriptConstants.writeInstallMachineHeader(machineUserLogin()));
240        // write the operating system dependent part of the install script
241        res.append(osInstallScript());
242        return res.toString();
243    }
244
245    /**
246     * Make the script for starting this machine. This is put into the entire startall script for the physical location.
247     *
248     * @return The script to start this machine.
249     */
250    public String writeToGlobalStartScript() {
251        StringBuilder res = new StringBuilder();
252        res.append(ScriptConstants.writeStartMachineHeader(machineUserLogin()));
253        // write the operating system dependent part of the start script
254        res.append(osStartScript());
255        return res.toString();
256    }
257
258    /**
259     * Copy inherited securityPolicyFile to local directory.
260     *
261     * @param directory The local directory for this machine.
262     * @throws IOFailure If an error occurred during the creation of the security policy file.
263     */
264    protected void createSecurityPolicyFile(File directory) throws IOFailure {
265        // make file
266        File secPolFile = new File(directory, Constants.SECURITY_POLICY_FILE_NAME);
267        try {
268            // init writer
269            PrintWriter secPrinter = new PrintWriter(secPolFile, getTargetEncoding());
270            try {
271                // read the inherited security policy file.
272                String prop = FileUtils.readFile(inheritedSecurityPolicyFile);
273
274                // change the jmx monitor role (if defined in settings)
275                String monitorRole = settings.getLeafValue(Constants.SETTINGS_MONITOR_JMX_NAME_LEAF);
276                if (monitorRole != null) {
277                    prop = prop.replace(Constants.SECURITY_JMX_PRINCIPAL_NAME_TAG, monitorRole);
278                }
279
280                // Change the common temp dir (if defined in settings)
281                String ctd = settings.getLeafValue(Constants.SETTINGS_TEMPDIR_LEAF);
282                if (ctd != null) {
283                    prop = prop.replace(Constants.SECURITY_COMMON_TEMP_DIR_TAG, ctd);
284                }
285
286                // write to file.
287                secPrinter.write(prop);
288
289                // initialise list of directories to add
290                List<String> dirs = new ArrayList<String>();
291
292                // get all directories to add and put them into the list
293                for (Application app : applications) {
294                    // get archive.fileDir directory.
295                    String[] tmpDirs = app.getSettingsValues(Constants.SETTINGS_BITARCHIVE_BASEFILEDIR_LEAF);
296                    if (tmpDirs != null && tmpDirs.length > 0) {
297                        for (String st : tmpDirs) {
298                            dirs.add(st);
299                        }
300                    }
301                }
302
303                // append file directories
304                if (!dirs.isEmpty()) {
305                    secPrinter.write("grant {" + "\n");
306                    for (String dir : dirs) {
307                        secPrinter.write(ScriptConstants
308                                .writeSecurityPolicyDirPermission(changeFileDirPathForSecurity(dir)));
309                    }
310                    secPrinter.write("};");
311                }
312            } finally {
313                secPrinter.close();
314            }
315        } catch (IOException e) {
316            log.warn("IOException while creating security policy file: ", e);
317            throw new IOFailure("Cannot create security policy file.", e);
318        }
319    }
320
321    /**
322     * Creates a the SLF4J config file for every application. This is done by taking the inherited log file and changing
323     * "APPID" in the file into the identification of the application.
324     *
325     * @param directory The local directory for this machine
326     * @throws IOFailure If an error occurred during the creationg of the log property file.
327     */
328    protected void createSlf4jConfigFiles(File directory) throws IOFailure {
329        // make config file for every application
330        for (Application app : applications) {
331            // make file
332            File logProp = new File(directory, Constants.SLF4J_CONFIG_APPLICATION_PREFIX + app.getIdentification()
333                    + Constants.SLF4J_CONFIG_APPLICATION_SUFFIX);
334            try {
335                // init writer
336                PrintWriter logPrinter = new PrintWriter(logProp, getTargetEncoding());
337
338                try {
339                    // read the inherited log property file.
340                    String prop = FileUtils.readFile(inheritedSlf4jConfigFile);
341
342                    // append stuff!
343                    prop = prop.replace(Constants.LOG_PROPERTY_APPLICATION_ID_TAG, app.getIdentification());
344                    prop = modifyLogProperties(prop);
345                    // write to file.
346                    logPrinter.write(prop);
347                } finally {
348                    logPrinter.close();
349                }
350            } catch (IOException e) {
351                log.warn("IOException while creating SLF4J config file:", e);
352                throw new IOFailure("Cannot create SLF4J config file.", e);
353            }
354        }
355    }
356
357    /**
358     * Make any OS-specific modifications to logging properties. The default makes no modifications, but this can be
359     * overridden in subclasses.
360     *
361     * @param logProperties the contents of the logging properties file.
362     * @return the contents of the logging properties file with any desired modifications.
363     */
364    protected String modifyLogProperties(String logProperties) {
365        return logProperties;
366    }
367
368    /**
369     * Creates the jmxremote.password file, based on the settings.
370     *
371     * @param directory The local directory for this machine
372     * @throws IOFailure If an error occurred during the creation of the jmx remote password file.
373     */
374    protected void createJmxRemotePasswordFile(File directory) throws IOFailure {
375        // make file
376        File jmxFile = new File(directory, Constants.JMX_PASSWORD_FILE_NAME);
377        try {
378            // init writer
379            PrintWriter jw = new PrintWriter(jmxFile, getTargetEncoding());
380            try {
381                // Write the header of the jmxremote.password file.
382                jw.print(ScriptConstants.JMXREMOTE_PASSWORD_HEADER);
383
384                // Get the username and password for monitor and heritrix.
385                StringBuilder logins = new StringBuilder();
386
387                // Append the jmx logins for monitor and heritrix.
388                logins.append(getMonitorLogin());
389                logins.append(getHeritrixLogin());
390
391                jw.print(logins.toString());
392            } finally {
393                jw.close();
394            }
395        } catch (IOException e) {
396            log.trace("IOException while creating jmxremote.password:", e);
397            throw new IOFailure("Cannot create jmxremote.password.", e);
398        }
399    }
400
401    /**
402     * Creates the jmxremote.password file, based on the settings.
403     *
404     * @param directory The local directory for this machine
405     * @throws IOFailure If an error occurred during the creation of the jmx remote access file.
406     */
407    protected void createJmxRemoteAccessFile(File directory) throws IOFailure {
408        // make file
409        File jmxFile = new File(directory, Constants.JMX_ACCESS_FILE_NAME);
410        try {
411            // init writer
412            PrintWriter jw = new PrintWriter(jmxFile, getTargetEncoding());
413            try {
414                // Write the header of the jmxremote.password file.
415                jw.print(ScriptConstants.JMXREMOTE_ACCESS_HEADER);
416
417                // Get the username and password for monitor and heritrix.
418                StringBuilder logins = new StringBuilder();
419
420                // Append the jmx logins for monitor and heritrix.
421                logins.append(getMonitorUsername());
422                logins.append(getHeritrixUsername());
423
424                jw.print(logins.toString());
425            } finally {
426                jw.close();
427            }
428        } catch (IOException e) {
429            log.trace("IOException while creating jmxremote.access file:", e);
430            throw new IOFailure("Cannot create jmxremote.access file.", e);
431        }
432    }
433
434    /**
435     * For finding the jmxUsernames and jmxPasswords under the monitor branch in the settings. Goes through all
436     * applications, which all must have the same username and the same passwords.
437     *
438     * @return The string to add to the jmxremote.password file.
439     * @throws IllegalState If there is a different amount of usernames and passwords, or if two application has
440     * different values for their username or passwords (applications without values are ignored).
441     */
442    protected String getMonitorLogin() throws IllegalState {
443        StringBuilder res = new StringBuilder();
444        // initialise list of usernames and passwords to add
445        List<String> usernames = new ArrayList<String>();
446        List<String> passwords = new ArrayList<String>();
447        String[] tmpVals;
448
449        // get values from applications and put them into the lists
450        for (Application app : applications) {
451            // get monitor.jmxUsername
452            tmpVals = app.getSettingsValues(Constants.SETTINGS_MONITOR_JMX_NAME_LEAF);
453            if (tmpVals != null && tmpVals.length > 0) {
454                for (String st : tmpVals) {
455                    usernames.add(st);
456                }
457            }
458            // get monitor.jmxPassword
459            tmpVals = app.getSettingsValues(Constants.SETTINGS_MONITOR_JMX_PASSWORD_LEAF);
460            if (tmpVals != null && tmpVals.length > 0) {
461                for (String st : tmpVals) {
462                    passwords.add(st);
463                }
464            }
465        }
466
467        // if different amount of usernames and passwords => DIE
468        if (usernames.size() != passwords.size()) {
469            String msg = "Different amount of usernames and passwords in monitor under applications on machine: '"
470                    + hostname + "'";
471            log.warn(msg);
472            throw new IllegalState(msg);
473        }
474
475        // warn if no usernames for monitor.
476        if (usernames.size() == 0) {
477            log.warn("No usernames or passwords for monitor on machine: '{}'", hostname);
478        }
479
480        // check if the usernames and passwords are the same.
481        for (int i = 1; i < usernames.size(); i++) {
482            if (!usernames.get(0).equals(usernames.get(i)) || !passwords.get(0).equals(passwords.get(i))) {
483                String msg = "Different usernames or passwords under monitor on the same machine: '" + hostname + "'";
484                log.warn(msg);
485                throw new IllegalState(msg);
486            }
487        }
488
489        // make the resulting string
490        if (usernames.size() > 0) {
491            res.append(usernames.get(0));
492            res.append(Constants.SPACE);
493            res.append(passwords.get(0));
494            res.append(Constants.NEWLINE);
495        }
496        return res.toString();
497    }
498
499    /**
500     * For retrieving the monitor username for the jmxremote.access file. This will have the rights 'readonly'.
501     *
502     * @return The string for the jmxremote.access file for allowing the monitor user to readonly.
503     * @throws IllegalState If different applications on the machine have different user names.
504     */
505    protected String getMonitorUsername() throws IllegalState {
506        StringBuilder res = new StringBuilder();
507        // initialise list of usernames and passwords to add
508        List<String> usernames = new ArrayList<String>();
509        String[] tmpVals;
510
511        // get values from applications and put them into the lists
512        for (Application app : applications) {
513            // get monitor.jmxUsername
514            tmpVals = app.getSettingsValues(Constants.SETTINGS_MONITOR_JMX_NAME_LEAF);
515            if (tmpVals != null && tmpVals.length > 0) {
516                for (String st : tmpVals) {
517                    usernames.add(st);
518                }
519            }
520        }
521
522        // check if the usernames and passwords are the same.
523        for (int i = 1; i < usernames.size(); i++) {
524            if (!usernames.get(0).equals(usernames.get(i))) {
525                String msg = "Different usernames for the monitor on the same machine: '" + hostname + "'";
526                log.warn(msg);
527                throw new IllegalState(msg);
528            }
529        }
530
531        // make the resulting string
532        if (usernames.size() > 0) {
533            res.append(usernames.get(0));
534            res.append(Constants.SPACE);
535            res.append(ScriptConstants.JMXREMOTE_MONITOR_PRIVILEGES);
536            res.append(Constants.NEWLINE);
537        }
538        return res.toString();
539    }
540
541    /**
542     * For finding the jmxUsernames and jmxPasswords under the harvest.harvesting.heritrix branch under in the settings.
543     * Goes through all applications, which all must have the same username and the same passwords.
544     *
545     * @return The string to add to the jmxremote.password file.
546     * @throws IllegalState If there is a different amount of usernames and passwords, or if two application has
547     * different values for their username or passwords (applications without values are ignored).
548     */
549    protected String getHeritrixLogin() throws IllegalState {
550        StringBuilder res = new StringBuilder();
551        // initialise list of usernames and passwords to add
552        List<String> usernames = new ArrayList<String>();
553        List<String> passwords = new ArrayList<String>();
554        String[] tmpVals;
555
556        // get values from applications and put them into the lists
557        for (Application app : applications) {
558            // get heritrix.jmxUsername
559            tmpVals = app.getSettingsValues(Constants.SETTINGS_HERITRIX_JMX_USERNAME_LEAF);
560            if (tmpVals != null && tmpVals.length > 0) {
561                for (String st : tmpVals) {
562                    usernames.add(st);
563                }
564            }
565            // get heritrix.jmxPassword
566            tmpVals = app.getSettingsValues(Constants.SETTINGS_HERITRIX_JMX_PASSWORD_LEAF);
567            if (tmpVals != null && tmpVals.length > 0) {
568                for (String st : tmpVals) {
569                    passwords.add(st);
570                }
571            }
572        }
573
574        // if different amount of usernames and passwords. DIE
575        if (usernames.size() != passwords.size()) {
576            String msg = "Different amount of usernames and passwords in heritrix under applications on machine: '"
577                    + hostname + "'";
578            log.warn(msg);
579            throw new IllegalState(msg);
580        }
581
582        // if no usernames, and thus no passwords, finish!
583        if (usernames.size() == 0) {
584            return "";
585        }
586
587        // check if the usernames and passwords are the same.
588        for (int i = 1; i < usernames.size(); i++) {
589            if (!usernames.get(0).equals(usernames.get(i)) || !passwords.get(0).equals(passwords.get(i))) {
590                String msg = "Different usernames or passwords " + "under heritrix on machine: '" + hostname + "'";
591                log.warn(msg);
592                throw new IllegalState(msg);
593            }
594        }
595
596        // make the resulting string
597        if (usernames.size() > 0) {
598            res.append(usernames.get(0));
599            res.append(Constants.SPACE);
600            res.append(passwords.get(0));
601            res.append(Constants.NEWLINE);
602        }
603        return res.toString();
604    }
605
606    /**
607     * For retrieving the Heritrix username for the jmxremote.access file. This will have the rights 'readwrite'.
608     *
609     * @return The string for the jmxremote.access file for allowing the heritrix user to readonly.
610     */
611    protected String getHeritrixUsername() {
612        StringBuilder res = new StringBuilder();
613        // initialise list of usernames and passwords to add
614        List<String> usernames = new ArrayList<String>();
615        String[] tmpVals;
616
617        // get values from applications and put them into the lists
618        for (Application app : applications) {
619            // get heritrix.jmxUsername
620            tmpVals = app.getSettingsValues(Constants.SETTINGS_HERITRIX_JMX_USERNAME_LEAF);
621            if (tmpVals != null && tmpVals.length > 0) {
622                for (String st : tmpVals) {
623                    usernames.add(st);
624                }
625            }
626        }
627
628        // check if the usernames and passwords are the same.
629        for (int i = 1; i < usernames.size(); i++) {
630            if (!usernames.get(0).equals(usernames.get(i))) {
631                String msg = "Different usernames for Heritrix on the same machine: '" + hostname + "'";
632                log.warn(msg);
633                throw new IllegalState(msg);
634            }
635        }
636
637        // make the resulting string
638        if (usernames.size() > 0) {
639            res.append(usernames.get(0));
640            res.append(Constants.SPACE);
641            res.append(ScriptConstants.JMXREMOTE_HERITRIX_PRIVILEGES);
642            res.append(Constants.NEWLINE);
643        }
644        return res.toString();
645    }
646
647    /**
648     * The string for accessing this machine through SSH.
649     *
650     * @return The access through SSH to the machine
651     */
652    protected String machineUserLogin() {
653        return machineParameters.getMachineUserName().getStringValue().trim() + Constants.AT + hostname;
654    }
655
656    /**
657     * For retrieving the environment name variable.
658     *
659     * @return The environment name.
660     */
661    protected String getEnvironmentName() {
662        return settings.getSubChildValue(Constants.SETTINGS_ENVIRONMENT_NAME_LEAF);
663    }
664
665    /**
666     * Creates the kill scripts for all the applications.
667     *
668     * @param directory The directory for this machine (use global variable?).
669     */
670    protected abstract void createApplicationKillScripts(File directory);
671
672    /**
673     * Creates the start scripts for all the applications.
674     *
675     * @param directory The directory for this machine (use global variable?).
676     */
677    protected abstract void createApplicationStartScripts(File directory);
678
679    /**
680     * This function creates the script to start all applications on this machine. The scripts calls all the start
681     * script for each application.
682     *
683     * @param directory The directory for this machine (use global variable?).
684     */
685    protected abstract void createOSLocalStartAllScript(File directory);
686
687    /**
688     * This function creates the script to kill all applications on this machine. The scripts calls all the kill script
689     * for each application.
690     *
691     * @param directory The directory for this machine (use global variable?).
692     */
693    protected abstract void createOSLocalKillAllScript(File directory);
694
695    /**
696     * The operation system specific path to the installation directory.
697     *
698     * @return Install path.
699     */
700    protected abstract String getInstallDirPath();
701
702    /**
703     * The operation system specific path to the conf directory.
704     *
705     * @return Conf path.
706     */
707    protected abstract String getConfDirPath();
708
709    /**
710     * The operation system specific path to the lib directory.
711     *
712     * @return Lib path.
713     */
714    protected abstract String getLibDirPath();
715
716    /**
717     * Creates the operation system specific killing script for this machine.
718     *
719     * @return Operation system specific part of the killscript.
720     */
721    protected abstract String osKillScript();
722
723    /**
724     * Creates the operation system specific installation script for this machine.
725     *
726     * @return Operation system specific part of the installscript.
727     */
728    protected abstract String osInstallScript();
729
730    /**
731     * Creates the specified directories in the deploy-configuration file.
732     *
733     * @return The script for creating the directories.
734     */
735    protected abstract String osInstallScriptCreateDir();
736
737    /**
738     * Creates the operation system specific starting script for this machine.
739     *
740     * @return Operation system specific part of the startscript.
741     */
742    protected abstract String osStartScript();
743
744    /**
745     * Makes all the class paths into the operation system specific syntax, and puts them into a string where they are
746     * separated by the operation system specific separator (':' for linux, ';' for windows).
747     *
748     * @param app The application which has the class paths.
749     * @return The class paths in operation system specific syntax.
750     */
751    protected abstract String osGetClassPath(Application app);
752
753    /**
754     * Checks if a specific directory for the database is given in the settings, and thus if the database should be
755     * installed on this machine.
756     * <p>
757     * If no specific database is given as deploy argument (databaseFileName = null) then use the standard database
758     * extracted from NetarchiveSuite.zip. Else send the given new database to the standard database location.
759     * <p>
760     * Extract the database in the standard database location to the specified database directory.
761     *
762     * @return The script for installing the database (if needed).
763     */
764    protected abstract String osInstallDatabase();
765
766    /**
767     * Checks if a specific directory for the archive database is given in the settings, and thus if the archive
768     * database should be installed on this machine.
769     * <p>
770     * If not specific database is given (adminDatabaseFileName = null) then use the default in the NetarchiveSuite.zip
771     * package. Else send the new archive database to the standard database location, and extract it to the given
772     * location.
773     *
774     * @return The script for installing the archive database (if needed).
775     */
776    protected abstract String osInstallArchiveDatabase();
777
778    /**
779     * This function makes the part of the install script for installing the external jar files from within the
780     * jarFolder. If the jarFolder is null, then no action will be performed.
781     *
782     * @return The script for installing the external jar files (if needed).
783     */
784    protected abstract String osInstallExternalJarFiles();
785
786    /**
787     * This functions makes the script for creating the new directories.
788     * <p>
789     * Linux creates directories directly through ssh. Windows creates an install a script file for installing the
790     * directories, which has to be sent to the machine, then executed and finally deleted.
791     *
792     * @param dir The name of the directory to create.
793     * @param clean Whether the directory should be cleaned\reset.
794     * @return The lines of code for creating the directories.
795     * @see #createInstallDirScript(File)
796     */
797    protected abstract String scriptCreateDir(String dir, boolean clean);
798
799    /**
800     * Creates the script for creating the application specified directories. Also creates the directories along the
801     * path to the directories.
802     *
803     * @return The script for creating the application specified directories.
804     */
805    protected abstract String getAppDirectories();
806
807    /**
808     * This method does the following: Retrieves the path to the jmxremote.access and jmxremote.password files. Moves
809     * these files, if they are different from standard. Makes the jmxremote.access and jmxremote.password files
810     * readonly.
811     *
812     * @return The commands for handling the jmxremote files.
813     */
814    protected abstract String getJMXremoteFilesCommand();
815
816    /**
817     * Function to create the script which installs the new directories. This is only used for windows machines!
818     *
819     * @param dir The directory to put the file
820     */
821    protected abstract void createInstallDirScript(File dir);
822
823    /**
824     * Creates a script for restating all the applications on a given machine.
825     *
826     * @param dir The directory where the script will be placed.
827     */
828    protected abstract void createRestartScript(File dir);
829
830    /**
831     * Creates a script for starting the archive database on a given machine. This is only created if the
832     * &lt;globalArchiveDatabaseDir&gt; parameter is defined on the machine level.
833     *
834     * @param dir The directory where the script will be placed.
835     */
836    protected abstract void createArchiveDatabaseStartScript(File dir);
837
838    /**
839     * Creates a script for killing the archive database on a given machine. This is only created if the
840     * &lt;globalArchiveDatabaseDir&gt; parameter is defined on the machine level.
841     *
842     * @param dir The directory where the script will be placed.
843     */
844    protected abstract void createArchiveDatabaseKillScript(File dir);
845
846    /**
847     * Creates a script for starting the harvest database on a given machine. This is only created if the
848     * &lt;deployHarvestDatabaseDir&gt; parameter is defined on the machine level.
849     *
850     * @param dir The directory where the script will be placed.
851     */
852    protected abstract void createHarvestDatabaseStartScript(File dir);
853
854    /**
855     * Creates a script for killing the harvest database on a given machine. This is only created if the
856     * &lt;globalHarvestDatabaseDir&gt; parameter is defined on the machine level.
857     *
858     * @param dir The directory where the script will be placed.
859     */
860    protected abstract void createHarvestDatabaseKillScript(File dir);
861
862    /**
863     * Changes the file directory path to the format used in the security policy.
864     *
865     * @param path The current path.
866     * @return The formatted path.
867     */
868    protected abstract String changeFileDirPathForSecurity(String path);
869
870    /**
871     * create a harvestDatabaseUpdatescript in the given machineDirectory.
872     *
873     * @param machineDirectory a given MachineDirectory.
874     */
875    protected abstract void createHarvestDatabaseUpdateScript(File machineDirectory);
876
877    protected String getTargetEncoding() {
878        return targetEncoding;
879    }
880
881}