org.paxle.tools.ieporter.cm.impl.ConfigurationIEPorter.java Source code

Java tutorial

Introduction

Here is the source code for org.paxle.tools.ieporter.cm.impl.ConfigurationIEPorter.java

Source

/**
 * This file is part of the Paxle project.
 * Visit http://www.paxle.net for more information.
 * Copyright 2007-2010 the original author or authors.
 *
 * Licensed under the terms of the Common Public License 1.0 ("CPL 1.0").
 * Any use, reproduction or distribution of this program constitutes the recipient's acceptance of this agreement.
 * The full license text is available under http://www.opensource.org/licenses/cpl1.0.txt
 * or in the file LICENSE.txt in the root directory of the Paxle distribution.
 *
 * Unless required by applicable law or agreed to in writing, this software is distributed
 * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 */

package org.paxle.tools.ieporter.cm.impl;

import java.io.BufferedInputStream;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Array;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Collections;
import java.util.Dictionary;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.Map;
import java.util.Vector;
import java.util.Map.Entry;
import java.util.zip.ZipEntry;
import java.util.zip.ZipInputStream;
import java.util.zip.ZipOutputStream;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Result;
import javax.xml.transform.Source;
import javax.xml.transform.Transformer;
import javax.xml.transform.TransformerException;
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.TransformerFactoryConfigurationError;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.apache.commons.io.IOUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.felix.scr.annotations.Component;
import org.apache.felix.scr.annotations.Reference;
import org.apache.felix.scr.annotations.Service;
import org.osgi.framework.Constants;
import org.osgi.service.cm.Configuration;
import org.osgi.service.cm.ConfigurationAdmin;
import org.paxle.tools.ieporter.cm.IConfigurationIEPorter;
import org.w3c.dom.DOMException;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;

@SuppressWarnings("serial")
@Component(immediate = true, metatype = false)
@Service(IConfigurationIEPorter.class)
public class ConfigurationIEPorter implements IConfigurationIEPorter {
    private static final String ELEM_VALUE = "value";
    private static final String ELEM_VALUES = "values";
    private static final String ELEM_PROPERTY = "property";
    private static final String ELEM_PROPERTIES = "properties";
    private static final String ELEM_CONFIG = "config";
    private static final String ATTRIB_PROPERTY_TYPE = "type";
    private static final String ATTRIBUTE_PROPERTY_KEY = "key";

    /**
     * All {@link Class classes} that are supported by the {@link ConfigurationAdmin} service.
     */
    private static final HashSet<Class<?>> SUPPORTED_CLASSES = new HashSet<Class<?>>() {
        {
            add(String.class);
            add(Long.class);
            add(Integer.class);
            add(Short.class);
            add(Character.class);
            add(Byte.class);
            add(Double.class);
            add(Float.class);
            add(Boolean.class);
        }
    };

    private static final HashMap<String, Class<?>> WRAPPERS = new HashMap<String, Class<?>>();
    private static final HashMap<String, Class<?>> NAMELOOKUP = new HashMap<String, Class<?>>();
    static {
        for (Class<?> clazz : SUPPORTED_CLASSES) {
            try {
                // add wrapper class
                NAMELOOKUP.put(clazz.getSimpleName(), clazz);
                if (clazz.equals(String.class)) {
                    WRAPPERS.put(String.class.getSimpleName(), String.class);
                    continue;
                }

                // add primitive type
                Field primitiveTypeField = clazz.getDeclaredField("TYPE");
                Class<?> primitiveType = (Class<?>) primitiveTypeField.get(null);

                NAMELOOKUP.put(primitiveType.getSimpleName(), primitiveType);
                WRAPPERS.put(primitiveType.getSimpleName(), clazz);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    }

    @Reference
    protected ConfigurationAdmin cm;

    /**
     * For logging
     */
    private Log logger = LogFactory.getLog(this.getClass());

    private Document createNewXMLDocument(String rootElementName, String namespaceURI)
            throws ParserConfigurationException {
        // creating a new document builder factory
        DocumentBuilderFactory newDocBuilderFactory = DocumentBuilderFactory.newInstance();

        // creating a new document builder
        DocumentBuilder newDocBuilder = newDocBuilderFactory.newDocumentBuilder();

        // creating a new xml document
        Document newXMLDocument = newDocBuilder.newDocument();

        if (rootElementName != null) {
            // creating the xml root document
            Element rootElement = (namespaceURI != null)
                    ? newXMLDocument.createElementNS(namespaceURI, rootElementName)
                    : newXMLDocument.createElement(rootElementName);
            newXMLDocument.appendChild(rootElement);
        }

        return newXMLDocument;
    }

    /**
     * Read an XML document from {@link File}
     * @param xmlFile
     * @return
     */
    private Document readXMLDocument(File xmlFile) throws Exception {
        // creating a new document builder factory
        DocumentBuilderFactory newDocBuilderFactory = DocumentBuilderFactory.newInstance();

        // creating a new document builder
        DocumentBuilder newDocBuilder = newDocBuilderFactory.newDocumentBuilder();

        // parse document
        return newDocBuilder.parse(xmlFile);
    }

    private Document readXMLStream(InputStream input) throws Exception {
        // creating a new document builder factory
        DocumentBuilderFactory newDocBuilderFactory = DocumentBuilderFactory.newInstance();

        // creating a new document builder
        DocumentBuilder newDocBuilder = newDocBuilderFactory.newDocumentBuilder();

        // parse document
        return newDocBuilder.parse(input);
    }

    public Map<String, Dictionary<String, Object>> importConfigurations(File file) throws Exception {
        BufferedInputStream input = null;
        Map<String, Dictionary<String, Object>> configs = new HashMap<String, Dictionary<String, Object>>();
        try {
            input = new BufferedInputStream(new FileInputStream(file), 5);

            // pre-read data to detect file type
            byte[] test = new byte[5];
            input.mark(5);
            input.read(test);
            input.reset();

            if (new String(test, "UTF-8").equals("<?xml")) {
                // XML Document found
                Document doc = this.readXMLDocument(file);
                Map<String, Dictionary<String, Object>> config = this.importConfigurations(doc);
                configs.putAll(config);
            } else if (new String(test, 0, 2).equals("PK")) {
                // open zip file
                final ZipInputStream zis = new ZipInputStream(input);

                // loop through entries
                ZipEntry ze;
                while ((ze = zis.getNextEntry()) != null) {
                    // skip directories
                    if (ze.isDirectory())
                        continue;

                    // read data into memory
                    long size = ze.getSize();
                    ByteArrayOutputStream bout = (size < 0) ? new ByteArrayOutputStream()
                            : new ByteArrayOutputStream((int) size);
                    IOUtils.copy(zis, bout);
                    bout.close();

                    // read XML
                    ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray());
                    Document doc = this.readXMLStream(bin);
                    bin.close();

                    // parser configuration
                    Map<String, Dictionary<String, Object>> config = this.importConfigurations(doc);
                    configs.putAll(config);
                }

                zis.close();
            } else {
                // Unknown file
                throw new IllegalArgumentException("Unknown file type");
            }
        } finally {
            if (input != null)
                try {
                    input.close();
                } catch (Exception e) {
                    /* ignore this */}
        }

        return configs;
    }

    public Map<String, Dictionary<String, Object>> importConfigurations(Document doc) {
        return this.importConfigurations(new Document[] { doc });
    }

    public Map<String, Dictionary<String, Object>> importConfigurations(Document[] docs) {
        if (docs == null)
            return null;

        Map<String, Dictionary<String, Object>> propsMap = new HashMap<String, Dictionary<String, Object>>();

        // loap through docs
        for (Document doc : docs) {
            Dictionary<String, Object> props = this.importConfiguration(doc);
            String servicePid = (String) props.get(Constants.SERVICE_PID);

            if (servicePid != null) {
                propsMap.put(servicePid, props);
            }
        }

        return propsMap;
    }

    public void exportConfigsAsZip(Map<String, String> pidBundleLocationTupel, File zipFile) throws Exception {
        // convert configs to doc
        Map<String, Document> docs = this.exportConfigsAsDoc(pidBundleLocationTupel);

        // write them into a zip file
        if (docs != null) {
            FileOutputStream fileOutputStream = new FileOutputStream(zipFile);
            ZipOutputStream zos = new ZipOutputStream(fileOutputStream);

            for (Entry<String, Document> doc : docs.entrySet()) {
                ZipEntry ze = new ZipEntry(doc.getKey() + ".xml");
                zos.putNextEntry(ze);
                this.writeToOut(doc.getValue(), zos);
                zos.closeEntry();
            }

            zos.close();
        }
    }

    public Map<String, Document> exportConfigsAsDoc(Map<String, String> pidBundleLocationTupel) throws Exception {
        if (pidBundleLocationTupel == null)
            return null;

        // build result structure
        HashMap<String, Document> docs = new HashMap<String, Document>();
        for (Entry<String, String> entry : pidBundleLocationTupel.entrySet()) {
            String pid = entry.getKey();
            String bundleLocation = entry.getValue();

            // getting the configuration
            Configuration config = this.cm.getConfiguration(pid, bundleLocation);
            if (config != null) {
                Map<String, Document> doc = this.exportConfiguration(config);
                docs.putAll(doc);
            }
        }

        return docs;
    }

    @SuppressWarnings("unchecked")
    public Dictionary<String, Object> importConfiguration(Document doc) {
        if (doc == null)
            return null;

        Dictionary<String, Object> props = new Hashtable<String, Object>();
        try {
            Element configElement = doc.getDocumentElement();

            // getting the service-pid
            Element pidElement = (Element) configElement.getElementsByTagName(Constants.SERVICE_PID).item(0);
            props.put(Constants.SERVICE_PID, pidElement.getFirstChild().getNodeValue());

            // loop through all properties
            Element propsElement = (Element) configElement.getElementsByTagName(ELEM_PROPERTIES).item(0);
            NodeList propsList = propsElement.getElementsByTagName(ELEM_PROPERTY);

            for (int i = 0; i < propsList.getLength(); i++) {
                Element propertyElement = (Element) propsList.item(i);

                Object value = null;
                String key = propertyElement.getAttributes().getNamedItem(ATTRIBUTE_PROPERTY_KEY).getNodeValue();
                String type = propertyElement.getAttributes().getNamedItem(ATTRIB_PROPERTY_TYPE).getNodeValue();

                if (type.endsWith("[]") || type.equals(Vector.class.getSimpleName())) {
                    Element valueElements = (Element) propertyElement.getElementsByTagName(ELEM_VALUES).item(0);
                    NodeList valueElementList = valueElements.getElementsByTagName(ELEM_VALUE);

                    if (type.endsWith("[]")) {
                        // get type class
                        Class clazz = NAMELOOKUP.get(type.substring(0, type.length() - 2));

                        // create a new array
                        value = Array.newInstance(clazz, valueElementList.getLength());
                    } else {
                        // create a new vector
                        value = new Vector();
                    }

                    // append all values to the array/vector
                    for (int j = 0; j < valueElementList.getLength(); j++) {
                        Element valueElement = (Element) valueElementList.item(j);
                        Object valueObj = this.valueOf(type, valueElement);

                        if (type.endsWith("[]")) {
                            Array.set(value, j, valueObj);
                        } else {
                            ((Vector<Object>) value).add(valueObj);
                        }
                    }
                } else {
                    Element valueElement = (Element) propertyElement.getElementsByTagName(ELEM_VALUE).item(0);

                    // get concrete value
                    value = this.valueOf(type, valueElement);
                }

                // add value
                props.put(key, value);
            }

        } catch (Exception e) {
            e.printStackTrace();
        }

        return props;
    }

    Object valueOf(String type, Element valueElement) throws SecurityException, NoSuchMethodException,
            IllegalArgumentException, DOMException, IllegalAccessException, InvocationTargetException {
        Class<?> clazz = null;
        if (type.endsWith("[]")) {
            clazz = WRAPPERS.get(type.substring(0, type.length() - 2));
        } else {
            clazz = NAMELOOKUP.get(type);
        }

        String valueElementString = valueElement.getFirstChild() == null ? ""
                : valueElement.getFirstChild().getNodeValue();

        // get parser-method
        Method valueOf = null;
        try {
            valueOf = clazz.getMethod("valueOf", String.class);
        } catch (NoSuchMethodException e) {
            valueOf = clazz.getMethod("valueOf", Object.class);
        }

        // get concrete value
        return valueOf.invoke(null, valueElementString);
    }

    @SuppressWarnings("unchecked")
    Map<String, Document> exportConfiguration(Configuration config) throws ParserConfigurationException {
        if (config == null)
            return Collections.emptyMap();
        else if (config.getPid() == null)
            return Collections.emptyMap();
        else if (config.getProperties() == null)
            return Collections.emptyMap();

        // create a new XML document
        Document doc = this.createNewXMLDocument(ELEM_CONFIG, "http://www.paxle.net/config");
        Element root = doc.getDocumentElement();

        // adding the pid
        Element pidElem = doc.createElement(Constants.SERVICE_PID);
        pidElem.appendChild(doc.createTextNode(config.getPid()));
        root.appendChild(pidElem);

        // <properties>
        Element propsElem = doc.createElement(ELEM_PROPERTIES);
        root.appendChild(propsElem);

        // loop through all parameters
        Dictionary<String, Object> props = config.getProperties();
        Enumeration<String> keys = props.keys();
        while (keys.hasMoreElements()) {
            final String key = keys.nextElement();
            final Object value = props.get(key);
            if (key.equalsIgnoreCase(Constants.SERVICE_PID))
                continue;
            if (value == null)
                continue; // TODO we should set nil instead

            // <property key="xxx" type="xxx">
            Element propertyElement = doc.createElement(ELEM_PROPERTY);
            propertyElement.setAttribute(ATTRIBUTE_PROPERTY_KEY, key);
            propertyElement.setAttribute(ATTRIB_PROPERTY_TYPE, value.getClass().getSimpleName());
            propsElem.appendChild(propertyElement);

            if (value.getClass().isArray() || value instanceof Vector) {
                Element valuesElem = doc.createElement(ELEM_VALUES);
                propertyElement.appendChild(valuesElem);

                // <values>
                int length = (value.getClass().isArray()) ? Array.getLength(value) : ((Vector) value).size();
                for (int i = 0; i < length; i++) {
                    // <value>
                    Object valueItem = (value.getClass().isArray()) ? Array.get(value, i) : ((Vector) value).get(i);
                    Element valueElem = doc.createElement(ELEM_VALUE);
                    valueElem.appendChild(doc.createTextNode(valueItem.toString()));
                    valuesElem.appendChild(valueElem);
                    // </value>
                }
                // </values>
            } else {
                // <value>
                Element valueElem = doc.createElement(ELEM_VALUE);
                valueElem.appendChild(doc.createTextNode(value.toString()));
                propertyElement.appendChild(valueElem);
                // </value>
            }
            // </property>
        }
        // </properties>

        HashMap<String, Document> result = new HashMap<String, Document>();
        result.put(config.getPid(), doc);
        return result;
    }

    private void writeToOut(Document doc, OutputStream out)
            throws TransformerFactoryConfigurationError, TransformerException {
        // Prepare the DOM document for writing
        Source source = new DOMSource(doc);

        // Prepare the output file
        Result result = new StreamResult(out);

        // Write the DOM document to the file
        Transformer xformer = TransformerFactory.newInstance().newTransformer();
        xformer.transform(source, result);
    }
}