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.util.List; 027 028import org.dom4j.Document; 029import org.dom4j.DocumentException; 030import org.dom4j.Element; 031import org.dom4j.io.SAXReader; 032import org.slf4j.Logger; 033import org.slf4j.LoggerFactory; 034 035import dk.netarkivet.common.exceptions.ArgumentNotValid; 036import dk.netarkivet.common.exceptions.IOFailure; 037import dk.netarkivet.common.utils.FileUtils; 038 039/** 040 * Class for evaluating a config file. Tests the settings in the config file against default settings to test for 041 * wrongly assigned elements. 042 */ 043public class EvaluateConfigFile { 044 045 /** The elements to check the settings against. */ 046 private Element completeSettings; 047 /** The root element in the xml tree. */ 048 private XmlStructure root; 049 /** the log, for logging stuff instead of displaying them directly. */ 050 private static final Logger log = LoggerFactory.getLogger(EvaluateConfigFile.class); 051 052 /** 053 * Constructor. Only initialises the config file and settings list. 054 * 055 * @param deployConfigFile The file to evaluate. 056 * @param encoding the encoding to use to read from file 057 */ 058 public EvaluateConfigFile(File deployConfigFile, String encoding) { 059 ArgumentNotValid.checkNotNull(deployConfigFile, "File deployConfigFile"); 060 initLoadDefaultSettings(); 061 root = new XmlStructure(deployConfigFile, encoding); 062 } 063 064 /** 065 * Evaluates the config file. This is done by evaluating the settings branch for all the instances in the XML-tree 066 * (global, physical locaiton, machine and application) 067 */ 068 @SuppressWarnings("unchecked") 069 public void evaluate() { 070 try { 071 // check global settings 072 evaluateElement(root.getChild(Constants.COMPLETE_SETTINGS_BRANCH)); 073 List<Element> physLocs = root.getChildren(Constants.DEPLOY_PHYSICAL_LOCATION); 074 for (Element pl : physLocs) { 075 // check physical location settings 076 evaluateElement(pl.element(Constants.COMPLETE_SETTINGS_BRANCH)); 077 List<Element> macs = pl.elements(Constants.DEPLOY_MACHINE); 078 for (Element mac : macs) { 079 // check machine settings 080 evaluateElement(mac.element(Constants.COMPLETE_SETTINGS_BRANCH)); 081 List<Element> apps = mac.elements(Constants.DEPLOY_APPLICATION_NAME); 082 for (Element app : apps) { 083 // check application settings 084 evaluateElement(app.element(Constants.COMPLETE_SETTINGS_BRANCH)); 085 } 086 } 087 } 088 } catch (Exception e) { 089 log.error("Error occured during evaluation: ", e); 090 } 091 } 092 093 /** 094 * Load the default settings files as reference trees. These are used for testing whether the branches in the 095 * settings file are to be used or not. 096 */ 097 private void initLoadDefaultSettings() { 098 File f = FileUtils.getResourceFileFromClassPath(Constants.BUILD_COMPLETE_SETTINGS_FILE_PATH); 099 try { 100 Document doc; 101 SAXReader reader = new SAXReader(); 102 if (f.canRead()) { 103 doc = reader.read(f); 104 completeSettings = doc.getRootElement(); 105 } else { 106 log.warn("Cannot read file: '{}'", f.getAbsolutePath()); 107 } 108 } catch (DocumentException e) { 109 log.error("Cannot handle complete settings file.", e); 110 throw new IOFailure("Cannot handle complete settings file.", e); 111 } 112 } 113 114 /** 115 * Evaluates a element (has to called with the settings branch). Then tries to evaluate all the branches to the 116 * element. The method is called recursively for the children of curElem. 117 * 118 * @param curElem The current element to evaluate. Null element represents in this context that no settings branch 119 * exists for the current instance. 120 */ 121 @SuppressWarnings("unchecked") 122 private void evaluateElement(Element curElem) { 123 // make sure to catch null-pointers 124 if (curElem == null) { 125 return; 126 } 127 List<Element> elList = curElem.elements(); 128 for (Element el : elList) { 129 boolean valid = false; 130 // get path 131 String path = getSettingsPath(el); 132 133 // check if path exists in any default setting. 134 valid = existBranch(completeSettings, path.split(Constants.SLASH)); 135 136 if (valid) { 137 if (!el.isTextOnly()) { 138 evaluateElement(el); 139 } 140 } else { 141 // Print out the 'illegal' branches. 142 System.out.println("Branch in settings not found: " + path.replace(Constants.SLASH, Constants.DOT)); 143 } 144 } 145 } 146 147 /** 148 * For testing whether a branch with the current path exists. 149 * 150 * @param settings The root of the default settings XML-tree. 151 * @param path The path to the branch to test. 152 * @return Whether the branch at the end of the path in the root exists. 153 */ 154 private boolean existBranch(Element settings, String[] path) { 155 Element curE = settings; 156 for (String st : path) { 157 if (curE == null) { 158 return false; 159 } 160 curE = curE.element(st); 161 } 162 163 // return whether the final branch exists. 164 return (curE != null); 165 } 166 167 /** 168 * Gets the path from settings of an element. 169 * 170 * @param el The element to get the settings path. 171 * @return The path from settings to the element, in the XML-tree. 172 */ 173 private String getSettingsPath(Element el) { 174 String[] elList = el.getPath().split(Constants.SLASH); 175 176 StringBuilder res = new StringBuilder(); 177 int i = 0; 178 // find the index for settings 179 while (i < elList.length && !elList[i].equalsIgnoreCase(Constants.COMPLETE_SETTINGS_BRANCH)) { 180 ++i; 181 } 182 183 // TODO WTF?! 184 for (i++; i < elList.length; i++) { 185 res.append(elList[i]); 186 res.append(Constants.SLASH); 187 } 188 189 // remove last '/' 190 res.deleteCharAt(res.length() - 1); 191 192 return res.toString(); 193 } 194 195}