| /* |
| * 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.ArrayList; |
| import java.util.Arrays; |
| import java.util.HashMap; |
| import java.util.List; |
| 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.lenya.cms.publication.DocumentFactory; |
| 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.SiteTreeNode; |
| import org.apache.lenya.util.Assert; |
| import org.apache.lenya.util.StringUtil; |
| |
| /** |
| * Site tree node. |
| */ |
| public class TreeNodeImpl extends AbstractLogEnabled implements TreeNode { |
| |
| private TreeNode parent; |
| private String name; |
| |
| /** |
| * A top level node. |
| * @param parent The parent. |
| * @param name The name. |
| * @param visible The navigation visibility. |
| * @param logger The logger. |
| */ |
| public TreeNodeImpl(TreeNode parent, String name, boolean visible, Logger logger) { |
| ContainerUtil.enableLogging(this, logger); |
| Assert.notNull("name", name); |
| this.name = name; |
| this.parent = parent; |
| this.isVisible = visible; |
| } |
| |
| /** |
| * Sets the UUID. |
| * @param uuid The UUID. |
| */ |
| protected void setUuid(String uuid) { |
| Assert.notNull("uuid", uuid); |
| if (this.language2link.keySet().size() > 0) { |
| throw new RuntimeException("Can't set the UUID if the node has links."); |
| } |
| |
| if (this.uuid != null) { |
| String[] languages = getLanguages(); |
| for (int i = 0; i < languages.length; i++) { |
| getTree().linkRemoved(this.uuid, languages[i]); |
| } |
| } |
| |
| this.uuid = uuid; |
| |
| String[] languages = getLanguages(); |
| for (int i = 0; i < languages.length; i++) { |
| try { |
| getTree().linkAdded(getLink(languages[i])); |
| } catch (SiteException e) { |
| throw new RuntimeException(e); |
| } |
| } |
| } |
| |
| public void delete() { |
| deleteInternal(); |
| changed(); |
| } |
| |
| protected void deleteInternal() { |
| String[] languages = getLanguages(); |
| for (int i = 0; i < languages.length; i++) { |
| removeLinkInternal(languages[i]); |
| } |
| SiteNode[] children = getChildren(); |
| for (int i = 0; i < children.length; i++) { |
| ((TreeNodeImpl) children[i]).deleteInternal(); |
| } |
| ((TreeNodeImpl) this.parent).removeChild(getName()); |
| } |
| |
| private Map language2link = new HashMap(); |
| private String uuid; |
| private boolean isVisible; |
| |
| public String[] getLanguages() { |
| Set languages = this.language2link.keySet(); |
| return (String[]) languages.toArray(new String[languages.size()]); |
| } |
| |
| public Link getLink(String language) throws SiteException { |
| Assert.notNull("language", language); |
| if (!this.language2link.containsKey(language)) { |
| throw new SiteException("No link contained for language [" + language + "]"); |
| } |
| return (Link) this.language2link.get(language); |
| } |
| |
| public String getName() { |
| return this.name; |
| } |
| |
| public SiteNode getParent() throws SiteException { |
| if (isTopLevel()) { |
| throw new SiteException("This is a top level node."); |
| } |
| return (SiteNode) this.parent; |
| } |
| |
| public String getPath() { |
| return this.parent.getPath() + "/" + getName(); |
| } |
| |
| public SiteStructure getStructure() { |
| return getTree(); |
| } |
| |
| public String getUuid() { |
| return this.uuid; |
| } |
| |
| public boolean hasLink(String language) { |
| Assert.notNull("language", language); |
| return this.language2link.containsKey(language); |
| } |
| |
| public boolean isTopLevel() { |
| return this.parent instanceof RootNode; |
| } |
| |
| public boolean isVisible() { |
| return this.isVisible; |
| } |
| |
| public void setVisible(boolean visibleInNav) { |
| this.isVisible = visibleInNav; |
| changed(); |
| } |
| |
| protected void changed() { |
| getTree().changed(); |
| } |
| |
| public SiteTreeNode[] getPrecedingSiblings() { |
| SiteNode[] children = this.parent.getChildren(); |
| int pos = Arrays.asList(children).indexOf(this); |
| List siblings = new ArrayList(); |
| for (int i = 0; i < pos ; i++) { |
| siblings.add(children[i]); |
| } |
| return (SiteTreeNode[]) siblings.toArray(new TreeNodeImpl[siblings.size()]); |
| } |
| |
| public SiteTreeNode[] getNextSiblings() { |
| SiteNode[] children = this.parent.getChildren(); |
| int pos = Arrays.asList(children).indexOf(this); |
| List siblings = new ArrayList(); |
| for (int i = pos + 1; i < children.length; i++) { |
| siblings.add(children[i]); |
| } |
| return (SiteTreeNode[]) siblings.toArray(new TreeNodeImpl[siblings.size()]); |
| } |
| |
| public SiteTreeImpl getTree() { |
| return this.parent.getTree(); |
| } |
| |
| protected Link addLink(String lang, String label) { |
| Assert.notNull("language", lang); |
| Assert.notNull("label", label); |
| Link link = addLinkInternal(lang, label); |
| changed(); |
| return link; |
| } |
| |
| protected Link addLinkInternal(String lang, String label) { |
| Assert.notNull("language", lang); |
| Assert.notNull("label", label); |
| if (this.language2link.containsKey(lang)) { |
| throw new RuntimeException("The language [" + lang + "] is already contained."); |
| } |
| DocumentFactory factory = getTree().getPublication().getFactory(); |
| Link link = new SiteTreeLink(factory, this, label, lang); |
| this.language2link.put(lang, link); |
| getTree().linkAdded(link); |
| return link; |
| } |
| |
| protected void removeLink(String language) { |
| removeLinkInternal(language); |
| deleteIfEmpty(); |
| changed(); |
| } |
| |
| protected void removeLinkInternal(String language) { |
| Assert.notNull("language", language); |
| this.language2link.remove(language); |
| getTree().linkRemoved(getUuid(), language); |
| } |
| |
| protected void deleteIfEmpty() { |
| if (isEmpty()) { |
| deleteInternal(); |
| } |
| } |
| |
| protected boolean isEmpty() { |
| return this.language2link.isEmpty() && this.name2child.isEmpty(); |
| } |
| |
| public String toString() { |
| return getPath() + "[" + StringUtil.join(getLanguages(), ",") + "]"; |
| } |
| |
| private List children = new ArrayList(); |
| |
| public SiteNode[] getChildren() { |
| return (SiteNode[]) this.children.toArray(new SiteNode[this.children.size()]); |
| } |
| |
| public SiteNode[] preOrder() { |
| List preOrder = new ArrayList(); |
| preOrder.add(this); |
| SiteNode[] children = getChildren(); |
| for (int i = 0; i < children.length; i++) { |
| TreeNode child = (TreeNode) children[i]; |
| preOrder.addAll(Arrays.asList(child.preOrder())); |
| } |
| return (SiteNode[]) preOrder.toArray(new SiteNode[preOrder.size()]); |
| } |
| |
| protected void removeChild(String name) { |
| Assert.notNull("name", name); |
| if (!this.name2child.containsKey(name)) { |
| throw new RuntimeException("The node [" + name + "] is not contained!"); |
| } |
| SiteNode node = (SiteNode) this.name2child.get(name); |
| this.name2child.remove(node.getName()); |
| this.children.remove(node); |
| getTree().nodeRemoved(getPath() + "/" + name); |
| deleteIfEmpty(); |
| } |
| |
| private Map name2child = new HashMap(); |
| |
| public SiteNode addChild(String name, boolean visible) { |
| Assert.notNull("name", name); |
| return addChild(name, this.children.size(), visible); |
| } |
| |
| public SiteNode addChild(String name, String followingNodeName, boolean visible) { |
| Assert.notNull("name", name); |
| Assert.notNull("following node name", followingNodeName); |
| SiteNode followingSibling = getChild(followingNodeName); |
| int pos = this.children.indexOf(followingSibling); |
| return addChild(name, pos, visible); |
| } |
| |
| protected SiteNode addChild(String name, int pos, boolean visible) { |
| Assert.notNull("name", name); |
| |
| if (this.name2child.containsKey(name)) { |
| throw new RuntimeException("The child [" + name + "] is already contained."); |
| } |
| |
| SiteNode node = new TreeNodeImpl(this, name, visible, getLogger()); |
| this.children.add(pos, node); |
| this.name2child.put(name, node); |
| getTree().nodeAdded(node); |
| getTree().changed(); |
| return node; |
| } |
| |
| protected SiteNode getChild(String name) { |
| Assert.notNull("name", name); |
| if (this.name2child.containsKey(name)) { |
| return (SiteNode) this.name2child.get(name); |
| } else { |
| throw new RuntimeException("No such child [" + name + "]"); |
| } |
| } |
| |
| protected int getPosition(SiteNode child) { |
| Assert.notNull("child", child); |
| Assert.isTrue("contains", this.children.contains(child)); |
| return this.children.indexOf(child); |
| } |
| |
| public void moveDown(String name) { |
| SiteNode child = getChild(name); |
| int pos = getPosition(child); |
| Assert.isTrue("not last", pos < this.children.size() - 1); |
| this.children.remove(child); |
| this.children.add(pos + 1, child); |
| changed(); |
| } |
| |
| public void moveUp(String name) { |
| SiteNode child = getChild(name); |
| int pos = getPosition(child); |
| Assert.isTrue("not first", pos > 0); |
| this.children.remove(child); |
| this.children.add(pos - 1, child); |
| changed(); |
| } |
| |
| public String getHref() { |
| return null; |
| } |
| |
| public String getSuffix() { |
| return null; |
| } |
| |
| public boolean hasLink() { |
| return false; |
| } |
| |
| } |