eu.uqasar.model.tree.TreeNode.java Source code

Java tutorial

Introduction

Here is the source code for eu.uqasar.model.tree.TreeNode.java

Source

package eu.uqasar.model.tree;

/*
 * #%L
 * U-QASAR
 * %%
 * Copyright (C) 2012 - 2015 U-QASAR Consortium
 * %%
 * 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.
 * #L%
 */

import java.util.Collections;
import java.util.LinkedList;
import java.util.List;

import javax.persistence.CascadeType;
import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.JoinColumn;
import javax.persistence.Lob;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.OrderColumn;
import javax.xml.bind.annotation.XmlAccessType;
import javax.xml.bind.annotation.XmlAccessorType;
import javax.xml.bind.annotation.XmlElement;
import javax.xml.bind.annotation.XmlSeeAlso;
import javax.xml.bind.annotation.XmlTransient;

import org.apache.commons.lang.StringUtils;
import org.codehaus.jackson.annotate.JsonBackReference;
import org.codehaus.jackson.annotate.JsonIgnore;
import org.codehaus.jackson.annotate.JsonManagedReference;
import org.codehaus.jackson.annotate.JsonTypeInfo;
import org.codehaus.jackson.annotate.JsonTypeInfo.As;
import org.hibernate.search.annotations.Analyze;
import org.hibernate.search.annotations.Field;
import org.hibernate.search.annotations.Index;
import org.hibernate.search.annotations.IndexedEmbedded;
import org.hibernate.search.annotations.Store;
import org.hibernate.search.annotations.TermVector;
import org.jboss.solder.logging.Logger;

import com.github.slugify.Slugify;

import de.agilecoders.wicket.core.markup.html.bootstrap.image.IconType;
import eu.uqasar.model.AbstractEntity;
import eu.uqasar.model.lifecycle.LifeCycleStage;
import eu.uqasar.util.UQasarUtil.SuggestionType;

@Entity
@Inheritance(strategy = InheritanceType.JOINED)
@XmlAccessorType(XmlAccessType.FIELD)
@XmlTransient
@XmlSeeAlso({ QualityObjective.class, QualityIndicator.class, Metric.class })
@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, include = As.PROPERTY, property = "@class")
public class TreeNode extends AbstractEntity implements ITreeNode<String> {

    private static final Logger logger = Logger.getLogger(TreeNode.class);

    private static final long serialVersionUID = -3121513789680716019L;

    @JsonIgnore
    @XmlTransient
    @Field(index = Index.YES, analyze = Analyze.YES, store = Store.NO, termVector = TermVector.YES)
    String nodeKey;

    @Field(index = Index.YES, analyze = Analyze.YES, store = Store.NO, termVector = TermVector.YES)
    String name;

    @Field(index = Index.YES, analyze = Analyze.YES, store = Store.NO, termVector = TermVector.YES)
    @Lob
    String description;

    @XmlTransient
    @Field(index = Index.YES, analyze = Analyze.YES, store = Store.NO, termVector = TermVector.YES)
    @Enumerated(EnumType.STRING)
    private QualityStatus qualityStatus = QualityStatus.Gray;

    @XmlTransient
    @Field(index = Index.YES, analyze = Analyze.YES, store = Store.NO, termVector = TermVector.YES)
    @Enumerated(EnumType.STRING)
    private LifeCycleStage lifeCycleStage = LifeCycleStage.Requirements;

    @XmlTransient
    @ManyToOne(cascade = CascadeType.ALL)
    @IndexedEmbedded(depth = 3)
    @JsonBackReference("parent")
    private TreeNode parent;

    // Set the type of the suggestion and the belonging value, but do not store 
    // those to the DB as they are computed on the fly 
    @XmlTransient
    private SuggestionType suggestionType;

    @XmlTransient
    private String suggestionValue;

    @XmlElement
    @OneToMany(cascade = CascadeType.ALL)
    @JoinColumn(name = "parent_id")
    @OrderColumn
    @JsonManagedReference("parent")
    @IndexedEmbedded(depth = 3)
    private List<TreeNode> children = new LinkedList<>();

    protected TreeNode() {
    }

    public TreeNode(final TreeNode parent) {
        if (parent == null) {
            throw new IllegalArgumentException("parent required");
        }

        this.parent = parent;
        registerInChildren();
    }

    private void registerInChildren() {
        if (this.parent != null) {
            this.parent.children.add(this);
        }
    }

    @JsonIgnore
    @Override
    public List<TreeNode> getSiblings() {
        return getSiblings(true);
    }

    @JsonIgnore
    @Override
    public List<TreeNode> getSiblings(boolean includeSelf) {
        return Collections.unmodifiableList(getMutableSiblings(includeSelf));
    }

    @JsonIgnore
    private List<TreeNode> getMutableSiblings() {
        return getMutableSiblings(true);
    }

    @JsonIgnore
    private List<TreeNode> getMutableSiblings(boolean includeSelf) {
        if (this instanceof Project) {
            // TODO not sure if projects cannot have siblings!
            LinkedList<TreeNode> list = new LinkedList<>();
            if (includeSelf) {
                list.add(this);
            }
            return list;
        } else {
            if (includeSelf) {
                return getParent().getChildren();
            } else {
                LinkedList<TreeNode> siblings = (LinkedList<TreeNode>) getParent().getChildren().clone();
                siblings.remove(this);
                return siblings;
            }
        }
    }

    @Override
    public boolean canChangePositionWithNextSibling() {
        return canChangePositionWithNextSibling(true);
    }

    @Override
    public boolean canChangePositionWithNextSibling(boolean changeParents) {
        LinkedList<TreeNode> directSiblings = (LinkedList<TreeNode>) getMutableSiblings();
        int currentIndex = directSiblings.indexOf(this);
        int newIndex = currentIndex + 1;
        if (newIndex < directSiblings.size()) {
            // switch currently selected node with the next one
            return true;
        } else if (newIndex >= directSiblings.size() && changeParents) {
            // add currently selected node as first entry to the next parent
            // sibling
            LinkedList<TreeNode> parentSiblings = (LinkedList<TreeNode>) this.getParent().getMutableSiblings();
            int parentIndex = parentSiblings.indexOf(this.getParent());
            int newParentIndex = parentIndex + 1;
            if (newParentIndex < parentSiblings.size()) {
                return true;
            }
        }
        return false;
    }

    @Override
    public boolean changePositionWithNextSibling() {
        return changePositionWithNextSibling(true);
    }

    @SuppressWarnings("unchecked")
    @Override
    public boolean changePositionWithNextSibling(boolean changeParents) {
        LinkedList<TreeNode> directSiblings = (LinkedList<TreeNode>) getMutableSiblings();
        int currentIndex = directSiblings.indexOf(this);
        int newIndex = currentIndex + 1;
        if (newIndex < directSiblings.size()) {
            // switch currently selected node with the next one
            TreeNode movedNode = directSiblings.remove(currentIndex);
            directSiblings.add(newIndex, movedNode);
            getParent().setChildren(directSiblings);
            logger.info(String.format("Moving %s from index %s to %s", this, currentIndex, newIndex));
            return true;
        } else if (newIndex >= directSiblings.size() && changeParents) {
            // add currently selected node as first entry to the next parent
            // sibling
            LinkedList<TreeNode> parentSiblings = (LinkedList<TreeNode>) this.getParent().getMutableSiblings();
            int parentIndex = parentSiblings.indexOf(this.getParent());
            int newParentIndex = parentIndex + 1;
            if (newParentIndex < parentSiblings.size()) {
                TreeNode oldParent = this.getParent();
                LinkedList<TreeNode> oldParentChildren = oldParent.getChildren();
                oldParentChildren.removeLast();
                oldParent.setChildren(oldParentChildren);

                TreeNode newParent = parentSiblings.get(newParentIndex);
                logger.info(String.format("Moving %s from parent %s to %s", this, this.getParent(), newParent));
                this.setParent(newParent);
                return true;
            }
        }
        return false;
    }

    @Override
    public boolean canChangePositionWithPreviousSibling() {
        return canChangePositionWithPreviousSibling(true);
    }

    @Override
    public boolean canChangePositionWithPreviousSibling(boolean changeParents) {
        LinkedList<TreeNode> directSiblings = (LinkedList<TreeNode>) getMutableSiblings();
        int currentIndex = directSiblings.indexOf(this);
        if (currentIndex > 0) {
            // switch currently selected node with the previous one
            return true;
        } else if (currentIndex == 0 && changeParents) {
            // add currently selected node as last entry to the previous
            // parent sibling
            LinkedList<TreeNode> parentSiblings = (LinkedList<TreeNode>) this.getParent().getMutableSiblings();
            int parentIndex = parentSiblings.indexOf(this.getParent());
            return parentIndex > 0;
        }
        return false;
    }

    @Override
    public boolean changePositionWithPreviousSibling() {
        return changePositionWithPreviousSibling(true);
    }

    @SuppressWarnings("unchecked")
    @Override
    public boolean changePositionWithPreviousSibling(boolean changeParents) {
        LinkedList<TreeNode> directSiblings = (LinkedList<TreeNode>) getMutableSiblings();
        int currentIndex = directSiblings.indexOf(this);
        int newIndex = currentIndex - 1;
        if (currentIndex > 0) {
            // switch currently selected node with the previous one
            TreeNode movedNode = directSiblings.remove(currentIndex);
            directSiblings.add(newIndex, movedNode);
            getParent().setChildren(directSiblings);
            logger.info(String.format("Moving %s from index %s to %s", this, currentIndex, newIndex));
            return true;
        } else if (currentIndex == 0 && changeParents) {
            // add currently selected node as last entry to the previous
            // parent sibling
            LinkedList<TreeNode> parentSiblings = (LinkedList<TreeNode>) this.getParent().getMutableSiblings();
            int parentIndex = parentSiblings.indexOf(this.getParent());
            int newParentIndex = parentIndex - 1;
            if (parentIndex > 0) {
                TreeNode oldParent = this.getParent();
                LinkedList<TreeNode> oldParentChildren = oldParent.getChildren();
                oldParentChildren.remove(0);
                oldParent.setChildren(oldParentChildren);

                TreeNode newParent = parentSiblings.get(newParentIndex);
                logger.info(String.format("Moving %s from parent %s to %s", this, this.getParent(), newParent));
                this.setParent(newParent);
                return true;
            }
        }
        return false;
    }

    /**
     * @return the suggestionType
     */
    public SuggestionType getSuggestionType() {
        return suggestionType;
    }

    /**
     * @param suggestionType the suggestionType to set
     */
    @JsonIgnore
    public void setSuggestionType(SuggestionType suggestionType) {
        this.suggestionType = suggestionType;
    }

    @SuppressWarnings("ReturnOfCollectionOrArrayField")
    @JsonManagedReference("parent")
    @Override
    public LinkedList<TreeNode> getChildren() {
        if (children instanceof LinkedList) {
            return (LinkedList<TreeNode>) children;
        } else {
            return new LinkedList<>(children);
        }
    }

    @JsonIgnore
    @JsonManagedReference("parent")
    public void setChildren(List<TreeNode> children) {
        if (children instanceof LinkedList) {
            this.children = children;
        } else {
            this.children = new LinkedList<>(children);
        }
    }

    @Override
    public String getName() {
        return name;
    }

    @JsonIgnore
    public void setName(String name) {
        this.name = name;
    }

    @XmlTransient
    @JsonBackReference("parent")
    @Override
    public TreeNode getParent() {
        return parent;
    }

    @JsonIgnore
    @JsonBackReference("parent")
    public void setParent(TreeNode parent) {
        this.parent = parent;
        this.parent.children.add(this);
    }

    @Override
    public String getNodeKey() {
        if (StringUtils.isBlank(nodeKey)) {
            nodeKey = Slugify.slugify(getName());
        }
        return nodeKey;
    }

    @JsonIgnore
    void setNodeKey(String mKey) {
        this.nodeKey = mKey;
    }

    @Override
    public QualityStatus getQualityStatus() {
        if (qualityStatus == null)
            qualityStatus = QualityStatus.Gray;
        return this.qualityStatus;
    }

    @JsonIgnore
    void setQualityStatus(QualityStatus status) {
        this.qualityStatus = status;
    }

    @Override
    public void addChild(ITreeNode<String> child) {
        if (!this.children.contains(child)) {
            this.children.add((TreeNode) child);
        }
    }

    public String getDescription() {
        if (description == null) {
            description = "";
        }
        return description;
    }

    @JsonIgnore
    public void setDescription(String description) {
        this.description = description;
    }

    public LifeCycleStage getLifeCycleStage() {
        if (lifeCycleStage == null)
            lifeCycleStage = LifeCycleStage.Requirements;
        return lifeCycleStage;
    }

    @JsonIgnore
    public void setLifeCycleStage(LifeCycleStage lifeCycleStage) {
        this.lifeCycleStage = lifeCycleStage;
    }

    @JsonIgnore
    public final String getChildrenString() {
        return getChildrenString("", "");
    }

    @JsonIgnore
    public final String getChildrenString(final String prefix, final String suffix) {
        String builder = prefix + StringUtils.join(getChildren(), ", ") + suffix;
        return builder;
    }

    @JsonIgnore
    public Project getProject() {
        return getProject(this);
    }

    @JsonIgnore
    public QualityObjective getQualityObjective() {
        return getQualityObjective(this);
    }

    @JsonIgnore
    public QualityIndicator getQualityIndicator() {
        return getQualityIndicator(this);
    }

    @JsonIgnore
    private static QualityIndicator getQualityIndicator(ITreeNode<String> node) {
        if (node instanceof QualityIndicator) {
            return (QualityIndicator) node;
        }
        if (node.getParent() == null) {
            return null;
        }
        return getQualityIndicator(node.getParent());
    }

    @JsonIgnore
    private static QualityObjective getQualityObjective(ITreeNode<String> node) {
        if (node instanceof QualityObjective) {
            return (QualityObjective) node;
        }
        if (node.getParent() == null) {
            return null;
        }
        return getQualityObjective(node.getParent());
    }

    @JsonIgnore
    private static Project getProject(ITreeNode<String> node) {
        if (node.getParent() == null || node instanceof Project) {
            return (Project) node;
        }
        return getProject(node.getParent());
    }

    @Override
    public String toString() {
        return name;
    }

    @JsonIgnore
    @Override
    public Class<? extends ITreeNode<String>> getChildType() {
        return Project.class;
    }

    @JsonIgnore
    @Override
    public IconType getIconType() {
        return IconType.globe;
    }

    public void removeChild(TreeNode node) {
        children.remove(node);
    }

    public void removeChild(long id) {
        children.remove(id);
    }

    /**
     * @return the suggestionValue
     */
    @JsonIgnore
    public String getSuggestionValue() {
        return suggestionValue;
    }

    /**
     * @param suggestionValue the suggestionValue to set
     */
    @JsonIgnore
    public void setSuggestionValue(String suggestionValue) {
        this.suggestionValue = suggestionValue;
    }

}