Improve ACR.
authorMathieu Baudier <mbaudier@argeo.org>
Thu, 16 Jun 2022 10:27:40 +0000 (12:27 +0200)
committerMathieu Baudier <mbaudier@argeo.org>
Thu, 16 Jun 2022 10:27:40 +0000 (12:27 +0200)
25 files changed:
jcr/org.argeo.cms.jcr/src/org/argeo/cms/jcr/acr/JcrContent.java
jcr/org.argeo.cms.jcr/src/org/argeo/cms/jcr/acr/JcrContentProvider.java
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/CmsUiProvider.java
org.argeo.api.acr/src/org/argeo/api/acr/ContentSession.java
org.argeo.api.acr/src/org/argeo/api/acr/spi/ContentProvider.java
org.argeo.api.acr/src/org/argeo/api/acr/spi/ProvidedSession.java
org.argeo.api.cms/src/org/argeo/api/cms/CmsContext.java
org.argeo.api.cms/src/org/argeo/api/cms/CmsState.java
org.argeo.cms/OSGI-INF/cmsContext.xml
org.argeo.cms/OSGI-INF/cmsState.xml
org.argeo.cms/src/org/argeo/cms/acr/AbstractContentRepository.java
org.argeo.cms/src/org/argeo/cms/acr/CmsContentRepository.java
org.argeo.cms/src/org/argeo/cms/acr/CmsContentSession.java
org.argeo.cms/src/org/argeo/cms/acr/ContentUtils.java
org.argeo.cms/src/org/argeo/cms/acr/SingleUserContentRepository.java
org.argeo.cms/src/org/argeo/cms/acr/fs/FsContent.java
org.argeo.cms/src/org/argeo/cms/acr/fs/FsContentProvider.java
org.argeo.cms/src/org/argeo/cms/acr/xml/DomContentProvider.java
org.argeo.cms/src/org/argeo/cms/auth/CmsAuthUtils.java
org.argeo.cms/src/org/argeo/cms/internal/auth/CmsSessionImpl.java
org.argeo.cms/src/org/argeo/cms/internal/http/WebCmsSessionImpl.java
org.argeo.cms/src/org/argeo/cms/internal/runtime/CmsContextImpl.java
org.argeo.cms/src/org/argeo/cms/internal/runtime/CmsStateImpl.java
org.argeo.cms/src/org/argeo/cms/internal/runtime/DeployedContentRepository.java
org.argeo.cms/src/org/argeo/cms/runtime/StaticCms.java

index 63bf8dfffae04110938d08fc56ef418cbc6382ca..116e45c7bf09fc0d546aeadc216a7239bcab4b9b 100644 (file)
@@ -222,6 +222,14 @@ public class JcrContent extends AbstractContent {
 
        }
 
+       boolean exists() {
+               try {
+                       return provider.getJcrSession(session, jcrWorkspace).itemExists(jcrPath);
+               } catch (RepositoryException e) {
+                       throw new JcrException("Cannot check whether " + jcrPath + " exists", e);
+               }
+       }
+
        /*
         * ADAPTERS
         */
index 198a2a3ed4480054cc87e738d770c818489d2774..235e27d1a922139558d8e8c42da322199340dda5 100644 (file)
@@ -12,6 +12,7 @@ import javax.jcr.RepositoryException;
 import javax.jcr.Session;
 import javax.xml.namespace.NamespaceContext;
 
+import org.argeo.api.acr.Content;
 import org.argeo.api.acr.spi.ContentProvider;
 import org.argeo.api.acr.spi.ProvidedContent;
 import org.argeo.api.acr.spi.ProvidedSession;
@@ -47,12 +48,19 @@ public class JcrContentProvider implements ContentProvider, NamespaceContext {
        }
 
        @Override
-       public ProvidedContent get(ProvidedSession contentSession, String mountPath, String relativePath) {
+       public ProvidedContent get(ProvidedSession contentSession, String relativePath) {
                String jcrWorkspace = ContentUtils.getParentPath(mountPath)[1];
                String jcrPath = "/" + relativePath;
                return new JcrContent(contentSession, this, jcrWorkspace, jcrPath);
        }
 
+       @Override
+       public boolean exists(ProvidedSession contentSession, String relativePath) {
+               String jcrWorkspace = ContentUtils.getParentPath(mountPath)[1];
+               String jcrPath = "/" + relativePath;
+               return new JcrContent(contentSession, this, jcrWorkspace, jcrPath).exists();
+       }
+
        public Session getJcrSession(ProvidedSession contentSession, String jcrWorkspace) {
                JcrSessionAdapter sessionAdapter = sessionAdapters.get(contentSession);
                if (sessionAdapter == null) {
@@ -67,6 +75,10 @@ public class JcrContentProvider implements ContentProvider, NamespaceContext {
                return jcrSession;
        }
 
+       public Session getJcrSession(Content content, String jcrWorkspace) {
+               return getJcrSession(((ProvidedContent) content).getSession(), jcrWorkspace);
+       }
+
        @Override
        public String getMountPath() {
                return mountPath;
index 4473498c19459b5dedc8642f7a54c00050b30d52..5f2377be566f05a6ad618f1e30cea3c8e943b3e4 100644 (file)
@@ -11,7 +11,6 @@ import org.eclipse.swt.widgets.Composite;
 import org.eclipse.swt.widgets.Control;
 
 /** Stateless factory building an SWT user interface given a JCR context. */
-@FunctionalInterface
 public interface CmsUiProvider extends SwtUiProvider {
        /**
         * Initialises a user interface.
@@ -19,7 +18,10 @@ public interface CmsUiProvider extends SwtUiProvider {
         * @param parent  the parent composite
         * @param context a context node (holding the JCR underlying session), or null
         */
-       Control createUi(Composite parent, Node context) throws RepositoryException;
+       default Control createUi(Composite parent, Node context) throws RepositoryException {
+               // does nothing by default
+               return null;
+       }
 
        default Control createUiPart(Composite parent, Node context) {
                try {
@@ -37,7 +39,12 @@ public interface CmsUiProvider extends SwtUiProvider {
                        Node node = ((JcrContent) context).getJcrNode();
                        return createUiPart(parent, node);
                } else {
-                       throw new IllegalArgumentException("Content " + context + " is not compatible with JCR");
+//                     CmsLog.getLog(CmsUiProvider.class)
+//                                     .warn("In " + getClass() + ", content " + context + " is not compatible with JCR.");
+//                     return createUiPart(parent, (Node) null);
+
+                       throw new IllegalArgumentException(
+                                       "In " + getClass() + ", content " + context + " is not compatible with JCR");
                }
        }
 
index 3adde724bc9bbf5d5d16a0bbcd2952ea0035e009..b7d37dc10a876d38a14bad895c9e0e0a4d3280fc 100644 (file)
@@ -13,6 +13,8 @@ public interface ContentSession extends NamespaceContext {
        Locale getLocale();
 
        Content get(String path);
+       
+       boolean exists(String path);
 
        CompletionStage<ContentSession> edit(Consumer<ContentSession> work);
 }
index 850760134258b1f10d9c8457de8fbc02e2734a85..72aa162b3b59716af8972c256b6a36d06d476053 100644 (file)
@@ -6,7 +6,9 @@ import javax.xml.namespace.NamespaceContext;
 
 public interface ContentProvider extends NamespaceContext {
 
-       ProvidedContent get(ProvidedSession session, String mountPath, String relativePath);
+       ProvidedContent get(ProvidedSession session, String relativePath);
+
+       boolean exists(ProvidedSession session, String relativePath);
 
        String getMountPath();
 
index 075f7bd1beccd47a4a9c38a258c96b9ce58eec63..ba915ac4000a9e6268920b13e4535897af9ea047 100644 (file)
@@ -1,6 +1,7 @@
 package org.argeo.api.acr.spi;
 
 import java.util.Iterator;
+import java.util.UUID;
 import java.util.concurrent.CompletionStage;
 
 import org.argeo.api.acr.Content;
@@ -18,6 +19,10 @@ public interface ProvidedSession extends ContentSession {
 
        void notifyModification(ProvidedContent content);
 
+       UUID getUuid();
+
+       Content getSessionRunDir();
+
        /*
         * NAMESPACE CONTEXT
         */
index 8f4161c507e2244b7b3bf52fca1647122bf2d4d6..05108beac3e2ad0bc5a18842d8419255ced8b308 100644 (file)
@@ -27,4 +27,6 @@ public interface CmsContext {
 
        /** Get the CMS session of this subject. */
        CmsSession getCmsSession(Subject subject);
+       
+       CmsState getCmsState();
 }
index ed8698fcaccdb2aabe25ad6fd1de360c779aecfc..3828b080b6e029983de83f2311051243ca870ee1 100644 (file)
@@ -1,9 +1,12 @@
 package org.argeo.api.cms;
 
+import java.util.UUID;
+
 /** A running node process. */
 public interface CmsState {
        String getHostname();
 
        Long getAvailableSince();
 
+       UUID getUuid();
 }
index 63d43192e9b6294084e9d4a83c37d6b1980881f1..bec00335069b71d194f7afe6b46583b23b26c729 100644 (file)
@@ -7,4 +7,6 @@
    </service>
    <reference bind="setCmsState" cardinality="1..1" interface="org.argeo.api.cms.CmsState" name="CmsState" policy="static"/>
    <reference bind="setUserAdmin" cardinality="1..1" interface="org.osgi.service.useradmin.UserAdmin" name="UserAdmin" policy="static"/>
+   <reference bind="setUuidFactory" cardinality="1..1" interface="org.argeo.api.uuid.UuidFactory" name="UuidFactory" policy="static"/>
+   <reference bind="setContentRepository" cardinality="1..1" interface="org.argeo.api.acr.spi.ProvidedRepository" name="ProvidedRepository" policy="static"/>
 </scr:component>
index a81e9f0681c17a03a65ab57a024c9cf5ba877be2..71dc6d4db41c19ac8a3c7b2c3e9e866ca3383f98 100644 (file)
@@ -4,4 +4,5 @@
    <service>
       <provide interface="org.argeo.api.cms.CmsState"/>
    </service>
+   <reference bind="setUuidFactory" cardinality="1..1" interface="org.argeo.api.uuid.UuidFactory" name="UuidFactory" policy="static"/>
 </scr:component>
index 6ca7b3591a8cae1d27f42755833dded275687ba3..cfffea027855b2fcd3a8e3301fa7f80bc6dfc267 100644 (file)
@@ -22,7 +22,6 @@ 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.cms.CmsLog;
-import org.argeo.api.uuid.UuidFactory;
 import org.argeo.cms.acr.xml.DomContentProvider;
 import org.argeo.cms.acr.xml.DomUtils;
 import org.w3c.dom.DOMException;
@@ -36,8 +35,6 @@ import org.xml.sax.SAXException;
 public abstract class AbstractContentRepository implements ProvidedRepository {
        private final static CmsLog log = CmsLog.getLog(AbstractContentRepository.class);
 
-       private UuidFactory uuidFactory;
-
        private MountManager mountManager;
        private TypesManager typesManager;
 
@@ -199,9 +196,4 @@ public abstract class AbstractContentRepository implements ProvidedRepository {
        TypesManager getTypesManager() {
                return typesManager;
        }
-
-       public void setUuidFactory(UuidFactory uuidFactory) {
-               this.uuidFactory = uuidFactory;
-       }
-
 }
index c2d6b21e406f61a5930e43f235de6fa8e7c2e42b..46222ce1ac0d2248b58f67ed8bdb3e13b8a6e68a 100644 (file)
@@ -12,6 +12,8 @@ import org.argeo.api.acr.ContentSession;
 import org.argeo.api.acr.spi.ProvidedRepository;
 import org.argeo.api.cms.CmsAuth;
 import org.argeo.api.cms.CmsSession;
+import org.argeo.api.cms.CmsState;
+import org.argeo.api.uuid.UuidFactory;
 import org.argeo.cms.auth.CurrentUser;
 import org.argeo.cms.internal.runtime.CmsContextImpl;
 
@@ -19,9 +21,13 @@ import org.argeo.cms.internal.runtime.CmsContextImpl;
  * Multi-session {@link ProvidedRepository}, integrated with a CMS.
  */
 public class CmsContentRepository extends AbstractContentRepository {
+       public final static String RUN_BASE = "/run";
 
        private Map<CmsSession, CmsContentSession> userSessions = Collections.synchronizedMap(new HashMap<>());
 
+       private CmsState cmsState;
+       private UuidFactory uuidFactory;
+
        /*
         * REPOSITORY
         */
@@ -37,7 +43,8 @@ public class CmsContentRepository extends AbstractContentRepository {
                CmsSession cmsSession = CurrentUser.getCmsSession();
                CmsContentSession contentSession = userSessions.get(cmsSession);
                if (contentSession == null) {
-                       final CmsContentSession newContentSession = new CmsContentSession(this, cmsSession.getSubject(), locale);
+                       final CmsContentSession newContentSession = new CmsContentSession(this, cmsSession.getUuid(),
+                                       cmsSession.getSubject(), locale);
                        cmsSession.addOnCloseCallback((c) -> {
                                newContentSession.close();
                                userSessions.remove(cmsSession);
@@ -57,7 +64,20 @@ public class CmsContentRepository extends AbstractContentRepository {
                        throw new RuntimeException("Could not login as data admin", e1);
                } finally {
                }
-               return new CmsContentSession(this, loginContext.getSubject(), Locale.getDefault());
+               return new CmsContentSession(this, getCmsState().getUuid(), loginContext.getSubject(),
+                               Locale.getDefault());
+       }
+
+       protected CmsState getCmsState() {
+               return cmsState;
+       }
+
+       public void setCmsState(CmsState cmsState) {
+               this.cmsState = cmsState;
+       }
+
+       public void setUuidFactory(UuidFactory uuidFactory) {
+               this.uuidFactory = uuidFactory;
        }
 
 }
index 5e5fb272c24aed96d9ca8d3126f56a3a0964ef15..0255856344e34109d05c301465be74d1415c32d7 100644 (file)
@@ -5,6 +5,7 @@ import java.util.Locale;
 import java.util.Map;
 import java.util.Set;
 import java.util.TreeSet;
+import java.util.UUID;
 import java.util.concurrent.CompletableFuture;
 import java.util.concurrent.CompletionStage;
 import java.util.function.Consumer;
@@ -14,6 +15,7 @@ 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.NamespaceUtils;
 import org.argeo.api.acr.spi.ContentProvider;
 import org.argeo.api.acr.spi.ProvidedContent;
@@ -25,6 +27,7 @@ import org.argeo.cms.acr.xml.DomContentProvider;
 class CmsContentSession implements ProvidedSession {
        final private AbstractContentRepository contentRepository;
 
+       private final UUID uuid;
        private Subject subject;
        private Locale locale;
 
@@ -34,14 +37,21 @@ class CmsContentSession implements ProvidedSession {
 
        private Set<ContentProvider> modifiedProviders = new TreeSet<>();
 
-       public CmsContentSession(AbstractContentRepository contentRepository, Subject subject, Locale locale) {
+       private Content sessionRunDir;
+
+       public CmsContentSession(AbstractContentRepository contentRepository, UUID uuid, Subject subject, Locale locale) {
                this.contentRepository = contentRepository;
                this.subject = subject;
                this.locale = locale;
+               this.uuid = uuid;
+
        }
 
        public void close() {
                closed.complete(this);
+
+               if (sessionRunDir != null)
+                       sessionRunDir.remove();
        }
 
        @Override
@@ -53,11 +63,24 @@ class CmsContentSession implements ProvidedSession {
        public Content get(String path) {
                ContentProvider contentProvider = contentRepository.getMountManager().findContentProvider(path);
                String mountPath = contentProvider.getMountPath();
+               String relativePath = extractRelativePath(mountPath, path);
+               ProvidedContent content = contentProvider.get(CmsContentSession.this, relativePath);
+               return content;
+       }
+
+       @Override
+       public boolean exists(String path) {
+               ContentProvider contentProvider = contentRepository.getMountManager().findContentProvider(path);
+               String mountPath = contentProvider.getMountPath();
+               String relativePath = extractRelativePath(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);
-               ProvidedContent content = contentProvider.get(CmsContentSession.this, mountPath, relativePath);
-               return content;
+               return relativePath;
        }
 
        @Override
@@ -130,6 +153,26 @@ class CmsContentSession implements ProvidedSession {
                modifiedProviders.add(contentProvider);
        }
 
+       @Override
+       public UUID getUuid() {
+               return uuid;
+       }
+
+       @Override
+       public Content getSessionRunDir() {
+               if (sessionRunDir == null) {
+                       String runDirPath = CmsContentRepository.RUN_BASE + '/' + uuid.toString();
+                       if (exists(runDirPath))
+                               sessionRunDir = get(runDirPath);
+                       else {
+                               Content runDir = get(CmsContentRepository.RUN_BASE);
+                               // TODO deal with no run dir available?
+                               sessionRunDir = runDir.add(uuid.toString(), CrName.COLLECTION.get());
+                       }
+               }
+               return sessionRunDir;
+       }
+
 //             @Override
 //             public String findNamespace(String prefix) {
 //                     return prefixes.get(prefix);
index 2dcaeafaada5349810b0b659de825ffd3b390871..5609cf7778ca65555824c500e48d3769be944f69 100644 (file)
@@ -6,6 +6,7 @@ import java.util.function.BiConsumer;
 import javax.xml.namespace.QName;
 
 import org.argeo.api.acr.Content;
+import org.argeo.api.cms.CmsSession;
 
 /** Utilities and routines around {@link Content}. */
 public class ContentUtils {
index 09efa72740c2118f0d6251301badcf316e577407..cac407495a70be147447e9c27986ccecf448cbe4 100644 (file)
@@ -4,6 +4,7 @@ import java.nio.file.Path;
 import java.nio.file.Paths;
 import java.util.Locale;
 import java.util.Objects;
+import java.util.UUID;
 
 import javax.security.auth.Subject;
 import javax.security.auth.x500.X500Principal;
@@ -21,6 +22,8 @@ public class SingleUserContentRepository extends AbstractContentRepository {
        private final Subject subject;
        private final Locale locale;
 
+       private UUID uuid;
+
        // the single session
        private CmsContentSession contentSession;
 
@@ -34,6 +37,9 @@ public class SingleUserContentRepository extends AbstractContentRepository {
 
                this.subject = subject;
                this.locale = locale;
+
+               // TODO use an UUID factory
+               this.uuid = UUID.randomUUID();
        }
 
        @Override
@@ -45,7 +51,7 @@ public class SingleUserContentRepository extends AbstractContentRepository {
                initRootContentProvider(null);
                if (contentSession != null)
                        throw new IllegalStateException("Repository is already started, stop it first.");
-               contentSession = new CmsContentSession(this, subject, locale);
+               contentSession = new CmsContentSession(this, uuid, subject, locale);
        }
 
        @Override
@@ -70,7 +76,7 @@ public class SingleUserContentRepository extends AbstractContentRepository {
 
        @Override
        protected CmsContentSession newSystemSession() {
-               return new CmsContentSession(this, subject, Locale.getDefault());
+               return new CmsContentSession(this, uuid, subject, Locale.getDefault());
        }
 
        public static void main(String... args) {
index e71acdabd2bb973770fccfd5cd0bb5d54e5ce64b..5c9c1096e69722cf65ac634a8cde86d8cacb110d 100644 (file)
@@ -213,7 +213,7 @@ public class FsContent extends AbstractContent implements ProvidedContent {
                                                QName[] classes = null;
                                                ContentProvider contentProvider = session.getRepository().getMountContentProvider(fsContent,
                                                                false, classes);
-                                               Content mountedContent = contentProvider.get(session, fsContent.getPath(), "");
+                                               Content mountedContent = contentProvider.get(session, "");
                                                return mountedContent;
                                        } else {
                                                return (Content) fsContent;
@@ -247,7 +247,7 @@ public class FsContent extends AbstractContent implements ProvidedContent {
 
                if (session.getRepository().shouldMount(classes)) {
                        ContentProvider contentProvider = session.getRepository().getMountContentProvider(fsContent, true, classes);
-                       Content mountedContent = contentProvider.get(session, fsContent.getPath(), "");
+                       Content mountedContent = contentProvider.get(session, "");
                        fsContent.put(CrName.MOUNT.get(), "true");
                        return mountedContent;
 
index 62b20af3df7570df6380a06671dedcc14e26a717..9d696b07f1cbcf6609f50c29017576250af228f0 100644 (file)
@@ -33,7 +33,7 @@ public class FsContentProvider implements ContentProvider {
        public FsContentProvider(String mountPath, Path rootPath) {
                Objects.requireNonNull(mountPath);
                Objects.requireNonNull(rootPath);
-               
+
                this.mountPath = mountPath;
                this.rootPath = rootPath;
                // FIXME make it more robust
@@ -112,7 +112,7 @@ public class FsContentProvider implements ContentProvider {
        }
 
        @Override
-       public ProvidedContent get(ProvidedSession session, String mountPath, String relativePath) {
+       public ProvidedContent get(ProvidedSession session, String relativePath) {
                return new FsContent(session, this, rootPath.resolve(relativePath));
        }
 
@@ -120,6 +120,11 @@ public class FsContentProvider implements ContentProvider {
         * NAMESPACE CONTEXT
         */
 
+       @Override
+       public boolean exists(ProvidedSession session, String relativePath) {
+               return Files.exists(rootPath.resolve(relativePath));
+       }
+
        @Override
        public String getNamespaceURI(String prefix) {
                return NamespaceUtils.getNamespaceURI((p) -> prefixes.get(p), prefix);
index 423b60eadd15f982cba3fb1cd4d115ea3f8c2646..54013e2ad1301deb66235671fcce278e6be64b58 100644 (file)
@@ -61,27 +61,40 @@ public class DomContentProvider implements ContentProvider, NamespaceContext {
 //     }
 
        @Override
-       public ProvidedContent get(ProvidedSession session, String mountPath, String relativePath) {
+       public ProvidedContent get(ProvidedSession session, String relativePath) {
                if ("".equals(relativePath))
                        return new DomContent(session, this, document.getDocumentElement());
+
+               NodeList nodes = findContent(relativePath);
+               if (nodes.getLength() > 1)
+                       throw new IllegalArgumentException("Multiple content found for " + relativePath + " under " + mountPath);
+               if (nodes.getLength() == 0)
+                       throw new ContentNotFoundException("Path " + relativePath + " under " + mountPath + " was not found");
+               Element element = (Element) nodes.item(0);
+               return new DomContent(session, this, element);
+       }
+
+       protected NodeList findContent(String relativePath) {
                if (relativePath.startsWith("/"))
                        throw new IllegalArgumentException("Relative path cannot start with /");
-
                String xPathExpression = '/' + relativePath;
                if ("/".equals(mountPath))
                        xPathExpression = "/cr:root" + xPathExpression;
                try {
                        NodeList nodes = (NodeList) xPath.get().evaluate(xPathExpression, document, XPathConstants.NODESET);
-                       if (nodes.getLength() > 1)
-                               throw new IllegalArgumentException(
-                                               "Multiple content found for " + relativePath + " under " + mountPath);
-                       if (nodes.getLength() == 0)
-                               throw new ContentNotFoundException("Path " + relativePath + " under " + mountPath + " was not found");
-                       Element element = (Element) nodes.item(0);
-                       return new DomContent(session, this, element);
+                       return nodes;
                } catch (XPathExpressionException e) {
                        throw new IllegalArgumentException("XPath expression " + xPathExpression + " cannot be evaluated", e);
                }
+
+       }
+
+       @Override
+       public boolean exists(ProvidedSession session, String relativePath) {
+               if ("".equals(relativePath))
+                       return true;
+               NodeList nodes = findContent(relativePath);
+               return nodes.getLength() != 0;
        }
 
        public void persist(ProvidedSession session) {
index 928afc0d54960b102ac05b1b35388e00e0a1d6ad..1efb93afdd36b9ad1432f4976d4351c48dfa2277 100644 (file)
@@ -141,7 +141,8 @@ class CmsAuthUtils {
                                        if (currentLocalSessionAnonymous) {
                                                currentLocalSession.close();
                                                // new CMS session
-                                               cmsSession = new WebCmsSessionImpl(subject, authorization, locale, request);
+                                               UUID cmsSessionUuid = CmsContextImpl.getCmsContext().getUuidFactory().timeUUID();
+                                               cmsSession = new WebCmsSessionImpl(cmsSessionUuid, subject, authorization, locale, request);
                                                CmsContextImpl.getCmsContext().registerCmsSession(cmsSession);
                                        } else if (!authorization.getName().equals(currentLocalSession.getAuthorization().getName())) {
                                                throw new IllegalStateException("Inconsistent user " + authorization.getName()
@@ -163,7 +164,8 @@ class CmsAuthUtils {
                                }
                        } else {
                                // new CMS session
-                               cmsSession = new WebCmsSessionImpl(subject, authorization, locale, request);
+                               UUID cmsSessionUuid = CmsContextImpl.getCmsContext().getUuidFactory().timeUUID();
+                               cmsSession = new WebCmsSessionImpl(cmsSessionUuid, subject, authorization, locale, request);
                                CmsContextImpl.getCmsContext().registerCmsSession(cmsSession);
                        }
 
@@ -182,7 +184,8 @@ class CmsAuthUtils {
                } else {
                        CmsSessionImpl cmsSession = CmsContextImpl.getCmsContext().getCmsSessionByLocalId(SINGLE_USER_LOCAL_ID);
                        if (cmsSession == null) {
-                               cmsSession = new CmsSessionImpl(subject, authorization, locale, SINGLE_USER_LOCAL_ID);
+                               UUID cmsSessionUuid = CmsContextImpl.getCmsContext().getUuidFactory().timeUUID();
+                               cmsSession = new CmsSessionImpl(cmsSessionUuid, subject, authorization, locale, SINGLE_USER_LOCAL_ID);
                                CmsContextImpl.getCmsContext().registerCmsSession(cmsSession);
                        }
                        CmsSessionId nodeSessionId = new CmsSessionId(cmsSession.getUuid());
index a3670c0cb4b8cbf4313a7a8eea3aa82a26b77b57..164d319f197ae92074b2c5965233deb6f7c1be5c 100644 (file)
@@ -6,13 +6,12 @@ import java.security.AccessController;
 import java.security.PrivilegedAction;
 import java.time.ZonedDateTime;
 import java.util.ArrayList;
-import java.util.Collection;
 import java.util.Collections;
 import java.util.HashMap;
-import java.util.Hashtable;
 import java.util.List;
 import java.util.Locale;
 import java.util.Map;
+import java.util.Objects;
 import java.util.Set;
 import java.util.UUID;
 import java.util.function.Consumer;
@@ -30,10 +29,6 @@ import org.argeo.api.cms.CmsLog;
 import org.argeo.api.cms.CmsSession;
 import org.argeo.cms.internal.runtime.CmsContextImpl;
 import org.argeo.cms.security.NodeSecurityUtils;
-import org.osgi.framework.BundleContext;
-import org.osgi.framework.FrameworkUtil;
-import org.osgi.framework.InvalidSyntaxException;
-import org.osgi.framework.ServiceReference;
 import org.osgi.framework.ServiceRegistration;
 import org.osgi.service.useradmin.Authorization;
 
@@ -61,7 +56,10 @@ public class CmsSessionImpl implements CmsSession, Serializable {
 
        private List<Consumer<CmsSession>> onCloseCallbacks = Collections.synchronizedList(new ArrayList<>());
 
-       public CmsSessionImpl(Subject initialSubject, Authorization authorization, Locale locale, String localSessionId) {
+       public CmsSessionImpl(UUID uuid, Subject initialSubject, Authorization authorization, Locale locale,
+                       String localSessionId) {
+               Objects.requireNonNull(uuid);
+
                this.creationTime = ZonedDateTime.now();
                this.locale = locale;
                this.accessControlContext = Subject.doAs(initialSubject, new PrivilegedAction<AccessControlContext>() {
@@ -86,14 +84,7 @@ public class CmsSessionImpl implements CmsSession, Serializable {
                        this.userDn = NodeSecurityUtils.ROLE_ANONYMOUS_NAME;
                        this.anonymous = true;
                }
-               // TODO use time-based UUID?
-               this.uuid = UUID.randomUUID();
-               // register as service
-//             Hashtable<String, String> props = new Hashtable<>();
-//             props.put(CmsSession.USER_DN, userDn.toString());
-//             props.put(CmsSession.SESSION_UUID, uuid.toString());
-//             props.put(CmsSession.SESSION_LOCAL_ID, localSessionId);
-//             serviceRegistration = bc.registerService(CmsSession.class, this, props);
+               this.uuid = uuid;
        }
 
        public void close() {
@@ -210,57 +201,4 @@ public class CmsSessionImpl implements CmsSession, Serializable {
        public String toString() {
                return "CMS Session " + userDn + " localId=" + localSessionId + ", uuid=" + uuid;
        }
-
-//     public static CmsSessionImpl getByLocalId(String localId) {
-//             Collection<ServiceReference<CmsSession>> sr;
-//             try {
-//                     sr = bc.getServiceReferences(CmsSession.class, "(" + CmsSession.SESSION_LOCAL_ID + "=" + localId + ")");
-//             } catch (InvalidSyntaxException e) {
-//                     throw new IllegalArgumentException("Cannot get CMS session for id " + localId, e);
-//             }
-//             ServiceReference<CmsSession> cmsSessionRef;
-//             if (sr.size() == 1) {
-//                     cmsSessionRef = sr.iterator().next();
-//                     return (CmsSessionImpl) bc.getService(cmsSessionRef);
-//             } else if (sr.size() == 0) {
-//                     return null;
-//             } else
-//                     throw new IllegalStateException(sr.size() + " CMS sessions registered for " + localId);
-//
-//     }
-//
-//     public static CmsSessionImpl getByUuid(Object uuid) {
-//             Collection<ServiceReference<CmsSession>> sr;
-//             try {
-//                     sr = bc.getServiceReferences(CmsSession.class, "(" + CmsSession.SESSION_UUID + "=" + uuid + ")");
-//             } catch (InvalidSyntaxException e) {
-//                     throw new IllegalArgumentException("Cannot get CMS session for uuid " + uuid, e);
-//             }
-//             ServiceReference<CmsSession> cmsSessionRef;
-//             if (sr.size() == 1) {
-//                     cmsSessionRef = sr.iterator().next();
-//                     return (CmsSessionImpl) bc.getService(cmsSessionRef);
-//             } else if (sr.size() == 0) {
-//                     return null;
-//             } else
-//                     throw new IllegalStateException(sr.size() + " CMS sessions registered for " + uuid);
-//
-//     }
-//
-//     public static void closeInvalidSessions() {
-//             Collection<ServiceReference<CmsSession>> srs;
-//             try {
-//                     srs = bc.getServiceReferences(CmsSession.class, null);
-//                     for (ServiceReference<CmsSession> sr : srs) {
-//                             CmsSession cmsSession = bc.getService(sr);
-//                             if (!cmsSession.isValid()) {
-//                                     ((CmsSessionImpl) cmsSession).close();
-//                                     if (log.isDebugEnabled())
-//                                             log.debug("Closed expired CMS session " + cmsSession);
-//                             }
-//                     }
-//             } catch (InvalidSyntaxException e) {
-//                     throw new IllegalArgumentException("Cannot get CMS sessions", e);
-//             }
-//     }
 }
index eb6c89d37b52a49aa01963a826c09a67dacfcea8..4b4a77641ce6a3c0d11adbb26da85e55fac7c740 100644 (file)
@@ -1,6 +1,7 @@
 package org.argeo.cms.internal.http;
 
 import java.util.Locale;
+import java.util.UUID;
 
 import javax.security.auth.Subject;
 
@@ -14,9 +15,9 @@ public class WebCmsSessionImpl extends CmsSessionImpl {
        private static final long serialVersionUID = -5178883380637048025L;
        private RemoteAuthSession httpSession;
 
-       public WebCmsSessionImpl(Subject initialSubject, Authorization authorization, Locale locale,
+       public WebCmsSessionImpl(UUID uuid, Subject initialSubject, Authorization authorization, Locale locale,
                        RemoteAuthRequest request) {
-               super(initialSubject, authorization, locale, request.getSession().getId());
+               super(uuid, initialSubject, authorization, locale, request.getSession().getId());
                httpSession = request.getSession();
        }
 
@@ -26,8 +27,4 @@ public class WebCmsSessionImpl extends CmsSessionImpl {
                        return false;
                return httpSession.isValid();
        }
-
-//     public static CmsSessionImpl getCmsSession(RemoteAuthRequest request) {
-//             return CmsSessionImpl.getByLocalId(request.getSession().getId());
-//     }
 }
index 93ed319f153d61df8af7650c504b7b9336b0a373..10bda17fb79fbde5a579efbe383f8dddf0e99bab 100644 (file)
@@ -13,6 +13,8 @@ import java.util.concurrent.ExecutionException;
 
 import javax.security.auth.Subject;
 
+import org.argeo.api.acr.spi.ProvidedContent;
+import org.argeo.api.acr.spi.ProvidedRepository;
 import org.argeo.api.cms.CmsConstants;
 import org.argeo.api.cms.CmsContext;
 import org.argeo.api.cms.CmsDeployment;
@@ -20,6 +22,7 @@ import org.argeo.api.cms.CmsLog;
 import org.argeo.api.cms.CmsSession;
 import org.argeo.api.cms.CmsSessionId;
 import org.argeo.api.cms.CmsState;
+import org.argeo.api.uuid.UuidFactory;
 import org.argeo.cms.LocaleUtils;
 import org.argeo.cms.internal.auth.CmsSessionImpl;
 import org.ietf.jgss.GSSCredential;
@@ -35,6 +38,8 @@ public class CmsContextImpl implements CmsContext {
        private CmsState cmsState;
        private CmsDeployment cmsDeployment;
        private UserAdmin userAdmin;
+       private UuidFactory uuidFactory;
+       private ProvidedRepository contentRepository;
 
        // i18n
        private Locale defaultLocale;
@@ -152,6 +157,22 @@ public class CmsContextImpl implements CmsContext {
                this.userAdmin = userAdmin;
        }
 
+       public UuidFactory getUuidFactory() {
+               return uuidFactory;
+       }
+
+       public void setUuidFactory(UuidFactory uuidFactory) {
+               this.uuidFactory = uuidFactory;
+       }
+
+       public ProvidedRepository getContentRepository() {
+               return contentRepository;
+       }
+
+       public void setContentRepository(ProvidedRepository contentRepository) {
+               this.contentRepository = contentRepository;
+       }
+
        @Override
        public Locale getDefaultLocale() {
                return defaultLocale;
@@ -171,6 +192,11 @@ public class CmsContextImpl implements CmsContext {
                return availableSince != null;
        }
 
+       @Override
+       public CmsState getCmsState() {
+               return cmsState;
+       }
+
        /*
         * STATIC
         */
index a0c4b0c0b8a445346e34921d3d3c3a29b7fdab81..41e32653432cc7b4e621109c0c9d67bfc92b9dc6 100644 (file)
@@ -3,13 +3,14 @@ package org.argeo.cms.internal.runtime;
 import java.net.InetAddress;
 import java.net.URL;
 import java.net.UnknownHostException;
+import java.util.UUID;
 
 import javax.security.auth.login.Configuration;
 
 import org.argeo.api.cms.CmsLog;
 import org.argeo.api.cms.CmsState;
+import org.argeo.api.uuid.UuidFactory;
 import org.argeo.cms.auth.ident.IdentClient;
-import org.osgi.framework.Constants;
 
 /**
  * Implementation of a {@link CmsState}, initialising the required services.
@@ -20,10 +21,12 @@ public class CmsStateImpl implements CmsState {
        // REFERENCES
        private Long availableSince;
 
-       private String stateUuid;
+       private UUID uuid;
 //     private final boolean cleanState;
        private String hostname;
 
+       private UuidFactory uuidFactory;
+
        public void start() {
 //             Runtime.getRuntime().addShutdownHook(new CmsShutdown());
 
@@ -34,7 +37,9 @@ public class CmsStateImpl implements CmsState {
                        if (log.isTraceEnabled())
                                log.trace("CMS State started");
 
-                       this.stateUuid = KernelUtils.getFrameworkProp(Constants.FRAMEWORK_UUID);
+//                     String stateUuidStr = KernelUtils.getFrameworkProp(Constants.FRAMEWORK_UUID);
+//                     this.uuid = UUID.fromString(stateUuidStr);
+                       this.uuid = uuidFactory.timeUUID();
 //             this.cleanState = stateUuid.equals(frameworkUuid);
                        try {
                                this.hostname = InetAddress.getLocalHost().getHostName();
@@ -46,7 +51,7 @@ public class CmsStateImpl implements CmsState {
                        if (log.isDebugEnabled())
                                // log.debug("## CMS starting... stateUuid=" + this.stateUuid + (cleanState ? "
                                // (clean state) " : " "));
-                               log.debug("## CMS starting... (" + stateUuid + ")");
+                               log.debug("## CMS starting... (" + uuid + ")");
 
 //             initI18n();
 //             initServices();
@@ -70,13 +75,12 @@ public class CmsStateImpl implements CmsState {
 
        public void stop() {
                if (log.isDebugEnabled())
-                       log.debug("CMS stopping...  (" + this.stateUuid + ")");
+                       log.debug("CMS stopping...  (" + this.uuid + ")");
 
                long duration = ((System.currentTimeMillis() - availableSince) / 1000) / 60;
                log.info("## ARGEO CMS STOPPED after " + (duration / 60) + "h " + (duration % 60) + "min uptime ##");
        }
 
-
        @Override
        public Long getAvailableSince() {
                return availableSince;
@@ -89,6 +93,15 @@ public class CmsStateImpl implements CmsState {
                return hostname;
        }
 
+       @Override
+       public UUID getUuid() {
+               return uuid;
+       }
+
+       public void setUuidFactory(UuidFactory uuidFactory) {
+               this.uuidFactory = uuidFactory;
+       }
+
        /*
         * STATIC
         */
index 7d3eb283bf2e2b54b698ecf6df33b63a64cf25cd..cff9bc5148a3464678dc98ae310f93d035332724 100644 (file)
@@ -1,27 +1,36 @@
 package org.argeo.cms.internal.runtime;
 
+import java.io.IOException;
+import java.nio.file.Files;
 import java.nio.file.Path;
 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.OS;
 
 public class DeployedContentRepository extends CmsContentRepository {
        private final static String ROOT_XML = "cr:root.xml";
-       private CmsState cmsState;
 
        @Override
        public void start() {
-               super.start();
-               Path rootXml = KernelUtils.getOsgiInstancePath(ROOT_XML);
-               initRootContentProvider(null);
+               try {
+                       super.start();
+                       Path rootXml = KernelUtils.getOsgiInstancePath(ROOT_XML);
+                       initRootContentProvider(null);
 
 //             Path srvPath = KernelUtils.getOsgiInstancePath(CmsConstants.SRV_WORKSPACE);
 //             FsContentProvider srvContentProvider = new FsContentProvider("/" + CmsConstants.SRV_WORKSPACE, srvPath, false);
 //             addProvider(srvContentProvider);
+
+                       Path runDirPath =  KernelUtils.getOsgiInstancePath(CmsContentRepository.RUN_BASE);
+                       Files.createDirectories(runDirPath);
+                       FsContentProvider runContentProvider = new FsContentProvider(CmsContentRepository.RUN_BASE, runDirPath);
+                       addProvider(runContentProvider);
+               } catch (IOException e) {
+                       throw new IllegalStateException("Cannot start content repository", e);
+               }
        }
 
        @Override
@@ -37,8 +46,4 @@ public class DeployedContentRepository extends CmsContentRepository {
        public void removeContentProvider(ContentProvider provider, Map<String, Object> properties) {
        }
 
-       public void setCmsState(CmsState cmsState) {
-               this.cmsState = cmsState;
-       }
-
 }
index 27b23233f3f982a3052bebfac8fa61e9fb5bdb14..e4087e13903ee00f707ea5ec159f9f5335c86b37 100644 (file)
@@ -35,12 +35,19 @@ public class StaticCms {
        private CompletableFuture<Void> stopped = new CompletableFuture<Void>();
 
        public void start() {
+               // UID factory
+               CmsUuidFactory uuidFactory = new CmsUuidFactory();
+               Component<CmsUuidFactory> uuidFactoryC = new Component.Builder<>(uuidFactory) //
+                               .addType(UuidFactory.class) //
+                               .build(register);
+
                // CMS State
                CmsStateImpl cmsState = new CmsStateImpl();
                Component<CmsStateImpl> cmsStateC = new Component.Builder<>(cmsState) //
                                .addType(CmsState.class) //
                                .addActivation(cmsState::start) //
                                .addDeactivation(cmsState::stop) //
+                               .addDependency(uuidFactoryC.getType(UuidFactory.class), cmsState::setUuidFactory, null) //
                                .build(register);
 
                // Deployment Configuration
@@ -81,6 +88,17 @@ public class StaticCms {
                                }, null) //
                                .build(register);
 
+               // Content Repository
+               DeployedContentRepository contentRepository = new DeployedContentRepository();
+               Component<DeployedContentRepository> contentRepositoryC = new Component.Builder<>(contentRepository) //
+                               .addType(ProvidedRepository.class) //
+                               .addType(ContentRepository.class) //
+                               .addActivation(contentRepository::start) //
+                               .addDeactivation(contentRepository::stop) //
+                               .addDependency(cmsStateC.getType(CmsState.class), contentRepository::setCmsState, null) //
+                               .addDependency(uuidFactoryC.getType(UuidFactory.class), contentRepository::setUuidFactory, null) //
+                               .build(register);
+
                // CMS Context
                CmsContextImpl cmsContext = new CmsContextImpl();
                Component<CmsContextImpl> cmsContextC = new Component.Builder<>(cmsContext) //
@@ -90,26 +108,12 @@ public class StaticCms {
                                .addDependency(cmsStateC.getType(CmsState.class), cmsContext::setCmsState, null) //
                                .addDependency(cmsDeploymentC.getType(CmsDeployment.class), cmsContext::setCmsDeployment, null) //
                                .addDependency(userAdminC.getType(UserAdmin.class), cmsContext::setUserAdmin, null) //
+                               .addDependency(uuidFactoryC.getType(UuidFactory.class), cmsContext::setUuidFactory, null) //
+                               .addDependency(contentRepositoryC.getType(ProvidedRepository.class), cmsContext::setContentRepository,
+                                               null) //
                                .build(register);
                assert cmsContextC.get() == cmsContext;
 
-               // UID factory
-               CmsUuidFactory uuidFactory = new CmsUuidFactory();
-               Component<CmsUuidFactory> uuidFactoryC = new Component.Builder<>(uuidFactory) //
-                               .addType(UuidFactory.class) //
-                               .build(register);
-
-               // Content Repository
-               DeployedContentRepository contentRepository = new DeployedContentRepository();
-               Component<DeployedContentRepository> contentRepositoryC = new Component.Builder<>(contentRepository) //
-                               .addType(ProvidedRepository.class) //
-                               .addType(ContentRepository.class) //
-                               .addActivation(contentRepository::start) //
-                               .addDeactivation(contentRepository::stop) //
-                               .addDependency(cmsStateC.getType(CmsState.class), contentRepository::setCmsState, null) //
-                               .addDependency(uuidFactoryC.getType(UuidFactory.class), contentRepository::setUuidFactory, null) //
-                               .build(register);
-
                register.activate();
        }