1 package org
.argeo
.cms
.acr
;
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
;
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
;
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
;
38 * Base implementation of a {@link ProvidedRepository}.
40 public abstract class AbstractContentRepository
implements ProvidedRepository
{
41 private final static CmsLog log
= CmsLog
.getLog(AbstractContentRepository
.class);
43 private MountManager mountManager
;
44 private TypesManager typesManager
;
46 private CmsContentSession systemSession
;
48 private Set
<ContentProvider
> providersToAdd
= new HashSet
<>();
51 /** Should be used only to copy source and results. */
52 private TransformerFactory identityTransformerFactory
= TransformerFactory
.newInstance();
54 // public final static String ACR_MOUNT_PATH_PROPERTY = "acr.mount.path";
56 public AbstractContentRepository() {
57 long begin
= System
.currentTimeMillis();
59 typesManager
= new TypesManager();
61 Set
<QName
> types
= typesManager
.listTypes();
62 if (log
.isTraceEnabled())
63 for (QName type
: types
) {
64 log
.trace(type
+ " - " + typesManager
.getAttributeTypes(type
));
66 long duration
= System
.currentTimeMillis() - begin
;
67 log
.debug(() -> "CMS content types available (initialisation took " + duration
+ " ms)");
70 protected abstract CmsContentSession
newSystemSession();
73 systemSession
= newSystemSession();
75 mountManager
= new MountManager(systemSession
);
79 systemSession
.close();
87 public void addProvider(ContentProvider provider
) {
88 if (mountManager
== null) {
89 providersToAdd
.add(provider
);
91 () -> "Will add provider " + provider
.getMountPath() + " (" + provider
.getClass().getName() + ")");
93 mountManager
.addStructuralContentProvider(provider
);
94 log
.debug(() -> "Added provider " + provider
.getMountPath() + " (" + provider
.getClass().getName() + ")");
99 public void registerTypes(ContentNamespace
... namespaces
) {
100 typesManager
.registerTypes(namespaces
);
106 public void initRootContentProvider(Path path
) {
108 // DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
109 // factory.setNamespaceAware(true);
110 // factory.setXIncludeAware(true);
111 // factory.setSchema(contentTypesManager.getSchema());
113 DocumentBuilder dBuilder
= typesManager
.newDocumentBuilder();
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);
122 document
= dBuilder
.newDocument();
123 Element root
= document
.createElementNS(ArgeoNamespace
.CR_NAMESPACE_URI
,
124 NamespaceUtils
.toPrefixedName(CrName
.root
.qName()));
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
));
133 document
.appendChild(root
);
137 try (OutputStream out
= Files
.newOutputStream(path
)) {
138 writeDom(document
, out
);
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
);
150 // add content providers already notified
151 for (ContentProvider contentProvider
: providersToAdd
)
152 addProvider(contentProvider
);
153 providersToAdd
.clear();
156 public void writeDom(Document document
, OutputStream out
) throws IOException
{
158 Transformer transformer
= identityTransformerFactory
.newTransformer();
159 transformer
.setOutputProperty(OutputKeys
.ENCODING
, "UTF-8");
160 transformer
.setOutputProperty(OutputKeys
.INDENT
, "yes");
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
);
176 public ContentProvider
getMountContentProvider(Content mountPoint
, boolean initialize
, QName
... types
) {
177 String mountPath
= mountPoint
.getPath();
178 // TODO check consistency with types
180 return mountManager
.getOrAddMountedProvider(mountPath
, (path
) -> {
181 DocumentBuilder dBuilder
= typesManager
.newDocumentBuilder();
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
);
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
);
199 DomContentProvider contentProvider
= new DomContentProvider(path
, document
);
200 return contentProvider
;
205 public boolean shouldMount(QName
... types
) {
206 if (types
.length
== 0)
208 QName firstType
= types
[0];
209 Set
<QName
> registeredTypes
= typesManager
.listTypes();
210 if (registeredTypes
.contains(firstType
))
215 MountManager
getMountManager() {
219 TypesManager
getTypesManager() {
223 CmsContentSession
getSystemSession() {
224 return systemSession
;