X-Git-Url: https://git.argeo.org/?a=blobdiff_plain;f=org.argeo.cms%2Fsrc%2Forg%2Fargeo%2Fcms%2Facr%2FCmsContentRepository.java;h=b416d93654c52b36748da5d5cdb16d4f5eed41f0;hb=8acca40eb96fef7df712f0cbf5e5ffc13d48fcbd;hp=2493a89bedc0993c856d7c85cb6b5014d5fa7cb7;hpb=9174f78c93c94b9c148dff66c38204baf55bc8f2;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 2493a89be..b416d9365 100644 --- a/org.argeo.cms/src/org/argeo/cms/acr/CmsContentRepository.java +++ b/org.argeo.cms/src/org/argeo/cms/acr/CmsContentRepository.java @@ -1,55 +1,44 @@ package org.argeo.cms.acr; import java.io.IOException; -import java.io.Writer; -import java.nio.charset.StandardCharsets; +import java.io.InputStream; +import java.io.OutputStream; 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.TreeMap; -import java.util.concurrent.CompletableFuture; -import java.util.concurrent.CompletionStage; -import java.util.stream.Collectors; +import java.util.Set; -import javax.security.auth.Subject; import javax.security.auth.login.LoginContext; import javax.security.auth.login.LoginException; +import javax.xml.namespace.QName; import javax.xml.parsers.DocumentBuilder; -import javax.xml.parsers.DocumentBuilderFactory; -import javax.xml.parsers.ParserConfigurationException; +import javax.xml.transform.OutputKeys; 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 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; import org.argeo.cms.acr.xml.DomContentProvider; +import org.argeo.cms.acr.xml.DomUtils; 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. @@ -57,24 +46,32 @@ import org.xml.sax.SAXParseException; 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 final MountManager mountManager; + private final TypesManager typesManager; private CmsContentSession systemSession; private Map userSessions = Collections.synchronizedMap(new HashMap<>()); + // utilities + private TransformerFactory transformerFactory = TransformerFactory.newInstance(); + + public final static String ACR_MOUNT_PATH_PROPERTY = "acr.mount.path"; + 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); + // types + typesManager = new TypesManager(); + typesManager.init(); + Set types = typesManager.listTypes(); + for (QName type : types) { + log.debug(type + " - " + typesManager.getAttributeTypes(type)); + } systemSession = newSystemSession(); + + // mounts + mountManager = new MountManager(systemSession); + } protected CmsContentSession newSystemSession() { @@ -86,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() { @@ -111,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); @@ -121,28 +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 registerPrefix(String prefix, String namespaceURI) { - 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 + public void registerTypes(String prefix, String namespaceURI, String schemaSystemId) { + typesManager.registerTypes(prefix, namespaceURI, schemaSystemId); } /* @@ -150,156 +131,113 @@ public class CmsContentRepository implements ProvidedRepository { */ 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); - - } - }); +// DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance(); +// factory.setNamespaceAware(true); +// factory.setXIncludeAware(true); +// factory.setSchema(contentTypesManager.getSchema()); +// + DocumentBuilder dBuilder = typesManager.newDocumentBuilder(); Document document; - if (path != null && 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.createElementNS(CrName.CR_NAMESPACE_URI, CrName.ROOT.get().toPrefixedString()); - // root.setAttribute("xmlns", ""); -// root.setAttribute("xmlns:" + CrName.CR_DEFAULT_PREFIX, CrName.CR_NAMESPACE_URI); - document.appendChild(root); +// if (path != null && 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.CR_NAMESPACE_URI, CrName.ROOT.get().toPrefixedString()); + + 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, typesManager.getPrefixes().get(prefix)); + } + + document.appendChild(root); - // write it - if (path != null) { - 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); - } + // write it + if (path != null) { + try (OutputStream out = Files.newOutputStream(path)) { + writeDom(document, out); } } +// } - DomContentProvider contentProvider = new DomContentProvider(document); - addProvider("/", contentProvider); - } catch (DOMException | ParserConfigurationException | SAXException | IOException - | TransformerFactoryConfigurationError | TransformerException e) { + String mountPath = "/"; + DomContentProvider contentProvider = new DomContentProvider(mountPath, document); + addProvider(contentProvider); + } catch (DOMException | IOException e) { throw new IllegalStateException("Cannot init ACR root " + path, e); } } - /* - * NAMESPACE CONTEXT - */ + public void writeDom(Document document, OutputStream out) throws IOException { + try { + Transformer transformer = transformerFactory.newTransformer(); + transformer.setOutputProperty(OutputKeys.ENCODING, "UTF-8"); + transformer.setOutputProperty(OutputKeys.INDENT, "yes"); + + DOMSource source = new DOMSource(document); + typesManager.validate(source); + StreamResult result = new StreamResult(out); + transformer.transform(source, result); + } catch (TransformerException e) { + throw new IOException("Cannot write dom", e); + } + } /* - * SESSION + * MOUNT MANAGEMENT */ - class CmsContentSession implements ProvidedSession { - 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); - 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; - } - - /* - * NAMESPACE CONTEXT - */ + @Override + public ContentProvider getMountContentProvider(Content mountPoint, boolean initialize, QName... types) { + String mountPath = mountPoint.getPath(); + // TODO check consistency with types - @Override - public String getNamespaceURI(String prefix) { - return NamespaceUtils.getNamespaceURI((p) -> prefixes.get(p), prefix); - } + 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(path, document); + return contentProvider; + }); + } - @Override - 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 boolean shouldMount(QName... types) { + if (types.length == 0) + return false; + QName firstType = types[0]; + Set registeredTypes = typesManager.listTypes(); + if (registeredTypes.contains(firstType)) + return true; + return false; + } -// @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; } }