001 /** 002 * Licensed to the Apache Software Foundation (ASF) under one or more 003 * contributor license agreements. See the NOTICE file distributed with 004 * this work for additional information regarding copyright ownership. 005 * The ASF licenses this file to You under the Apache License, Version 2.0 006 * (the "License"); you may not use this file except in compliance with 007 * the License. You may obtain a copy of the License at 008 * 009 * http://www.apache.org/licenses/LICENSE-2.0 010 * 011 * Unless required by applicable law or agreed to in writing, software 012 * distributed under the License is distributed on an "AS IS" BASIS, 013 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 014 * See the License for the specific language governing permissions and 015 * limitations under the License. 016 */ 017 package org.apache.geronimo.monitoring.snapshot; 018 019 import java.io.File; 020 import java.io.FileOutputStream; 021 import java.util.ArrayList; 022 023 import javax.xml.parsers.DocumentBuilder; 024 import javax.xml.parsers.DocumentBuilderFactory; 025 import javax.xml.parsers.ParserConfigurationException; 026 027 import org.apache.commons.logging.Log; 028 import org.apache.commons.logging.LogFactory; 029 import org.apache.xmlbeans.XmlCursor; 030 import org.apache.xmlbeans.XmlObject; 031 import org.w3c.dom.Document; 032 import org.w3c.dom.Element; 033 import org.w3c.dom.Node; 034 import org.w3c.dom.NodeList; 035 036 /** 037 * In charge of dealing with the XML processing of the snapshot's data. 038 */ 039 public class SnapshotConfigXMLBuilder { 040 private static Log log = LogFactory.getLog(SnapshotConfigXMLBuilder.class); 041 042 private static final String pathToXML = 043 System.getProperty("org.apache.geronimo.home.dir") + "/var/monitoring/snapshot-config.xml"; 044 045 private static final String SNAPSHOT_CONFIG = "snapshot-config"; 046 private static final String DURATION = "duration"; 047 private static final String RETENTION = "retention"; 048 private static final String MBEAN = "mbean"; 049 050 /** 051 * @return A list of all mbean names that have been previously saved. 052 * These mbean names are those to keep track of for per snapshot. 053 */ 054 public static ArrayList<String> getMBeanNames() { 055 ArrayList<String> mbeanList = new ArrayList<String>(); 056 // get an instance of the document 057 Document doc = openDocument(); 058 // get the root element node 059 Element rootElement = doc.getDocumentElement(); 060 // get all children in the root node (i.e. all config properties) 061 NodeList configNodes = rootElement.getChildNodes(); 062 // find the duration node and save it 063 for(int i = 0; i < configNodes.getLength(); i++) { 064 if(MBEAN.equals(configNodes.item(i).getNodeName())) { 065 mbeanList.add( configNodes.item(i).getTextContent() ); 066 } 067 } 068 return mbeanList; 069 } 070 071 /** 072 * Adds to the snapshot-config.xml another configuration element <mbean> 073 * in order to persistently keep track of all user requested statistics. 074 * If there is a duplicate, nothing will be done. 075 */ 076 public static boolean removeMBeanName(String mbeanName) { 077 ArrayList<String> mbeanList = getMBeanNames(); 078 // operate on the snapshot-config.xml if there exists the mbean name 079 if(mbeanList.contains(mbeanName)) { 080 // get an instance of the document 081 Document doc = openDocument(); 082 // get the root element node 083 Element rootElement = doc.getDocumentElement(); 084 // find the Node that represents the mbeanName 085 NodeList list = rootElement.getChildNodes(); 086 for(int i = 0; i < list.getLength(); i++) { 087 // check the Node's text context for a match with mbeanName 088 if(list.item(i).getTextContent().equals(mbeanName)) { 089 // remove the node from rootElement 090 Node toRemoveNode = list.item(i); 091 rootElement.removeChild(toRemoveNode); 092 break; 093 } 094 } 095 // save the document 096 saveDocument(doc, pathToXML); 097 return true; 098 } else { 099 return false; 100 } 101 } 102 103 /** 104 * Removes from the snapshot-config.xml a configuration element <mbean> 105 * in order to persistently keep track of all user requested statistics. 106 * If there does not exist an instance of the mbeanNAme, nothing will be done. 107 */ 108 public static boolean addMBeanName(String mbeanName) { 109 ArrayList<String> mbeanList = getMBeanNames(); 110 if(mbeanList.contains(mbeanName)) { 111 return false; 112 } else { 113 // get an instance of the document 114 Document doc = openDocument(); 115 // get the root element node 116 Element rootElement = doc.getDocumentElement(); 117 // create <mbean> element 118 Element mbeanElement = doc.createElement(MBEAN); 119 mbeanElement.setTextContent(mbeanName); 120 // add <mbean> element to the rootElement 121 rootElement.appendChild(mbeanElement); 122 try { 123 Thread.sleep(1000); 124 } catch(Exception e) { 125 126 } 127 // save the document 128 saveDocument(doc, pathToXML); 129 return true; 130 } 131 } 132 133 /** 134 * Saves the duration of the snapshot as a configuration attribute 135 * @param duration 136 */ 137 public static void saveDuration(long duration) { 138 saveAttribute(DURATION, duration); 139 } 140 141 /** 142 * Saves the retention of the snapshot as a configuration attribute 143 * @param retention 144 */ 145 public static void saveRetention(int retention) { 146 saveAttribute(RETENTION, retention); 147 } 148 149 /** 150 * Saves a generic attribute value into the node with text = attribute name. 151 * Creates one if there is not an instance of one. 152 * @param attrName 153 * @param attributeValue 154 */ 155 private static void saveAttribute(String attrName, long attributeValue) { 156 Document doc = openDocument(); 157 // get the root node 158 Element rootElement = doc.getDocumentElement(); 159 // get all children in the root node (i.e. all config properties) 160 NodeList configNodes = rootElement.getChildNodes(); 161 // find the duration node and save it 162 boolean foundNode = false; 163 for(int i = 0; i < configNodes.getLength() && !foundNode; i++) { 164 Node configNode = configNodes.item(i); 165 if(attrName.equals(configNode.getNodeName())) { 166 // found a match 167 configNode.setTextContent(attributeValue + ""); 168 foundNode = true; 169 } 170 } 171 // if there was not a duration node, make one 172 if(!foundNode) { 173 Element element = doc.createElement(attrName); 174 element.setTextContent(attributeValue + ""); 175 rootElement.appendChild(element); 176 } 177 try { 178 Thread.sleep(1000); 179 } catch(Exception e) { 180 181 } 182 log.info("***saving: " + attrName + " = " + attributeValue); 183 // save the document to file 184 saveDocument(doc, pathToXML); 185 } 186 187 /** 188 * Returns the value of the configuration attribute, defined by the key 189 * @param key 190 * @return 191 * @throws Exception 192 */ 193 public static String getAttributeValue(String key) throws Exception { 194 // ensure that there exists the 'monitor' directory 195 ensureMonitorDir(); 196 // get an instance of the document 197 Document doc = openDocument(); 198 // get the root element node 199 Element rootElement = doc.getDocumentElement(); 200 // get all children in the root node (i.e. all config properties) 201 NodeList configNodes = rootElement.getChildNodes(); 202 // find the duration node and save it 203 for(int i = 0; i < configNodes.getLength(); i++) { 204 if(key.equals(configNodes.item(i).getNodeName())) { 205 return configNodes.item(i).getTextContent(); 206 } 207 } 208 throw new Exception("[WARNING] " + key + " is not found in " + SNAPSHOT_CONFIG); 209 } 210 211 /** 212 * Ensures that there is an existing XML file. Creates one if there 213 * does not exist one already. 214 */ 215 public static void checkXMLExists() { 216 File docFile = new File(pathToXML); 217 // create an XML document if it does not exist 218 if(!docFile.exists()) { 219 Document doc = setUpDocument( createDocument() ); 220 saveDocument(doc, pathToXML); 221 } 222 } 223 224 /** 225 * Prepares the root element for a document. 226 */ 227 public static Document setUpDocument(Document document) { 228 // add <snapshot-config> tag as the root 229 Element rootElement = document.createElement("snapshot-config"); 230 document.appendChild(rootElement); 231 return document; 232 } 233 234 /** 235 * Creates an instance of a Document and returns it 236 */ 237 public static Document createDocument() { 238 // get an instance of factory 239 DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); 240 try { 241 // get an instance of builder 242 DocumentBuilder db = dbf.newDocumentBuilder(); 243 // create an instance of DOM 244 return db.newDocument(); 245 } catch(ParserConfigurationException pce) { 246 log.error("Error while trying to instantiate DocumentBuilder", pce); 247 } 248 return null; 249 } 250 251 /** 252 * Write the document object to the file location specified by 253 * the path. 254 */ 255 public static void saveDocument(Document document, String path) { 256 try { 257 // before saving, make sure the directory is present 258 ensureMonitorDir(); 259 260 //TODO GERONIMO-3719. Hack to use xmlbeans to write out xml instead of sun specific classes. 261 XmlObject xmlObject = XmlObject.Factory.parse(document.getDocumentElement()); 262 xmlObject.save(new File(path)); 263 264 // formatting the doc 265 // generate a file output 266 } catch(Exception e) { 267 log.error(e.getMessage(), e); 268 } 269 } 270 271 /** 272 * Parses the XML document specified by the private member 'pathToXML' 273 * and stores the information in the a Document object 274 */ 275 public static Document openDocument() { 276 // ensure that the XML file is there 277 checkXMLExists(); 278 // get the factory 279 DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance(); 280 // continue to attempt to parse 281 while(true) { 282 try { 283 // Using factory get an instance of document builder 284 DocumentBuilder db = dbf.newDocumentBuilder(); 285 // parse using builder to get DOM representation of the XML file 286 Document doc = db.parse(pathToXML); 287 return doc; 288 } catch(Exception e) { 289 // Either this file is being read/written to by snapshot thread 290 // or there is an UNKNOWN error 291 log.error(e.getMessage(), e); 292 } 293 } 294 } 295 296 /** 297 * Checks to see if the GERONIMO_HOME/var/monitoring/ directory was made. 298 * If not, the method creates it. 299 */ 300 public static void ensureMonitorDir() { 301 final String pathToDir = 302 System.getProperty("org.apache.geronimo.home.dir") + "/var/monitoring/"; 303 File dir = new File(pathToDir); 304 if(dir.exists() && dir.isDirectory()) { 305 // all good 306 return; 307 } else { 308 // make a directory 309 if(dir.mkdir()) { 310 // directory was successfully created 311 log.info("/var/monitoring directory created."); 312 return; 313 } else { 314 log.error("Could not make the directory " + pathToDir); 315 } 316 } 317 } 318 }