All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.empire.xml.XMLConfiguration Maven / Gradle / Ivy

The newest version!
/*
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements.  See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership.  The ASF licenses this file
 * to you under the Apache License, Version 2.0 (the
 * "License"); you may not use this file except in compliance
 * with the License.  You may obtain a copy of the License at
 *
 *  http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing,
 * software distributed under the License is distributed on an
 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
 * KIND, either express or implied.  See the License for the
 * specific language governing permissions and limitations
 * under the License.
 */
package org.apache.empire.xml;

import java.io.Closeable;
import java.io.FileNotFoundException;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Modifier;
import java.util.HashMap;
import java.util.Map;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.apache.commons.beanutils.BeanUtils;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.empire.commons.ObjectUtils;
import org.apache.empire.commons.StringUtils;
import org.apache.empire.exceptions.EmpireException;
import org.apache.empire.exceptions.FileParseException;
import org.apache.empire.exceptions.FileReadException;
import org.apache.empire.exceptions.InternalException;
import org.apache.empire.exceptions.InvalidArgumentException;
import org.apache.empire.exceptions.ItemNotFoundException;
import org.apache.empire.exceptions.ObjectNotValidException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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.InputSource;
import org.xml.sax.SAXException;


/**
 * 
 * This class manages the configuration of a Java Bean by an xml configuration file.
 * It also supports configuration of Log4J.
 * 
* */ public class XMLConfiguration { private static final Logger log = LoggerFactory.getLogger(XMLConfiguration.class); private Element configRootNode = null; /* * Variable prefix and suffix */ protected final String VAR_BEGIN; protected final char VAR_END; protected final char VAR_DEFAULT; /** * Standard Constructor without variable support */ public XMLConfiguration() { this(null); // No variable support for legacy purposes } /** * Constructor allowing to specify a variable prefix (e.g. $ or #) * @param varIndicator the variable prefix */ public XMLConfiguration(String varIndicator) { this.VAR_BEGIN = (varIndicator!=null ? (varIndicator.endsWith("{") ? varIndicator : varIndicator+"{") : null); this.VAR_END = '}'; this.VAR_DEFAULT = '|'; } /** * Initialize the configuration. * * @param filename the file * @param fromResource will read from the classpath if true */ public void init(String filename, boolean fromResource) { // Read the properties file readConfiguration(filename, fromResource); } /** * returns the configuration root element or null if init() has not been called. * @return the configuration root element */ public Element getRootNode() { return configRootNode; } /** * Reads the configuration file and parses the XML Configuration. */ protected void readConfiguration(String fileName, boolean fromResource) { FileReader reader = null; InputStream inputStream = null; try { DocumentBuilder docBuilder = DocumentBuilderFactory.newInstance().newDocumentBuilder(); Document doc = null; if (fromResource) { // Open Resource log.info("reading resource file: " + fileName); inputStream = getClass().getClassLoader().getResourceAsStream(fileName); // Parse File doc = docBuilder.parse(inputStream); } else { // Open File log.info("reading configuration file: " + fileName); reader = new FileReader(fileName); // Parse File doc = docBuilder.parse(new InputSource(reader)); } // Get Root Element configRootNode = doc.getDocumentElement(); } catch (FileNotFoundException e) { log.error("Configuration file {} not found!", fileName, e); throw new FileReadException(fileName, e); } catch (IOException e) { log.error("Error reading configuration file {}", fileName, e); throw new FileReadException(fileName, e); } catch (SAXException e) { log.error("Invalid XML in configuration file {}", fileName, e); throw new FileParseException(fileName, e); } catch (ParserConfigurationException e) { log.error("ParserConfigurationException: {}", e.getMessage(), e); throw new InternalException(e); } finally { close(reader); close(inputStream); } } /** * reads all properties from a given properties node and applies them to the given bean * @param bean the bean to which to apply the configuration * @param propertiesNodeNames the name of the properties node below the root element */ public void readProperties(Object bean, String... propertiesNodeNames) { // Check state if (configRootNode == null) throw new ObjectNotValidException(this); // Check arguments if (bean == null) throw new InvalidArgumentException("bean", bean); Element propertiesNode = configRootNode; for(String nodeName : propertiesNodeNames) { if (StringUtils.isEmpty(nodeName)) throw new InvalidArgumentException("propertiesNodeNames", null); // Get configuration node propertiesNode = XMLUtil.findFirstChild(propertiesNode, nodeName); if (propertiesNode == null) { // Configuration log.warn("Property-Node {} has not been found.", nodeName); throw new ItemNotFoundException(nodeName); } } // read the properties readProperties(bean, propertiesNode); } /** * reads all properties from a given properties node and applies them to the given bean * @param bean the bean to which to apply the configuration * @param propertiesNode the properties node */ public void readProperties(Object bean, Element propertiesNode) { // Check arguments if (propertiesNode == null) throw new InvalidArgumentException("propertiesNode", propertiesNode); if (bean == null) throw new InvalidArgumentException("bean", bean); // apply configuration log.info("reading bean properties from node: {}", propertiesNode.getNodeName()); NodeList nodeList = propertiesNode.getChildNodes(); for (int i = 0; i < nodeList.getLength(); i++) { Node item = nodeList.item(i); if (item.getNodeType() != Node.ELEMENT_NODE) continue; // Get the Text and set the Property if ((item instanceof Element) && isProperty((Element)item)) { setPropertyValue(bean, (Element)item); } } } /** * Checks if the element is a property * @param item the xml element * @return true if the element is a property */ protected boolean isProperty(Element item) { String value = item.getAttribute("property"); if (value==null || value.length()==0) return true; // assume yes return ObjectUtils.getBoolean(value); } /** * Sets the property value of an XML Element * @param bean the java bean containing the property * @param item the configuration node */ @SuppressWarnings("unchecked") protected void setPropertyValue(Object bean, Element item) { String name = item.getNodeName(); String prop = name; try { Class valueType = PropertyUtils.getPropertyType(bean, name); if (valueType==null) { // No property in class log.info("Element <{}> has no Property in Class {}", name, bean.getClass().getName()); return; } // Has Attributes? if (item.hasAttributes() && Map.class.isAssignableFrom(valueType)) { // It's a map type Object value = PropertyUtils.getNestedProperty(bean, name); Map map; if (value instanceof Map) { // Use existing map = (Map)value; } else { // Create and Set map = new HashMap(); PropertyUtils.setProperty(bean, name, map); } // copy to map NamedNodeMap nm = item.getAttributes(); for (int i = 0; i valueType, String value) { if (value==null) return null; int beg = (StringUtils.isNotEmpty(VAR_BEGIN) ? value.indexOf(VAR_BEGIN) : -1); if (beg<0) return value; // resolve variable int end = findVarEnd(value, beg+2); if (end<0) throw new InvalidArgumentException("value", value); // resolve String defaultValue = null; String var = value.substring(beg+2, end); int def = var.indexOf(VAR_DEFAULT); if (def>0) { // Default value provided defaultValue = (String)resolveValue(String.class, var.substring(def+1)); var = var.substring(0, def); } String varVal = resolveVariable(var, defaultValue); if (varVal==null) throw new ItemNotFoundException(var); StringBuilder b = new StringBuilder(value.length()+varVal.length()-(end-beg)-1); b.append(value.substring(0, beg)); b.append(varVal); b.append(value.substring(end+1)); return resolveValue(valueType, b.toString()); } /** * Returns the value for a given variable * If a variable value cannot be resolved the function should return the default value * @param var the variable name * @param defaultValue the default value or null * @return the variable value */ protected String resolveVariable(String var, String defaultValue) { log.debug("Config: Resolving variable {}", var); String value = System.getProperty(var); return (value!=null ? value : defaultValue); } /* Implementation of toString */ private static String EOL = "\r\n"; private static String EOC = "----------------------------------------\r\n"; // end of class @Override public String toString() { StringBuilder b = new StringBuilder(EOC); Class clazz = getClass(); while (clazz!=null && clazz!=XMLConfiguration.class) { appendConfigProperties(clazz, this, b, true); clazz = clazz.getSuperclass(); } return b.toString(); } protected void appendConfigProperties(Class clazz, Object object, StringBuilder b, boolean appendClassInfo) { Field[] fields = clazz.getDeclaredFields(); for (Field field : fields) { // ignore static fields int modifiers = field.getModifiers(); if (Modifier.isStatic(modifiers) || Modifier.isFinal(modifiers)) continue; // make accessible try { Object value = PropertyUtils.getProperty(object, field.getName()); if (value!=null && !(value instanceof Map)) { Class vc = value.getClass(); boolean simple = (vc.isPrimitive() || vc.isEnum() || vc == String.class || vc == Character.class || vc == Byte.class || vc == Integer.class || vc == Long.class || vc == Short.class || vc == Double.class || vc == Float.class || vc == Boolean.class || vc == Class.class); // Nested? if (!simple) { // Nested Class b.append(EOC); b.append(field.getName()); b.append("["); b.append(clazz.getName()); b.append("]="); b.append(EOL); appendConfigProperties(value.getClass(), value, b, false); return; } } // class info if (appendClassInfo) { appendClassInfo = false; b.append("[Properties of "); b.append(clazz.getName()); b.append("]"); b.append(EOL); } // property value b.append(field.getName()); b.append("="); b.append(String.valueOf(value)); b.append(EOL); } catch (IllegalAccessException | InvocationTargetException | NoSuchMethodException e) { log.warn("Field {} is ignored due to Exception {}", field.getName(), e.toString()); } } if (appendClassInfo==false) b.append(EOC); } /* helpers */ private int findVarEnd(String value, int from) { final char NEST_CHAR = VAR_BEGIN.charAt(VAR_BEGIN.length()-1); for (int nestCount = 0;from




© 2015 - 2025 Weber Informatics LLC | Privacy Policy