/************************************************************************* * Copyright 2009-2012 Eucalyptus Systems, Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; version 3 of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see http://www.gnu.org/licenses/. * * Please contact Eucalyptus Systems, Inc., 6755 Hollister Ave., Goleta * CA 93117, USA or visit http://www.eucalyptus.com/licenses/ if you need * additional information or have any questions. * * This file may incorporate work covered under the following copyright * and permission notice: * * Software License Agreement (BSD License) * * Copyright (c) 2008, Regents of the University of California * All rights reserved. * * Redistribution and use of this software in source and binary forms, * with or without modification, are permitted provided that the * following conditions are met: * * Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * * Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer * in the documentation and/or other materials provided with the * distribution. * * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. USERS OF THIS SOFTWARE ACKNOWLEDGE * THE POSSIBLE PRESENCE OF OTHER OPEN SOURCE LICENSED MATERIAL, * COPYRIGHTED MATERIAL OR PATENTED MATERIAL IN THIS SOFTWARE, * AND IF ANY SUCH MATERIAL IS DISCOVERED THE PARTY DISCOVERING * IT MAY INFORM DR. RICH WOLSKI AT THE UNIVERSITY OF CALIFORNIA, * SANTA BARBARA WHO WILL THEN ASCERTAIN THE MOST APPROPRIATE REMEDY, * WHICH IN THE REGENTS' DISCRETION MAY INCLUDE, WITHOUT LIMITATION, * REPLACEMENT OF THE CODE SO IDENTIFIED, LICENSING OF THE CODE SO * IDENTIFIED, OR WITHDRAWAL OF THE CODE CAPABILITY TO THE EXTENT * NEEDED TO COMPLY WITH ANY SUCH LICENSES OR RIGHTS. ************************************************************************/ package com.eucalyptus.component.fault; import java.io.File; import java.io.FileFilter; import java.io.IOException; import java.util.HashMap; import java.util.HashSet; import java.util.Map; import java.util.Set; import javax.xml.parsers.DocumentBuilder; import org.apache.log4j.Logger; import org.w3c.dom.Document; import org.w3c.dom.Element; import org.w3c.dom.NamedNodeMap; import org.w3c.dom.Node; import org.w3c.dom.NodeList; import org.xml.sax.SAXException; import com.eucalyptus.util.XMLParser; public class FaultRegistry { private static final Logger LOG = Logger.getLogger(FaultRegistry.class); private static final String EUCAFAULTS = "eucafaults"; private static final String COMMON = "common"; private static final String VAR = "var"; private static final String FAULT = "fault"; private static final String ID = "id"; private static final String VERSION = "version"; private static final String DESCRIPTION = "description"; private static final String NAME = "name"; private static final String VALUE = "value"; private static final String LOCALIZED = "localized"; private static final String MESSAGE = "message"; private static final String XML_SUFFIX = ".xml"; private static final String COMMON_XML = COMMON + XML_SUFFIX; public static final Fault SUPPRESSED_FAULT = new Fault(); // token to indicate fault is suppressed public FaultRegistry() { commonMap = new HashMap<String, Common>(); faultMap = new HashMap<Integer, Fault>(); suppressedFaults = new HashSet<Integer>(); } void crawlDirectory(File rootDir) { LOG.debug("Crawling fault directory " + rootDir); if (rootDir != null && rootDir.isDirectory()) { File commonXMLFile = new File(rootDir, COMMON_XML); if ( commonXMLFile.isFile( ) ) { parseCommonXMLFile( commonXMLFile, commonMap ); File[] faultFiles = rootDir.listFiles( new FaultFileFilter( ) ); if ( faultFiles != null ) { for ( File faultFile : faultFiles ) { parseFaultXMLFile( faultFile, faultMap, commonMap, suppressedFaults ); } } } else { LOG.info(commonXMLFile + " either does not exist or is not a file, skipping directory."); } } else { LOG.info(rootDir + " either does not exist or is not a directory, skipping."); } } private void parseCommonXMLFile(File commonXMLFile, Map<String, Common> commonMap) { try { LOG.warn("Parsing common file " + commonXMLFile); DocumentBuilder dBuilder = XMLParser.getDocBuilder(); if (dBuilder != null) { Document doc = dBuilder.parse(commonXMLFile); Element docElement = doc.getDocumentElement(); docElement.normalize(); if (!EUCAFAULTS.equalsIgnoreCase(docElement.getTagName())) { LOG.warn("File " + commonXMLFile + " contains the wrong outer XML tag, will not be parsed."); } else { NodeList children = docElement.getChildNodes(); final int length = children.getLength(); for (int i=0;i < length; i++) { Node currentNode = children.item(i); if (currentNode.getNodeType() == Node.ELEMENT_NODE) { Element currentElement = (Element) currentNode; if (COMMON.equalsIgnoreCase(currentElement.getTagName())) { parseCommonElement(currentElement, commonMap); } } } } LOG.debug("Successfully parsed " + commonXMLFile); } } catch (SAXException ex) { LOG.error(ex); } catch (IOException ex) { LOG.error(ex); } } private void parseFaultXMLFile(File faultXMLFile, Map<Integer, Fault> faultMap, Map<String, Common> commonMap, Set<Integer> suppressedFaults) { try { LOG.debug("Parsing fault file " + faultXMLFile); // Special case, zero length file. (Turn on or off) int faultId = parseIdFromFileName(faultXMLFile.getName()); if (suppressedFaults.contains(faultId) && faultXMLFile.length() != 0) { LOG.debug("Unsupressing fault " + faultId); suppressedFaults.remove(faultId); // Zero length means suppress fault } else if (faultXMLFile.exists() && faultXMLFile.length() == 0) { LOG.debug("Supressing fault " + faultId); faultMap.remove(faultId); suppressedFaults.add(faultId); return; } DocumentBuilder dBuilder = XMLParser.getDocBuilder(); Document doc = dBuilder.parse(faultXMLFile); Element docElement = doc.getDocumentElement(); docElement.normalize(); if (!EUCAFAULTS.equalsIgnoreCase(docElement.getTagName())) { LOG.warn("File " + faultXMLFile + " contains the wrong outer XML tag, will not be parsed."); } else { // The way C parses the code, it uses exactly one common.xml file, the highest priority one. // We will do the same here. All existing faults have a reference to the common map though, // and it is possible that a different common.xml file will be parsed. We will thus keep // the map reference around, and clear it out when we find a new common.xml file. // TODO: consider simply overwriting values in the map. commonMap.clear(); // Since all faults reference this common map, and we have a ner // common.xml file, we will start over, rather than overwrite fields. NodeList children = docElement.getChildNodes(); final int length = children.getLength(); for (int i=0;i < length; i++) { Node currentNode = children.item(i); if (currentNode.getNodeType() == Node.ELEMENT_NODE) { Element currentElement = (Element) currentNode; if (FAULT.equalsIgnoreCase(currentElement.getTagName())) { Fault fault = parseFaultElement(currentElement, commonMap); if (fault.getId() != faultId) { LOG.warn("Fault " + fault.getId() + " found in file " + faultXMLFile + ", in the wrong file. Will not be processed"); } else { LOG.debug("Successfully parsed " + faultXMLFile + " and read in fault " + fault.getId()); faultMap.put(fault.getId(), fault); } } } } } } catch (SAXException ex) { LOG.error(ex); } catch (IOException ex) { LOG.error(ex); } } private Fault parseFaultElement(Element element, Map<String, Common> commonMap2) { if (element == null) return null; Fault fault = new Fault(); fault.setId(-1); try { fault.setId(Integer.parseInt(getAttribute(element, ID))); } catch (Exception ex) { LOG.warn("Illegal ID passed in, will use -1"); } fault.setCommonMap(commonMap); FaultMessage message = new FaultMessage(); fault.setMessage(message); message.setMessage(getAttribute(element, MESSAGE)); message.setLocalized(getAttribute(element, LOCALIZED)); fault.setFaultFieldMap(new HashMap<FaultFieldName, FaultField>()); NodeList children = element.getChildNodes(); final int length = children.getLength(); for (int i=0;i < length; i++) { Node currentNode = children.item(i); if (currentNode.getNodeType() == Node.ELEMENT_NODE) { Element currentElement = (Element) currentNode; FaultFieldName name = null; try { name = FaultFieldName.valueOf(currentElement.getTagName()); } catch (Exception ex) { // not a tag we like continue; } FaultField faultField = new FaultField(); faultField.setName(name); faultField.setLocalizedAttribute(getAttribute(currentElement, LOCALIZED)); faultField.setMessageAttribute(getAttribute(currentElement, MESSAGE)); faultField.setLocalizedElement(getTextElement(currentElement, LOCALIZED)); faultField.setMessageElement(getTextElement(currentElement, MESSAGE)); fault.getFaultFieldMap().put(faultField.getName(), faultField); } } return fault; } private String getTextElement(Element element, String subElementName) { if (element == null || subElementName == null) return null; NodeList children = element.getChildNodes(); final int length = children.getLength(); for (int i=0;i < length; i++) { Node currentNode = children.item(i); if (currentNode.getNodeType() == Node.ELEMENT_NODE) { Element currentElement = (Element) currentNode; if (subElementName.equalsIgnoreCase(currentElement.getTagName())) { // for text elements, it is the first child try { return currentElement.getChildNodes().item(0).getNodeValue(); } catch (Exception ex) { return null; } } } } return null; } private int parseIdFromFileName(String name) { // filename should be NNNN.xml try { return Integer.parseInt(name.substring(0, name.length() - XML_SUFFIX.length())); } catch (Exception ex) { return -1; } } private void parseCommonElement(Element element, Map<String, Common> commonMap) { if (element == null) return; NodeList children = element.getChildNodes(); final int length = children.getLength(); for (int i=0;i < length; i++) { Node currentNode = children.item(i); if (currentNode.getNodeType() == Node.ELEMENT_NODE) { Element currentElement = (Element) currentNode; if (VAR.equalsIgnoreCase(currentElement.getTagName())) { Common common = new Common(); common.setName(getAttribute(currentElement, NAME)); common.setValue(getAttribute(currentElement, VALUE)); common.setLocalized(getAttribute(currentElement, LOCALIZED)); if (common.getName() != null) { commonMap.put(common.getName(), common); } } } } } private Set<Integer> suppressedFaults; // new request private Map<String, Common> commonMap; private Map<Integer, Fault> faultMap; private String getAttribute(Element element, String attributeName) { if (element == null) return null; NamedNodeMap namedNodeMap = element.getAttributes(); if (namedNodeMap == null) return null; Node localizedNode = namedNodeMap.getNamedItem(attributeName); if (localizedNode == null) return null; return localizedNode.getNodeValue(); } public class FaultFileFilter implements FileFilter { @Override public boolean accept(File f) { if (f != null && f.isFile() && f.getName().toLowerCase().endsWith(XML_SUFFIX)) { String name = f.getName().toLowerCase(); String prefix = name.substring(0, name.length() - XML_SUFFIX.length()); try { return Integer.parseInt(prefix) > 0; } catch (NumberFormatException ignore) { ; } } return false; } } public Fault lookupFault(int id) { if (suppressedFaults.contains(id)) { return SUPPRESSED_FAULT; } Fault fault = faultMap.get(id); if (fault == null) { return fault; } else { return (Fault) fault.clone(); // so they can do withVar() w/o damaging the template } } }