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