org.onehippo.forge.content.pojo.model.ContentNode.java Source code

Java tutorial

Introduction

Here is the source code for org.onehippo.forge.content.pojo.model.ContentNode.java

Source

/*
 *  Copyright 2015-2015 Hippo B.V. (http://www.onehippo.com)
 *
 *  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 org.onehippo.forge.content.pojo.model;

import java.util.LinkedHashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;

import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlElementWrapper;
import javax.xml.bind.annotation.XmlElements;
import javax.xml.bind.annotation.XmlRootElement;
import javax.xml.bind.annotation.XmlTransient;
import javax.xml.bind.annotation.XmlType;

import org.apache.commons.collections.ListUtils;
import org.apache.commons.collections.SetUtils;
import org.apache.commons.jxpath.JXPathContext;
import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.apache.commons.lang.builder.ToStringBuilder;

import com.fasterxml.jackson.annotation.JsonIgnore;

/**
 * Serializable POJO abstraction for content node (e.g, {@link javax.jcr.Node}).
 */
@XmlRootElement(name = "node")
@XmlType(propOrder = { "primaryType", "mixinTypes", "properties", "nodes" })
public class ContentNode extends ContentItem {

    private static final long serialVersionUID = 1L;

    /**
     * Primary content node type.
     */
    private String primaryType;

    /**
     * Mixin content node types.
     */
    private Set<String> mixinTypes;

    /**
     * Content properties embedded in this content node.
     */
    private List<ContentProperty> properties;

    /**
     * Child content nodes embedded in this content node.
     */
    private List<ContentNode> nodes;

    /**
     * Default constructor for deserialization.
     */
    public ContentNode() {
        super();
    }

    /**
     * Constructor with content node name and content node primary type.
     * @param name content node name
     * @param primaryType content node primary type name
     */
    public ContentNode(String name, String primaryType) {
        super(name);
        this.primaryType = primaryType;
    }

    /**
     * Transient or ignore-able (in JSON marshaling) property, always returning true.
     */
    @JsonIgnore
    @XmlTransient
    public boolean isNode() {
        return true;
    }

    /**
     * Returns content node primary type name.
     * @return content node primary type name
     */
    @XmlElement(name = "primaryType")
    public String getPrimaryType() {
        return primaryType;
    }

    /**
     * Sets content node primary type name.
     * @param primaryType content node primary type name
     */
    public void setPrimaryType(String primaryType) {
        this.primaryType = primaryType;
    }

    /**
     * Returns a non-null set of content node mixin type names.
     * @return a non-null set of content node mixin type names
     */
    @XmlElementWrapper(name = "mixinTypes")
    @XmlElements(@XmlElement(name = "mixinType"))
    public Set<String> getMixinTypes() {
        if (mixinTypes == null) {
            mixinTypes = new LinkedHashSet<>();
        }

        return mixinTypes;
    }

    /**
     * Adds a mixin content node type to this content node.
     * @param mixinType mixin content node type name
     */
    public void addMixinType(String mixinType) {
        getMixinTypes().add(mixinType);
    }

    /**
     * Removes a mixin content node type name from this content node.
     * @param mixinType a mixin content node type name
     */
    public void removeMixinType(String mixinType) {
        if (mixinTypes != null && !mixinTypes.isEmpty()) {
            mixinTypes.remove(mixinType);
        }
    }

    /**
     * Returns a non-null list of embedded content properties in this content node.
     * @return a non-null list of embedded content properties in this content node
     */
    @XmlElementWrapper(name = "properties")
    @XmlElements(@XmlElement(name = "property"))
    public List<ContentProperty> getProperties() {
        if (properties == null) {
            properties = new LinkedList<>();
        }

        return properties;
    }

    /**
     * Returns true if this content node has a content property named by the {@code name}.
     * @param name content property name
     * @return true if this content node has a content property named by the {@code name}
     */
    public boolean hasProperty(String name) {
        return getProperty(name) != null;
    }

    /**
     * Finds and return the content property by the {@code name}.
     * @param name content property name
     * @return the content property by the {@code name}
     */
    public ContentProperty getProperty(String name) {
        if (properties != null) {
            for (ContentProperty contentProp : properties) {
                if (contentProp.getName().equals(name)) {
                    return contentProp;
                }
            }
        }

        return null;
    }

    /**
     * Sets a content property by {@link ContentProperty} instance.
     * @param property content property
     */
    public void setProperty(ContentProperty property) {
        if (!getProperties().isEmpty()) {
            int index = 0;

            for (ContentProperty contentProp : getProperties()) {
                if (contentProp.getName().equals(property.getName())) {
                    properties.set(index, property);
                    return;
                }
                ++index;
            }
        }

        getProperties().add(property);
    }

    /**
     * Sets a {@link ContentPropertyType#STRING} typed content property having the {@code name} to the {@code value}. 
     * @param name content property name
     * @param value string content property value
     */
    public void setProperty(String name, String value) {
        setProperty(name, ContentPropertyType.STRING, value);
    }

    /**
     * Sets a content property of {@code type} to the stringified {@code value}.
     * @param name content property name
     * @param type content property type
     * @param value stringified content property value
     */
    public void setProperty(String name, ContentPropertyType type, String value) {
        ContentProperty prop = new ContentProperty(name, type);
        prop.setValue(value);
        setProperty(prop);
    }

    /**
     * Sets a content property of a string array type to {@code values}.
     * @param name content property name
     * @param values string array of property values
     */
    public void setProperty(String name, String[] values) {
        setProperty(name, ContentPropertyType.STRING, values);
    }

    /**
     * Sets a content property having {@code name} of {@code type} to the stringified {@code values}.
     * @param name content property name
     * @param type content property type
     * @param values stringified property value array
     */
    public void setProperty(String name, ContentPropertyType type, String[] values) {
        ContentProperty prop = new ContentProperty(name, type, true);

        if (values != null) {
            for (String value : values) {
                prop.addValue(value);
            }
        }

        setProperty(prop);
    }

    /**
     * Sets a property having {@code name} to the given {@link BinaryValue} object.
     * @param name content property name
     * @param binaryValue {@link BinaryValue} object
     */
    public void setProperty(String name, BinaryValue binaryValue) {
        ContentProperty prop = new ContentProperty(name, ContentPropertyType.BINARY);
        prop.setValue(binaryValue);
        setProperty(prop);
    }

    /**
     * Sets a property having {@code name} to the given array of {@link BinaryValue} objects.
     * @param name content property name
     * @param binaryValues array of {@link BinaryValue} objects
     */
    public void setProperty(String name, BinaryValue[] binaryValues) {
        ContentProperty prop = new ContentProperty(name, ContentPropertyType.BINARY, true);

        if (binaryValues != null) {
            for (BinaryValue binaryValue : binaryValues) {
                prop.addValue(binaryValue);
            }
        }

        setProperty(prop);
    }

    /**
     * Returns a non-null child content nodes.
     * @return a non-null child content nodes
     */
    @XmlElementWrapper(name = "nodes")
    @XmlElements(@XmlElement(name = "node"))
    public List<ContentNode> getNodes() {
        if (nodes == null) {
            nodes = new LinkedList<>();
        }

        return nodes;
    }

    /**
     * Returns true if this content node has any child content node having the {@code name}.
     * @param name child content node name
     * @return true if this content node has any child content node having the {@code name}
     */
    public boolean hasNode(String name) {
        return getNode(name) != null;
    }

    /**
     * Returns the child content node having the {@code name} if existing. Null otherwise.
     * @param name child content node name
     * @return the child content node having the {@code name} if existing. Null otherwise.
     */
    public ContentNode getNode(String name) {
        if (nodes != null) {
            for (ContentNode node : nodes) {
                if (node.getName().equals(name)) {
                    return node;
                }
            }
        }

        return null;
    }

    /**
     * Adds a child content node.
     * @param node child content node
     */
    public void addNode(ContentNode node) {
        getNodes().add(node);
    }

    /**
     * Queries and returns single content node from this base content node by
     * the <a href="https://commons.apache.org/proper/commons-jxpath/">JXPath</a> expression ({@code jxpath}).
     * @param jxpath <a href="https://commons.apache.org/proper/commons-jxpath/">JXPath</a> expression
     * @return single content node from this base content node from the JXPath query execution
     */
    public ContentNode queryNodeByXPath(String jxpath) {
        return (ContentNode) queryObjectByXPath(jxpath);
    }

    /**
     * Queries and returns single content property from this base content node by
     * the <a href="https://commons.apache.org/proper/commons-jxpath/">JXPath</a> expression ({@code jxpath}).
     * @param jxpath <a href="https://commons.apache.org/proper/commons-jxpath/">JXPath</a> expression
     * @return single content property from this base content node from the JXPath query execution
     */
    public ContentProperty queryPropertyByXPath(String jxpath) {
        return (ContentProperty) queryObjectByXPath(jxpath);
    }

    /**
     * Queries and returns a list of content nodes from this base content node by
     * the <a href="https://commons.apache.org/proper/commons-jxpath/">JXPath</a> expression ({@code jxpath}).
     * @param jxpath <a href="https://commons.apache.org/proper/commons-jxpath/">JXPath</a> expression
     * @return list of content nodes from this base content node from the JXPath query execution
     */
    public List<ContentNode> queryNodesByXPath(String jxpath) {
        return (List<ContentNode>) queryObjectsByXPath(jxpath);
    }

    /**
     * Queries and returns a list of content properties from this base content node by
     * the <a href="https://commons.apache.org/proper/commons-jxpath/">JXPath</a> expression ({@code jxpath}).
     * @param jxpath <a href="https://commons.apache.org/proper/commons-jxpath/">JXPath</a> expression
     * @return list of content properties from this base content node from the JXPath query execution
     */
    public List<ContentProperty> queryPropertiesByXPath(String jxpath) {
        return (List<ContentProperty>) queryObjectsByXPath(jxpath);
    }

    /**
     * Queries and returns an object from this base content node by
     * the <a href="https://commons.apache.org/proper/commons-jxpath/">JXPath</a> expression ({@code jxpath}).
     * @param jxpath <a href="https://commons.apache.org/proper/commons-jxpath/">JXPath</a> expression
     * @return an object from this base content node from the JXPath query execution
     */
    public Object queryObjectByXPath(String jxpath) {
        return createJXPathContext().getValue(jxpath);
    }

    /**
     * Queries and returns a list of objects from this base content node by
     * the <a href="https://commons.apache.org/proper/commons-jxpath/">JXPath</a> expression ({@code jxpath}).
     * @param jxpath <a href="https://commons.apache.org/proper/commons-jxpath/">JXPath</a> expression
     * @return a list of objects from this base content node from the JXPath query execution
     */
    public List<?> queryObjectsByXPath(String jxpath) {
        return createJXPathContext().selectNodes(jxpath);
    }

    /**
     * Creates and returns a {@link JXPathContext} instance used by default.
     * @return a {@link JXPathContext} instance used by default
     */
    private JXPathContext createJXPathContext() {
        JXPathContext jxpathCtx = JXPathContext.newContext(this);
        jxpathCtx.setLenient(true);
        return jxpathCtx;
    }

    /**
     * Deep-clone this content node object.
     * @return deep-cloned content node object
     */
    @Override
    public Object clone() {
        ContentNode clone = new ContentNode(getName(), primaryType);

        if (mixinTypes != null) {
            for (String mixinType : mixinTypes) {
                clone.addMixinType(mixinType);
            }
        }

        if (properties != null) {
            for (ContentProperty contentProp : properties) {
                clone.setProperty((ContentProperty) contentProp.clone());
            }
        }

        if (nodes != null) {
            for (ContentNode node : nodes) {
                clone.addNode((ContentNode) node.clone());
            }
        }

        return clone;
    }

    @Override
    public int hashCode() {
        return new HashCodeBuilder().append(getName()).append(primaryType).append(mixinTypes).append(properties)
                .append(nodes).toHashCode();
    }

    @Override
    public boolean equals(Object o) {
        if (!(o instanceof ContentNode)) {
            return false;
        }

        ContentNode that = (ContentNode) o;

        if (!StringUtils.equals(getName(), that.getName())) {
            return false;
        }

        if (!StringUtils.equals(primaryType, that.primaryType)) {
            return false;
        }

        if (!SetUtils.isEqualSet(mixinTypes, that.mixinTypes)) {
            return false;
        }

        if (properties == null) {
            if (that.properties != null) {
                return false;
            }
        } else {
            if (!ListUtils.isEqualList(properties, that.properties)) {
                return false;
            }
        }

        if (!ListUtils.isEqualList(nodes, that.nodes)) {
            return false;
        }

        return true;
    }

    @Override
    public String toString() {
        return new ToStringBuilder(this).append("name", getName()).append("primaryType", primaryType)
                .append("mixinTypes", mixinTypes).append("properties", properties).append("nodes", nodes)
                .toString();
    }
}