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.simple;
019:
020: import java.util.ArrayList;
021: import java.util.HashMap;
022: import java.util.HashSet;
023: import java.util.Iterator;
024: import java.util.List;
025: import java.util.Map;
026: import java.util.Set;
027: import java.util.WeakHashMap;
028:
029: import org.apache.avalon.framework.logger.Logger;
030: import org.apache.lenya.cms.publication.Document;
031: import org.apache.lenya.cms.publication.DocumentBuildException;
032: import org.apache.lenya.cms.publication.DocumentException;
033: import org.apache.lenya.cms.publication.Publication;
034: import org.apache.lenya.cms.repository.Node;
035: import org.apache.lenya.cms.repository.Session;
036: import org.apache.lenya.cms.site.Link;
037: import org.apache.lenya.cms.site.SiteException;
038: import org.apache.lenya.cms.site.SiteNode;
039: import org.apache.lenya.cms.site.SiteStructure;
040: import org.apache.lenya.modules.collection.CollectionWrapper;
041: import org.apache.lenya.transaction.TransactionException;
042: import org.apache.lenya.util.Assert;
043: import org.apache.lenya.xml.NamespaceHelper;
044: import org.w3c.dom.Element;
045:
046: /**
047: * Site structure object which stores a list of documents.
048: *
049: * @version $Id: DocumentStore.java 565766 2007-08-14 14:09:21Z andreas $
050: */
051: public class DocumentStore extends CollectionWrapper implements
052: SiteStructure {
053:
054: /**
055: * The identifiable type.
056: */
057: public static final String IDENTIFIABLE_TYPE = "documentstore";
058:
059: protected static final Object SITE_PATH = "/sitestructure";
060:
061: /**
062: * @param doc The document where the collection is stored.
063: * @param logger The logger.
064: * @throws DocumentException if an error occurs.
065: */
066: public DocumentStore(Document doc, Logger logger)
067: throws DocumentException {
068: super (doc, logger);
069: this .doc2path.put(getKey(doc.getUUID(), doc.getLanguage()),
070: SITE_PATH);
071: }
072:
073: protected static final String NAMESPACE = "http://apache.org/lenya/sitemanagement/simple/1.0";
074:
075: protected static final String ATTRIBUTE_LANGUAGE = "xml:lang";
076: protected static final String ATTRIBUTE_PATH = "path";
077:
078: private Map doc2path = new HashMap();
079:
080: protected String getKey(String uuid, String language) {
081: return uuid + ":" + language;
082: }
083:
084: protected String getLanguage(String key) {
085: return key.split(":")[1];
086: }
087:
088: protected String getUuid(String key) {
089: return key.split(":")[0];
090: }
091:
092: /**
093: * @see org.apache.lenya.modules.collection.CollectionWrapper#createDocumentElement(org.apache.lenya.cms.publication.Document,
094: * org.apache.lenya.xml.NamespaceHelper)
095: */
096: protected Element createDocumentElement(Document document,
097: NamespaceHelper helper) throws DocumentException {
098: Element element = super .createDocumentElement(document, helper);
099: element
100: .setAttribute(ATTRIBUTE_LANGUAGE, document
101: .getLanguage());
102: String path = getPath(document.getUUID(), document
103: .getLanguage());
104: element.setAttribute(ATTRIBUTE_PATH, path);
105: return element;
106: }
107:
108: /**
109: * @see org.apache.lenya.modules.collection.CollectionWrapper#loadDocument(org.w3c.dom.Element)
110: */
111: protected Document loadDocument(Element documentElement)
112: throws DocumentBuildException {
113: String uuid = documentElement.getAttribute(ATTRIBUTE_UUID);
114: String language = documentElement
115: .getAttribute(ATTRIBUTE_LANGUAGE);
116: String path = documentElement.getAttribute(ATTRIBUTE_PATH);
117: Document document = getDelegate().getFactory().get(
118: getDelegate().getPublication(),
119: getDelegate().getArea(), uuid, language);
120: String key = getKey(uuid, language);
121: if (!this .doc2path.containsKey(key)) {
122: this .doc2path.put(key, path);
123: }
124: return document;
125: }
126:
127: /**
128: * @return if the document exists.
129: * @throws DocumentException if an error occurs.
130: */
131: public boolean exists() throws DocumentException {
132: try {
133: return getDelegate().exists();
134: } catch (Exception e) {
135: throw new DocumentException(e);
136: }
137: }
138:
139: public Node getRepositoryNode() {
140: return getDelegate().getRepositoryNode();
141: }
142:
143: public boolean contains(String path) {
144: return doc2path().values().contains(path);
145: }
146:
147: public boolean containsByUuid(String uuid, String language) {
148: return doc2path().containsKey(getKey(uuid, language));
149: }
150:
151: public boolean containsInAnyLanguage(String uuid) {
152: return doc2path().containsKey(uuid);
153: }
154:
155: protected Document getDocument(String uuid) {
156: Document[] docs;
157: try {
158: docs = getDocuments();
159: } catch (DocumentException e) {
160: throw new RuntimeException(e);
161: }
162: for (int i = 0; i < docs.length; i++) {
163: if (docs[i].getUUID().equals(uuid)) {
164: return docs[i];
165: }
166: }
167: return null;
168: }
169:
170: public Link getByUuid(String uuid, String language)
171: throws SiteException {
172: String path = getPath(uuid, language);
173: SiteNode node = new SimpleSiteNode(this , path, uuid,
174: getLogger());
175: return node.getLink(language);
176: }
177:
178: protected String getPath(String uuid, String language) {
179: String key = getKey(uuid, language);
180: Assert.isTrue("contains [" + key + "]", containsByUuid(uuid,
181: language));
182: return (String) doc2path().get(key);
183: }
184:
185: private Map path2node = new WeakHashMap();
186:
187: public SiteNode getNode(String path) throws SiteException {
188:
189: SiteNode node = (SiteNode) this .path2node.get(path);
190: if (node == null) {
191: Set keys = doc2path().keySet();
192: for (Iterator i = keys.iterator(); i.hasNext();) {
193: String key = (String) i.next();
194: String value = (String) doc2path().get(key);
195: if (value.equals(path)) {
196: String uuid = getUuid(key);
197: node = new SimpleSiteNode(this , path, uuid,
198: getLogger());
199: this .path2node.put(path, node);
200: }
201: }
202: }
203: if (node != null) {
204: return node;
205: }
206: throw new SiteException("[" + this
207: + "] does not contain the path [" + path + "]");
208: }
209:
210: public String toString() {
211: return getPublication().getId() + ":" + getArea();
212: }
213:
214: public Publication getPublication() {
215: return getDelegate().getPublication();
216: }
217:
218: public String getArea() {
219: return getDelegate().getArea();
220: }
221:
222: public Link add(String path, Document document)
223: throws SiteException {
224: Assert.notNull("path", path);
225: Assert.notNull("document", document);
226:
227: try {
228: Assert.isTrue("document [" + document
229: + "] is already contained!", !contains(document));
230: String key = getKey(document.getUUID(), document
231: .getLanguage());
232: if (!doc2path().containsKey(key)) {
233: doc2path().put(key, path);
234: }
235: super .add(document);
236: save();
237: } catch (DocumentException e) {
238: throw new SiteException(e);
239: }
240:
241: return getNode(path).getLink(document.getLanguage());
242: }
243:
244: /**
245: * Sets the path for a document.
246: * @param document
247: * @param path
248: * @throws TransactionException
249: */
250: public void setPath(Document document, String path)
251: throws TransactionException {
252: Assert.notNull("path", path);
253: Assert.notNull("document", document);
254: String key = getKey(document.getUUID(), document.getLanguage());
255: doc2path().put(key, path);
256: save();
257: }
258:
259: protected Map doc2path() {
260: load();
261: return this .doc2path;
262: }
263:
264: public SiteNode[] getNodes() {
265: try {
266: Document[] docs = getDocuments();
267: Set paths = new HashSet();
268: for (int i = 0; i < docs.length; i++) {
269: paths.add(getPath(docs[i].getUUID(), docs[i]
270: .getLanguage()));
271: }
272: Set nodes = new HashSet();
273: for (Iterator i = paths.iterator(); i.hasNext();) {
274: String path = (String) i.next();
275: nodes.add(getNode(path));
276: }
277: return (SiteNode[]) nodes
278: .toArray(new SiteNode[nodes.size()]);
279: } catch (Exception e) {
280: throw new RuntimeException(e);
281: }
282: }
283:
284: public SiteNode add(String path) throws SiteException {
285: throw new SiteException("This operation is not supported by ["
286: + getClass().getName() + "]!");
287: }
288:
289: public void remove(Document document) throws DocumentException {
290: super .remove(document);
291: this .doc2path.remove(getKey(document.getUUID(), document
292: .getLanguage()));
293: save();
294: }
295:
296: public SiteNode add(String path, String followingSiblingPath)
297: throws SiteException {
298: return add(path);
299: }
300:
301: public SiteNode[] getTopLevelNodes() {
302: SiteNode[] nodes = getNodes();
303: List topLevelNodes = new ArrayList();
304: for (int i = 0; i < nodes.length; i++) {
305: if (nodes[i].isTopLevel()) {
306: topLevelNodes.add(nodes[i]);
307: }
308: }
309: return (SiteNode[]) topLevelNodes
310: .toArray(new SiteNode[topLevelNodes.size()]);
311: }
312:
313: public boolean contains(String path, String language) {
314: if (contains(path)) {
315: SiteNode node;
316: try {
317: node = getNode(path);
318: } catch (SiteException e) {
319: throw new RuntimeException(e);
320: }
321: return node.hasLink(language);
322: }
323: return false;
324: }
325:
326: public Session getSession() {
327: return getRepositoryNode().getSession();
328: }
329: }
|