blob: 99ecced0b48786bb2a2d2561ffff4dbd7a45755b [file] [log] [blame]
/*
* 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;
}
}