X-Git-Url: https://git.argeo.org/?a=blobdiff_plain;f=org.argeo.cms%2Fsrc%2Forg%2Fargeo%2Fcms%2Facr%2FCmsContentRepository.java;h=092876d397fc2bccc37622502b0fa45ceaf37ce0;hb=cc1dd97ebcc32e1bd754073ad23def182f460452;hp=d91fb16fec9ae8936fe28e72c6e889b88d27bf88;hpb=584b2b87593892c6ded7b645425b603a4f554026;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 d91fb16fe..092876d39 100644 --- a/org.argeo.cms/src/org/argeo/cms/acr/CmsContentRepository.java +++ b/org.argeo.cms/src/org/argeo/cms/acr/CmsContentRepository.java @@ -7,18 +7,10 @@ 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.function.Consumer; -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.namespace.QName; @@ -29,17 +21,13 @@ import javax.xml.transform.TransformerException; import javax.xml.transform.TransformerFactory; import javax.xml.transform.dom.DOMSource; import javax.xml.transform.stream.StreamResult; -import javax.xml.validation.Validator; 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.ProvidedContent; 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; @@ -58,13 +46,8 @@ import org.xml.sax.SAXException; 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 ContentTypesManager contentTypesManager; + private final MountManager mountManager; + private final TypesManager typesManager; private CmsContentSession systemSession; @@ -76,14 +59,19 @@ public class CmsContentRepository implements ProvidedRepository { public final static String ACR_MOUNT_PATH_PROPERTY = "acr.mount.path"; public CmsContentRepository() { - contentTypesManager = new ContentTypesManager(); - contentTypesManager.init(); - Set types = contentTypesManager.listTypes(); + // types + typesManager = new TypesManager(); + typesManager.init(); + Set types = typesManager.listTypes(); for (QName type : types) { log.debug(type); } systemSession = newSystemSession(); + + // mounts + mountManager = new MountManager(systemSession); + } protected CmsContentSession newSystemSession() { @@ -95,7 +83,7 @@ public class CmsContentRepository implements ProvidedRepository { throw new RuntimeException("Could not login as data admin", e1); } finally { } - return new CmsContentSession(loginContext.getSubject(), Locale.getDefault()); + return new CmsContentSession(this, loginContext.getSubject(), Locale.getDefault()); } public void start() { @@ -120,7 +108,7 @@ public class CmsContentRepository implements ProvidedRepository { CmsSession cmsSession = CurrentUser.getCmsSession(); CmsContentSession contentSession = userSessions.get(cmsSession); if (contentSession == null) { - final CmsContentSession newContentSession = new CmsContentSession(cmsSession.getSubject(), locale); + final CmsContentSession newContentSession = new CmsContentSession(this, cmsSession.getSubject(), locale); cmsSession.addOnCloseCallback((c) -> { newContentSession.close(); userSessions.remove(cmsSession); @@ -130,29 +118,12 @@ public class CmsContentRepository implements ProvidedRepository { 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 addProvider(ContentProvider provider) { + mountManager.addStructuralContentProvider(provider); } public void registerTypes(String prefix, String namespaceURI, String schemaSystemId) { - contentTypesManager.registerTypes(prefix, namespaceURI, schemaSystemId); -// String registeredUri = prefixes.get(prefix); -// if (registeredUri == null) { -// prefixes.put(prefix, namespaceURI); -// return; -// } -// if (!registeredUri.equals(namespaceURI)) -// throw new IllegalStateException("Prefix " + prefix + " is already registred for " + registeredUri); -// // do nothing if same namespace is already registered + typesManager.registerTypes(prefix, namespaceURI, schemaSystemId); } /* @@ -165,7 +136,7 @@ public class CmsContentRepository implements ProvidedRepository { // factory.setXIncludeAware(true); // factory.setSchema(contentTypesManager.getSchema()); // - DocumentBuilder dBuilder = contentTypesManager.newDocumentBuilder(); + DocumentBuilder dBuilder = typesManager.newDocumentBuilder(); Document document; // if (path != null && Files.exists(path)) { @@ -177,10 +148,10 @@ public class CmsContentRepository implements ProvidedRepository { document = dBuilder.newDocument(); Element root = document.createElementNS(CrName.CR_NAMESPACE_URI, CrName.ROOT.get().toPrefixedString()); - for (String prefix : contentTypesManager.getPrefixes().keySet()) { + for (String prefix : typesManager.getPrefixes().keySet()) { // root.setAttributeNS(XMLConstants.XMLNS_ATTRIBUTE_NS_URI, XMLConstants.XMLNS_ATTRIBUTE + ":" + prefix, // contentTypesManager.getPrefixes().get(prefix)); - DomUtils.addNamespace(root, prefix, contentTypesManager.getPrefixes().get(prefix)); + DomUtils.addNamespace(root, prefix, typesManager.getPrefixes().get(prefix)); } document.appendChild(root); @@ -193,8 +164,9 @@ public class CmsContentRepository implements ProvidedRepository { } // } - DomContentProvider contentProvider = new DomContentProvider(null, document); - addProvider("/", contentProvider); + String mountPath = "/"; + DomContentProvider contentProvider = new DomContentProvider(mountPath, document); + addProvider(contentProvider); } catch (DOMException | IOException e) { throw new IllegalStateException("Cannot init ACR root " + path, e); } @@ -208,7 +180,7 @@ public class CmsContentRepository implements ProvidedRepository { transformer.setOutputProperty(OutputKeys.INDENT, "yes"); DOMSource source = new DOMSource(document); - contentTypesManager.validate(source); + typesManager.validate(source); StreamResult result = new StreamResult(out); transformer.transform(source, result); } catch (TransformerException e) { @@ -223,176 +195,49 @@ public class CmsContentRepository implements ProvidedRepository { @Override public ContentProvider getMountContentProvider(Content mountPoint, boolean initialize, QName... types) { String mountPath = mountPoint.getPath(); - if (partitions.containsKey(mountPath)) - // TODO check consistency with types - return partitions.get(mountPath); - DocumentBuilder dBuilder = contentTypesManager.newDocumentBuilder(); - Document document; - if (initialize) { - QName firstType = types[0]; - document = dBuilder.newDocument(); - String prefix = ((ProvidedContent) mountPoint).getSession().getPrefix(firstType.getNamespaceURI()); - Element root = document.createElementNS(firstType.getNamespaceURI(), - prefix + ":" + firstType.getLocalPart()); - DomUtils.addNamespace(root, prefix, firstType.getNamespaceURI()); - document.appendChild(root); -// try (OutputStream out = mountPoint.open(OutputStream.class)) { -// writeDom(document, out); -// } catch (IOException e) { -// throw new IllegalStateException("Cannot write mount from " + mountPoint, e); -// } - } else { - try (InputStream in = mountPoint.open(InputStream.class)) { - document = dBuilder.parse(in); - // TODO check consistency with types - } catch (IOException | SAXException e) { - throw new IllegalStateException("Cannot load mount from " + mountPoint, e); + // TODO check consistency with types + + return mountManager.getOrAddMountedProvider(mountPath, (path) -> { + DocumentBuilder dBuilder = typesManager.newDocumentBuilder(); + Document document; + if (initialize) { + QName firstType = types[0]; + document = dBuilder.newDocument(); + String prefix = ((ProvidedContent) mountPoint).getSession().getPrefix(firstType.getNamespaceURI()); + Element root = document.createElementNS(firstType.getNamespaceURI(), + prefix + ":" + firstType.getLocalPart()); + DomUtils.addNamespace(root, prefix, firstType.getNamespaceURI()); + document.appendChild(root); + } else { + try (InputStream in = mountPoint.open(InputStream.class)) { + document = dBuilder.parse(in); + // TODO check consistency with types + } catch (IOException | SAXException e) { + throw new IllegalStateException("Cannot load mount from " + mountPoint, e); + } } - } - DomContentProvider contentProvider = new DomContentProvider(mountPath, document); - partitions.put(mountPath, contentProvider); - return contentProvider; + DomContentProvider contentProvider = new DomContentProvider(path, document); + return contentProvider; + }); } @Override public boolean shouldMount(QName... types) { if (types.length == 0) - throw new IllegalArgumentException("Types must be provided"); + return false; QName firstType = types[0]; - Set registeredTypes = contentTypesManager.listTypes(); + Set registeredTypes = typesManager.listTypes(); if (registeredTypes.contains(firstType)) return true; return false; } - /* - * NAMESPACE CONTEXT - */ - - /* - * SESSION - */ - - class CmsContentSession implements ProvidedSession { - private Subject subject; - private Locale locale; - - private CompletableFuture closed = new CompletableFuture<>(); - - private CompletableFuture edition; - - 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); - if (entry == null) - throw new IllegalArgumentException("No entry provider found for " + path); - String mountPath = entry.getKey(); - ContentProvider provider = entry.getValue(); - String relativePath = path.substring(mountPath.length()); - if (relativePath.length() > 0 && relativePath.charAt(0) == '/') - relativePath = relativePath.substring(1); - return provider.get(CmsContentSession.this, mountPath, relativePath); - } - - @Override - public Subject getSubject() { - return subject; - } - - @Override - public Locale getLocale() { - return locale; - } - - @Override - public ProvidedRepository getRepository() { - return CmsContentRepository.this; - } - - /* - * MOUNT MANAGEMENT - */ - @Override - public Content getMountPoint(String path) { - String[] parent = ContentUtils.getParentPath(path); - ProvidedContent mountParent = (ProvidedContent) get(parent[0]); -// Content mountPoint = mountParent.getProvider().get(CmsContentSession.this, null, path); - return mountParent.getMountPoint(parent[1]); - } - - /* - * NAMESPACE CONTEXT - */ - - @Override - public String getNamespaceURI(String prefix) { - return NamespaceUtils.getNamespaceURI((p) -> contentTypesManager.getPrefixes().get(p), prefix); - } - - @Override - public Iterator getPrefixes(String namespaceURI) { - return NamespaceUtils.getPrefixes( - (ns) -> contentTypesManager.getPrefixes().entrySet().stream().filter(e -> e.getValue().equals(ns)) - .map(Map.Entry::getKey).collect(Collectors.toUnmodifiableSet()), - namespaceURI); - } - - @Override - public CompletionStage edit(Consumer work) { - edition = CompletableFuture.supplyAsync(() -> { - work.accept(this); - return this; - }).thenApply((s) -> { - // TODO optimise - for (ContentProvider provider : partitions.values()) { - if (provider instanceof DomContentProvider) { - ((DomContentProvider) provider).persist(s); - } - } - return s; - }); - return edition.minimalCompletionStage(); - } - - @Override - public boolean isEditing() { - return edition != null && !edition.isDone(); - } - -// @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); -// } + MountManager getMountManager() { + return mountManager; + } + TypesManager getTypesManager() { + return typesManager; } }