shell.setText(basePath.toString());
shell.setLayout(new FillLayout());
- FsContentProvider contentSession = new FsContentProvider(basePath, true);
+ FsContentProvider contentSession = new FsContentProvider(null, basePath, true);
// GcrContentTreeView treeView = new GcrContentTreeView(shell, 0, contentSession.get("/"));
shell.setSize(shell.computeSize(800, 600));
import javax.xml.transform.stream.StreamSource;
import org.argeo.api.acr.Content;
+import org.argeo.api.acr.ContentUtils;
import org.argeo.api.acr.NamespaceUtils;
import org.argeo.api.acr.spi.AbstractContent;
import org.argeo.api.acr.spi.ProvidedSession;
public QName getName() {
String name = Jcr.getName(getJcrNode());
if (name.equals("")) {// root
- name = Jcr.getWorkspaceName(getJcrNode());
+ String mountPath = provider.getMountPath();
+ name = ContentUtils.getParentPath(mountPath)[1];
+ // name = Jcr.getWorkspaceName(getJcrNode());
}
return NamespaceUtils.parsePrefixedName(provider, name);
}
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
+import java.util.Objects;
import javax.jcr.Repository;
import javax.jcr.RepositoryException;
import org.argeo.api.acr.ContentUtils;
import org.argeo.api.acr.spi.ContentProvider;
import org.argeo.api.acr.spi.ProvidedSession;
+import org.argeo.cms.acr.CmsContentRepository;
import org.argeo.cms.jcr.CmsJcrUtils;
import org.argeo.jcr.JcrException;
import org.argeo.jcr.JcrUtils;
private Repository jcrRepository;
private Session adminSession;
+ private String mountPath;
+
private Map<ProvidedSession, JcrSessionAdapter> sessionAdapters = Collections.synchronizedMap(new HashMap<>());
- public void start() {
+ public void start(Map<String, String> properties) {
+ mountPath = properties.get(CmsContentRepository.ACR_MOUNT_PATH_PROPERTY);
+ Objects.requireNonNull(mountPath);
adminSession = CmsJcrUtils.openDataAdminSession(jcrRepository, null);
}
return jcrSession;
}
+ @Override
+ public String getMountPath() {
+ return mountPath;
+ }
+
/*
* NAMESPACE CONTEXT
*/
import java.util.List;
import java.util.Map;
import java.util.Optional;
+import java.util.concurrent.CompletableFuture;
import javax.xml.XMLConstants;
import javax.xml.namespace.QName;
<A> Optional<List<A>> getMultiple(QName key, Class<A> clss);
+ @SuppressWarnings("unchecked")
default <A> List<A> getMultiple(QName key) {
Class<A> type;
try {
/*
* CONTENT OPERATIONS
*/
+// default CompletionStage<Content> edit(Consumer<Content> work) {
+// return CompletableFuture.supplyAsync(() -> {
+// work.accept(this);
+// return this;
+// }).minimalCompletionStage();
+// }
+
Content add(QName name, QName... classes);
default Content add(String name, QName... classes) {
* DEFAULT METHODS
*/
default <A> A adapt(Class<A> clss) throws IllegalArgumentException {
- throw new IllegalArgumentException("Cannot adapt content " + this + " to " + clss.getName());
+ throw new UnsupportedOperationException("Cannot adapt content " + this + " to " + clss.getName());
+ }
+
+ default <C extends Closeable> C open(Class<C> clss) throws IOException {
+ throw new UnsupportedOperationException("Cannot open content " + this + " as " + clss.getName());
}
- default <C extends Closeable> C open(Class<C> clss) throws IOException, IllegalArgumentException {
- throw new IllegalArgumentException("Cannot open content " + this + " as " + clss.getName());
+ default <A> CompletableFuture<A> write(Class<A> clss) {
+ throw new UnsupportedOperationException("Cannot write content " + this + " as " + clss.getName());
}
/*
package org.argeo.api.acr;
import java.util.Locale;
+import java.util.concurrent.CompletionStage;
+import java.util.function.Consumer;
import javax.security.auth.Subject;
import javax.xml.namespace.NamespaceContext;
Content get(String path);
+ CompletionStage<ContentSession> edit(Consumer<ContentSession> work);
}
Content get(ProvidedSession session, String mountPath, String relativePath);
+ String getMountPath();
+
/*
* NAMESPACE CONTEXT
*/
ProvidedSession getSession();
ContentProvider getProvider();
+
+ default ProvidedContent getMountPoint(String relativePath) {
+ throw new UnsupportedOperationException("This content doe not support mount");
+ }
}
package org.argeo.api.acr.spi;
+import javax.xml.namespace.QName;
+
+import org.argeo.api.acr.Content;
import org.argeo.api.acr.ContentRepository;
public interface ProvidedRepository extends ContentRepository {
- public void registerTypes(String prefix, String namespaceURI, String schemaSystemId);
+ void registerTypes(String prefix, String namespaceURI, String schemaSystemId);
+
+ ContentProvider getMountContentProvider(Content mountPoint, boolean initialize, QName... types);
+
+
+ boolean shouldMount(QName... types);
}
import java.util.Iterator;
import java.util.concurrent.CompletionStage;
-import javax.xml.namespace.NamespaceContext;
-
+import org.argeo.api.acr.Content;
import org.argeo.api.acr.ContentSession;
public interface ProvidedSession extends ContentSession {
CompletionStage<ProvidedSession> onClose();
+ Content getMountPoint(String path);
+
+ boolean isEditing();
/*
* NAMESPACE CONTEXT
*/
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.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.XMLConstants;
+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 javax.xml.validation.Validator;
import org.argeo.api.acr.Content;
import org.argeo.api.acr.ContentSession;
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.
private Map<CmsSession, CmsContentSession> userSessions = Collections.synchronizedMap(new HashMap<>());
+ // utilities
+ private TransformerFactory transformerFactory = TransformerFactory.newInstance();
+
+ public final static String ACR_MOUNT_PATH_PROPERTY = "acr.mount.path";
+
public CmsContentRepository() {
contentTypesManager = new ContentTypesManager();
contentTypesManager.init();
- contentTypesManager.listTypes();
-
+ Set<QName> types = contentTypesManager.listTypes();
+ for (QName type : types) {
+ log.debug(type);
+ }
+
systemSession = newSystemSession();
}
*/
public void initRootContentProvider(Path path) {
try {
- DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
- factory.setNamespaceAware(true);
- factory.setXIncludeAware(true);
- // factory.setSchema(schema);
-
- factory.setSchema(contentTypesManager.getSchema());
-
- 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 = contentTypesManager.newDocumentBuilder();
Document document;
// if (path != null && Files.exists(path)) {
Element root = document.createElementNS(CrName.CR_NAMESPACE_URI, CrName.ROOT.get().toPrefixedString());
for (String prefix : contentTypesManager.getPrefixes().keySet()) {
- root.setAttributeNS(XMLConstants.XMLNS_ATTRIBUTE_NS_URI, XMLConstants.XMLNS_ATTRIBUTE + ":" + prefix,
- contentTypesManager.getPrefixes().get(prefix));
+// root.setAttributeNS(XMLConstants.XMLNS_ATTRIBUTE_NS_URI, XMLConstants.XMLNS_ATTRIBUTE + ":" + prefix,
+// contentTypesManager.getPrefixes().get(prefix));
+ DomUtils.addNamespace(root, prefix, contentTypesManager.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);
+ try (OutputStream out = Files.newOutputStream(path)) {
+ writeDom(document, out);
}
}
// }
- DomContentProvider contentProvider = new DomContentProvider(document);
+ DomContentProvider contentProvider = new DomContentProvider(null, document);
addProvider("/", contentProvider);
- } catch (DOMException | ParserConfigurationException | IOException | TransformerFactoryConfigurationError
- | TransformerException e) {
+ } catch (DOMException | IOException e) {
throw new IllegalStateException("Cannot init ACR root " + path, e);
}
}
+ 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);
+ contentTypesManager.validate(source);
+ StreamResult result = new StreamResult(out);
+ transformer.transform(source, result);
+ } catch (TransformerException e) {
+ throw new IOException("Cannot write dom", e);
+ }
+ }
+
+ /*
+ * MOUNT MANAGEMENT
+ */
+
+ @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);
+ }
+ }
+ DomContentProvider contentProvider = new DomContentProvider(mountPath, document);
+ partitions.put(mountPath, contentProvider);
+ return contentProvider;
+ }
+
+ @Override
+ public boolean shouldMount(QName... types) {
+ if (types.length == 0)
+ throw new IllegalArgumentException("Types must be provided");
+ QName firstType = types[0];
+ Set<QName> registeredTypes = contentTypesManager.listTypes();
+ if (registeredTypes.contains(firstType))
+ return true;
+ return false;
+ }
+
/*
* NAMESPACE CONTEXT
*/
private CompletableFuture<ProvidedSession> closed = new CompletableFuture<>();
+ private CompletableFuture<ContentSession> edition;
+
public CmsContentSession(Subject subject, Locale locale) {
this.subject = subject;
this.locale = locale;
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
*/
namespaceURI);
}
+ @Override
+ public CompletionStage<ContentSession> edit(Consumer<ContentSession> 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);
package org.argeo.cms.acr;
+import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
+import java.util.NavigableSet;
+import java.util.Objects;
+import java.util.Set;
import java.util.TreeMap;
+import java.util.TreeSet;
+import javax.xml.namespace.QName;
+import javax.xml.parsers.DocumentBuilder;
+import javax.xml.parsers.DocumentBuilderFactory;
+import javax.xml.parsers.ParserConfigurationException;
import javax.xml.transform.Source;
import javax.xml.transform.stream.StreamSource;
import javax.xml.validation.Schema;
import javax.xml.validation.SchemaFactory;
+import javax.xml.validation.Validator;
import org.apache.xerces.impl.xs.XSImplementationImpl;
import org.apache.xerces.impl.xs.util.StringListImpl;
import org.apache.xerces.xs.XSTypeDefinition;
import org.argeo.api.acr.CrName;
import org.argeo.api.cms.CmsLog;
+import org.xml.sax.ErrorHandler;
import org.xml.sax.SAXException;
+import org.xml.sax.SAXParseException;
public class ContentTypesManager {
private final static CmsLog log = CmsLog.getLog(ContentTypesManager.class);
private Map<String, String> prefixes = new TreeMap<>();
+ // immutable factories
+ private SchemaFactory schemaFactory;
+
+ /** Schema sources. */
private List<Source> sources = new ArrayList<>();
- private SchemaFactory schemaFactory;
+ // cached
private Schema schema;
+ DocumentBuilderFactory documentBuilderFactory;
+ private XSModel xsModel;
+ private NavigableSet<QName> types;
+
+ private boolean validating = true;
public ContentTypesManager() {
schemaFactory = SchemaFactory.newDefaultInstance();
+ // types
+ types = new TreeSet<>((qn1, qn2) -> {
+ if (Objects.equals(qn1.getNamespaceURI(), qn2.getNamespaceURI())) {// same namespace
+ return qn1.getLocalPart().compareTo(qn2.getLocalPart());
+ } else {
+ return qn1.getNamespaceURI().compareTo(qn2.getNamespaceURI());
+ }
+ });
+
}
public synchronized void init() {
prefixes.put("owner", CrName.CR_NAMESPACE_URI);
prefixes.put("posix", CrName.CR_NAMESPACE_URI);
- try {
- for (CmsContentTypes cs : CmsContentTypes.values()) {
- StreamSource source = new StreamSource(cs.getResource().toExternalForm());
- sources.add(source);
- if (prefixes.containsKey(cs.getDefaultPrefix()))
- throw new IllegalStateException("Prefix " + cs.getDefaultPrefix() + " is already mapped with "
- + prefixes.get(cs.getDefaultPrefix()));
- prefixes.put(cs.getDefaultPrefix(), cs.getNamespace());
- }
-
- schema = schemaFactory.newSchema(sources.toArray(new Source[sources.size()]));
- } catch (SAXException e) {
- throw new IllegalStateException("Cannot initialise types", e);
+ for (CmsContentTypes cs : CmsContentTypes.values()) {
+ StreamSource source = new StreamSource(cs.getResource().toExternalForm());
+ sources.add(source);
+ if (prefixes.containsKey(cs.getDefaultPrefix()))
+ throw new IllegalStateException("Prefix " + cs.getDefaultPrefix() + " is already mapped with "
+ + prefixes.get(cs.getDefaultPrefix()));
+ prefixes.put(cs.getDefaultPrefix(), cs.getNamespace());
}
+ reload();
}
public synchronized void registerTypes(String defaultPrefix, String namespace, String xsdSystemId) {
- try {
- if (prefixes.containsKey(defaultPrefix))
- throw new IllegalStateException(
- "Prefix " + defaultPrefix + " is already mapped with " + prefixes.get(defaultPrefix));
- prefixes.put(defaultPrefix, namespace);
+ if (prefixes.containsKey(defaultPrefix))
+ throw new IllegalStateException(
+ "Prefix " + defaultPrefix + " is already mapped with " + prefixes.get(defaultPrefix));
+ prefixes.put(defaultPrefix, namespace);
- sources.add(new StreamSource(xsdSystemId));
- schema = schemaFactory.newSchema(sources.toArray(new Source[sources.size()]));
- } catch (SAXException e) {
- throw new IllegalStateException("Cannot initialise types " + namespace + " based on " + xsdSystemId, e);
- }
+ sources.add(new StreamSource(xsdSystemId));
+ reload();
+ }
+ public Set<QName> listTypes() {
+// TODO cache it?
+ return types;
}
- public void listTypes() {
+ private synchronized void reload() {
try {
- // Find an XMLSchema loader instance
+ // schema
+ schema = schemaFactory.newSchema(sources.toArray(new Source[sources.size()]));
+
+ // document builder factory
+ documentBuilderFactory = DocumentBuilderFactory.newInstance();
+ documentBuilderFactory.setNamespaceAware(true);
+ documentBuilderFactory.setXIncludeAware(true);
+ documentBuilderFactory.setSchema(getSchema());
+ documentBuilderFactory.setValidating(validating);
+
+ // XS model
+ // TODO use JVM implementation?
// DOMImplementationRegistry registry = DOMImplementationRegistry.newInstance();
// XSImplementation implementation = (XSImplementation) registry.getDOMImplementation("XS-Loader");
- XSImplementation implementation = new XSImplementationImpl();
- XSLoader loader = implementation.createXSLoader(null);
-
- // Load the XML Schema
+ XSImplementation xsImplementation = new XSImplementationImpl();
+ XSLoader xsLoader = xsImplementation.createXSLoader(null);
List<String> systemIds = new ArrayList<>();
for (Source source : sources) {
systemIds.add(source.getSystemId());
}
StringList sl = new StringListImpl(systemIds.toArray(new String[systemIds.size()]), systemIds.size());
- XSModel xsModel = loader.loadURIList(sl);
+ xsModel = xsLoader.loadURIList(sl);
+
+ // types
+ XSNamedMap map = xsModel.getComponents(XSConstants.ELEMENT_DECLARATION);
+ for (int i = 0; i < map.getLength(); i++) {
+ XSElementDeclaration eDec = (XSElementDeclaration) map.item(i);
+ QName type = new QName(eDec.getNamespace(), eDec.getName());
+ types.add(type);
+ }
+ } catch (XSException | SAXException e) {
+ throw new IllegalStateException("Cannot relaod types");
+ }
+ }
+
+ public DocumentBuilder newDocumentBuilder() {
+ try {
+ DocumentBuilder dBuilder = documentBuilderFactory.newDocumentBuilder();
+ dBuilder.setErrorHandler(new ErrorHandler() {
+
+ @Override
+ public void warning(SAXParseException exception) throws SAXException {
+ log.warn(exception);
+ }
+
+ @Override
+ public void fatalError(SAXParseException exception) throws SAXException {
+ log.error(exception);
+ }
+
+ @Override
+ public void error(SAXParseException exception) throws SAXException {
+ log.error(exception);
+ }
+ });
+ return dBuilder;
+ } catch (ParserConfigurationException e) {
+ throw new IllegalStateException("Cannot create document builder", e);
+ }
+ }
+
+ public void printTypes() {
+ try {
// Convert top level complex type definitions to node types
log.debug("\n## TYPES");
}
+ public void validate(Source source) throws IOException {
+ if (!validating)
+ return;
+ Validator validator;
+ synchronized (this) {
+ validator = schema.newValidator();
+ }
+ try {
+ validator.validate(source);
+ } catch (SAXException e) {
+ throw new IllegalArgumentException("Provided source is not valid", e);
+ }
+ }
+
public Map<String, String> getPrefixes() {
return prefixes;
}
package org.argeo.cms.acr.fs;
+import java.io.Closeable;
import java.io.IOException;
+import java.io.InputStream;
+import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import org.argeo.api.acr.Content;
import org.argeo.api.acr.ContentName;
import org.argeo.api.acr.ContentResourceException;
+import org.argeo.api.acr.ContentUtils;
import org.argeo.api.acr.CrName;
import org.argeo.api.acr.NamespaceUtils;
import org.argeo.api.acr.spi.AbstractContent;
+import org.argeo.api.acr.spi.ContentProvider;
import org.argeo.api.acr.spi.ProvidedContent;
import org.argeo.api.acr.spi.ProvidedSession;
import org.argeo.util.FsUtils;
this.path = path;
this.isRoot = contentProvider.isRoot(path);
// TODO check file names with ':' ?
- if (isRoot)
- this.name = CrName.ROOT.get();
- else {
+ if (isRoot) {
+ String mountPath = provider.getMountPath();
+ if (mountPath != null) {
+ Content mountPoint = session.getMountPoint(mountPath);
+ this.name = mountPoint.getName();
+ } else {
+ this.name = CrName.ROOT.get();
+ }
+ } else {
QName providerName = NamespaceUtils.parsePrefixedName(provider, path.getFileName().toString());
this.name = new ContentName(providerName, session);
}
public Iterator<Content> iterator() {
if (Files.isDirectory(path)) {
try {
- return Files.list(path).map((p) -> (Content) new FsContent(this, p)).iterator();
+ return Files.list(path).map((p) -> {
+ FsContent fsContent = new FsContent(this, p);
+ Optional<String> isMount = fsContent.get(CrName.MOUNT.get(), String.class);
+ if (isMount.orElse("false").equals("true")) {
+ QName[] classes = null;
+ ContentProvider contentProvider = session.getRepository().getMountContentProvider(fsContent,
+ false, classes);
+ Content mountedContent = contentProvider.get(session, fsContent.getPath(), "");
+ return mountedContent;
+ } else {
+ return (Content) fsContent;
+ }
+ }).iterator();
} catch (IOException e) {
throw new ContentResourceException("Cannot list " + path, e);
}
@Override
public Content add(QName name, QName... classes) {
+ FsContent fsContent;
try {
Path newPath = path.resolve(NamespaceUtils.toPrefixedName(provider, name));
if (ContentName.contains(classes, CrName.COLLECTION.get()))
// for(ContentClass clss:classes) {
// Files.setAttribute(newPath, name, newPath, null)
// }
- return new FsContent(this, newPath);
+ fsContent = new FsContent(this, newPath);
} catch (IOException e) {
throw new ContentResourceException("Cannot create new content", e);
}
+
+ if (session.getRepository().shouldMount(classes)) {
+ ContentProvider contentProvider = session.getRepository().getMountContentProvider(fsContent, true, classes);
+ Content mountedContent = contentProvider.get(session, fsContent.getPath(), "");
+ fsContent.put(CrName.MOUNT.get(), "true");
+ return mountedContent;
+
+ } else {
+ return fsContent;
+ }
}
@Override
@Override
public Content getParent() {
- if (isRoot)
- return null;// TODO deal with mounts
+ if (isRoot) {
+ String mountPath = provider.getMountPath();
+ if (mountPath == null)
+ return null;
+ String[] parent = ContentUtils.getParentPath(mountPath);
+ return session.get(parent[0]);
+ }
return new FsContent(this, path.getParent());
}
+ @Override
+ public <C extends Closeable> C open(Class<C> clss) throws IOException, IllegalArgumentException {
+ if (InputStream.class.isAssignableFrom(clss)) {
+ if (Files.isDirectory(path))
+ throw new UnsupportedOperationException("Cannot open " + path + " as stream, since it is a directory");
+ return (C) Files.newInputStream(path);
+ } else if (OutputStream.class.isAssignableFrom(clss)) {
+ if (Files.isDirectory(path))
+ throw new UnsupportedOperationException("Cannot open " + path + " as stream, since it is a directory");
+ return (C) Files.newOutputStream(path);
+ }
+ return super.open(clss);
+ }
+
+ /*
+ * MOUNT MANAGEMENT
+ */
+ @Override
+ public ProvidedContent getMountPoint(String relativePath) {
+ Path childPath = path.resolve(relativePath);
+ // TODO check that it is a mount
+ return new FsContent(this, childPath);
+ }
+
/*
* ACCESSORS
*/
public class FsContentProvider implements ContentProvider {
final static String XMLNS_ = "xmlns:";
+ private final String mountPath;
private final Path rootPath;
private final boolean isRoot;
private NavigableMap<String, String> prefixes = new TreeMap<>();
- public FsContentProvider(Path rootPath, boolean isRoot) {
+ public FsContentProvider(String mountPath, Path rootPath, boolean isRoot) {
+ this.mountPath = mountPath;
this.rootPath = rootPath;
this.isRoot = isRoot;
initNamespaces();
}
}
+
+
+@Override
+ public String getMountPath() {
+ return mountPath;
+ }
boolean isRoot(Path path) {
try {
package org.argeo.cms.acr.xml;
+import java.nio.CharBuffer;
+import java.nio.file.Path;
import java.util.HashSet;
import java.util.Iterator;
import java.util.Optional;
import java.util.Set;
+import java.util.concurrent.CompletableFuture;
import javax.xml.XMLConstants;
import javax.xml.namespace.NamespaceContext;
import org.argeo.api.acr.Content;
import org.argeo.api.acr.ContentName;
+import org.argeo.api.acr.ContentUtils;
+import org.argeo.api.acr.CrName;
import org.argeo.api.acr.spi.AbstractContent;
import org.argeo.api.acr.spi.ProvidedContent;
import org.argeo.api.acr.spi.ProvidedSession;
+import org.argeo.cms.acr.fs.FsContent;
import org.w3c.dom.Attr;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
@Override
public QName getName() {
+ if (element.getParentNode() == null) {// root
+ String mountPath = provider.getMountPath();
+ if (mountPath != null) {
+ Content mountPoint = session.getMountPoint(mountPath);
+ return mountPoint.getName();
+ }
+ }
return toQName(this.element);
}
@Override
public Content getParent() {
- Node parent = element.getParentNode();
- if (parent == null)
- return null;
- if (parent instanceof Document)
+ Node parentNode = element.getParentNode();
+ if (parentNode == null) {
+ String mountPath = provider.getMountPath();
+ if (mountPath == null)
+ return null;
+ String[] parent = ContentUtils.getParentPath(mountPath);
+ return session.get(parent[0]);
+ }
+ if (parentNode instanceof Document)
return null;
- if (!(parent instanceof Element))
+ if (!(parentNode instanceof Element))
throw new IllegalStateException("Parent is not an element");
- return new DomContent(this, (Element) parent);
+ return new DomContent(this, (Element) parentNode);
}
@Override
}
+ @Override
+ public <A> A adapt(Class<A> clss) throws IllegalArgumentException {
+ if (CharBuffer.class.isAssignableFrom(clss)) {
+ String textContent = element.getTextContent();
+ CharBuffer buf = CharBuffer.wrap(textContent);
+ return (A) buf;
+ }
+ return super.adapt(clss);
+ }
+
+ public <A> CompletableFuture<A> write(Class<A> clss) {
+ if (String.class.isAssignableFrom(clss)) {
+ CompletableFuture<String> res = new CompletableFuture<>();
+ res.thenAccept((s) -> element.setTextContent(s));// .thenRun(() -> provider.persist(session));
+ return (CompletableFuture<A>) res;
+ }
+ return super.write(clss);
+ }
+
+ /*
+ * MOUNT MANAGEMENT
+ */
+ @Override
+ public ProvidedContent getMountPoint(String relativePath) {
+ // FIXME use qualified names
+ Element childElement = (Element) element.getElementsByTagName(relativePath).item(0);
+ // TODO check that it is a mount
+ return new DomContent(this, childElement);
+ }
+
public ProvidedSession getSession() {
return session;
}
package org.argeo.cms.acr.xml;
+import java.io.IOException;
+import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import org.argeo.api.acr.NamespaceUtils;
import org.argeo.api.acr.spi.ContentProvider;
import org.argeo.api.acr.spi.ProvidedSession;
+import org.argeo.cms.acr.CmsContentRepository;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NodeList;
public class DomContentProvider implements ContentProvider, NamespaceContext {
- private Document document;
+ private final Document document;
// XPath
// TODO centralise in some executor?
private final ThreadLocal<XPath> xPath;
- public DomContentProvider(Document document) {
+ private String mountPath;
+
+ public DomContentProvider(String mountPath, Document document) {
+ this.mountPath = mountPath;
this.document = document;
this.document.normalizeDocument();
XPathFactory xPathFactory = XPathFactory.newInstance();
}
}
+ public void persist(ProvidedSession session) {
+ if (mountPath != null) {
+ Content mountPoint = session.getMountPoint(mountPath);
+ try (OutputStream out = mountPoint.open(OutputStream.class)) {
+ CmsContentRepository contentRepository = (CmsContentRepository) session.getRepository();
+ contentRepository.writeDom(document, out);
+ } catch (IOException e) {
+ throw new IllegalStateException("Cannot persist " + mountPath, e);
+ }
+ }
+ }
+
+ @Override
+ public String getMountPath() {
+ return mountPath;
+ }
+
/*
* NAMESPACE CONTEXT
*/
--- /dev/null
+package org.argeo.cms.acr.xml;
+
+import java.io.IOException;
+import java.io.OutputStream;
+
+import javax.xml.XMLConstants;
+import javax.xml.transform.OutputKeys;
+import javax.xml.transform.Transformer;
+import javax.xml.transform.TransformerException;
+import javax.xml.transform.TransformerFactory;
+import javax.xml.transform.dom.DOMSource;
+import javax.xml.transform.stream.StreamResult;
+
+import org.w3c.dom.Document;
+import org.w3c.dom.Element;
+
+public class DomUtils {
+ public static void addNamespace(Element element, String prefix, String namespace) {
+ element.setAttributeNS(XMLConstants.XMLNS_ATTRIBUTE_NS_URI, XMLConstants.XMLNS_ATTRIBUTE + ":" + prefix,
+ namespace);
+ }
+
+// public static void writeDom(TransformerFactory transformerFactory, 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);
+// StreamResult result = new StreamResult(out);
+// transformer.transform(source, result);
+// } catch (TransformerException e) {
+// throw new IOException("Cannot write dom", e);
+// }
+// }
+
+ /** singleton */
+ private DomUtils() {
+
+ }
+}
}
public static void main(String[] args) throws IOException {
+ Path dir = Paths.get(args[0]);
XmlNormalizer xmlNormalizer = new XmlNormalizer();
- DirectoryStream<Path> ds = Files.newDirectoryStream(
- Paths.get("/mnt/mbaudier/dev/git/unstable/argeo-suite/org.argeo.app.theme.default/icons/types/svg"),
- "*.svg");
+ DirectoryStream<Path> ds = Files.newDirectoryStream(dir, "*.svg");
xmlNormalizer.normalizeXmlFiles(ds);
}
import java.util.Map;
import org.argeo.api.acr.spi.ContentProvider;
+import org.argeo.api.cms.CmsConstants;
import org.argeo.api.cms.CmsState;
import org.argeo.cms.acr.CmsContentRepository;
+import org.argeo.cms.acr.fs.FsContentProvider;
import org.argeo.util.LangUtils;
public class DeployedContentRepository extends CmsContentRepository {
private final static String ROOT_XML = "cr:root.xml";
- private final static String ACR_MOUNT_PATH = "acr.mount.path";
-
private CmsState cmsState;
@Override
Path rootXml = KernelUtils.getOsgiInstancePath(ROOT_XML);
initRootContentProvider(rootXml);
-// Path srvPath = KernelUtils.getOsgiInstancePath(CmsConstants.SRV_WORKSPACE);
-// FsContentProvider srvContentProvider = new FsContentProvider(srvPath, false);
-// addProvider("/" + CmsConstants.SRV_WORKSPACE, srvContentProvider);
+ Path srvPath = KernelUtils.getOsgiInstancePath(CmsConstants.SRV_WORKSPACE);
+ FsContentProvider srvContentProvider = new FsContentProvider(CmsConstants.SRV_WORKSPACE, srvPath, false);
+ addProvider("/" + CmsConstants.SRV_WORKSPACE, srvContentProvider);
}
@Override
}
public void addContentProvider(ContentProvider provider, Map<String, Object> properties) {
- String base = LangUtils.get(properties, ACR_MOUNT_PATH);
+ String base = LangUtils.get(properties, CmsContentRepository.ACR_MOUNT_PATH_PROPERTY);
addProvider(base, provider);
}