Improve ACR, introduce migration from JCR.
[lgpl/argeo-commons.git] / org.argeo.cms / src / org / argeo / cms / acr / xml / DomContentProvider.java
index efca3effdd7737e9dc13c464a74d41e640d3d472..f76d38ce07a338401452834a3541400892c5cccf 100644 (file)
@@ -1,13 +1,14 @@
 package org.argeo.cms.acr.xml;
 
+import java.io.IOException;
+import java.io.OutputStream;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.Iterator;
 import java.util.List;
 
 import javax.xml.namespace.NamespaceContext;
-import javax.xml.parsers.DocumentBuilder;
-import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.transform.TransformerFactory;
 import javax.xml.xpath.XPath;
 import javax.xml.xpath.XPathConstants;
 import javax.xml.xpath.XPathExpressionException;
@@ -16,32 +17,40 @@ import javax.xml.xpath.XPathFactory;
 import org.argeo.api.acr.Content;
 import org.argeo.api.acr.ContentNotFoundException;
 import org.argeo.api.acr.CrName;
+import org.argeo.api.acr.NamespaceUtils;
 import org.argeo.api.acr.spi.ContentProvider;
+import org.argeo.api.acr.spi.ProvidedContent;
 import org.argeo.api.acr.spi.ProvidedSession;
+import org.argeo.cms.acr.CmsContentRepository;
 import org.w3c.dom.Document;
 import org.w3c.dom.Element;
 import org.w3c.dom.NodeList;
-import org.xml.sax.ErrorHandler;
-import org.xml.sax.SAXException;
-import org.xml.sax.SAXParseException;
 
 public class DomContentProvider implements ContentProvider, NamespaceContext {
-       private Document document;
+       private final Document document;
 
        // XPath
        // TODO centralise in some executor?
        private final ThreadLocal<XPath> xPath;
 
-       public DomContentProvider(Document document) {
+       private TransformerFactory transformerFactory;
+
+       private String mountPath;
+
+       public DomContentProvider(String mountPath, Document document) {
+               this.mountPath = mountPath;
                this.document = document;
                this.document.normalizeDocument();
+
+               transformerFactory = TransformerFactory.newInstance();
+
                XPathFactory xPathFactory = XPathFactory.newInstance();
                xPath = new ThreadLocal<>() {
 
                        @Override
                        protected XPath initialValue() {
                                // TODO set the document as namespace context?
-                               XPath res= xPathFactory.newXPath();
+                               XPath res = xPathFactory.newXPath();
                                res.setNamespaceContext(DomContentProvider.this);
                                return res;
                        }
@@ -59,27 +68,61 @@ public class DomContentProvider implements ContentProvider, NamespaceContext {
 //     }
 
        @Override
-       public Content get(ProvidedSession session, String mountPath, String relativePath) {
+       public ProvidedContent get(ProvidedSession session, String relativePath) {
                if ("".equals(relativePath))
                        return new DomContent(session, this, document.getDocumentElement());
+
+               NodeList nodes = findContent(relativePath);
+               if (nodes.getLength() > 1)
+                       throw new IllegalArgumentException("Multiple content found for " + relativePath + " under " + mountPath);
+               if (nodes.getLength() == 0)
+                       throw new ContentNotFoundException("Path " + relativePath + " under " + mountPath + " was not found");
+               Element element = (Element) nodes.item(0);
+               return new DomContent(session, this, element);
+       }
+
+       protected NodeList findContent(String relativePath) {
                if (relativePath.startsWith("/"))
                        throw new IllegalArgumentException("Relative path cannot start with /");
-
                String xPathExpression = '/' + relativePath;
                if ("/".equals(mountPath))
-                       xPathExpression = "/cr:root" + xPathExpression;
+                       xPathExpression = "/" + CrName.root.qName() + xPathExpression;
                try {
                        NodeList nodes = (NodeList) xPath.get().evaluate(xPathExpression, document, XPathConstants.NODESET);
-                       if (nodes.getLength() > 1)
-                               throw new IllegalArgumentException(
-                                               "Multiple content found for " + relativePath + " under " + mountPath);
-                       if (nodes.getLength() == 0)
-                               throw new ContentNotFoundException("Path " + relativePath + " under " + mountPath + " was not found");
-                       Element element = (Element) nodes.item(0);
-                       return new DomContent(session, this, element);
+                       return nodes;
                } catch (XPathExpressionException e) {
                        throw new IllegalArgumentException("XPath expression " + xPathExpression + " cannot be evaluated", e);
                }
+
+       }
+
+       @Override
+       public boolean exists(ProvidedSession session, String relativePath) {
+               if ("".equals(relativePath))
+                       return true;
+               NodeList nodes = findContent(relativePath);
+               return nodes.getLength() != 0;
+       }
+
+       public void persist(ProvidedSession session) {
+               if (mountPath != null) {
+                       Content mountPoint = session.getMountPoint(mountPath);
+                       try (OutputStream out = mountPoint.open(OutputStream.class)) {
+                               CmsContentRepository contentRepository = (CmsContentRepository) session.getRepository();
+                               contentRepository.writeDom(document, out);
+                       } catch (IOException e) {
+                               throw new IllegalStateException("Cannot persist " + mountPath, e);
+                       }
+               }
+       }
+
+       @Override
+       public String getMountPath() {
+               return mountPath;
+       }
+
+       public void registerPrefix(String prefix, String namespace) {
+               DomUtils.addNamespace(document.getDocumentElement(), prefix, namespace);
        }
 
        /*
@@ -87,11 +130,17 @@ public class DomContentProvider implements ContentProvider, NamespaceContext {
         */
        @Override
        public String getNamespaceURI(String prefix) {
+               String namespaceURI = NamespaceUtils.getStandardNamespaceURI(prefix);
+               if (namespaceURI != null)
+                       return namespaceURI;
                return document.lookupNamespaceURI(prefix);
        }
 
        @Override
        public String getPrefix(String namespaceURI) {
+               String prefix = NamespaceUtils.getStandardPrefix(namespaceURI);
+               if (prefix != null)
+                       return prefix;
                return document.lookupPrefix(namespaceURI);
        }
 
@@ -102,5 +151,8 @@ public class DomContentProvider implements ContentProvider, NamespaceContext {
                return Collections.unmodifiableList(res).iterator();
        }
 
-       
+       TransformerFactory getTransformerFactory() {
+               return transformerFactory;
+       }
+
 }