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

org.enhydra.xml.xmlc.metadata.MetaDataElement Maven / Gradle / Ivy

The newest version!
/*
 * Enhydra Java Application Server Project
 * 
 * The contents of this file are subject to the Enhydra Public License
 * Version 1.1 (the "License"); you may not use this file except in
 * compliance with the License. You may obtain a copy of the License on
 * the Enhydra web site ( http://www.enhydra.org/ ).
 * 
 * Software distributed under the License is distributed on an "AS IS"
 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See 
 * the License for the specific terms governing rights and limitations
 * under the License.
 * 
 * The Initial Developer of the Enhydra Application Server is Lutris
 * Technologies, Inc. The Enhydra Application Server and portions created
 * by Lutris Technologies, Inc. are Copyright Lutris Technologies, Inc.
 * All Rights Reserved.
 * 
 * Contributor(s):
 * 
 * $Id: MetaDataElement.java,v 1.3 2005/01/26 08:29:24 jkjome Exp $
 */

package org.enhydra.xml.xmlc.metadata;

import java.lang.reflect.Array;
import java.util.StringTokenizer;

import org.enhydra.apache.xerces.dom.DocumentImpl;
import org.enhydra.apache.xerces.dom.ElementImpl;
import org.enhydra.xml.xmlc.XMLCException;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.Node;

/**
 * Base DOM class for all XMLC metadata element classes.  This provides
 * methods to implement attribute and child lookup
 */
public class MetaDataElement extends ElementImpl {
    /**
     * An empty string array.
     */
    private static final String[] emptyStringArray = new String[0];

    /**
     * This is the change counter of the object taken when it was
     * marked as being allDefaults.  This is used to determine if
     * a node as any custom values in or are only defaults.
     * FIXME: implement
     */

    /**
     * Constructor.
     */
    protected MetaDataElement(Document ownerDoc,
                              String name) {
    	super((DocumentImpl)ownerDoc, name);
    }

    /**
     * Get the metadata document object.
     */
    public MetaDataDocument getDocument() {
        return (MetaDataDocument)getOwnerDocument();
    }

    /**
     * Get the metadata root element object.
     */
    public MetaData getMetaData() {
        return getDocument().getMetaData();
    }

    // FIXME: the mechanism for defaulting children and the creation
    // on the fly of needed children may have some undesriable
    // side affects (if one child updates another).   What really
    // needs to happen is that the defaulted child are all created
    // initialally and marked as defaulted.

    /**
     * Locate a child element given its class.  This is used when only
     * a single instance of an element can be a child.
     *
     * @return The first child elment of the specified class.
     */
    protected MetaDataElement getCreateChild(Class elementClass) {
        Node child = getChild(elementClass);
        if (child == null) {
            // Need to create
            child = getDocument().createElement(elementClass);
            appendChild(child);
        }
        return (MetaDataElement)child;
    }

    /**
     * Locate a child element given its class, creating if if it doesn't
     * exist.
     *
     * @return The first child elment of the specified class or null
     * in no child element implements the class.
     */
    protected MetaDataElement getChild(Class elementClass) {
        for (Node child = getFirstChild(); child != null;
             child = child.getNextSibling()) {
            if (elementClass.isInstance(child)) {
                return (MetaDataElement)child;
            }
        }
        return null;
    }

    /**
     * Add or replace a child element.  This is used when only
     * a single instance of an element can be a child. 
     */
    protected void setChild(MetaDataElement element) {
        Node current = getChild(element.getClass());
        if (current == null) {
            appendChild(element);
        } else {
            replaceChild(element, current);
        }
    }

    /**
     * Delete a child element given its class.  This is used when only
     * a single instance of an element can be a child.  If the element
     * does not exist, the call is ignored.
     */
    protected void deleteChild(Class elementClass) {
        Node current = getChild(elementClass.getClass());
        if (current != null) {
            removeChild(current);
        }
    }

    /**
     * Get all children of the specified class.
     */
    protected Node[] getChildren(Class elementClass) {
        // Count
        int numChildren = 0;
        for (Node child = getFirstChild(); child != null;
             child = child.getNextSibling()) {
            if (elementClass.isInstance(child)) {
                numChildren++;
            }
        }
        
        // Create array of the children
        Node[] children = (Node[])Array.newInstance(elementClass, numChildren);
        int idx = 0;
        for (Node child = getFirstChild();
             (child != null) && (idx < numChildren);
             child = child.getNextSibling()) {
            if (elementClass.isInstance(child)) {
                children[idx++] = child;
            }
        }
        return children;
    }


    /**
     * Determine if an attribute is specified.
     */
    protected boolean isAttributeSpecified(String attrName) {
        Attr attr = getAttributeNode(attrName);
        if (attr == null) {
            return false;
        } else {
            return attr.getSpecified();
        }
    }
    

    /**
     * Get the value of a boolean object attribute.  Boolean objects
     * are used ot value that can be true, false, or unspecified.
     * 
     * @param attrName The name of the attribute.
     * @return The value of the object, or null if it doesn't exists.
     */
    protected Boolean getBooleanObjectAttribute(String attrName) {
        String attrValue = getAttributeNull(attrName);
        if (attrValue == null) {
            return null;
        } else {
            if (attrValue.equalsIgnoreCase("true")
                || attrValue.equalsIgnoreCase("yes")) {
                return Boolean.TRUE;
            } else {
                return Boolean.FALSE;
            }
        }
    }

    /**
     * Set or delete the value of a boolean object attribute.  Boolean objects
     * are used for value that can be true, false, or unspecified.
     *
     * @param attrName The name of the attribute.
     * @param value The value of the attribute, or null to delete.
     */
    protected void setBooleanObjectAttribute(String attrName,
                                             Boolean value) {
        if (value == null) {
            removeAttribute(attrName);
        } else {
            setAttribute(attrName, value.toString());
        }
    }

    /**
     * Get the value of a boolean primitive attribute.
     * 
     * @param attrName The name of the attribute.
     * @param defaultValue Value to return if attribute doesn't exist.
     * @return The value of the object.
     */
    protected boolean getBooleanAttribute(String attrName,
                                          boolean defaultValue) {
        String attrValue = getAttributeNull(attrName);
        if (attrValue == null) {
            return defaultValue;
        } else {
            if (attrValue.equalsIgnoreCase("true")
                || attrValue.equalsIgnoreCase("yes")) {
                return true;
            } else {
                return false;
            }
        }
    }

    /**
     * Get the value of a boolean primitive attribute, with the default
     * being false.
     * 
     * @param attrName The name of the attribute.
     * @return The value of the object.
     */
    protected boolean getBooleanAttribute(String attrName) {
        return getBooleanAttribute(attrName, false);
    }

    /**
     * Set the value of a boolean primitive attribute.
     *
     * @param attrName The name of the attribute.
     * @param value The value of the attribute.
     * @param defaultValue The default value for the attribute.
     *  If the value matches the default value, the attribute
     *  is removed rather than set.  This must match the default
     *  passed to get.
     */
    protected void setBooleanAttribute(String attrName,
                                       boolean value,
                                       boolean defaultValue) {
        if (value == defaultValue) {
            removeAttribute(attrName);
        } else {
            setAttribute(attrName, (value ? "true" : "false"));
        }
    }

    /**
     * Set the value of a boolean primitive attribute, with a
     * default of false.
     *
     * @param attrName The name of the attribute.
     * @param value The value of the attribute.
     */
    protected void setBooleanAttribute(String attrName,
                                       boolean value) {
        setBooleanAttribute(attrName, value, false);
    }

    /**
     * Get the value of a string attribute, or null if its not defined.
     */
    protected String getAttributeNull(String attrName) {
        Attr attr = getAttributeNode(attrName);
        if (attr == null) {
            return null;
        } else {
            return attr.getValue();
        }
    }

    /**
     * Set or remove a string attribute.  If the value is null, it is removed.
     */
    protected void setRemoveAttribute(String attrName,
                                      String value) {
        if (value == null) {
            removeAttribute(attrName);
        } else {
            setAttribute(attrName, value);
        }
    }

    /**
     * Get the value of a String array attribute.
     */
    protected String[] getStringArrayAttribute(String attrName) {
        String value = getAttributeNull(attrName);
        String[] values;
        if (value == null) {
            values = emptyStringArray;
        } else {
            // Parse into tokens
            StringTokenizer tokenizer = new StringTokenizer(value);
            values = new String[tokenizer.countTokens()];
            for (int idx = 0; idx < values.length; idx++) {
                values[idx] = tokenizer.nextToken();
            }
        }
        return values;
    }

    /**
     * Set or remove a String array attribute.  If the values is null, it is
     * removed.
     */
    protected void setRemoveStringArrayAttribute(String attrName,
                                                 String[] values) {
        if (values == null) {
            removeAttribute(attrName);
        } else {
            // Join into a string.
            StringBuffer value = new StringBuffer();
            for (int idx = 0; idx < values.length; idx++) {
                if (idx > 0) {
                    value.append(' ');
                }
                value.append(values[idx]);
            }
            setAttribute(attrName, value.toString());
        }
    }

    /**
     * Add a addtribute to a String array attribute.
     */
    protected void addStringArrayAttribute(String attrName,
                                           String value) {
        String currentValue = getAttributeNull(attrName);
        if (currentValue == null) {
            currentValue = "";
        }
        StringBuffer currentBuf = new StringBuffer(currentValue);
        if (currentBuf.length() > 0) {
            currentBuf.append(' ');
        }
        currentBuf.append(value);
        setAttribute(attrName, currentBuf.toString());
    }

    /**
     * Complete modifications to DOM.  This method is called on all elements
     * in the DOM in a bottom-first manner once a read or set of modifications
     * are complete.  Elements should override this method if they need to do
     * any processing.  Normally, they will call super.completeModifications()
     * first to traverse the subtree, then do their work. This is also useful
     * in report errors upfront rather than at access time.
     */
    protected void completeModifications() throws XMLCException {
        for (Node child = getFirstChild();
             child != null;
             child = child.getNextSibling()) {
            if (child instanceof MetaDataElement) {
                ((MetaDataElement)child).completeModifications();
            }
        }
    }

    /**
     * Merge attributes from another element into this element,
     * with the other element overriding current attributes.
     */
    protected void mergeAttributes(Element srcElement) {
        Document doc = getOwnerDocument();
        NamedNodeMap attrs = srcElement.getAttributes();
        int len = attrs.getLength();
        for (int idx = 0; idx < len; idx++) {
            Attr attr = (Attr)attrs.item(idx);
            if (attr.getSpecified()) {
                setAttributeNode((Attr)doc.importNode(attr, true));
            }
        }
    }
    
    /**
     * Merge a specified singleton child node, if it exists, otherwise
     * clone it (if it exists).
     */
    protected void mergeSingletonChild(Class childClass,
                                       MetaDataElement srcElement) {
        MetaDataElement srcChild = srcElement.getChild(childClass);
        if (srcChild != null) {
            MetaDataElement destChild = getChild(childClass);
            if (destChild != null) {
                destChild.mergeElement(srcChild);
            } else {
                appendChild(getOwnerDocument().importNode(srcChild, true));
            }
        }
    }
    
    /**
     * Merge another element into this element.  This merges the attributes,
     * the children and then appends clones the children. This
     * maybe overriden.  In particular, calling mergeElement to 
     * merge children is desired if there should only be one child of 
     * a particular type.
     */
    protected void mergeElement(MetaDataElement srcElement) {
        mergeAttributes(srcElement);

        Document document = getOwnerDocument();
        for (Node child = srcElement.getFirstChild();
             child != null;
             child = child.getNextSibling()) {
            appendChild(document.importNode(child, true));
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy