X-Git-Url: https://git.argeo.org/?a=blobdiff_plain;f=org.argeo.cms%2Fsrc%2Forg%2Fargeo%2Fcms%2Facr%2FCmsContentRepository.java;h=6d17ea87dd4d6fc463e01cfcee3f75ca0c061549;hb=c615307d7b87bcb260d8a9f402c6e0a880862f38;hp=9cd8bd22dd6e8eef8670a45fada48cf5a8037f5f;hpb=da848d7b6bcf3e509890bdd42c3c59fba1adbe14;p=lgpl%2Fargeo-commons.git diff --git a/org.argeo.cms/src/org/argeo/cms/acr/CmsContentRepository.java b/org.argeo.cms/src/org/argeo/cms/acr/CmsContentRepository.java index 9cd8bd22d..6d17ea87d 100644 --- a/org.argeo.cms/src/org/argeo/cms/acr/CmsContentRepository.java +++ b/org.argeo.cms/src/org/argeo/cms/acr/CmsContentRepository.java @@ -1,38 +1,97 @@ package org.argeo.cms.acr; -import java.security.AccessController; +import java.io.IOException; +import java.io.Writer; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; import java.util.Locale; import java.util.Map; import java.util.NavigableMap; import java.util.Set; import java.util.TreeMap; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.CompletionStage; import java.util.stream.Collectors; import javax.security.auth.Subject; +import javax.security.auth.login.LoginContext; +import javax.security.auth.login.LoginException; +import javax.xml.parsers.DocumentBuilder; +import javax.xml.parsers.DocumentBuilderFactory; +import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.Transformer; +import javax.xml.transform.TransformerException; +import javax.xml.transform.TransformerFactory; +import javax.xml.transform.TransformerFactoryConfigurationError; +import javax.xml.transform.dom.DOMSource; +import javax.xml.transform.stream.StreamResult; +import javax.xml.validation.Schema; import org.argeo.api.acr.Content; import org.argeo.api.acr.ContentSession; +import org.argeo.api.acr.ContentUtils; import org.argeo.api.acr.CrName; +import org.argeo.api.acr.NamespaceUtils; import org.argeo.api.acr.spi.ContentProvider; import org.argeo.api.acr.spi.ProvidedRepository; import org.argeo.api.acr.spi.ProvidedSession; +import org.argeo.api.cms.CmsAuth; +import org.argeo.api.cms.CmsLog; +import org.argeo.api.cms.CmsSession; +import org.argeo.cms.acr.xml.DomContentProvider; +import org.argeo.cms.auth.CurrentUser; import org.argeo.cms.internal.runtime.CmsContextImpl; +import org.w3c.dom.DOMException; +import org.w3c.dom.Document; +import org.w3c.dom.Element; +import org.xml.sax.ErrorHandler; +import org.xml.sax.InputSource; +import org.xml.sax.SAXException; +import org.xml.sax.SAXParseException; +/** + * Base implementation of a {@link ProvidedRepository} integrated with a CMS. + */ public class CmsContentRepository implements ProvidedRepository { + private final static CmsLog log = CmsLog.getLog(CmsContentRepository.class); + private NavigableMap partitions = new TreeMap<>(); // TODO synchronize ? private NavigableMap prefixes = new TreeMap<>(); + private Schema schema; + + private CmsContentSession systemSession; + + private Map userSessions = Collections.synchronizedMap(new HashMap<>()); + public CmsContentRepository() { prefixes.put(CrName.CR_DEFAULT_PREFIX, CrName.CR_NAMESPACE_URI); prefixes.put("basic", CrName.CR_NAMESPACE_URI); prefixes.put("owner", CrName.CR_NAMESPACE_URI); prefixes.put("posix", CrName.CR_NAMESPACE_URI); + + systemSession = newSystemSession(); } - public void start() { + protected CmsContentSession newSystemSession() { + LoginContext loginContext; + try { + loginContext = new LoginContext(CmsAuth.DATA_ADMIN.getLoginContextName()); + loginContext.login(); + } catch (LoginException e1) { + throw new RuntimeException("Could not login as data admin", e1); + } finally { + } + return new CmsContentSession(loginContext.getSubject(), Locale.getDefault()); + } + public void start() { } public void stop() { @@ -50,12 +109,31 @@ public class CmsContentRepository implements ProvidedRepository { @Override public ContentSession get(Locale locale) { - Subject subject = Subject.getSubject(AccessController.getContext()); - return new CmsContentSession(subject, locale); + // Subject subject = Subject.getSubject(AccessController.getContext()); + CmsSession cmsSession = CurrentUser.getCmsSession(); + CmsContentSession contentSession = userSessions.get(cmsSession); + if (contentSession == null) { + final CmsContentSession newContentSession = new CmsContentSession(cmsSession.getSubject(), locale); + cmsSession.addOnCloseCallback((c) -> { + newContentSession.close(); + userSessions.remove(cmsSession); + }); + contentSession = newContentSession; + } + return contentSession; } public void addProvider(String base, ContentProvider provider) { partitions.put(base, provider); + if ("/".equals(base))// root + return; + String[] parentPath = ContentUtils.getParentPath(base); + Content parent = systemSession.get(parentPath[0]); + Content mount = parent.add(parentPath[1]); + // TODO use a boolean + // ContentName name = new ContentName(CrName.MOUNT.getNamespaceURI(), + // CrName.MOUNT.name(), systemSession); + mount.put(CrName.MOUNT.get(), "true"); } public void registerPrefix(String prefix, String namespaceURI) { @@ -69,6 +147,68 @@ public class CmsContentRepository implements ProvidedRepository { // do nothing if same namespace is already registered } + /* + * FACTORIES + */ + public void initRootContentProvider(Path path) { + try { + DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); + factory.setNamespaceAware(true); + factory.setXIncludeAware(true); + // factory.setSchema(schema); + + DocumentBuilder dBuilder = factory.newDocumentBuilder(); + dBuilder.setErrorHandler(new ErrorHandler() { + + @Override + public void warning(SAXParseException exception) throws SAXException { + } + + @Override + public void fatalError(SAXParseException exception) throws SAXException { + } + + @Override + public void error(SAXParseException exception) throws SAXException { + log.error(exception); + + } + }); + + Document document; + if (Files.exists(path)) { + InputSource inputSource = new InputSource(path.toAbsolutePath().toUri().toString()); + inputSource.setEncoding(StandardCharsets.UTF_8.name()); + // TODO public id as well? + document = dBuilder.parse(inputSource); + } else { + document = dBuilder.newDocument(); +// Element root = document.createElementNS(CrName.ROOT.getNamespaceURI(), +// CrName.ROOT.get().toPrefixedString()); + Element root = document.createElement(CrName.ROOT.get().toPrefixedString()); + // root.setAttribute("xmlns", ""); + root.setAttribute("xmlns:" + CrName.CR_DEFAULT_PREFIX, CrName.CR_NAMESPACE_URI); + document.appendChild(root); + + // write it + TransformerFactory transformerFactory = TransformerFactory.newInstance(); + Transformer transformer = transformerFactory.newTransformer(); + DOMSource source = new DOMSource(document); + try (Writer writer = Files.newBufferedWriter(path, StandardCharsets.UTF_8)) { + StreamResult result = new StreamResult(writer); + transformer.transform(source, result); + } + } + + DomContentProvider contentProvider = new DomContentProvider(document); + addProvider("/", contentProvider); + } catch (DOMException | ParserConfigurationException | SAXException | IOException + | TransformerFactoryConfigurationError | TransformerException e) { + throw new IllegalStateException("Cannot init ACR root " + path, e); + } + + } + /* * NAMESPACE CONTEXT */ @@ -81,11 +221,22 @@ public class CmsContentRepository implements ProvidedRepository { private Subject subject; private Locale locale; + private CompletableFuture closed = new CompletableFuture<>(); + public CmsContentSession(Subject subject, Locale locale) { this.subject = subject; this.locale = locale; } + public void close() { + closed.complete(this); + } + + @Override + public CompletionStage onClose() { + return closed.minimalCompletionStage(); + } + @Override public Content get(String path) { Map.Entry entry = partitions.floorEntry(path); @@ -115,24 +266,35 @@ public class CmsContentRepository implements ProvidedRepository { */ @Override - public String findNamespace(String prefix) { - return prefixes.get(prefix); + public String getNamespaceURI(String prefix) { + return NamespaceUtils.getNamespaceURI((p) -> prefixes.get(p), prefix); } @Override - public Set findPrefixes(String namespaceURI) { - Set res = prefixes.entrySet().stream().filter(e -> e.getValue().equals(namespaceURI)) - .map(Map.Entry::getKey).collect(Collectors.toUnmodifiableSet()); - - return res; + public Iterator getPrefixes(String namespaceURI) { + return NamespaceUtils.getPrefixes((ns) -> prefixes.entrySet().stream().filter(e -> e.getValue().equals(ns)) + .map(Map.Entry::getKey).collect(Collectors.toUnmodifiableSet()), namespaceURI); } - @Override - public String findPrefix(String namespaceURI) { - if (CrName.CR_NAMESPACE_URI.equals(namespaceURI) && prefixes.containsKey(CrName.CR_DEFAULT_PREFIX)) - return CrName.CR_DEFAULT_PREFIX; - return ProvidedSession.super.findPrefix(namespaceURI); - } +// @Override +// public String findNamespace(String prefix) { +// return prefixes.get(prefix); +// } +// +// @Override +// public Set findPrefixes(String namespaceURI) { +// Set res = prefixes.entrySet().stream().filter(e -> e.getValue().equals(namespaceURI)) +// .map(Map.Entry::getKey).collect(Collectors.toUnmodifiableSet()); +// +// return res; +// } +// +// @Override +// public String findPrefix(String namespaceURI) { +// if (CrName.CR_NAMESPACE_URI.equals(namespaceURI) && prefixes.containsKey(CrName.CR_DEFAULT_PREFIX)) +// return CrName.CR_DEFAULT_PREFIX; +// return ProvidedSession.super.findPrefix(namespaceURI); +// } }