net.contextfw.web.application.component.DOMBuilder.java Source code

Java tutorial

Introduction

Here is the source code for net.contextfw.web.application.component.DOMBuilder.java

Source

/**
 * Copyright 2010 Marko Lavikainen
 *
 * Licensed 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 net.contextfw.web.application.component;

import java.util.ArrayList;
import java.util.Collection;
import java.util.List;

import net.contextfw.web.application.WebApplicationException;
import net.contextfw.web.application.internal.component.ComponentBuilder;
import net.contextfw.web.application.internal.configuration.KeyValue;
import net.contextfw.web.application.serialize.AttributeSerializer;

import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.Node;

/**
 * This class is responsible for actually building the DOM-tree during rendering phase.
 * 
 * <p>
 *  DOMBuilder can be accessed by using {@link CustomBuild} on component method.
 * </p>
 */
public final class DOMBuilder {

    private final Document document;
    private final AttributeSerializer<Object> serializer;
    private final Element root;
    private final ComponentBuilder componentBuilder;

    public DOMBuilder(String rootName, AttributeSerializer<Object> serializer, ComponentBuilder componentBuilder,
            Collection<KeyValue<String, String>> namespaces) {

        this.serializer = serializer;
        root = DocumentHelper.createElement(rootName);
        document = DocumentHelper.createDocument();
        document.setRootElement(root);
        for (KeyValue<String, String> namespace : namespaces) {
            root.add(DocumentHelper.createNamespace(namespace.getKey(), namespace.getValue()));
        }

        this.componentBuilder = componentBuilder;
    }

    private DOMBuilder(Document document, Element root, AttributeSerializer<Object> serializer,
            ComponentBuilder componentBuilder) {
        this.document = document;
        this.root = root;
        this.serializer = serializer;
        this.componentBuilder = componentBuilder;
    }

    //    public DOMBuilder child(String elementName, CSimpleElement element) {
    //        descend(elementName).child(element);
    //        return this;
    //    }

    /**
     * Adds an attribute to current element 
     * 
     * @param name
     *      Name of the attribute
     * @param value
     *      Value of the attribute. Is converted to String by using proper {@AttributeSerializer}.
     * @return
     *      Current DOMBuilder
     */
    public DOMBuilder attr(String name, Object value) {
        root.addAttribute(name, serializer.serialize(value));
        return this;
    }

    /**
     * Adds a child to this DOM-tree.
     * 
     * <p>
     *  This method can be used to add pre-existing DOM-trees to this DOM-tree.
     * </p>
     * 
     * @param element
     *    The element to be added
     * @return
     *    Current DOMBuilder
     */
    public DOMBuilder child(Node element) {
        root.add(element);
        return this;
    }

    /**
     * Adds a child to the DOM-tree
     * 
     * <p>
     *  This method is used to add Buildable-classes and Components into the DOM-tree.
     *  If object is not buildable, it will be run through <code>AttributeSerializer</code> 
     *  and added as text.
     * </p>
     * 
     * <h3>Buildins</h3>
     * 
     * <p>
     *  Buildin is similar concept to mixin.It is possible to add more objects to same DOM-tree. 
     *  The attributes and elements from each buildin are added as they were part of the
     *  original object. The wrapping classes are ignored for buildins.  
     * </p>
     * 
     * 
     * @param object
     *  The Object o be added
     * @param buildins
     *  The buildins to be added
     * @return
     *  Current DOMBuilder
     */
    public DOMBuilder child(Object object, Object... buildins) {
        componentBuilder.build(this, object, buildins);
        return this;
    }

    /**
     * Gets the root element where this DOMBuilder is at.
     * @return
     *  The current root element
     */
    public Element getCurrentRoot() {
        return root;
    }

    /**
     * Finds a path from current DOM-tree and returns a new DOMBuilder for it.
     * 
     * <p>
     *  This method is useful when DOM-tree has been built into to some point
     *  and needs to be changed.
     * </p>
     * 
     * @param xpath
     *  The xpath
     * @return
     *  new DOMBuilder or <code>null</code> if no path is matched
     */
    public DOMBuilder findByXPath(String xpath) {
        Element element = (Element) root.selectSingleNode(xpath);
        if (element != null) {
            return new DOMBuilder(document, element, serializer, componentBuilder);
        } else {
            return null;
        }
    }

    /**
     * Gets a path from current DOM-tree and returns a new DOMBuilder for it.
     * 
     * <p>
     *  See documentation from <code>findXPath</code>
     * </p>
     * 
     * @param xpath
     *  The xpath
     * @return
     *  new DOMBuilder or throws exception if no path is matched
     */

    public DOMBuilder getByXPath(String xpath) {
        DOMBuilder b = findByXPath(xpath);
        if (b == null) {
            throw new WebApplicationException("Element for xpath '" + xpath + "' was not found");
        }
        return b;
    }

    /**
     * Lists all paths from current DOM-tree and returns a new DOMBuilder for it.
     * 
     * <p>
     *  See documentation from <code>findXPath</code>
     * </p>
     * 
     * @param xpath
     *  The xpath
     * @return
     *  List of found DOMBuilders or empty list if nothing is found.
     */
    public List<DOMBuilder> listByXPath(String xpath) {
        List<DOMBuilder> rv = new ArrayList<DOMBuilder>();
        @SuppressWarnings("unchecked")
        List<Element> elements = (List<Element>) root.selectNodes(xpath);
        for (Element element : elements) {
            rv.add(new DOMBuilder(document, element, serializer, componentBuilder));
        }
        return rv;
    }

    /**
     * Returns the entire document of the DOM-tree
     */
    public Document toDocument() {
        return document;
    }

    /**
     * Adds text element to the dom-tree.
     * 
     * <p>
     *  The given argument is run through <code>AttributeSerializer</code>.
     * </p>
     * @param value
     * @return
     */
    public DOMBuilder text(Object value) {
        if (value != null) {
            root.addText(serializer.serialize(value));
        }
        return this;
    }

    /**
     * Adds a new child element and retuns a new DOMBuilder using the child as a root.
     *  
     * @param elementName
     *   Element name
     * @return
     *   New DOMBuilder using the created element as a root.
     */
    public DOMBuilder descend(String elementName) {
        return new DOMBuilder(document, root.addElement(elementName), serializer, componentBuilder);
    }
}