]> git.argeo.org Git - lgpl/argeo-commons.git/blob - org.argeo.cms/src/org/argeo/cms/acr/xml/DomContentProvider.java
39d9c2a90b56d5a8483c9813fb5637e0b94dc7d3
[lgpl/argeo-commons.git] / org.argeo.cms / src / org / argeo / cms / acr / xml / DomContentProvider.java
1 package org.argeo.cms.acr.xml;
2
3 import java.io.IOException;
4 import java.io.OutputStream;
5 import java.util.ArrayList;
6 import java.util.Collections;
7 import java.util.Iterator;
8 import java.util.List;
9
10 import javax.xml.namespace.NamespaceContext;
11 import javax.xml.transform.TransformerFactory;
12 import javax.xml.xpath.XPath;
13 import javax.xml.xpath.XPathConstants;
14 import javax.xml.xpath.XPathExpressionException;
15 import javax.xml.xpath.XPathFactory;
16
17 import org.argeo.api.acr.Content;
18 import org.argeo.api.acr.ContentNotFoundException;
19 import org.argeo.api.acr.CrName;
20 import org.argeo.api.acr.NamespaceUtils;
21 import org.argeo.api.acr.spi.ContentProvider;
22 import org.argeo.api.acr.spi.ProvidedContent;
23 import org.argeo.api.acr.spi.ProvidedSession;
24 import org.argeo.cms.acr.CmsContentRepository;
25 import org.argeo.cms.acr.ContentUtils;
26 import org.w3c.dom.Document;
27 import org.w3c.dom.Element;
28 import org.w3c.dom.NodeList;
29
30 public class DomContentProvider implements ContentProvider, NamespaceContext {
31 private final Document document;
32
33 // XPath
34 // TODO centralise in some executor?
35 private final ThreadLocal<XPath> xPath;
36
37 private TransformerFactory transformerFactory;
38
39 private String mountPath;
40
41 public DomContentProvider(String mountPath, Document document) {
42 this.mountPath = mountPath;
43 this.document = document;
44 this.document.normalizeDocument();
45
46 transformerFactory = TransformerFactory.newInstance();
47
48 XPathFactory xPathFactory = XPathFactory.newInstance();
49 xPath = new ThreadLocal<>() {
50
51 @Override
52 protected XPath initialValue() {
53 // TODO set the document as namespace context?
54 XPath res = xPathFactory.newXPath();
55 res.setNamespaceContext(DomContentProvider.this);
56 return res;
57 }
58 };
59 }
60
61 @Override
62 public ProvidedContent get(ProvidedSession session, String relativePath) {
63 if ("".equals(relativePath))
64 return new DomContent(session, this, document.getDocumentElement());
65
66 NodeList nodes = findContent(relativePath);
67 if (nodes.getLength() > 1)
68 throw new IllegalArgumentException("Multiple content found for " + relativePath + " under " + mountPath);
69 if (nodes.getLength() == 0)
70 throw new ContentNotFoundException(session, mountPath + "/" + relativePath,
71 "Path " + relativePath + " under " + mountPath + " was not found");
72 Element element = (Element) nodes.item(0);
73 return new DomContent(session, this, element);
74 }
75
76 protected NodeList findContent(String relativePath) {
77 if (relativePath.startsWith("/"))
78 throw new IllegalArgumentException("Relative path cannot start with /");
79 String xPathExpression = '/' + relativePath;
80 if (ContentUtils.SLASH_STRING.equals(mountPath)) // repository root
81 xPathExpression = "/" + CrName.root.qName() + xPathExpression;
82 try {
83 NodeList nodes = (NodeList) xPath.get().evaluate(xPathExpression, document, XPathConstants.NODESET);
84 return nodes;
85 } catch (XPathExpressionException e) {
86 throw new IllegalArgumentException("XPath expression " + xPathExpression + " cannot be evaluated", e);
87 }
88
89 }
90
91 @Override
92 public boolean exists(ProvidedSession session, String relativePath) {
93 if ("".equals(relativePath))
94 return true;
95 NodeList nodes = findContent(relativePath);
96 return nodes.getLength() != 0;
97 }
98
99 @Override
100 public void persist(ProvidedSession session) {
101 if (mountPath != null) {
102 Content mountPoint = session.getMountPoint(mountPath);
103 try (OutputStream out = mountPoint.open(OutputStream.class)) {
104 CmsContentRepository contentRepository = (CmsContentRepository) session.getRepository();
105 contentRepository.writeDom(document, out);
106 } catch (IOException e) {
107 throw new IllegalStateException("Cannot persist " + mountPath, e);
108 }
109 }
110 }
111
112 @Override
113 public String getMountPath() {
114 return mountPath;
115 }
116
117 public void registerPrefix(String prefix, String namespace) {
118 DomUtils.addNamespace(document.getDocumentElement(), prefix, namespace);
119 }
120
121 /*
122 * NAMESPACE CONTEXT
123 */
124 @Override
125 public String getNamespaceURI(String prefix) {
126 String namespaceURI = NamespaceUtils.getStandardNamespaceURI(prefix);
127 if (namespaceURI != null)
128 return namespaceURI;
129 return document.lookupNamespaceURI(prefix);
130 }
131
132 @Override
133 public String getPrefix(String namespaceURI) {
134 String prefix = NamespaceUtils.getStandardPrefix(namespaceURI);
135 if (prefix != null)
136 return prefix;
137 return document.lookupPrefix(namespaceURI);
138 }
139
140 @Override
141 public Iterator<String> getPrefixes(String namespaceURI) {
142 List<String> res = new ArrayList<>();
143 res.add(getPrefix(namespaceURI));
144 return Collections.unmodifiableList(res).iterator();
145 }
146
147 TransformerFactory getTransformerFactory() {
148 return transformerFactory;
149 }
150
151 }