Improve ACR / JCR integration.
authorMathieu Baudier <mbaudier@argeo.org>
Thu, 2 Jun 2022 08:34:18 +0000 (10:34 +0200)
committerMathieu Baudier <mbaudier@argeo.org>
Thu, 2 Jun 2022 08:34:18 +0000 (10:34 +0200)
12 files changed:
eclipse/org.argeo.cms.e4/bnd.bnd
eclipse/org.argeo.cms.swt/src/org/argeo/cms/swt/acr/SwtUiProvider.java
jcr/org.argeo.cms.jcr/OSGI-INF/jcrContentProvider.xml
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.jcr/src/org/argeo/cms/jcr/acr/JcrSessionAdapter.java
jcr/org.argeo.cms.ui/src/org/argeo/cms/ui/CmsUiProvider.java
org.argeo.api.cms/src/org/argeo/api/cms/MvcProvider.java
org.argeo.cms.ux/src/org/argeo/cms/ux/CmsUxUtils.java [new file with mode: 0644]
org.argeo.cms.ux/src/org/argeo/cms/ux/widgets/HierarchicalPart.java [new file with mode: 0644]
org.argeo.cms/src/org/argeo/cms/auth/CurrentUser.java
rap/org.argeo.cms.ui.rap/bnd.bnd

index ea9504384b570b6b14edaaba23717b9141798016..8026f9869b41463c7e3a161696410fc24d0d3327 100644 (file)
@@ -3,7 +3,9 @@ OSGI-INF/userAdminWrapper.xml,\
 OSGI-INF/defaultCallbackHandler.xml
 Bundle-ActivationPolicy: lazy
 
-Import-Package: org.eclipse.swt,\
+Import-Package: \
+org.argeo.api.acr,\
+org.eclipse.swt,\
 org.eclipse.swt.widgets;version="0.0.0",\
 org.eclipse.e4.ui.model.application.ui,\
 org.eclipse.e4.ui.model.application,\
index 46166b85987530b9acad9062c13cc00c58b89c32..4988fc6b897b6300fcc601c87918200fe71ddd46 100644 (file)
@@ -1,11 +1,10 @@
 package org.argeo.cms.swt.acr;
 
 import org.argeo.api.acr.Content;
-import org.argeo.api.cms.MvcProvider;
 import org.eclipse.swt.widgets.Composite;
 import org.eclipse.swt.widgets.Control;
 
 @FunctionalInterface
-public interface SwtUiProvider extends MvcProvider<Composite, Content, Control> {
-
+public interface SwtUiProvider {
+       Control createUiPart(Composite parent, Content context);
 }
index eb15b4c81462dd4c4999df721d2de85f2e13e013..47d724aeaab9f32e78b824cbe510ed83bb242d54 100644 (file)
@@ -5,5 +5,6 @@
    <property name="acr.mount.path" type="String" value="/sys"/>
    <service>
       <provide interface="org.argeo.api.acr.spi.ContentProvider"/>
+      <provide interface="org.argeo.cms.jcr.acr.JcrContentProvider"/>
    </service>
 </scr:component>
index 134f68162fcdfa5525d14bc0793c1dd9c4a2cc0c..dab41979498957a91a3906eb0402acfe4c85b57d 100644 (file)
@@ -31,6 +31,7 @@ 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;
+import org.argeo.api.cms.CmsConstants;
 import org.argeo.jcr.Jcr;
 import org.argeo.jcr.JcrException;
 import org.argeo.jcr.JcrUtils;
@@ -284,4 +285,22 @@ public class JcrContent extends AbstractContent {
 //             }
 //
 //     }
+       /*
+        * STATIC UTLITIES
+        */
+       public static Content nodeToContent(Node node) {
+               if (node == null)
+                       return null;
+               try {
+                       ProvidedSession contentSession = (ProvidedSession) node.getSession()
+                                       .getAttribute(ProvidedSession.class.getName());
+                       if (contentSession == null)
+                               throw new IllegalArgumentException(
+                                               "Cannot adapt " + node + " to content, because it was not loaded from a content session");
+                       return contentSession.get(CmsConstants.SYS_WORKSPACE + node.getPath());
+               } catch (RepositoryException e) {
+                       throw new JcrException("Cannot adapt " + node + " to a content", e);
+               }
+       }
+
 }
index f7bfd0949f422b5ce359111347c6e8723de1ca11..9e0a0089ab5c4ffb6ac4e4118526a20db459c97d 100644 (file)
@@ -54,7 +54,7 @@ public class JcrContentProvider implements ContentProvider, NamespaceContext {
        public Session getJcrSession(ProvidedSession contentSession, String jcrWorkspace) {
                JcrSessionAdapter sessionAdapter = sessionAdapters.get(contentSession);
                if (sessionAdapter == null) {
-                       final JcrSessionAdapter newSessionAdapter = new JcrSessionAdapter(jcrRepository,
+                       final JcrSessionAdapter newSessionAdapter = new JcrSessionAdapter(jcrRepository, contentSession,
                                        contentSession.getSubject());
                        sessionAdapters.put(contentSession, newSessionAdapter);
                        contentSession.onClose().thenAccept((s) -> newSessionAdapter.close());
index f02b8d213d6573c04f1538ac7505c6ea1377af43..ae8ae80f29867636005d0c8428da88f3c769986d 100644 (file)
@@ -10,6 +10,8 @@ import javax.jcr.RepositoryException;
 import javax.jcr.Session;
 import javax.security.auth.Subject;
 
+import org.apache.jackrabbit.core.SessionImpl;
+import org.argeo.api.acr.spi.ProvidedSession;
 import org.argeo.jcr.JcrException;
 import org.argeo.jcr.JcrUtils;
 
@@ -18,14 +20,17 @@ class JcrSessionAdapter {
        private Repository repository;
        private Subject subject;
 
+       private ProvidedSession contentSession;
+
        private Map<Thread, Map<String, Session>> threadSessions = Collections.synchronizedMap(new HashMap<>());
 
        private boolean closed = false;
 
        private Thread lastRetrievingThread = null;
 
-       public JcrSessionAdapter(Repository repository, Subject subject) {
+       public JcrSessionAdapter(Repository repository, ProvidedSession contentSession, Subject subject) {
                this.repository = repository;
+               this.contentSession = contentSession;
                this.subject = subject;
        }
 
@@ -58,7 +63,12 @@ class JcrSessionAdapter {
                if (session == null) {
                        session = Subject.doAs(subject, (PrivilegedAction<Session>) () -> {
                                try {
+//                                     String username = CurrentUser.getUsername(subject);
+//                                     SimpleCredentials credentials = new SimpleCredentials(username, new char[0]);
+//                                     credentials.setAttribute(ProvidedSession.class.getName(), contentSession);
                                        Session sess = repository.login(workspace);
+                                       // Jackrabbit specific:
+                                       ((SessionImpl)sess).setAttribute(ProvidedSession.class.getName(), contentSession);
                                        return sess;
                                } catch (RepositoryException e) {
                                        throw new IllegalStateException("Cannot log in to " + workspace, e);
index ec76321fee31e2cbcd56a4c3355f1017a07099b3..08b100efa00f0ccd9d211f1d36fa953f88edb7ad 100644 (file)
@@ -3,13 +3,16 @@ package org.argeo.cms.ui;
 import javax.jcr.Node;
 import javax.jcr.RepositoryException;
 
-import org.argeo.api.cms.MvcProvider;
+import org.argeo.api.acr.Content;
+import org.argeo.cms.jcr.acr.JcrContent;
+import org.argeo.cms.swt.acr.SwtUiProvider;
+import org.argeo.jcr.JcrException;
 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 MvcProvider<Composite, Node, Control> {
+public interface CmsUiProvider extends SwtUiProvider {
        /**
         * Initialises a user interface.
         * 
@@ -18,12 +21,21 @@ public interface CmsUiProvider extends MvcProvider<Composite, Node, Control> {
         */
        Control createUi(Composite parent, Node context) throws RepositoryException;
 
-       @Override
        default Control createUiPart(Composite parent, Node context) {
                try {
                        return createUi(parent, context);
                } catch (RepositoryException e) {
-                       throw new IllegalStateException("Cannot create UI for context " + context, e);
+                       throw new JcrException("Cannot create UI for context " + context, e);
+               }
+       }
+
+       @Override
+       default Control createUiPart(Composite parent, Content context) {
+               if (context instanceof JcrContent) {
+                       Node node = ((JcrContent) context).getJcrNode();
+                       return createUiPart(parent, node);
+               } else {
+                       throw new IllegalArgumentException("Content " + context + " is not compatible with JCR");
                }
        }
 
index c1aa6006c793f2ad024481142f0332c5334524f2..92864ea5c307195f41491ab5b12eb4ca4f5f0a47 100644 (file)
@@ -9,6 +9,7 @@ import java.util.function.BiFunction;
  * are relevant for all created UI part.
  */
 @FunctionalInterface
+@Deprecated
 public interface MvcProvider<V, M, W> extends BiFunction<V, M, W> {
        W createUiPart(V parent, M context);
        
diff --git a/org.argeo.cms.ux/src/org/argeo/cms/ux/CmsUxUtils.java b/org.argeo.cms.ux/src/org/argeo/cms/ux/CmsUxUtils.java
new file mode 100644 (file)
index 0000000..9e23ff6
--- /dev/null
@@ -0,0 +1,17 @@
+package org.argeo.cms.ux;
+
+import org.argeo.api.acr.ContentRepository;
+import org.argeo.api.acr.ContentSession;
+import org.argeo.api.cms.CmsView;
+import org.argeo.cms.auth.CurrentUser;
+
+public class CmsUxUtils {
+       public static ContentSession getContentSession(ContentRepository contentRepository, CmsView cmsView) {
+               return CurrentUser.callAs(cmsView.getCmsSession().getSubject(), () -> contentRepository.get());
+       }
+
+       /** singleton */
+       private CmsUxUtils() {
+
+       }
+}
diff --git a/org.argeo.cms.ux/src/org/argeo/cms/ux/widgets/HierarchicalPart.java b/org.argeo.cms.ux/src/org/argeo/cms/ux/widgets/HierarchicalPart.java
new file mode 100644 (file)
index 0000000..244765e
--- /dev/null
@@ -0,0 +1,5 @@
+package org.argeo.cms.ux.widgets;
+
+public interface HierarchicalPart {
+
+}
index cbe4286921c527651e928eebc552d610d745f90e..b43bf98b5f707744591b26006535ca784d8252b7 100644 (file)
@@ -9,6 +9,8 @@ import java.util.HashSet;
 import java.util.Locale;
 import java.util.Set;
 import java.util.UUID;
+import java.util.concurrent.Callable;
+import java.util.concurrent.CompletionException;
 
 import javax.security.auth.Subject;
 import javax.security.auth.x500.X500Principal;
@@ -162,6 +164,29 @@ public final class CurrentUser {
                return true;
        }
 
+       /*
+        * PREPARE EVOLUTION OF JAVA APIs INTRODUCED IN JDK 18
+        * The following static methods will be added to Subject 
+        */
+       public Subject current() {
+               return currentSubject();
+       }
+
+       public static <T> T callAs(Subject subject, Callable<T> action) {
+               try {
+                       return Subject.doAs(subject, new PrivilegedExceptionAction<T>() {
+
+                               @Override
+                               public T run() throws Exception {
+                                       return action.call();
+                               }
+
+                       });
+               } catch (PrivilegedActionException e) {
+                       throw new CompletionException("Failed to execute action for " + subject, e.getCause());
+               }
+       }
+
        private CurrentUser() {
        }
 }
index dc528df8cd3bf3d41622be2c33392ff0cffbf326..1d7c4b08b39c78d684b0e3626038fd3632c6add5 100644 (file)
@@ -1,4 +1,5 @@
 Import-Package:\
+org.argeo.api.acr,\
 org.eclipse.swt,\
 org.argeo.eclipse.ui,\
 javax.jcr.nodetype,\