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