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; 039 040/** 041 * The physical location class. 042 */ 043public class PhysicalLocation { 044 045 /** the log, for logging stuff instead of displaying them directly. */ 046 private static final Logger log = LoggerFactory.getLogger(PhysicalLocation.class); 047 /** The root for the branch of this element in the XML-tree. */ 048 private Element physLocRoot; 049 /** The settings structure. */ 050 private XmlStructure settings; 051 /** The parameters for java. */ 052 private Parameters machineParameters; 053 /** The list of the machines. */ 054 private List<Machine> machines; 055 /** The name of this physical location. */ 056 private String name; 057 /** The inherited name for the NetarchiveSuite file. */ 058 private String netarchiveSuiteFileName; 059 /** The inherited SLF4J config file. */ 060 private File slf4JConfigFile; 061 /** The inherited security file. */ 062 private File securityPolicyFile; 063 /** The inherited database file name. */ 064 private File databaseFile; 065 /** The inherited archive database file name. */ 066 private File arcDatabaseFile; 067 /** The optional choice for resetting tempDir. */ 068 private boolean resetDirectory; 069 /** The folder for the external jar libraries. */ 070 private File jarFolder; 071 private final DeployConfiguration deployConfiguration; 072 073 /** 074 * The physical locations is referring to the position in the real world where the computers are located. One 075 * physical location can contain many machines. 076 * 077 * @param subTreeRoot The root of this branch in the XML structure. 078 * @param parentSettings The settings of the parent (deploy-config). 079 * @param param The parameters of the parent (deploy-config). 080 * @param netarchiveSuiteSource The name of the NetarchiveSuite file. 081 * @param securityPolicy The security policy file. 082 * @param dbFile The harvest definition database. 083 * @param arcdbFile The archive database. 084 * @param resetDir Whether the temporary directory should be reset. 085 * @param externalJarFolder The folder containing the external jar library files. 086 * @throws ArgumentNotValid If one of the following arguments are null: subTreeRoot, parentSettings, param, logProp, 087 * securityPolicy; or if the netarchiveSuiteSource if either null or empty. 088 */ 089 public PhysicalLocation(Element subTreeRoot, XmlStructure parentSettings, Parameters param, 090 String netarchiveSuiteSource, File slf4JConfig, File securityPolicy, File dbFile, 091 File arcdbFile, boolean resetDir, File externalJarFolder, DeployConfiguration deployConfiguration) throws ArgumentNotValid { 092 // test if valid arguments 093 ArgumentNotValid.checkNotNull(subTreeRoot, "Element elem (physLocRoot)"); 094 ArgumentNotValid.checkNotNull(parentSettings, "XmlStructure parentSettings"); 095 ArgumentNotValid.checkNotNull(param, "Parameters param"); 096 ArgumentNotValid.checkNotNullOrEmpty(netarchiveSuiteSource, "String netarchiveSuite"); 097 // ArgumentNotValid.checkNotNull(slf4JConfig, "File slf4JConfig"); 098 ArgumentNotValid.checkNotNull(securityPolicy, "File securityPolicy"); 099 100 // make a copy of parent, don't use it directly. 101 settings = new XmlStructure(parentSettings.getRoot()); 102 physLocRoot = subTreeRoot; 103 machineParameters = new Parameters(param); 104 netarchiveSuiteFileName = netarchiveSuiteSource; 105 slf4JConfigFile = slf4JConfig; 106 securityPolicyFile = securityPolicy; 107 databaseFile = dbFile; 108 arcDatabaseFile = arcdbFile; 109 resetDirectory = resetDir; 110 jarFolder = externalJarFolder; 111 this.deployConfiguration = deployConfiguration; 112 113 // retrieve the specific settings for this instance 114 Element tmpSet = physLocRoot.element(Constants.COMPLETE_SETTINGS_BRANCH); 115 // Generate the specific settings by combining the general settings 116 // and the specific, (only if this instance has specific settings) 117 if (tmpSet != null) { 118 settings.overWrite(tmpSet); 119 } 120 // check if new machine parameters 121 machineParameters.newParameters(physLocRoot); 122 // Retrieve the variables for this instance. 123 extractVariables(); 124 // generate the machines on this instance 125 extractMachines(); 126 } 127 128 /** 129 * Extract the local variables from the root. 130 * <p> 131 * It is only the name for this instance. This is then set in settings. 132 */ 133 private void extractVariables() { 134 // retrieve name 135 Attribute at = physLocRoot.attribute(Constants.PHYSICAL_LOCATION_NAME_ATTRIBUTE); 136 if (at != null) { 137 name = at.getText().trim(); 138 // insert the name in settings. 139 String xmlName = XmlStructure.pathAndContentToXML(name, Constants.COMPLETE_THIS_PHYSICAL_LOCATION_LEAF); 140 Element physLocName = XmlStructure.makeElementFromString(xmlName); 141 settings.overWrite(physLocName); 142 } else { 143 throw new IllegalState(Constants.MSG_ERROR_PHYSICAL_LOCATION_NO_NAME); 144 } 145 } 146 147 /** 148 * Extracts the XML for machines from the root, creates the machines, and puts them into the list. 149 */ 150 @SuppressWarnings("unchecked") 151 private void extractMachines() { 152 machines = new ArrayList<Machine>(); 153 List<Element> le = physLocRoot.elements(Constants.DEPLOY_MACHINE); 154 for (Element e : le) { 155 String os = getTrimmedAttributeValue(e, Constants.MACHINE_OPERATING_SYSTEM_ATTRIBUTE); 156 // only a windows machine, if the 'os' attribute exists and 157 // equals (not case-sensitive) 'windows'. Else linux machine 158 if (os != null && os.equalsIgnoreCase(Constants.OPERATING_SYSTEM_WINDOWS_ATTRIBUTE)) { 159 machines.add(new WindowsMachine(e, settings, machineParameters, netarchiveSuiteFileName, 160 slf4JConfigFile, securityPolicyFile, databaseFile, arcDatabaseFile, resetDirectory, jarFolder)); 161 } else { 162 machines.add(new LinuxMachine(e, settings, machineParameters, netarchiveSuiteFileName, 163 slf4JConfigFile, securityPolicyFile, databaseFile, arcDatabaseFile, resetDirectory, jarFolder, 164 deployConfiguration)); 165 } 166 } 167 } 168 169 private String getTrimmedAttributeValue(Element e, String attributeName) { 170 String value = e.attributeValue(attributeName); 171 return (value != null ? value.trim() : null); 172 } 173 174 /** 175 * Initiate the creation of global scripts and machine scripts. 176 * 177 * @param directory The directory where the files are to be placed. 178 * @throws ArgumentNotValid If the directory is null. 179 */ 180 public void write(File directory) throws ArgumentNotValid { 181 ArgumentNotValid.checkNotNull(directory, "File directory"); 182 // make the script in the directory! 183 makeScripts(directory); 184 // write all machine at this location 185 for (Machine mac : machines) { 186 mac.write(directory); 187 } 188 } 189 190 /** 191 * Creates the following scripts for this physical location. * killall. * install. * startall. 192 * <p> 193 * The scripts for a physical location will only work from Linux/Unix. 194 * 195 * @param directory The directory where the scripts are to be placed. 196 * @throws ArgumentNotValid If the directory is null. 197 * @throws IOFailure If an error occurs during the creation of the scripts. 198 */ 199 private void makeScripts(File directory) throws ArgumentNotValid, IOFailure { 200 ArgumentNotValid.checkNotNull(directory, "File directory"); 201 // make extension (e.g. '_kb.sh' in the script 'killall_kb.sh') 202 String ext = Constants.UNDERSCORE + name + Constants.SCRIPT_EXTENSION_LINUX; 203 // make script files 204 File killall = new File(directory, Constants.SCRIPT_NAME_KILL_ALL + ext); 205 File install = new File(directory, Constants.SCRIPT_NAME_INSTALL_ALL + ext); 206 File startall = new File(directory, Constants.SCRIPT_NAME_START_ALL + ext); 207 try { 208 // Make the killall script for the physical location 209 PrintWriter kWriter = new PrintWriter(killall); 210 try { 211 kWriter.println(ScriptConstants.BIN_BASH_COMMENT); 212 // insert machine data 213 for (Machine mac : machines) { 214 // write the call to the kill script of each machines 215 kWriter.println(ScriptConstants.writeDashLine()); 216 kWriter.print(mac.writeToGlobalKillScript()); 217 } 218 // write an extra line of dashes. 219 kWriter.println(ScriptConstants.writeDashLine()); 220 } finally { 221 // close writer 222 kWriter.flush(); 223 kWriter.close(); 224 } 225 226 // Make the install script for the physical location 227 PrintWriter iWriter = new PrintWriter(install); 228 try { 229 iWriter.println(ScriptConstants.BIN_BASH_COMMENT); 230 // insert machine data 231 for (Machine mac : machines) { 232 // write install script from machines 233 iWriter.println(ScriptConstants.writeDashLine()); 234 iWriter.print(mac.writeToGlobalInstallScript()); 235 } 236 // write an extra line of dashes. 237 iWriter.println(ScriptConstants.writeDashLine()); 238 } finally { 239 // close writer 240 iWriter.flush(); 241 iWriter.close(); 242 } 243 244 // Make the startall script for the physical location 245 PrintWriter sWriter = new PrintWriter(startall); 246 try { 247 sWriter.println(ScriptConstants.BIN_BASH_COMMENT); 248 // insert machine data 249 for (Machine mac : machines) { 250 // write start script from machines 251 sWriter.println(ScriptConstants.writeDashLine()); 252 sWriter.print(mac.writeToGlobalStartScript()); 253 } 254 sWriter.println(ScriptConstants.writeDashLine()); 255 } finally { 256 // close writer 257 sWriter.flush(); 258 sWriter.close(); 259 } 260 } catch (IOException e) { 261 String msg = "Cannot create the scripts for the physical " + "location: '" + name + "'."; 262 log.trace(msg, e); 263 throw new IOFailure(msg, e); 264 } 265 } 266 267}