001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: *
017: */
018: package org.apache.lenya.cms.site.tree2;
019:
020: import java.util.ArrayList;
021: import java.util.List;
022:
023: import org.apache.lenya.cms.publication.Area;
024: import org.apache.lenya.cms.publication.Document;
025: import org.apache.lenya.cms.publication.DocumentException;
026: import org.apache.lenya.cms.publication.DocumentFactory;
027: import org.apache.lenya.cms.publication.DocumentLocator;
028: import org.apache.lenya.cms.publication.Publication;
029: import org.apache.lenya.cms.publication.PublicationException;
030: import org.apache.lenya.cms.repository.RepositoryItemFactory;
031: import org.apache.lenya.cms.site.AbstractSiteManager;
032: import org.apache.lenya.cms.site.Link;
033: import org.apache.lenya.cms.site.NodeSet;
034: import org.apache.lenya.cms.site.SiteException;
035: import org.apache.lenya.cms.site.SiteNode;
036: import org.apache.lenya.cms.site.SiteStructure;
037: import org.apache.lenya.cms.site.tree.SiteTree;
038: import org.apache.lenya.cms.site.tree.SiteTreeNode;
039:
040: /**
041: * Tree-based site manager.
042: */
043: public class TreeSiteManager extends AbstractSiteManager {
044:
045: /**
046: * Returns the sitetree for a specific area of this publication. Sitetrees are created on demand
047: * and are cached.
048: *
049: * @param area The area.
050: * @return A site tree.
051: * @throws SiteException if an error occurs.
052: */
053: protected SiteTree getTree(Area area) throws SiteException {
054:
055: String key = getKey(area);
056: SiteTree sitetree;
057: RepositoryItemFactory factory = new SiteTreeFactory(
058: this .manager, getLogger());
059: try {
060: sitetree = (SiteTree) area.getPublication().getFactory()
061: .getSession().getRepositoryItem(factory, key);
062: } catch (Exception e) {
063: throw new SiteException(e);
064: }
065:
066: return sitetree;
067: }
068:
069: /**
070: * @param area The area.
071: * @return The key to store sitetree objects in the identity map.
072: */
073: protected String getKey(Area area) {
074: return area.getPublication().getId() + ":" + area.getName();
075: }
076:
077: public void add(String path, Document doc) throws SiteException {
078: getTree(doc.area()).add(path, doc);
079: }
080:
081: public boolean contains(Document doc) throws SiteException {
082: return getTree(doc.area()).containsByUuid(doc.getUUID(),
083: doc.getLanguage());
084: }
085:
086: public boolean containsInAnyLanguage(Document doc)
087: throws SiteException {
088: return getTree(doc.area()).containsInAnyLanguage(doc.getUUID());
089: }
090:
091: public void copy(Document srcDoc, Document destDoc)
092: throws SiteException {
093: SiteTree destinationTree = getTree(destDoc.area());
094:
095: try {
096: TreeNodeImpl sourceNode = (TreeNodeImpl) srcDoc.getLink()
097: .getNode();
098:
099: SiteTreeNode[] siblings = sourceNode.getNextSiblings();
100: SiteNode parent = sourceNode.getParent();
101: String parentId = "";
102: if (parent != null) {
103: parentId = parent.getPath();
104: }
105: TreeNodeImpl sibling = null;
106: String siblingPath = null;
107:
108: // same UUID -> insert at the same position
109: if (srcDoc.getUUID().equals(destDoc.getUUID())) {
110: for (int i = 0; i < siblings.length; i++) {
111: String path = parentId + "/"
112: + siblings[i].getName();
113: sibling = (TreeNodeImpl) destinationTree
114: .getNode(path);
115: if (sibling != null) {
116: siblingPath = path;
117: break;
118: }
119: }
120: }
121:
122: if (!sourceNode.hasLink(srcDoc.getLanguage())) {
123: // the node that we're trying to publish
124: // doesn't have this language
125: throw new SiteException("The node " + srcDoc.getPath()
126: + " doesn't contain a label for language "
127: + srcDoc.getLanguage());
128: }
129:
130: String destPath = destDoc.getPath();
131:
132: Link link = sourceNode.getLink(srcDoc.getLanguage());
133: SiteNode destNode = destinationTree.getNode(destPath);
134: if (destNode == null) {
135: if (siblingPath == null) {
136: // called for side effect of add, not return result
137: destNode = destinationTree.add(destPath);
138: } else {
139: // called for side effect of add, not return result
140: destNode = destinationTree.add(destPath,
141: siblingPath);
142: }
143: destinationTree.add(destPath, destDoc);
144: } else {
145: destDoc.getLink().setLabel(link.getLabel());
146: }
147: } catch (DocumentException e) {
148: throw new SiteException(e);
149: }
150: }
151:
152: public DocumentLocator getAvailableLocator(DocumentFactory factory,
153: DocumentLocator locator) throws SiteException {
154: return DocumentLocator.getLocator(locator.getPublicationId(),
155: locator.getArea(), computeUniquePath(factory, locator),
156: locator.getLanguage());
157: }
158:
159: /**
160: * compute an unique document id
161: * @param factory The factory.
162: * @param locator The locator.
163: * @return the unique documentid
164: * @throws SiteException if an error occurs.
165: */
166: protected String computeUniquePath(DocumentFactory factory,
167: DocumentLocator locator) throws SiteException {
168: String path = locator.getPath();
169:
170: Publication pub;
171: SiteTree tree;
172: try {
173: pub = factory.getPublication(locator.getPublicationId());
174: tree = getTree(pub.getArea(locator.getArea()));
175: } catch (PublicationException e) {
176: throw new SiteException(e);
177: }
178:
179: String suffix = null;
180: int version = 0;
181: String idwithoutsuffix = null;
182:
183: if (tree.contains(path)) {
184: int n = path.lastIndexOf("/");
185: String lastToken = "";
186: String substring = path;
187: lastToken = path.substring(n);
188: substring = path.substring(0, n);
189:
190: int l = lastToken.length();
191: int index = lastToken.lastIndexOf("-");
192: if (0 < index && index < l
193: && lastToken.substring(index + 1).matches("[\\d]*")) {
194: suffix = lastToken.substring(index + 1);
195: idwithoutsuffix = substring
196: + lastToken.substring(0, index);
197: version = Integer.parseInt(suffix);
198: } else {
199: idwithoutsuffix = substring + lastToken;
200: }
201:
202: while (tree.contains(path)) {
203: version = version + 1;
204: path = idwithoutsuffix + "-" + version;
205: }
206: }
207:
208: return path;
209: }
210:
211: public Document[] getDocuments(DocumentFactory factory,
212: Publication pub, String area) throws SiteException {
213: Area areaObj;
214: try {
215: areaObj = pub.getArea(area);
216: } catch (PublicationException e) {
217: throw new SiteException(e);
218: }
219: SiteTree tree = getTree(areaObj);
220: SiteNode[] preOrder = tree.preOrder();
221: List docs = new ArrayList();
222: for (int i = 0; i < preOrder.length; i++) {
223: String[] langs = preOrder[i].getLanguages();
224: for (int l = 0; l < langs.length; l++) {
225: docs.add(preOrder[i].getLink(langs[l]).getDocument());
226: }
227: }
228: return (Document[]) docs.toArray(new Document[docs.size()]);
229: }
230:
231: public DocumentLocator[] getRequiredResources(DocumentFactory map,
232: DocumentLocator loc) throws SiteException {
233: List ancestors = new ArrayList();
234: DocumentLocator locator = loc;
235: while (locator.getParent() != null) {
236: DocumentLocator parent = locator.getParent();
237: ancestors.add(parent);
238: locator = parent;
239: }
240: return (DocumentLocator[]) ancestors
241: .toArray(new DocumentLocator[ancestors.size()]);
242: }
243:
244: public SiteNode[] getRequiringResources(DocumentFactory map,
245: SiteNode resource) throws SiteException {
246: NodeSet nodes = new NodeSet(this .manager);
247: SiteTree tree = (SiteTree) resource.getStructure();
248:
249: TreeNode node = (TreeNode) tree.getNode(resource.getPath());
250: if (node != null) {
251: SiteNode[] preOrder = node.preOrder();
252:
253: // exclude original resource (does not require itself)
254: for (int i = 1; i < preOrder.length; i++) {
255: TreeNode descendant = (TreeNode) preOrder[i];
256: nodes.add(descendant);
257: }
258: }
259:
260: return nodes.getNodes();
261: }
262:
263: public SiteStructure getSiteStructure(DocumentFactory map,
264: Publication publication, String area) throws SiteException {
265: try {
266: return getTree(publication.getArea(area));
267: } catch (PublicationException e) {
268: throw new SiteException(e);
269: }
270: }
271:
272: public boolean isVisibleInNav(Document document)
273: throws SiteException {
274: try {
275: return document.getLink().getNode().isVisible();
276: } catch (DocumentException e) {
277: throw new SiteException(e);
278: }
279: }
280:
281: public boolean requires(DocumentFactory map, SiteNode depending,
282: SiteNode required) throws SiteException {
283: return depending.getPath().startsWith(required.getPath() + "/");
284: }
285:
286: public void set(String path, Document document)
287: throws SiteException {
288: if (contains(document)) {
289: throw new SiteException("The document [" + document
290: + "] is already contained!");
291: }
292: SiteTreeImpl tree = (SiteTreeImpl) getTree(document.area());
293: TreeNodeImpl node = (TreeNodeImpl) tree.getNode(path);
294: node.setUuid(document.getUUID());
295: tree.changed();
296: }
297:
298: public void setVisibleInNav(Document document, boolean visibleInNav)
299: throws SiteException {
300: try {
301: document.getLink().getNode().setVisible(visibleInNav);
302: } catch (DocumentException e) {
303: throw new SiteException(e);
304: }
305: }
306:
307: }
|