| /* |
| * 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.List; |
| |
| import org.apache.lenya.cms.publication.Area; |
| 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; |
| import org.apache.lenya.cms.site.tree.SiteTree; |
| import org.apache.lenya.cms.site.tree.SiteTreeNode; |
| |
| /** |
| * Tree-based site manager. |
| */ |
| public class TreeSiteManager extends AbstractSiteManager { |
| |
| /** |
| * Returns the sitetree for a specific area of this publication. Sitetrees are created on demand |
| * and are cached. |
| * |
| * @param area The area. |
| * @return A site tree. |
| * @throws SiteException if an error occurs. |
| */ |
| protected SiteTree getTree(Area area) throws SiteException { |
| |
| String key = getKey(area); |
| SiteTree sitetree; |
| RepositoryItemFactory factory = new SiteTreeFactory(this.manager, getLogger()); |
| try { |
| sitetree = (SiteTree) area.getPublication().getFactory().getSession() |
| .getRepositoryItem(factory, key); |
| } catch (Exception e) { |
| throw new SiteException(e); |
| } |
| |
| return sitetree; |
| } |
| |
| /** |
| * @param area The area. |
| * @return The key to store sitetree objects in the identity map. |
| */ |
| protected String getKey(Area area) { |
| return area.getPublication().getId() + ":" + area.getName(); |
| } |
| |
| public void add(String path, Document doc) throws SiteException { |
| getTree(doc.area()).add(path, doc); |
| } |
| |
| public boolean contains(Document doc) throws SiteException { |
| return getTree(doc.area()).containsByUuid(doc.getUUID(), doc.getLanguage()); |
| } |
| |
| public boolean containsInAnyLanguage(Document doc) throws SiteException { |
| return getTree(doc.area()).containsInAnyLanguage(doc.getUUID()); |
| } |
| |
| public void copy(Document srcDoc, Document destDoc) throws SiteException { |
| SiteTree destinationTree = getTree(destDoc.area()); |
| |
| try { |
| TreeNodeImpl sourceNode = (TreeNodeImpl) srcDoc.getLink().getNode(); |
| |
| SiteTreeNode[] siblings = sourceNode.getNextSiblings(); |
| SiteNode parent = sourceNode.getParent(); |
| String parentId = ""; |
| if (parent != null) { |
| parentId = parent.getPath(); |
| } |
| TreeNodeImpl sibling = null; |
| String siblingPath = null; |
| |
| // same UUID -> insert at the same position |
| if (srcDoc.getUUID().equals(destDoc.getUUID())) { |
| for (int i = 0; i < siblings.length; i++) { |
| String path = parentId + "/" + siblings[i].getName(); |
| sibling = (TreeNodeImpl) destinationTree.getNode(path); |
| if (sibling != null) { |
| siblingPath = path; |
| break; |
| } |
| } |
| } |
| |
| if (!sourceNode.hasLink(srcDoc.getLanguage())) { |
| // the node that we're trying to publish |
| // doesn't have this language |
| throw new SiteException("The node " + srcDoc.getPath() |
| + " doesn't contain a label for language " + srcDoc.getLanguage()); |
| } |
| |
| String destPath = destDoc.getPath(); |
| |
| Link link = sourceNode.getLink(srcDoc.getLanguage()); |
| SiteNode destNode = destinationTree.getNode(destPath); |
| if (destNode == null) { |
| if (siblingPath == null) { |
| // called for side effect of add, not return result |
| destNode = destinationTree.add(destPath); |
| } else { |
| // called for side effect of add, not return result |
| destNode = destinationTree.add(destPath, siblingPath); |
| } |
| destinationTree.add(destPath, destDoc); |
| } else { |
| destDoc.getLink().setLabel(link.getLabel()); |
| } |
| } catch (DocumentException e) { |
| throw new SiteException(e); |
| } |
| } |
| |
| 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; |
| SiteTree tree; |
| try { |
| pub = factory.getPublication(locator.getPublicationId()); |
| tree = getTree(pub.getArea(locator.getArea())); |
| } catch (PublicationException e) { |
| throw new SiteException(e); |
| } |
| |
| String suffix = null; |
| int version = 0; |
| String idwithoutsuffix = null; |
| |
| if (tree.contains(path)) { |
| int n = path.lastIndexOf("/"); |
| String lastToken = ""; |
| String substring = path; |
| lastToken = path.substring(n); |
| substring = path.substring(0, n); |
| |
| int l = lastToken.length(); |
| int index = lastToken.lastIndexOf("-"); |
| if (0 < index && index < l && lastToken.substring(index + 1).matches("[\\d]*")) { |
| 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 Document[] getDocuments(DocumentFactory factory, Publication pub, String area) |
| throws SiteException { |
| Area areaObj; |
| try { |
| areaObj = pub.getArea(area); |
| } catch (PublicationException e) { |
| throw new SiteException(e); |
| } |
| SiteTree tree = getTree(areaObj); |
| SiteNode[] preOrder = tree.preOrder(); |
| List docs = new ArrayList(); |
| for (int i = 0; i < preOrder.length; i++) { |
| String[] langs = preOrder[i].getLanguages(); |
| for (int l = 0; l < langs.length; l++) { |
| docs.add(preOrder[i].getLink(langs[l]).getDocument()); |
| } |
| } |
| return (Document[]) docs.toArray(new Document[docs.size()]); |
| } |
| |
| public DocumentLocator[] getRequiredResources(DocumentFactory map, 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()]); |
| } |
| |
| public SiteNode[] getRequiringResources(DocumentFactory map, SiteNode resource) |
| throws SiteException { |
| NodeSet nodes = new NodeSet(this.manager); |
| SiteTree tree = (SiteTree) resource.getStructure(); |
| |
| TreeNode node = (TreeNode) tree.getNode(resource.getPath()); |
| if (node != null) { |
| SiteNode[] preOrder = node.preOrder(); |
| |
| // exclude original resource (does not require itself) |
| for (int i = 1; i < preOrder.length; i++) { |
| TreeNode descendant = (TreeNode) preOrder[i]; |
| nodes.add(descendant); |
| } |
| } |
| |
| return nodes.getNodes(); |
| } |
| |
| public SiteStructure getSiteStructure(DocumentFactory map, Publication publication, String area) |
| throws SiteException { |
| try { |
| return getTree(publication.getArea(area)); |
| } catch (PublicationException e) { |
| throw new SiteException(e); |
| } |
| } |
| |
| public boolean isVisibleInNav(Document document) throws SiteException { |
| try { |
| return document.getLink().getNode().isVisible(); |
| } catch (DocumentException e) { |
| throw new SiteException(e); |
| } |
| } |
| |
| public boolean requires(DocumentFactory map, SiteNode depending, SiteNode required) |
| throws SiteException { |
| return depending.getPath().startsWith(required.getPath() + "/"); |
| } |
| |
| public void set(String path, Document document) throws SiteException { |
| if (contains(document)) { |
| throw new SiteException("The document [" + document + "] is already contained!"); |
| } |
| SiteTreeImpl tree = (SiteTreeImpl) getTree(document.area()); |
| TreeNodeImpl node = (TreeNodeImpl) tree.getNode(path); |
| node.setUuid(document.getUUID()); |
| tree.changed(); |
| } |
| |
| public void setVisibleInNav(Document document, boolean visibleInNav) throws SiteException { |
| try { |
| document.getLink().getNode().setVisible(visibleInNav); |
| } catch (DocumentException e) { |
| throw new SiteException(e); |
| } |
| } |
| |
| } |