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 }