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