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
.Collections
;
9 import java
.util
.HashMap
;
10 import java
.util
.Locale
;
14 import javax
.security
.auth
.login
.LoginContext
;
15 import javax
.security
.auth
.login
.LoginException
;
16 import javax
.xml
.namespace
.QName
;
17 import javax
.xml
.parsers
.DocumentBuilder
;
18 import javax
.xml
.transform
.OutputKeys
;
19 import javax
.xml
.transform
.Transformer
;
20 import javax
.xml
.transform
.TransformerException
;
21 import javax
.xml
.transform
.TransformerFactory
;
22 import javax
.xml
.transform
.dom
.DOMSource
;
23 import javax
.xml
.transform
.stream
.StreamResult
;
25 import org
.argeo
.api
.acr
.Content
;
26 import org
.argeo
.api
.acr
.ContentSession
;
27 import org
.argeo
.api
.acr
.CrName
;
28 import org
.argeo
.api
.acr
.spi
.ContentProvider
;
29 import org
.argeo
.api
.acr
.spi
.ProvidedContent
;
30 import org
.argeo
.api
.acr
.spi
.ProvidedRepository
;
31 import org
.argeo
.api
.cms
.CmsAuth
;
32 import org
.argeo
.api
.cms
.CmsLog
;
33 import org
.argeo
.api
.cms
.CmsSession
;
34 import org
.argeo
.cms
.acr
.xml
.DomContentProvider
;
35 import org
.argeo
.cms
.acr
.xml
.DomUtils
;
36 import org
.argeo
.cms
.auth
.CurrentUser
;
37 import org
.argeo
.cms
.internal
.runtime
.CmsContextImpl
;
38 import org
.w3c
.dom
.DOMException
;
39 import org
.w3c
.dom
.Document
;
40 import org
.w3c
.dom
.Element
;
41 import org
.xml
.sax
.SAXException
;
44 * Base implementation of a {@link ProvidedRepository} integrated with a CMS.
46 public class CmsContentRepository
implements ProvidedRepository
{
47 private final static CmsLog log
= CmsLog
.getLog(CmsContentRepository
.class);
49 private final MountManager mountManager
;
50 private final TypesManager typesManager
;
52 private CmsContentSession systemSession
;
54 private Map
<CmsSession
, CmsContentSession
> userSessions
= Collections
.synchronizedMap(new HashMap
<>());
57 private TransformerFactory transformerFactory
= TransformerFactory
.newInstance();
59 public final static String ACR_MOUNT_PATH_PROPERTY
= "acr.mount.path";
61 public CmsContentRepository() {
63 typesManager
= new TypesManager();
65 Set
<QName
> types
= typesManager
.listTypes();
66 for (QName type
: types
) {
67 log
.debug(type
+ " - " + typesManager
.getAttributeTypes(type
));
70 systemSession
= newSystemSession();
73 mountManager
= new MountManager(systemSession
);
77 protected CmsContentSession
newSystemSession() {
78 LoginContext loginContext
;
80 loginContext
= new LoginContext(CmsAuth
.DATA_ADMIN
.getLoginContextName());
82 } catch (LoginException e1
) {
83 throw new RuntimeException("Could not login as data admin", e1
);
86 return new CmsContentSession(this, loginContext
.getSubject(), Locale
.getDefault());
101 public ContentSession
get() {
102 return get(CmsContextImpl
.getCmsContext().getDefaultLocale());
106 public ContentSession
get(Locale locale
) {
107 // Subject subject = Subject.getSubject(AccessController.getContext());
108 CmsSession cmsSession
= CurrentUser
.getCmsSession();
109 CmsContentSession contentSession
= userSessions
.get(cmsSession
);
110 if (contentSession
== null) {
111 final CmsContentSession newContentSession
= new CmsContentSession(this, cmsSession
.getSubject(), locale
);
112 cmsSession
.addOnCloseCallback((c
) -> {
113 newContentSession
.close();
114 userSessions
.remove(cmsSession
);
116 contentSession
= newContentSession
;
118 return contentSession
;
121 public void addProvider(ContentProvider provider
) {
122 mountManager
.addStructuralContentProvider(provider
);
125 public void registerTypes(String prefix
, String namespaceURI
, String schemaSystemId
) {
126 typesManager
.registerTypes(prefix
, namespaceURI
, schemaSystemId
);
132 public void initRootContentProvider(Path path
) {
134 // DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
135 // factory.setNamespaceAware(true);
136 // factory.setXIncludeAware(true);
137 // factory.setSchema(contentTypesManager.getSchema());
139 DocumentBuilder dBuilder
= typesManager
.newDocumentBuilder();
142 // if (path != null && Files.exists(path)) {
143 // InputSource inputSource = new InputSource(path.toAbsolutePath().toUri().toString());
144 // inputSource.setEncoding(StandardCharsets.UTF_8.name());
145 // // TODO public id as well?
146 // document = dBuilder.parse(inputSource);
148 document
= dBuilder
.newDocument();
149 Element root
= document
.createElementNS(CrName
.CR_NAMESPACE_URI
, CrName
.ROOT
.get().toPrefixedString());
151 for (String prefix
: typesManager
.getPrefixes().keySet()) {
152 // root.setAttributeNS(XMLConstants.XMLNS_ATTRIBUTE_NS_URI, XMLConstants.XMLNS_ATTRIBUTE + ":" + prefix,
153 // contentTypesManager.getPrefixes().get(prefix));
154 DomUtils
.addNamespace(root
, prefix
, typesManager
.getPrefixes().get(prefix
));
157 document
.appendChild(root
);
161 try (OutputStream out
= Files
.newOutputStream(path
)) {
162 writeDom(document
, out
);
167 String mountPath
= "/";
168 DomContentProvider contentProvider
= new DomContentProvider(mountPath
, document
);
169 addProvider(contentProvider
);
170 } catch (DOMException
| IOException e
) {
171 throw new IllegalStateException("Cannot init ACR root " + path
, e
);
176 public void writeDom(Document document
, OutputStream out
) throws IOException
{
178 Transformer transformer
= transformerFactory
.newTransformer();
179 transformer
.setOutputProperty(OutputKeys
.ENCODING
, "UTF-8");
180 transformer
.setOutputProperty(OutputKeys
.INDENT
, "yes");
182 DOMSource source
= new DOMSource(document
);
183 typesManager
.validate(source
);
184 StreamResult result
= new StreamResult(out
);
185 transformer
.transform(source
, result
);
186 } catch (TransformerException e
) {
187 throw new IOException("Cannot write dom", e
);
196 public ContentProvider
getMountContentProvider(Content mountPoint
, boolean initialize
, QName
... types
) {
197 String mountPath
= mountPoint
.getPath();
198 // TODO check consistency with types
200 return mountManager
.getOrAddMountedProvider(mountPath
, (path
) -> {
201 DocumentBuilder dBuilder
= typesManager
.newDocumentBuilder();
204 QName firstType
= types
[0];
205 document
= dBuilder
.newDocument();
206 String prefix
= ((ProvidedContent
) mountPoint
).getSession().getPrefix(firstType
.getNamespaceURI());
207 Element root
= document
.createElementNS(firstType
.getNamespaceURI(),
208 prefix
+ ":" + firstType
.getLocalPart());
209 DomUtils
.addNamespace(root
, prefix
, firstType
.getNamespaceURI());
210 document
.appendChild(root
);
212 try (InputStream in
= mountPoint
.open(InputStream
.class)) {
213 document
= dBuilder
.parse(in
);
214 // TODO check consistency with types
215 } catch (IOException
| SAXException e
) {
216 throw new IllegalStateException("Cannot load mount from " + mountPoint
, e
);
219 DomContentProvider contentProvider
= new DomContentProvider(path
, document
);
220 return contentProvider
;
225 public boolean shouldMount(QName
... types
) {
226 if (types
.length
== 0)
228 QName firstType
= types
[0];
229 Set
<QName
> registeredTypes
= typesManager
.listTypes();
230 if (registeredTypes
.contains(firstType
))
235 MountManager
getMountManager() {
239 TypesManager
getTypesManager() {