Package org.apache.lenya.cms.site.tree2

Source Code of org.apache.lenya.cms.site.tree2.SiteTreeImpl

/*
* Licensed to the Apache Software Foundation (ASF) under one or more
*  contributor license agreements.  See the NOTICE file distributed with
*  this work for additional information regarding copyright ownership.
*  The ASF licenses this file to You 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.apache.lenya.cms.site.tree2;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import org.apache.avalon.framework.container.ContainerUtil;
import org.apache.avalon.framework.logger.AbstractLogEnabled;
import org.apache.avalon.framework.logger.Logger;
import org.apache.avalon.framework.service.ServiceException;
import org.apache.avalon.framework.service.ServiceManager;
import org.apache.lenya.cms.publication.Area;
import org.apache.lenya.cms.publication.Document;
import org.apache.lenya.cms.publication.Publication;
import org.apache.lenya.cms.repository.Node;
import org.apache.lenya.cms.repository.NodeFactory;
import org.apache.lenya.cms.repository.Persistable;
import org.apache.lenya.cms.repository.RepositoryException;
import org.apache.lenya.cms.repository.Session;
import org.apache.lenya.cms.site.Link;
import org.apache.lenya.cms.site.SiteException;
import org.apache.lenya.cms.site.SiteNode;
import org.apache.lenya.cms.site.SiteStructure;
import org.apache.lenya.cms.site.tree.SiteTree;
import org.apache.lenya.util.Assert;

/**
* Simple site tree implementation.
*/
public class SiteTreeImpl extends AbstractLogEnabled implements SiteStructure, SiteTree, Persistable {

    protected static final String SITETREE_FILE_NAME = "sitetree.xml";
    private Area area;
    protected ServiceManager manager;
    private RootNode root;
    private int revision;

    /**
     * @param manager The service manager.
     * @param area The area.
     * @param logger The logger.
     */
    public SiteTreeImpl(ServiceManager manager, Area area, Logger logger) {
        ContainerUtil.enableLogging(this, logger);
        this.area = area;
        this.manager = manager;
        initRoot();
    }

    protected void initRoot() {
        this.root = new RootNode(this, getLogger());
        nodeAdded(root);
    }

    private String sourceUri;

    protected String getSourceUri() {
        if (this.sourceUri == null) {
            String baseUri = this.area.getPublication().getContentURI(this.area.getName());
            this.sourceUri = baseUri + "/" + SITETREE_FILE_NAME;
        }
        return this.sourceUri;
    }

    private boolean loading = false;

    protected static final String NAMESPACE = "http://apache.org/cocoon/lenya/sitetree/1.0";

    private static final boolean DEFAULT_VISIBILITY = true;

    private boolean loaded = false;

    protected synchronized void load() {

        if (this.loaded || this.loading) {
            return;
        }

        Node repoNode = getRepositoryNode();

        try {
            repoNode.setPersistable(this);
           
            if (repoNode.exists()) {
                TreeBuilder builder = null;
                try {
                    this.loading = true;
                    builder = (TreeBuilder) this.manager.lookup(TreeBuilder.ROLE);
                    reset();
                    builder.buildTree(this);
                    Assert.isTrue("Latest revision loaded", getRevision() == getRevision(getRepositoryNode()));
                } finally {
                    this.loading = false;
                    if (builder != null) {
                        this.manager.release(builder);
                    }
                }
            }
            this.loaded = true;
            if (!repoNode.exists()) {
                reset();
            }
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }

    protected void reset() {
        this.path2node.clear();
        this.uuidLanguage2link.clear();
        initRoot();
    }

    protected RootNode getRoot() {
        load();
        return this.root;
    }

    public synchronized void save() throws RepositoryException {
        if (loading || !changed) {
            return;
        }
        TreeWriter writer = null;
        try {
            writer = (TreeWriter) this.manager.lookup(TreeWriter.ROLE);
            int revision = getRevision(getRepositoryNode()) + 1;
            writer.writeTree(this);
        } catch (RuntimeException e) {
            throw e;
        } catch (Exception e) {
            throw new RepositoryException(e);
        } finally {
            if (writer != null) {
                this.manager.release(writer);
            }
        }

    }

    protected int getRevision(Node repoNode) {
        int revision = 0;
        if (repoNode.getHistory().getRevisionNumbers().length > 0) {
            revision = repoNode.getHistory().getLatestRevision().getNumber();
        }
        return revision;
    }

    public Link add(String path, Document doc) throws SiteException {

        if (containsByUuid(doc.getUUID(), doc.getLanguage())) {
            throw new SiteException("The document [" + doc + "] is already contained!");
        }

        TreeNodeImpl node;
        if (contains(path)) {
            node = getTreeNode(path);
            if (node.getUuid() == null) {
                node.setUuid(doc.getUUID());
            } else if (!node.getUuid().equals(doc.getUUID())) {
                throw new SiteException("The node already has a different UUID!");
            }
        } else {
            node = (TreeNodeImpl) add(path);
            node.setUuid(doc.getUUID());
        }
        return node.addLink(doc.getLanguage(), "");
    }

    protected TreeNodeImpl getTreeNode(String path) throws SiteException {
        return (TreeNodeImpl) getNode(path);
    }

    public SiteNode add(String path) throws SiteException {
        String parentPath = getParentPath(path);
        String nodeName = path.substring(parentPath.length() + 1);
        if (!contains(parentPath)) {
            add(parentPath);
        }
        return getTreeNode(parentPath).addChild(nodeName, DEFAULT_VISIBILITY);
    }

    public SiteNode add(String path, String followingSiblingPath) throws SiteException {
        String parentPath = getParentPath(path);
        String nodeName = path.substring(parentPath.length() + 1);

        if (!followingSiblingPath.startsWith(parentPath + "/")) {
            throw new SiteException("Invalid following sibling path [" + followingSiblingPath + "]");
        }

        String followingNodeName = followingSiblingPath.substring(parentPath.length() + 1);

        if (!contains(parentPath)) {
            add(parentPath);
        }
        return getTreeNode(parentPath).addChild(nodeName, followingNodeName, DEFAULT_VISIBILITY);
    }

    protected String getParentPath(String path) {
        int lastIndex = path.lastIndexOf("/");
        String parentPath = path.substring(0, lastIndex);
        return parentPath;
    }

    private Map path2node = new HashMap();
    private Map uuidLanguage2link = new HashMap();

    protected void nodeAdded(SiteNode node) {
        String path = node.getPath();
        Assert.notNull("path", path);
        if (node != this.root) {
            Assert.isTrue("path not empty", path.length() > 0);
        }
        this.path2node.put(path, node);
    }

    protected void linkAdded(Link link) {
        if (link.getNode().getUuid() != null) {
            this.uuidLanguage2link.put(getKey(link), link);
        }
    }

    protected String getKey(Link link) {
        String uuid = link.getNode().getUuid();
        Assert.notNull("uuid", uuid);
        String language = link.getLanguage();
        Assert.notNull("language", language);
        return getKey(uuid, language);
    }

    protected String getKey(String uuid, String language) {
        Assert.notNull("uuid", uuid);
        Assert.notNull("language", language);
        return uuid + ":" + language;
    }

    protected void nodeRemoved(String path) {
        Assert.notNull("path", path);
        Assert.isTrue("path [" + path + "] contained", this.path2node.containsKey(path));
        this.path2node.remove(path);
    }

    protected Map getUuidLanguage2Link() {
        load();
        return this.uuidLanguage2link;
    }

    protected Map getPath2Node() {
        load();
        return this.path2node;
    }

    public boolean contains(String path) {
        load();
        Assert.notNull("path", path);
        return this.path2node.containsKey(path);
    }

    public boolean containsByUuid(String uuid, String language) {
        Assert.notNull("uuid", uuid);
        Assert.notNull("language", language);
        return getUuidLanguage2Link().containsKey(getKey(uuid, language));
    }

    public boolean containsInAnyLanguage(String uuid) {
        Assert.notNull("uuid", uuid);
        Set set = getUuidLanguage2Link().keySet();
        String[] keys = (String[]) set.toArray(new String[set.size()]);
        for (int i = 0; i < keys.length; i++) {
            if (keys[i].startsWith(uuid + ":")) {
                return true;
            }
        }
        return false;
    }

    public String getArea() {
        return this.area.getName();
    }

    public Link getByUuid(String uuid, String language) throws SiteException {
        Assert.notNull("uuid", uuid);
        Assert.notNull("language", language);
        String key = getKey(uuid, language);
        if (!getUuidLanguage2Link().containsKey(key)) {
            throw new SiteException("No link for [" + key + "]");
        }
        return (Link) getUuidLanguage2Link().get(key);
    }

    public SiteNode getNode(String path) throws SiteException {
        Assert.notNull("path", path);
        if (!getPath2Node().containsKey(path)) {
            throw new SiteException("No node for path [" + path + "]");
        }
        return (SiteNode) this.path2node.get(path);
    }

    public SiteNode[] getNodes() {
        return getRoot().preOrder();
    }

    public Publication getPublication() {
        return this.area.getPublication();
    }

    public Session getSession() {
        return this.area.getPublication().getFactory().getSession();
    }
   
    private NodeFactory nodeFactory;
    private boolean changed = false;
   
    protected NodeFactory getNodeFactory() {
        if (this.nodeFactory == null) {
            try {
                this.nodeFactory = (NodeFactory) manager.lookup(NodeFactory.ROLE);
            } catch (ServiceException e) {
                throw new RuntimeException("Creating repository node failed: ", e);
            }
        }
        return this.nodeFactory;
    }

    public Node getRepositoryNode() {
        try {
            return (Node) getSession().getRepositoryItem(getNodeFactory(), getSourceUri());
        } catch (RepositoryException e) {
            throw new RuntimeException("Creating repository node failed: ", e);
        }
    }

    public SiteNode[] getTopLevelNodes() {
        return getRoot().getChildren();
    }

    protected void linkRemoved(String uuid, String language) {
        Assert.notNull("uuid", uuid);
        Assert.notNull("language", language);
        String key = getKey(uuid, language);
        Assert.isTrue("contained", this.uuidLanguage2link.containsKey(key));
        this.uuidLanguage2link.remove(key);
    }

    protected String getPath() {
        return "";
    }

    /**
     * @return The nodes in pre-order enumeration.
     */
    public SiteNode[] preOrder() {
        return getRoot().preOrder();
    }

    public void moveDown(String path) throws SiteException {
        TreeNode node = getTreeNode(path);
        TreeNode parent = getParent(node);
        parent.moveDown(node.getName());

    }

    public void moveUp(String path) throws SiteException {
        TreeNode node = getTreeNode(path);
        TreeNode parent = getParent(node);
        parent.moveUp(node.getName());
    }

    /**
     * @param node A node.
     * @return The parent of the node, which is the root node for top level nodes.
     * @throws SiteException if an error occurs.
     */
    protected TreeNode getParent(TreeNode node) throws SiteException {
        TreeNode parent;
        if (node.isTopLevel()) {
            parent = getRoot();
        } else {
            parent = (TreeNode) node.getParent();
        }
        return parent;
    }

    public boolean contains(String path, String language) {
        if (contains(path)) {
            SiteNode node;
            try {
                node = getNode(path);
            } catch (SiteException e) {
                throw new RuntimeException(e);
            }
            return node.hasLink(language);
        }
        return false;
    }

    protected void changed() {
        if (!this.loading) {
            this.changed = true;
        }
    }

    public boolean isModified() {
        return this.changed;
    }

    protected int getRevision() {
        load();
        return this.revision;
    }
   
    protected void setRevision(int revision) {
        this.revision = revision;
    }

}
TOP

Related Classes of org.apache.lenya.cms.site.tree2.SiteTreeImpl

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.