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.FileWriter; 027import java.io.IOException; 028import java.nio.charset.Charset; 029import java.util.List; 030 031import org.dom4j.Element; 032 033import dk.netarkivet.common.exceptions.ArgumentNotValid; 034 035/** 036 * This class applies the test variables. 037 * <p> 038 * It creates a new instance of the settings where the variables are changed, and then writes it out as a new 039 * deploy-configuration file (does not overwrite the original, but creates a new in same directory). 040 * <p> 041 * This class is prompted by our need to be able to install and run multiple instances the NetarchiveSuite in our 042 * test-environment simultaneously. 043 */ 044public class CreateTestInstance { 045 /** The source configuration file. */ 046 private File source; 047 /** 048 * The configuration instance. Loaded from the source file, changed and saved. 049 */ 050 private XmlStructure deployConfiguration; 051 /** The string value of the calculated offset. */ 052 private String offsetVal; 053 /** The paths to where the positions the offset are to be used. */ 054 private OffsetSystem[] offsetPaths; 055 /** The new value for the HTTP port. */ 056 private String httpPortVal; 057 /** The path to the HTTP port. */ 058 private String[] httpPortPath; 059 /** The new value for the environment name. */ 060 private String environmentNameVal; 061 /** The path to the environment name. */ 062 private String[] environmentNamePath; 063 /** The new value of the mail receiver. */ 064 private String mailReceiverVal; 065 /** The path to the mail receiver. */ 066 private String[] mailReceiverPath; 067 068 /** 069 * The constructor. 070 * 071 * @param configSource The source configuration file. 072 */ 073 public CreateTestInstance(File configSource) { 074 ArgumentNotValid.checkNotNull(configSource, "File configSource"); 075 076 source = configSource; 077 deployConfiguration = new XmlStructure(source, Charset.defaultCharset().name()); 078 079 offsetPaths = new OffsetSystem[0]; 080 offsetVal = ""; 081 } 082 083 /** 084 * Function to apply the variables. 085 * 086 * @param offset The input offset value (1-9 below httpPort). 087 * @param httpPort The new value for the HTTP port. 088 * @param environmentName The new value for the environment name. 089 * @param mailReceiver The new value for the mailReceiver. 090 */ 091 public void applyTestArguments(String offset, String httpPort, String environmentName, String mailReceiver) { 092 ArgumentNotValid.checkNotNullOrEmpty(offset, "String offset"); 093 ArgumentNotValid.checkNotNullOrEmpty(httpPort, "String httpPort"); 094 ArgumentNotValid.checkNotNullOrEmpty(environmentName, "String environmentName"); 095 ArgumentNotValid.checkNotNullOrEmpty(mailReceiver, "String mailReceiver"); 096 097 // calculate offset 098 int offsetInt = (new Integer(httpPort)).intValue() - (new Integer(offset)).intValue(); 099 100 if (offsetInt > Constants.TEST_OFFSET_INTEGER_MAXIMUM_VALUE || offsetInt < 0) { 101 System.err.print(Constants.MSG_ERROR_TEST_OFFSET); 102 System.out.println(); 103 System.exit(1); 104 } 105 // change integer to string (easiest way to change integer to String) 106 offsetVal = Integer.toString(offsetInt); 107 108 // vaildate the environment name. 109 if (!Constants.validEnvironmentName(environmentName)) { 110 System.err.print(Constants.MSG_ERROR_INVALID_ENVIRONMENT_NAME + environmentName); 111 System.out.println(); 112 System.exit(1); 113 } 114 115 // Get values 116 httpPortVal = httpPort; 117 environmentNameVal = environmentName; 118 mailReceiverVal = mailReceiver; 119 120 // make paths 121 httpPortPath = Constants.COMPLETE_HTTP_PORT_LEAF; 122 environmentNamePath = Constants.COMPLETE_ENVIRONMENT_NAME_LEAF; 123 mailReceiverPath = Constants.SETTINGS_NOTIFICATION_RECEIVER_PATH; 124 125 // make offset paths 126 offsetPaths = new OffsetSystem[] { 127 new OffsetSystem(Constants.TEST_OFFSET_MONITOR_JMX_PORT, Constants.COMPLETE_JMX_PORT_PATH), 128 new OffsetSystem(Constants.TEST_OFFSET_MONITOR_RMI_PORT, Constants.COMPLETE_JMX_RMIPORT_PATH), 129 new OffsetSystem(Constants.TEST_OFFSET_HERITRIX_GUI_PORT, 130 Constants.COMPLETE_HARVEST_HERITRIX_GUI_PORT_PATH), 131 new OffsetSystem(Constants.TEST_OFFSET_HERITRIX_JMX_PORT, Constants.COMPLETE_HARVEST_HERITRIX_JMX_PORT), 132 // new OffsetSystem(Constants.TEST_OFFSET_ARCHIVE_DB_URL_PORT, 133 // Constants.COMPLETE_ARCHIVE_DATABASE_PORT), 134 // new OffsetSystem(Constants.TEST_OFFSET_HARVEST_DB_URL_PORT, 135 // Constants.COMPLETE_HARVEST_DATABASE_PORT) 136 }; 137 138 // apply the arguments 139 apply(); 140 } 141 142 /** 143 * Applies the new variables. Goes through all element instances and applies the variables. 144 */ 145 @SuppressWarnings("unchecked") 146 private void apply() { 147 // apply on root 148 applyOnElement(deployConfiguration.getRoot()); 149 150 List<Element> physLocs = deployConfiguration.getChildren(Constants.DEPLOY_PHYSICAL_LOCATION); 151 152 for (Element pl : physLocs) { 153 // apply on every physical location 154 applyOnElement(pl); 155 156 List<Element> machines = pl.elements(Constants.DEPLOY_MACHINE); 157 for (Element mac : machines) { 158 // apply on every machine 159 applyOnElement(mac); 160 161 List<Element> applications = mac.elements(Constants.DEPLOY_APPLICATION_NAME); 162 for (Element app : applications) { 163 // apply on every application 164 applyOnElement(app); 165 166 applyEnvironmentNameOnBaseFileDir(app); 167 } 168 } 169 } 170 } 171 172 /** 173 * Applies the new variables on a specific element. 174 * 175 * @param e The element where the variables are to be applied. 176 */ 177 private void applyOnElement(Element e) { 178 // Check argument valid 179 ArgumentNotValid.checkNotNull(e, "Element e"); 180 181 // Check the following! 182 deployConfiguration.overWriteOnly(e, httpPortVal, httpPortPath); 183 deployConfiguration.overWriteOnly(e, environmentNameVal, environmentNamePath); 184 deployConfiguration.overWriteOnly(e, mailReceiverVal, mailReceiverPath); 185 186 for (OffsetSystem ofs : offsetPaths) { 187 deployConfiguration.overWriteOnlyInt(e, ofs.getIndex(), offsetVal.charAt(0), ofs.getPath()); 188 } 189 } 190 191 /** 192 * Applies the environment name on the name of the file-directories. Thus: fileDir -> fileDir/environmentName 193 * 194 * @param app The application where this has to be applied. 195 */ 196 private void applyEnvironmentNameOnBaseFileDir(Element app) { 197 ArgumentNotValid.checkNotNull(app, "Element app"); 198 199 // Get the list of leaf elements along the path to the base_file_dir 200 List<Element> elems = XmlStructure.getAllChildrenAlongPath(app.element(Constants.COMPLETE_SETTINGS_BRANCH), 201 Constants.SETTINGS_BITARCHIVE_BASEFILEDIR_LEAF); 202 // append the environment name as sub directory to these leafs. 203 for (Element el : elems) { 204 StringBuilder content = new StringBuilder(el.getText().trim()); 205 // check if windows format has been used (if the index of the 206 // windows directory separator is different from -1). 207 if (content.indexOf(Constants.BACKSLASH) > -1) { 208 content.append(Constants.BACKSLASH + environmentNameVal); 209 } else { 210 content.append(Constants.SLASH + environmentNameVal); 211 } 212 // then set new value. 213 el.setText(content.toString()); 214 } 215 } 216 217 /** 218 * Creates a file containing the new configuration instance. 219 * 220 * @param filename The name of the file to be written. 221 * @throws IOException If anything goes wrong. 222 */ 223 public void createConfigurationFile(String filename) throws IOException { 224 ArgumentNotValid.checkNotNullOrEmpty(filename, "String filename"); 225 File f = new File(filename); 226 227 FileWriter fw = new FileWriter(f); 228 try { 229 fw.write(deployConfiguration.getXML()); 230 } finally { 231 if (fw != null) { 232 fw.close(); 233 } 234 } 235 } 236 237 /** 238 * Structure for handling where to apply the new offset value. 239 */ 240 private static class OffsetSystem { 241 /** The index of the decimal to be replaced by the offset. */ 242 private int index; 243 /** The path to the leaf where the offset are to be applied. */ 244 private String[] path; 245 246 /** 247 * The constructor. 248 * 249 * @param i The index variable. 250 * @param p The path variable. 251 */ 252 public OffsetSystem(int i, String[] p) { 253 index = i; 254 path = p; 255 } 256 257 /** 258 * For retrieving the index. 259 * 260 * @return The index where the offset should be applied. 261 */ 262 public int getIndex() { 263 return index; 264 } 265 266 /** 267 * For retrieving the path. 268 * 269 * @return The path in the xml-structure to the element which should have a character changed. 270 */ 271 public String[] getPath() { 272 return path; 273 } 274 } 275}