org.csstudio.utility.treemodel.builder.XmlFileContentModelBuilder.java Source code

Java tutorial

Introduction

Here is the source code for org.csstudio.utility.treemodel.builder.XmlFileContentModelBuilder.java

Source

/*
 * Copyright (c) 2010 Stiftung Deutsches Elektronen-Synchrotron,
 * Member of the Helmholtz Association, (DESY), HAMBURG, GERMANY.
 *
 * THIS SOFTWARE IS PROVIDED UNDER THIS LICENSE ON AN "../AS IS" BASIS.
 * WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED
 * TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR PARTICULAR PURPOSE AND
 * NON-INFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
 * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR
 * THE USE OR OTHER DEALINGS IN THE SOFTWARE. SHOULD THE SOFTWARE PROVE DEFECTIVE
 * IN ANY RESPECT, THE USER ASSUMES THE COST OF ANY NECESSARY SERVICING, REPAIR OR
 * CORRECTION. THIS DISCLAIMER OF WARRANTY CONSTITUTES AN ESSENTIAL PART OF THIS LICENSE.
 * NO USE OF ANY SOFTWARE IS AUTHORIZED HEREUNDER EXCEPT UNDER THIS DISCLAIMER.
 * DESY HAS NO OBLIGATION TO PROVIDE MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS,
 * OR MODIFICATIONS.
 * THE FULL LICENSE SPECIFYING FOR THE SOFTWARE THE REDISTRIBUTION, MODIFICATION,
 * USAGE AND OTHER RIGHTS AND OBLIGATIONS IS INCLUDED WITH THE DISTRIBUTION OF THIS
 * PROJECT IN THE FILE LICENSE.HTML. IF THE LICENSE IS NOT INCLUDED YOU MAY FIND A COPY
 * AT HTTP://WWW.DESY.DE/LEGAL/LICENSE.HTM
 *
 * $Id$
 */
package org.csstudio.utility.treemodel.builder;

import java.io.DataInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;

import javax.naming.InvalidNameException;
import javax.naming.directory.Attributes;
import javax.naming.directory.BasicAttributes;
import javax.naming.ldap.LdapName;
import javax.naming.ldap.Rdn;

import org.csstudio.utility.treemodel.ContentModel;
import org.csstudio.utility.treemodel.CreateContentModelException;
import org.csstudio.utility.treemodel.INodeComponent;
import org.csstudio.utility.treemodel.ISubtreeNodeComponent;
import org.csstudio.utility.treemodel.ITreeNodeConfiguration;
import org.csstudio.utility.treemodel.TreeNodeComponent;
import org.jdom.Attribute;
import org.jdom.Document;
import org.jdom.Element;
import org.jdom.JDOMException;
import org.jdom.filter.ElementFilter;
import org.jdom.input.SAXBuilder;

import com.google.common.collect.ImmutableSet;

/**
 * Builds a content model from an xml file.
 *
 * @author bknerr
 * @author $Author$
 * @version $Revision$
 * @since 21.05.2010
 * @param <T> the object class type for which a tree shall be created
 */
public class XmlFileContentModelBuilder<T extends Enum<T> & ITreeNodeConfiguration<T>>
        extends AbstractContentModelBuilder<T> {

    private final T _virtualConfRoot;
    private final T _root;
    private final InputStream _inStream;

    /**
     * Constructor.
     */
    public XmlFileContentModelBuilder(final T virtualConfigurationRoot, final InputStream stream) {
        _virtualConfRoot = virtualConfigurationRoot;
        _root = _virtualConfRoot.getNestedContainerTypes().iterator().next();
        _inStream = stream;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    protected final ContentModel<T> createContentModel() throws CreateContentModelException {
        try {
            // Convert our input stream to a dataInputStream
            final DataInputStream in = new DataInputStream(_inStream);

            final SAXBuilder builder = new SAXBuilder(true);
            final Document doc = builder.build(in);

            return createContentModelFromFile(doc, _virtualConfRoot, _root);

        } catch (final FileNotFoundException e) {
            throw new CreateContentModelException("File not found with exception " + e.getMessage(), e);
        } catch (final JDOMException e) {
            throw new CreateContentModelException("File contains parsing errors. " + e.getCause().getMessage(), e);
        } catch (final IOException e) {
            throw new CreateContentModelException("File could not be parsed due to I/O error.", e);
        }
    }

    /**
     * @param doc the xml document model
     * @param virtualConfRoot
     * @param root
     * @throws CreateContentModelException if Rdn or LdapName could not be constructed
     */
    private ContentModel<T> createContentModelFromFile(final Document doc, final T virtualConfRoot, final T root)
            throws CreateContentModelException {

        final Element xmlRootElement = doc.getRootElement();

        ContentModel<T> model = null;
        final String elementName = xmlRootElement.getName();

        if (!root.getNodeTypeName().equals(elementName)) {
            throw new CreateContentModelException(
                    "Root element does not match node type name in enum " + root.name(), null);
        }

        model = new ContentModel<T>(virtualConfRoot);

        processElement(model, xmlRootElement, model.getVirtualRoot(), virtualConfRoot);

        return model;
    }

    /**
     * Get direct 'structural' children that are those contained in <ecoms> <
     * @param element
     * @return
     */
    @SuppressWarnings("unchecked")
    private List<Element> getChildrenElements(final Element element) {
        final List<Element> children = element.getContent(new ElementFilter());
        return children;
    }

    /**
     * Recursive
     * @param model
     * @param element
     * @param virtualRoot
     * @param iLdapTreeComponent
     * @throws CreateContentModelException if Rdn or LdapName could not be constructed
     */
    private void processElement(final ContentModel<T> model, final Element element,
            final ISubtreeNodeComponent<T> ldapParent, final T virtualRoot) throws CreateContentModelException {

        final String type = element.getName();
        final T oc = virtualRoot.getNodeTypeByNodeTypeName(type);
        final String name = element.getAttributeValue("name");

        final List<Rdn> rdns = new ArrayList<Rdn>(ldapParent.getLdapName().getRdns());
        try {
            rdns.add(new Rdn(type, name));
        } catch (final InvalidNameException e) {
            throw new CreateContentModelException(
                    "Rdn for type=" + type + " and name=" + name + " could not be constructed.", e);
        }
        final LdapName fullName = new LdapName(rdns);

        if (model.getByTypeAndLdapName(oc, fullName) == null) {

            final Attributes attributes = extractAttributes(element, oc.getAttributes());

            ISubtreeNodeComponent<T> newLdapChild;
            try {
                newLdapChild = new TreeNodeComponent<T>(name, oc, ldapParent, attributes, fullName);
            } catch (final InvalidNameException e) {
                throw new CreateContentModelException("Component model with LdapName " + fullName
                        + " could not be constructed. Invalid LDAP name.", e);

            }
            model.addChild(ldapParent, newLdapChild);
        }
        final INodeComponent<T> ldapComponent = model.getByTypeAndLdapName(oc, fullName);

        final List<Element> children = getChildrenElements(element);

        // cycle through all immediate elements under the rootElement
        for (final Element child : children) {
            processElement(model, child, (ISubtreeNodeComponent<T>) ldapComponent, virtualRoot);
        }
    }

    @SuppressWarnings("unchecked")
    private Attributes extractAttributes(final Element element, final ImmutableSet<String> attributes) {

        final Attributes treeNodeAttributes = new BasicAttributes();

        final List<Attribute> xmlAttributes = element.getAttributes();

        for (final Attribute xmlAttribute : xmlAttributes) {
            final String attrName = xmlAttribute.getName();
            if (attributes.contains(attrName)) {
                treeNodeAttributes.put(attrName, xmlAttribute.getValue());
            }
        }

        return treeNodeAttributes;
    }

}