X-Git-Url: https://git.argeo.org/?a=blobdiff_plain;f=org.argeo.cms%2Fsrc%2Forg%2Fargeo%2Fcms%2Facr%2FCmsContentSession.java;h=04a6fea6cdf15ad231127f66b79c7153981289d1;hb=a97cc867b992ba7543e0ff3fc87b4fc41edeaa88;hp=ba7dfa32d59f7244bef7e417f39c66105c216545;hpb=b8f50d6d8e7b9c9215d156ba33f9dedfcee913a7;p=lgpl%2Fargeo-commons.git diff --git a/org.argeo.cms/src/org/argeo/cms/acr/CmsContentSession.java b/org.argeo.cms/src/org/argeo/cms/acr/CmsContentSession.java index ba7dfa32d..04a6fea6c 100644 --- a/org.argeo.cms/src/org/argeo/cms/acr/CmsContentSession.java +++ b/org.argeo.cms/src/org/argeo/cms/acr/CmsContentSession.java @@ -2,26 +2,35 @@ package org.argeo.cms.acr; import java.util.HashSet; import java.util.Locale; +import java.util.Map; +import java.util.NavigableMap; import java.util.Set; +import java.util.Spliterator; +import java.util.TreeMap; import java.util.UUID; import java.util.concurrent.CompletableFuture; import java.util.concurrent.CompletionStage; import java.util.function.Consumer; +import java.util.stream.Stream; +import java.util.stream.StreamSupport; import javax.security.auth.Subject; import org.argeo.api.acr.Content; import org.argeo.api.acr.ContentSession; -import org.argeo.api.acr.CrName; +import org.argeo.api.acr.DName; +import org.argeo.api.acr.search.BasicSearch; +import org.argeo.api.acr.search.BasicSearch.Scope; 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.uuid.UuidFactory; -import org.argeo.cms.acr.xml.DomContentProvider; +import org.argeo.api.uuid.UuidIdentified; +import org.argeo.cms.CurrentUser; /** Implements {@link ProvidedSession}. */ -class CmsContentSession implements ProvidedSession { +class CmsContentSession implements ProvidedSession, UuidIdentified { final private AbstractContentRepository contentRepository; private final UUID uuid; @@ -61,32 +70,25 @@ class CmsContentSession implements ProvidedSession { @Override public Content get(String path) { - if (!path.startsWith(ContentUtils.ROOT_SLASH)) + if (!path.startsWith(Content.ROOT_PATH)) throw new IllegalArgumentException(path + " is not an absolute path"); ContentProvider contentProvider = contentRepository.getMountManager().findContentProvider(path); String mountPath = contentProvider.getMountPath(); - String relativePath = extractRelativePath(mountPath, path); + String relativePath = CmsContent.relativize(mountPath, path); ProvidedContent content = contentProvider.get(CmsContentSession.this, relativePath); return content; } @Override public boolean exists(String path) { - if (!path.startsWith(ContentUtils.ROOT_SLASH)) + if (!path.startsWith(Content.ROOT_PATH)) throw new IllegalArgumentException(path + " is not an absolute path"); ContentProvider contentProvider = contentRepository.getMountManager().findContentProvider(path); String mountPath = contentProvider.getMountPath(); - String relativePath = extractRelativePath(mountPath, path); + String relativePath = CmsContent.relativize(mountPath, path); return contentProvider.exists(this, relativePath); } - private String extractRelativePath(String mountPath, String path) { - String relativePath = path.substring(mountPath.length()); - if (relativePath.length() > 0 && relativePath.charAt(0) == '/') - relativePath = relativePath.substring(1); - return relativePath; - } - @Override public Subject getSubject() { return subject; @@ -111,30 +113,15 @@ class CmsContentSession implements ProvidedSession { */ @Override public Content getMountPoint(String path) { - String[] parent = ContentUtils.getParentPath(path); + String[] parent = CmsContent.getParentPath(path); ProvidedContent mountParent = (ProvidedContent) get(parent[0]); // Content mountPoint = mountParent.getProvider().get(CmsContentSession.this, null, path); return mountParent.getMountPoint(parent[1]); } /* - * NAMESPACE CONTEXT + * EDITION */ - -// @Override -// public String getNamespaceURI(String prefix) { -// return RuntimeNamespaceContext.getNamespaceContext().getNamespaceURI(prefix); -//// return NamespaceUtils.getNamespaceURI((p) -> contentRepository.getTypesManager().getPrefixes().get(p), prefix); -// } -// -// @Override -// public Iterator getPrefixes(String namespaceURI) { -// return RuntimeNamespaceContext.getNamespaceContext().getPrefixes(namespaceURI); -//// return NamespaceUtils.getPrefixes((ns) -> contentRepository.getTypesManager().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(() -> { @@ -144,9 +131,10 @@ class CmsContentSession implements ProvidedSession { synchronized (CmsContentSession.this) { // TODO optimise for (ContentProvider provider : modifiedProviders) { - if (provider instanceof DomContentProvider) { - ((DomContentProvider) provider).persist(s); - } + provider.persist(s); +// if (provider instanceof DomContentProvider) { +// ((DomContentProvider) provider).persist(s); +// } } modifiedProviders.clear(); return s; @@ -167,11 +155,11 @@ class CmsContentSession implements ProvidedSession { } @Override - public UUID getUuid() { + public UUID uuid() { return uuid; } - @Override +// @Override public Content getSessionRunDir() { if (sessionRunDir == null) { String runDirPath = CmsContentRepository.RUN_BASE + '/' + uuid.toString(); @@ -180,30 +168,141 @@ class CmsContentSession implements ProvidedSession { else { Content runDir = get(CmsContentRepository.RUN_BASE); // TODO deal with no run dir available? - sessionRunDir = runDir.add(uuid.toString(), CrName.collection.qName()); + sessionRunDir = runDir.add(uuid.toString(), DName.collection.qName()); } } return sessionRunDir; } -// @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); -// } + /* + * OBJECT METHODS + */ + + @Override + public boolean equals(Object o) { + return UuidIdentified.equals(this, o); + } + + @Override + public int hashCode() { + return UuidIdentified.hashCode(this); + } + + @Override + public String toString() { + return "Content Session " + uuid + " (" + CurrentUser.getUsername(subject) + ")"; + } + + /* + * SEARCH + */ + @Override + public Stream search(Consumer search) { + BasicSearch s = new BasicSearch(); + search.accept(s); + NavigableMap searchPartitions = new TreeMap<>(); + for (Scope scope : s.getFrom()) { + String scopePath = scope.getUri().getPath(); + NavigableMap contentProviders = contentRepository.getMountManager() + .findContentProviders(scopePath); + for (Map.Entry contentProvider : contentProviders.entrySet()) { + assert scopePath.startsWith(contentProvider.getKey()) + : "scopePath=" + scopePath + ", contentProvider path=" + contentProvider.getKey(); + // TODO deal with depth + String relPath; + if (!scopePath.equals(contentProvider.getKey())) { + relPath = scopePath.substring(contentProvider.getKey().length() + 1, scopePath.length()); + } else { + relPath = null; + } + SearchPartition searchPartition = new SearchPartition(s, relPath, contentProvider.getValue()); + searchPartitions.put(contentProvider.getKey(), searchPartition); + } + } + if (searchPartitions.isEmpty()) + return Stream.empty(); + return StreamSupport.stream(new SearchPartitionsSpliterator(searchPartitions), true); + } + class SearchPartition { + BasicSearch search; + String relPath; + ContentProvider contentProvider; + + public SearchPartition(BasicSearch search, String relPath, ContentProvider contentProvider) { + super(); + this.search = search; + this.relPath = relPath; + this.contentProvider = contentProvider; + } + + public BasicSearch getSearch() { + return search; + } + + public String getRelPath() { + return relPath; + } + + public ContentProvider getContentProvider() { + return contentProvider; + } + + } + + class SearchPartitionsSpliterator implements Spliterator { + NavigableMap searchPartitions; + + Spliterator currentSpliterator; + + public SearchPartitionsSpliterator(NavigableMap searchPartitions) { + super(); + this.searchPartitions = searchPartitions; + SearchPartition searchPartition = searchPartitions.pollFirstEntry().getValue(); + currentSpliterator = searchPartition.getContentProvider().search(CmsContentSession.this, + searchPartition.getSearch(), searchPartition.getRelPath()); + } + + @Override + public boolean tryAdvance(Consumer action) { + boolean remaining = currentSpliterator.tryAdvance(action); + if (remaining) + return true; + if (searchPartitions.isEmpty()) + return false; + SearchPartition searchPartition = searchPartitions.pollFirstEntry().getValue(); + currentSpliterator = searchPartition.getContentProvider().search(CmsContentSession.this, + searchPartition.getSearch(), searchPartition.getRelPath()); + return true; + } + + @Override + public Spliterator trySplit() { + if (searchPartitions.isEmpty()) { + return null; + } else if (searchPartitions.size() == 1) { + NavigableMap newSearchPartitions = new TreeMap<>(searchPartitions); + searchPartitions.clear(); + return new SearchPartitionsSpliterator(newSearchPartitions); + } else { + NavigableMap newSearchPartitions = new TreeMap<>(); + for (int i = 0; i < searchPartitions.size() / 2; i++) { + Map.Entry searchPartition = searchPartitions.pollLastEntry(); + newSearchPartitions.put(searchPartition.getKey(), searchPartition.getValue()); + } + return new SearchPartitionsSpliterator(newSearchPartitions); + } + } + + @Override + public long estimateSize() { + return Long.MAX_VALUE; + } + + @Override + public int characteristics() { + return NONNULL; + } + + } } \ No newline at end of file