]> git.argeo.org Git - lgpl/argeo-commons.git/blob - AbstractContentRepository.java
2e65e7e691dee045cdb4eb940624691a61a8f8a6
[lgpl/argeo-commons.git] / AbstractContentRepository.java
1 package org.argeo.cms.acr;
2
3 import java.io.IOException;
4 import java.io.InputStream;
5 import java.io.OutputStream;
6 import java.nio.file.Files;
7 import java.nio.file.Path;
8 import java.util.HashSet;
9 import java.util.Set;
10
11 import javax.xml.namespace.QName;
12 import javax.xml.parsers.DocumentBuilder;
13 import javax.xml.transform.OutputKeys;
14 import javax.xml.transform.Transformer;
15 import javax.xml.transform.TransformerException;
16 import javax.xml.transform.TransformerFactory;
17 import javax.xml.transform.dom.DOMSource;
18 import javax.xml.transform.stream.StreamResult;
19
20 import org.argeo.api.acr.Content;
21 import org.argeo.api.acr.CrName;
22 import org.argeo.api.acr.RuntimeNamespaceContext;
23 import org.argeo.api.acr.spi.ContentProvider;
24 import org.argeo.api.acr.spi.ProvidedContent;
25 import org.argeo.api.acr.spi.ProvidedRepository;
26 import org.argeo.api.cms.CmsLog;
27 import org.argeo.cms.acr.xml.DomContentProvider;
28 import org.argeo.cms.acr.xml.DomUtils;
29 import org.w3c.dom.DOMException;
30 import org.w3c.dom.Document;
31 import org.w3c.dom.Element;
32 import org.xml.sax.SAXException;
33
34 /**
35 * Base implementation of a {@link ProvidedRepository}.
36 */
37 public abstract class AbstractContentRepository implements ProvidedRepository {
38 private final static CmsLog log = CmsLog.getLog(AbstractContentRepository.class);
39
40 private MountManager mountManager;
41 private TypesManager typesManager;
42
43 private CmsContentSession systemSession;
44
45 private Set<ContentProvider> providersToAdd = new HashSet<>();
46
47 // utilities
48 /** Should be used only to copy source and results. */
49 private TransformerFactory identityTransformerFactory = TransformerFactory.newInstance();
50
51 public final static String ACR_MOUNT_PATH_PROPERTY = "acr.mount.path";
52
53 public AbstractContentRepository() {
54 // types
55 typesManager = new TypesManager();
56 typesManager.init();
57 Set<QName> types = typesManager.listTypes();
58 if (log.isTraceEnabled())
59 for (QName type : types) {
60 log.trace(type + " - " + typesManager.getAttributeTypes(type));
61 }
62
63 }
64
65 protected abstract CmsContentSession newSystemSession();
66
67 public void start() {
68 systemSession = newSystemSession();
69 // mounts
70 mountManager = new MountManager(systemSession);
71 }
72
73 public void stop() {
74 systemSession.close();
75 systemSession = null;
76 }
77
78 /*
79 * REPOSITORY
80 */
81
82 public void addProvider(ContentProvider provider) {
83 if (mountManager == null)
84 providersToAdd.add(provider);
85 else
86 mountManager.addStructuralContentProvider(provider);
87 }
88
89 public void registerTypes(String prefix, String namespaceURI, String schemaSystemId) {
90 typesManager.registerTypes(prefix, namespaceURI, schemaSystemId);
91 }
92
93 /*
94 * FACTORIES
95 */
96 public void initRootContentProvider(Path path) {
97 try {
98 // DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
99 // factory.setNamespaceAware(true);
100 // factory.setXIncludeAware(true);
101 // factory.setSchema(contentTypesManager.getSchema());
102 //
103 DocumentBuilder dBuilder = typesManager.newDocumentBuilder();
104
105 Document document;
106 // if (path != null && Files.exists(path)) {
107 // InputSource inputSource = new InputSource(path.toAbsolutePath().toUri().toString());
108 // inputSource.setEncoding(StandardCharsets.UTF_8.name());
109 // // TODO public id as well?
110 // document = dBuilder.parse(inputSource);
111 // } else {
112 document = dBuilder.newDocument();
113 Element root = document.createElementNS(CrName.CR_NAMESPACE_URI, CrName.ROOT.get().toPrefixedString());
114
115 for (String prefix : RuntimeNamespaceContext.getPrefixes().keySet()) {
116 // root.setAttributeNS(XMLConstants.XMLNS_ATTRIBUTE_NS_URI, XMLConstants.XMLNS_ATTRIBUTE + ":" + prefix,
117 // contentTypesManager.getPrefixes().get(prefix));
118 DomUtils.addNamespace(root, prefix,
119 RuntimeNamespaceContext.getNamespaceContext().getNamespaceURI(prefix));
120 }
121
122 document.appendChild(root);
123
124 // write it
125 if (path != null) {
126 try (OutputStream out = Files.newOutputStream(path)) {
127 writeDom(document, out);
128 }
129 }
130 // }
131
132 String mountPath = "/";
133 DomContentProvider contentProvider = new DomContentProvider(mountPath, document);
134 addProvider(contentProvider);
135 } catch (DOMException | IOException e) {
136 throw new IllegalStateException("Cannot init ACR root " + path, e);
137 }
138
139 // add content providers already notified
140 for (ContentProvider contentProvider : providersToAdd)
141 addProvider(contentProvider);
142 providersToAdd.clear();
143 }
144
145 public void writeDom(Document document, OutputStream out) throws IOException {
146 try {
147 Transformer transformer = identityTransformerFactory.newTransformer();
148 transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8");
149 transformer.setOutputProperty(OutputKeys.INDENT, "yes");
150
151 DOMSource source = new DOMSource(document);
152 typesManager.validate(source);
153 StreamResult result = new StreamResult(out);
154 transformer.transform(source, result);
155 } catch (TransformerException e) {
156 throw new IOException("Cannot write dom", e);
157 }
158 }
159
160 /*
161 * MOUNT MANAGEMENT
162 */
163
164 @Override
165 public ContentProvider getMountContentProvider(Content mountPoint, boolean initialize, QName... types) {
166 String mountPath = mountPoint.getPath();
167 // TODO check consistency with types
168
169 return mountManager.getOrAddMountedProvider(mountPath, (path) -> {
170 DocumentBuilder dBuilder = typesManager.newDocumentBuilder();
171 Document document;
172 if (initialize) {
173 QName firstType = types[0];
174 document = dBuilder.newDocument();
175 String prefix = ((ProvidedContent) mountPoint).getSession().getPrefix(firstType.getNamespaceURI());
176 Element root = document.createElementNS(firstType.getNamespaceURI(),
177 prefix + ":" + firstType.getLocalPart());
178 DomUtils.addNamespace(root, prefix, firstType.getNamespaceURI());
179 document.appendChild(root);
180 } else {
181 try (InputStream in = mountPoint.open(InputStream.class)) {
182 document = dBuilder.parse(in);
183 // TODO check consistency with types
184 } catch (IOException | SAXException e) {
185 throw new IllegalStateException("Cannot load mount from " + mountPoint, e);
186 }
187 }
188 DomContentProvider contentProvider = new DomContentProvider(path, document);
189 return contentProvider;
190 });
191 }
192
193 @Override
194 public boolean shouldMount(QName... types) {
195 if (types.length == 0)
196 return false;
197 QName firstType = types[0];
198 Set<QName> registeredTypes = typesManager.listTypes();
199 if (registeredTypes.contains(firstType))
200 return true;
201 return false;
202 }
203
204 MountManager getMountManager() {
205 return mountManager;
206 }
207
208 TypesManager getTypesManager() {
209 return typesManager;
210 }
211 }