]> git.argeo.org Git - lgpl/argeo-commons.git/blob - jcr/org.argeo.cms.jcr/src/org/argeo/cms/jcr/acr/JcrContentUtils.java
Allow any element in dbk:info while reintroducing original constraints
[lgpl/argeo-commons.git] / jcr / org.argeo.cms.jcr / src / org / argeo / cms / jcr / acr / JcrContentUtils.java
1 package org.argeo.cms.jcr.acr;
2
3 import java.io.IOException;
4 import java.io.InputStream;
5 import java.io.PipedInputStream;
6 import java.io.PipedOutputStream;
7 import java.util.HashSet;
8 import java.util.Set;
9 import java.util.concurrent.CompletableFuture;
10 import java.util.concurrent.ExecutionException;
11
12 import javax.jcr.Node;
13 import javax.jcr.NodeIterator;
14 import javax.jcr.RepositoryException;
15 import javax.jcr.nodetype.NodeType;
16 import javax.xml.XMLConstants;
17 import javax.xml.namespace.QName;
18 import javax.xml.parsers.DocumentBuilder;
19 import javax.xml.parsers.DocumentBuilderFactory;
20 import javax.xml.parsers.ParserConfigurationException;
21 import javax.xml.transform.Source;
22 import javax.xml.transform.dom.DOMSource;
23
24 import org.argeo.api.acr.Content;
25 import org.argeo.api.acr.ContentName;
26 import org.argeo.api.acr.CrName;
27 import org.argeo.api.acr.NamespaceUtils;
28 import org.argeo.api.acr.spi.ProvidedContent;
29 import org.argeo.api.acr.spi.ProvidedSession;
30 import org.argeo.api.cms.CmsLog;
31 import org.argeo.jcr.Jcr;
32 import org.argeo.jcr.JcrException;
33 import org.argeo.jcr.JcrUtils;
34 import org.w3c.dom.Attr;
35 import org.w3c.dom.Document;
36 import org.w3c.dom.Element;
37 import org.w3c.dom.NamedNodeMap;
38 import org.w3c.dom.NodeList;
39 import org.xml.sax.SAXException;
40
41 /** Utilities around integration between JCR and ACR. */
42 public class JcrContentUtils {
43 private final static CmsLog log = CmsLog.getLog(JcrContentUtils.class);
44
45 public static void copyFiles(Node folder, Content collection, String... additionalCollectionTypes) {
46 try {
47 log.debug("Copy collection " + collection);
48 nodes: for (NodeIterator it = folder.getNodes(); it.hasNext();) {
49 Node node = it.nextNode();
50 String name = node.getName();
51 if (node.isNodeType(NodeType.NT_FILE)) {
52 Content file = collection.anyOrAddChild(new ContentName(name));
53 try (InputStream in = JcrUtils.getFileAsStream(node)) {
54 file.write(InputStream.class).complete(in);
55 }
56 } else if (node.isNodeType(NodeType.NT_FOLDER)) {
57 Content subCol = collection.add(name, CrName.collection.qName());
58 copyFiles(node, subCol, additionalCollectionTypes);
59 } else {
60 for (String collectionType : additionalCollectionTypes) {
61 if (node.isNodeType(collectionType)) {
62 Content subCol = collection.add(name, CrName.collection.qName());
63 copyFiles(node, subCol, additionalCollectionTypes);
64 continue nodes;
65 }
66 }
67
68 QName qName = NamespaceUtils.parsePrefixedName(name);
69 // if (NamespaceUtils.hasNamespace(qName)) {
70 if (node.getIndex() > 1) {
71 log.warn("Same name siblings not supported, skipping " + node);
72 continue nodes;
73 }
74 Content content = collection.add(qName, qName);
75 Source source = toSource(node);
76 ((ProvidedContent) content).getSession().edit((s) -> {
77 ((ProvidedSession) s).notifyModification((ProvidedContent) content);
78 content.write(Source.class).complete(source);
79 }).toCompletableFuture().join();
80
81 // } else {
82 // // ignore
83 // log.debug(() -> "Ignored " + node);
84 // continue nodes;
85 // }
86 }
87 }
88 } catch (RepositoryException e) {
89 throw new JcrException("Cannot copy files from " + folder + " to " + collection, e);
90 } catch (IOException e) {
91 throw new RuntimeException("Cannot copy files from " + folder + " to " + collection, e);
92 }
93 }
94
95 private static Source toSource(Node node) {
96 try (PipedInputStream in = new PipedInputStream();) {
97
98 CompletableFuture<Document> toDo = CompletableFuture.supplyAsync(() -> {
99 try {
100 DocumentBuilder documentBuilder = DocumentBuilderFactory.newNSInstance().newDocumentBuilder();
101 return documentBuilder.parse(in);
102 } catch (ParserConfigurationException | SAXException | IOException e) {
103 throw new RuntimeException("Cannot parse", e);
104 }
105 });
106
107 // TODO optimise
108 try (PipedOutputStream out = new PipedOutputStream(in)) {
109 node.getSession().exportDocumentView(node.getPath(), out, true, false);
110 } catch (IOException | RepositoryException e) {
111 throw new RuntimeException("Cannot export " + node + " in workspace " + Jcr.getWorkspaceName(node), e);
112 }
113 Document document = toDo.get();
114 cleanJcrDom(document);
115 return new DOMSource(document);
116 } catch (IOException | InterruptedException | ExecutionException e1) {
117 throw new RuntimeException("Cannot parse", e1);
118 }
119
120 }
121
122 static final String JCR_NAMESPACE_URI = "http://www.jcp.org/jcr/1.0";
123
124 public static void cleanJcrDom(Document document) {
125 Element documentElement = document.getDocumentElement();
126 Set<String> namespaceUris = new HashSet<>();
127 cleanJcrDom(documentElement, namespaceUris);
128
129 // remove unused namespaces
130 NamedNodeMap attrs = documentElement.getAttributes();
131 Set<Attr> toRemove = new HashSet<>();
132 for (int i = 0; i < attrs.getLength(); i++) {
133 Attr attr = (Attr) attrs.item(i);
134 // log.debug("Check "+i+" " + attr);
135 String prefix = attr.getPrefix();
136 if (prefix != null && prefix.equals(XMLConstants.XMLNS_ATTRIBUTE)) {
137 String namespaceUri = attr.getValue();
138 if (!namespaceUris.contains(namespaceUri)) {
139 toRemove.add(attr);
140 // log.debug("Removing "+i+" " + namespaceUri);
141 }
142 }
143 }
144 for (Attr attr : toRemove)
145 documentElement.removeAttributeNode(attr);
146
147 }
148
149 private static void cleanJcrDom(Element element, Set<String> namespaceUris) {
150 NodeList children = element.getElementsByTagName("*");
151 for (int i = 0; i < children.getLength(); i++) {
152 Element child = (Element) children.item(i);
153 if (!namespaceUris.contains(child.getNamespaceURI()))
154 namespaceUris.add(child.getNamespaceURI());
155 cleanJcrDom(child, namespaceUris);
156 }
157
158 NamedNodeMap attrs = element.getAttributes();
159 attributes: for (int i = 0; i < attrs.getLength(); i++) {
160 Attr attr = (Attr) attrs.item(i);
161 String namespaceUri = attr.getNamespaceURI();
162 if (namespaceUri == null)
163 continue attributes;
164 if (JCR_NAMESPACE_URI.equals(namespaceUri)) {
165 element.removeAttributeNode(attr);
166 continue attributes;
167 }
168 if (!namespaceUris.contains(namespaceUri))
169 namespaceUris.add(attr.getNamespaceURI());
170
171 }
172
173 }
174
175 /** singleton */
176 private JcrContentUtils() {
177 }
178
179 }