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