| /* |
| * 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.modules.collection; |
| |
| import java.io.IOException; |
| import java.util.ArrayList; |
| import java.util.Arrays; |
| import java.util.List; |
| |
| import javax.xml.parsers.ParserConfigurationException; |
| import javax.xml.transform.TransformerException; |
| |
| import org.apache.avalon.framework.logger.AbstractLogEnabled; |
| import org.apache.avalon.framework.logger.Logger; |
| import org.apache.avalon.framework.service.ServiceException; |
| import org.apache.lenya.cms.publication.Document; |
| import org.apache.lenya.cms.publication.DocumentBuildException; |
| import org.apache.lenya.cms.publication.DocumentException; |
| import org.apache.lenya.xml.DocumentHelper; |
| import org.apache.lenya.xml.NamespaceHelper; |
| import org.apache.xpath.XPathAPI; |
| import org.w3c.dom.DOMException; |
| import org.w3c.dom.Element; |
| import org.w3c.dom.Node; |
| import org.w3c.dom.NodeList; |
| import org.xml.sax.SAXException; |
| |
| /** |
| * Document wrapper for collection functionality. |
| */ |
| public class CollectionWrapper extends AbstractLogEnabled implements Collection { |
| |
| private Document delegate; |
| |
| protected static final String[] TYPES = { TYPE_CHILDREN, TYPE_MANUAL, TYPE_LINK }; |
| |
| /** |
| * Ctor. |
| * @param doc The document. |
| * @param logger The logger. |
| */ |
| public CollectionWrapper(Document doc, Logger logger) { |
| enableLogging(logger); |
| this.delegate = doc; |
| } |
| |
| public Document getDelegate() { |
| return this.delegate; |
| } |
| |
| private List documentsList; |
| |
| /** |
| * Returns the list that holds the documents. Use this method to invoke lazy |
| * loading. |
| * @return A list. |
| * @throws DocumentException when something went wrong. |
| */ |
| protected List documents() throws DocumentException { |
| load(); |
| return this.documentsList; |
| } |
| |
| /** |
| * @see org.apache.lenya.modules.collection.Collection#getDocuments() |
| */ |
| public Document[] getDocuments() throws DocumentException { |
| return (Document[]) documents().toArray(new Document[documents().size()]); |
| } |
| |
| /** |
| * @see org.apache.lenya.modules.collection.Collection#add(org.apache.lenya.cms.publication.Document) |
| */ |
| public void add(Document document) throws DocumentException { |
| documents().add(document); |
| } |
| |
| /** |
| * @see org.apache.lenya.modules.collection.Collection#add(int, |
| * org.apache.lenya.cms.publication.Document) |
| */ |
| public void add(int position, Document document) throws DocumentException { |
| documents().add(position, document); |
| } |
| |
| /** |
| * @see org.apache.lenya.modules.collection.Collection#remove(org.apache.lenya.cms.publication.Document) |
| */ |
| public void remove(Document document) throws DocumentException { |
| if (!documents().contains(document)) { |
| throw new DocumentException("Collection [" + this + "] does not contain document [" |
| + document + "]"); |
| } |
| documents().remove(document); |
| } |
| |
| private boolean isLoaded = false; |
| |
| /** |
| * Loads the collection from its XML source. |
| */ |
| protected final void load() { |
| if (!this.isLoaded) { |
| getLogger().debug("Loading: "); |
| NamespaceHelper helper; |
| try { |
| helper = getNamespaceHelper(); |
| } catch (Exception e) { |
| throw new RuntimeException(e); |
| } |
| loadXml(helper); |
| this.isLoaded = true; |
| } |
| } |
| |
| protected void loadXml(NamespaceHelper helper) { |
| try { |
| this.documentsList = new ArrayList(); |
| |
| Element collectionElement = helper.getDocument().getDocumentElement(); |
| Element[] documentElements = helper |
| .getChildren(collectionElement, ELEMENT_DOCUMENT); |
| |
| for (int i = 0; i < documentElements.length; i++) { |
| Element documentElement = documentElements[i]; |
| Document document = loadDocument(documentElement); |
| this.documentsList.add(document); |
| } |
| |
| if (collectionElement.hasAttribute(ATTRIBUTE_TYPE)) { |
| this.type = collectionElement.getAttribute(ATTRIBUTE_TYPE); |
| } |
| |
| if (collectionElement.hasAttribute(ATTRIBUTE_HREF)) { |
| this.href = collectionElement.getAttribute(ATTRIBUTE_HREF); |
| } |
| } catch (RuntimeException e) { |
| throw e; |
| } catch (Exception e) { |
| throw new RuntimeException(e); |
| } |
| } |
| |
| /** |
| * Loads a document from an XML element. |
| * @param documentElement The XML element. |
| * @return A document. |
| * @throws DocumentBuildException when something went wrong. |
| */ |
| protected Document loadDocument(Element documentElement) throws DocumentBuildException { |
| String documentId = documentElement.getAttribute(ATTRIBUTE_UUID); |
| Document document = getDelegate().getFactory().get(getDelegate().getPublication(), |
| getDelegate().getArea(), documentId, getDelegate().getLanguage()); |
| return document; |
| } |
| |
| /** |
| * Saves the collection. |
| */ |
| public final void save() { |
| try { |
| NamespaceHelper helper = getNamespaceHelper(); |
| saveXml(helper); |
| DocumentHelper.writeDocument(helper.getDocument(), getDelegate().getOutputStream()); |
| } catch (Exception e) { |
| throw new RuntimeException(e); |
| } |
| } |
| |
| /** |
| * @param helper Save the XML to the provided namespace helper. |
| * @throws TransformerException if an error occurs. |
| * @throws DocumentException if an error occurs. |
| */ |
| protected void saveXml(NamespaceHelper helper) throws TransformerException, DocumentException { |
| Element collectionElement = helper.getDocument().getDocumentElement(); |
| if (collectionElement.getAttributeNS(null, ATTRIBUTE_UUID).equals("") |
| || collectionElement.getAttribute(ATTRIBUTE_UUID).equals("")) { |
| collectionElement.setAttributeNS(null, ATTRIBUTE_UUID, getDelegate().getUUID()); |
| } |
| Element[] existingDocumentElements = helper.getChildren(collectionElement, |
| ELEMENT_DOCUMENT); |
| for (int i = 0; i < existingDocumentElements.length; i++) { |
| collectionElement.removeChild(existingDocumentElements[i]); |
| } |
| |
| collectionElement.setAttribute(ATTRIBUTE_TYPE, getType()); |
| |
| collectionElement.setAttribute(ATTRIBUTE_HREF, getHref()); |
| |
| collectionElement.normalize(); |
| |
| NodeList emptyTextNodes = XPathAPI.selectNodeList(collectionElement, "text()"); |
| for (int i = 0; i < emptyTextNodes.getLength(); i++) { |
| Node node = emptyTextNodes.item(i); |
| node = collectionElement.removeChild(node); |
| } |
| |
| Document[] documents = getDocuments(); |
| for (int i = 0; i < documents.length; i++) { |
| Element documentElement = createDocumentElement(documents[i], helper); |
| collectionElement.appendChild(documentElement); |
| } |
| } |
| |
| public String getType() { |
| load(); |
| return this.type; |
| } |
| |
| /** |
| * Creates an element to store a document. |
| * @param helper The namespace helper of the document. |
| * @param document The document. |
| * @return An XML element. |
| * @throws DocumentException when something went wrong. |
| */ |
| protected Element createDocumentElement(Document document, NamespaceHelper helper) |
| throws DocumentException { |
| try { |
| Element documentElement = helper.createElement(ELEMENT_DOCUMENT); |
| documentElement.setAttributeNS(null, ATTRIBUTE_UUID, document.getUUID()); |
| return documentElement; |
| } catch (final DOMException e) { |
| throw new DocumentException(e); |
| } |
| } |
| |
| /** |
| * Returns the namespace helper for the XML source. |
| * @return A namespace helper. |
| * @throws DocumentException when something went wrong. |
| * @throws ParserConfigurationException when something went wrong. |
| * @throws SAXException when something went wrong. |
| * @throws IOException when something went wrong. |
| * @throws ServiceException |
| */ |
| protected NamespaceHelper getNamespaceHelper() throws DocumentException, |
| ParserConfigurationException, SAXException, IOException, ServiceException { |
| |
| NamespaceHelper helper; |
| |
| if (getDelegate().exists()) { |
| org.w3c.dom.Document document = DocumentHelper.readDocument(getDelegate() |
| .getInputStream()); |
| helper = new NamespaceHelper(Collection.NAMESPACE, Collection.DEFAULT_PREFIX, document); |
| } else { |
| helper = initializeNamespaceHelper(); |
| } |
| return helper; |
| } |
| |
| /** |
| * @return A new, empty namespace helper. |
| */ |
| protected NamespaceHelper initializeNamespaceHelper() { |
| NamespaceHelper helper; |
| try { |
| helper = new NamespaceHelper(Collection.NAMESPACE, Collection.DEFAULT_PREFIX, |
| ELEMENT_COLLECTION); |
| } catch (ParserConfigurationException e) { |
| throw new RuntimeException(e); |
| } |
| return helper; |
| } |
| |
| /** |
| * @see org.apache.lenya.modules.collection.Collection#contains(org.apache.lenya.cms.publication.Document) |
| */ |
| public boolean contains(Document document) throws DocumentException { |
| return documents().contains(document); |
| } |
| |
| /** |
| * @see org.apache.lenya.modules.collection.Collection#clear() |
| */ |
| public void clear() throws DocumentException { |
| documents().clear(); |
| } |
| |
| /** |
| * @see org.apache.lenya.modules.collection.Collection#getFirstPosition(org.apache.lenya.cms.publication.Document) |
| */ |
| public int getFirstPosition(Document document) throws DocumentException { |
| load(); |
| if (!contains(document)) { |
| throw new DocumentException("The collection [" + this |
| + "] does not contain the document [" + document + "]"); |
| } |
| return documents().indexOf(document); |
| } |
| |
| /** |
| * @see org.apache.lenya.modules.collection.Collection#size() |
| */ |
| public int size() throws DocumentException { |
| return documents().size(); |
| } |
| |
| private String type = TYPE_MANUAL; |
| |
| public void setType(String type) { |
| load(); |
| if (!Arrays.asList(TYPES).contains(type)) { |
| throw new IllegalArgumentException("The type [" + type + "] is not supported!"); |
| } |
| this.type = type; |
| } |
| |
| private String href = ""; |
| |
| public String getHref() { |
| load(); |
| return this.href; |
| } |
| |
| public void setHref(String href) { |
| load(); |
| this.href = href; |
| } |
| |
| } |