blob: 38a1879d61d05a6d0df2f341781ee0f1997a3c1a [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.tree;
import java.util.ArrayList;
import java.util.List;
import org.apache.avalon.framework.service.Serviceable;
import org.apache.lenya.cms.publication.Document;
import org.apache.lenya.cms.publication.DocumentException;
import org.apache.lenya.cms.publication.DocumentFactory;
import org.apache.lenya.cms.publication.DocumentLocator;
import org.apache.lenya.cms.publication.Publication;
import org.apache.lenya.cms.publication.PublicationException;
import org.apache.lenya.cms.repository.RepositoryItemFactory;
import org.apache.lenya.cms.site.AbstractSiteManager;
import org.apache.lenya.cms.site.Link;
import org.apache.lenya.cms.site.NodeSet;
import org.apache.lenya.cms.site.SiteException;
import org.apache.lenya.cms.site.SiteNode;
import org.apache.lenya.cms.site.SiteStructure;
/**
* A tree-based site manager.
*
* @version $Id: TreeSiteManager.java 208766 2005-07-01 16:05:00Z andreas $
*/
public class TreeSiteManager extends AbstractSiteManager implements Serviceable {
/**
* Ctor.
*/
public TreeSiteManager() {
// do nothing
}
/**
* Returns the sitetree for a specific area of this publication. Sitetrees are created on demand
* and are cached.
*
* @param map The document identity map.
* @param publication The publication.
* @param area The area.
* @return A site tree.
* @throws SiteException if an error occurs.
*/
public DefaultSiteTree getTree(DocumentFactory map, Publication publication, String area)
throws SiteException {
String key = getKey(publication, area);
DefaultSiteTree sitetree;
RepositoryItemFactory factory = new SiteTreeFactory(this.manager, getLogger());
try {
sitetree = (DefaultSiteTree) map.getSession().getRepositoryItem(factory, key);
} catch (Exception e) {
throw new SiteException(e);
}
return sitetree;
}
protected DefaultSiteTree getTree(Document document) throws SiteException {
return getTree(document.getFactory(), document.getPublication(), document.getArea());
}
/**
* Returns the ancestors of a resource, beginning with the parent.
*
* @param node The resource.
* @return A list of resources.
* @throws SiteException if an error occurs.
*/
protected List getAncestors(SiteNode node) throws SiteException {
List ancestors = new ArrayList();
SiteNode parent = null;
try {
if (!node.isTopLevel()) {
parent = node.getParent();
ancestors.add(parent);
ancestors.addAll(getAncestors(parent));
}
} catch (Exception e) {
throw new SiteException(e);
}
return ancestors;
}
/**
* @see org.apache.lenya.cms.site.SiteManager#requires(org.apache.lenya.cms.publication.DocumentFactory,
* org.apache.lenya.cms.site.SiteNode, org.apache.lenya.cms.site.SiteNode)
*/
public boolean requires(DocumentFactory map, SiteNode dependingResource,
SiteNode requiredResource) throws SiteException {
return getAncestors(dependingResource).contains(requiredResource);
}
public DocumentLocator[] getRequiredResources(DocumentFactory map, final DocumentLocator loc)
throws SiteException {
List ancestors = new ArrayList();
DocumentLocator locator = loc;
while (locator.getParent() != null) {
DocumentLocator parent = locator.getParent();
ancestors.add(parent);
locator = parent;
}
return (DocumentLocator[]) ancestors.toArray(new DocumentLocator[ancestors.size()]);
}
/**
* @see org.apache.lenya.cms.site.SiteManager#getRequiringResources(org.apache.lenya.cms.publication.DocumentFactory,
* org.apache.lenya.cms.site.SiteNode)
*/
public SiteNode[] getRequiringResources(DocumentFactory map, SiteNode resource)
throws SiteException {
if (getLogger().isDebugEnabled()) {
getLogger().debug("Obtaining requiring resources of [" + resource + "]");
}
NodeSet nodes = new NodeSet(this.manager);
Publication pub = resource.getStructure().getPublication();
String area = resource.getStructure().getArea();
SiteTree tree = getTree(map, pub, area);
SiteTreeNodeImpl node = (SiteTreeNodeImpl) tree.getNode(resource.getPath());
if (node != null) {
List preOrder = node.preOrder();
// remove original resource (does not require itself)
preOrder.remove(0);
for (int i = 0; i < preOrder.size(); i++) {
SiteTreeNode descendant = (SiteTreeNode) preOrder.get(i);
nodes.add(descendant);
}
if (getLogger().isDebugEnabled()) {
getLogger().debug("Obtaining requiring resources completed.");
}
}
return nodes.getNodes();
}
/**
* @see org.apache.lenya.cms.site.SiteManager#contains(org.apache.lenya.cms.publication.Document)
*/
public boolean contains(Document resource) throws SiteException {
SiteTree tree = getTree(resource);
return tree.containsByUuid(resource.getUUID(), resource.getLanguage());
}
/**
* @see org.apache.lenya.cms.site.SiteManager#containsInAnyLanguage(org.apache.lenya.cms.publication.Document)
*/
public boolean containsInAnyLanguage(Document resource) throws SiteException {
SiteTree tree = getTree(resource);
return tree.containsInAnyLanguage(resource.getUUID());
}
/**
* @see org.apache.lenya.cms.site.SiteManager#copy(org.apache.lenya.cms.publication.Document,
* org.apache.lenya.cms.publication.Document)
*/
public void copy(Document sourceDocument, Document destinationDocument) throws SiteException {
DefaultSiteTree destinationTree = getTree(destinationDocument);
try {
SiteTreeNode sourceNode = (SiteTreeNode) sourceDocument.getLink().getNode();
SiteTreeNode[] siblings = sourceNode.getNextSiblings();
SiteNode parent = sourceNode.getParent();
String parentId = "";
if (parent != null) {
parentId = parent.getPath();
}
SiteTreeNode sibling = null;
String siblingPath = null;
// same UUID -> insert at the same position
if (sourceDocument.getUUID().equals(destinationDocument.getUUID())) {
for (int i = 0; i < siblings.length; i++) {
String path = parentId + "/" + siblings[i].getName();
sibling = (SiteTreeNode) destinationTree.getNode(path);
if (sibling != null) {
siblingPath = path;
break;
}
}
}
if (!sourceNode.hasLink(sourceDocument.getLanguage())) {
// the node that we're trying to publish
// doesn't have this language
throw new SiteException("The node " + sourceDocument.getPath()
+ " doesn't contain a label for language " + sourceDocument.getLanguage());
}
Link link = sourceNode.getLink(sourceDocument.getLanguage());
SiteTreeNode destinationNode = (SiteTreeNode) destinationTree.getNode(destinationDocument.getPath());
if (destinationNode == null) {
if (siblingPath == null) {
destinationTree.addNode(destinationDocument.getPath(),
destinationDocument.getUUID(),
sourceNode.isVisible(),
sourceNode.getHref(),
sourceNode.getSuffix(),
sourceNode.hasLink());
destinationTree.addLabel(destinationDocument.getPath(),
destinationDocument.getLanguage(),
link.getLabel());
} else {
destinationTree.addNode(destinationDocument.getPath(),
destinationDocument.getUUID(),
sourceNode.isVisible(),
sourceNode.getHref(),
sourceNode.getSuffix(),
sourceNode.hasLink(),
siblingPath);
destinationTree.addLabel(destinationDocument.getPath(),
destinationDocument.getLanguage(),
link.getLabel());
}
} else {
// if the node already exists in the live
// tree simply insert the label in the
// live tree
destinationDocument.getLink().setLabel(link.getLabel());
}
} catch (DocumentException e) {
throw new SiteException(e);
}
}
/**
* @see org.apache.lenya.cms.site.SiteManager#setVisibleInNav(org.apache.lenya.cms.publication.Document,
* boolean)
*/
public void setVisibleInNav(Document document, boolean visibleInNav) throws SiteException {
SiteTree tree = getTree(document);
try {
tree.getNode(document.getPath()).setVisible(visibleInNav);
} catch (DocumentException e) {
throw new SiteException(e);
}
}
/**
* Returns the label object of a document.
*
* @param document The document.
* @return A label.
* @throws SiteException if an error occurs.
*/
protected Link getLabelObject(Document document) throws SiteException {
Link label = null;
SiteTree siteTree = getTree(document);
if (siteTree != null) {
SiteTreeNode node = (SiteTreeNode) siteTree.getByUuid(document.getUUID(),
document.getLanguage()).getNode();
if (node == null) {
throw new SiteException("Node for document [" + document + "] does not exist!");
}
label = (Link) node.getLink(document.getLanguage());
}
if (label == null) {
throw new SiteException("The label of document [" + document + "] is null!");
}
return label;
}
/**
* @see org.apache.lenya.cms.site.SiteManager#getDocuments(org.apache.lenya.cms.publication.DocumentFactory,
* org.apache.lenya.cms.publication.Publication, java.lang.String)
*/
public Document[] getDocuments(DocumentFactory map, Publication publication, String area)
throws SiteException {
try {
SiteTreeNodeImpl root = (SiteTreeNodeImpl) getTree(map, publication, area).getNode("/");
List allNodes = root.preOrder();
List documents = new ArrayList();
for (int i = 1; i < allNodes.size(); i++) {
SiteTreeNode node = (SiteTreeNode) allNodes.get(i);
Document doc = map.get(publication, area, node.getUuid());
String[] languages = doc.getLanguages();
for (int l = 0; l < languages.length; l++) {
documents.add(doc.getTranslation(languages[l]));
}
}
return (Document[]) documents.toArray(new Document[documents.size()]);
} catch (Exception e) {
throw new SiteException(e);
}
}
public void add(String path, Document document) throws SiteException {
if (contains(document)) {
throw new SiteException("The document [" + document + "] is already contained!");
}
DefaultSiteTree tree = getTree(document);
SiteTreeNode node;
if (!tree.contains(path)) {
// done for side effect of calling addNodNode, not the resulting return value
node = tree.addNode(path, document.getUUID(), true, null, null, false);
} else {
node = (SiteTreeNode) tree.getNode(path);
if (node.getUuid() != null) {
((SiteTreeNodeImpl) node).setUUID(document.getUUID());
}
}
tree.addLabel(path, document.getLanguage(), "");
}
public void set(String path, Document document) throws SiteException {
if (contains(document)) {
throw new SiteException("The document [" + document + "] is already contained!");
}
DefaultSiteTree tree = getTree(document);
SiteTreeNodeImpl node = (SiteTreeNodeImpl) tree.getNode(path);
node.setUUID(document.getUUID());
tree.changed();
}
/**
* @param publication The publication.
* @param area The area.
* @return The key to store sitetree objects in the identity map.
*/
protected String getKey(Publication publication, String area) {
return publication.getId() + ":" + area;
}
/**
* @see org.apache.lenya.cms.site.SiteManager#getSiteStructure(org.apache.lenya.cms.publication.DocumentFactory,
* org.apache.lenya.cms.publication.Publication, java.lang.String)
*/
public SiteStructure getSiteStructure(DocumentFactory map, Publication publiation, String area)
throws SiteException {
return getTree(map, publiation, area);
}
/**
* @see org.apache.lenya.cms.site.SiteManager#getAvailableLocator(DocumentFactory,
* org.apache.lenya.cms.publication.DocumentLocator)
*/
public DocumentLocator getAvailableLocator(DocumentFactory factory, DocumentLocator locator)
throws SiteException {
return DocumentLocator.getLocator(locator.getPublicationId(),
locator.getArea(),
computeUniquePath(factory, locator),
locator.getLanguage());
}
/**
* compute an unique document id
* @param factory The factory.
* @param locator The locator.
* @return the unique documentid
* @throws SiteException if an error occurs.
*/
protected String computeUniquePath(DocumentFactory factory, DocumentLocator locator)
throws SiteException {
String path = locator.getPath();
Publication pub;
try {
pub = factory.getPublication(locator.getPublicationId());
} catch (PublicationException e) {
throw new SiteException(e);
}
SiteTree tree = getTree(factory, pub, locator.getArea());
String suffix = null;
int version = 0;
String idwithoutsuffix = null;
if (tree.contains(path)) {
int n = path.lastIndexOf("/");
String lastToken = "";
String substring = path;
if ((n < path.length()) && (n > 0)) {
lastToken = path.substring(n);
substring = path.substring(0, n);
}
int l = lastToken.length();
int index = lastToken.lastIndexOf("-");
if (0 < index && index < l) {
suffix = lastToken.substring(index + 1);
idwithoutsuffix = substring + lastToken.substring(0, index);
version = Integer.parseInt(suffix);
} else {
idwithoutsuffix = substring + lastToken;
}
while (tree.contains(path)) {
version = version + 1;
path = idwithoutsuffix + "-" + version;
}
}
return path;
}
public boolean isVisibleInNav(Document document) throws SiteException {
SiteTree tree = getTree(document);
try {
return tree.getNode(document.getPath()).isVisible();
} catch (DocumentException e) {
throw new SiteException(e);
}
}
protected String getPath(DocumentFactory factory, Publication pub, String area, String uuid,
String language) throws SiteException {
SiteTree tree = getTree(factory, pub, area);
SiteNode node = tree.getByUuid(uuid, language).getNode();
if (node == null) {
throw new SiteException("No node found for [" + pub.getId() + ":" + area + ":" + uuid
+ ":" + language + "]");
}
return node.getPath();
}
protected String getUUID(DocumentFactory factory, Publication pub, String area, String path)
throws SiteException {
SiteTree tree = getTree(factory, pub, area);
SiteNode node = tree.getNode(path);
if (node == null) {
throw new SiteException("No node found for [" + pub.getId() + ":" + area + ":" + path
+ "]");
}
return node.getUuid();
}
protected boolean contains(DocumentFactory factory, DocumentLocator locator)
throws SiteException {
Publication pub;
try {
pub = factory.getPublication(locator.getPublicationId());
} catch (PublicationException e) {
throw new SiteException(e);
}
SiteTree tree = getTree(factory, pub, locator.getArea());
if (tree.contains(locator.getPath())) {
SiteNode node = tree.getNode(locator.getPath());
return node.hasLink(locator.getLanguage());
} else {
return false;
}
}
}