Improve edition
[gpl/argeo-jcr.git] / org.argeo.cms.jcr / src / org / argeo / cms / jcr / acr / JcrSessionAdapter.java
index ae8ae80f29867636005d0c8428da88f3c769986d..e1ded7d1f8aab9141e05ef9e21cf409ad2a533a0 100644 (file)
@@ -4,14 +4,20 @@ import java.security.PrivilegedAction;
 import java.util.Collections;
 import java.util.HashMap;
 import java.util.Map;
+import java.util.Set;
+import java.util.TreeSet;
 
+import javax.jcr.Node;
 import javax.jcr.Repository;
 import javax.jcr.RepositoryException;
 import javax.jcr.Session;
+import javax.jcr.nodetype.NodeType;
+import javax.jcr.version.VersionManager;
 import javax.security.auth.Subject;
 
 import org.apache.jackrabbit.core.SessionImpl;
 import org.argeo.api.acr.spi.ProvidedSession;
+import org.argeo.jcr.Jcr;
 import org.argeo.jcr.JcrException;
 import org.argeo.jcr.JcrUtils;
 
@@ -28,6 +34,14 @@ class JcrSessionAdapter {
 
        private Thread lastRetrievingThread = null;
 
+//     private Thread writeThread;
+       private Map<String, Session> writeSessions = new HashMap<>();
+       /**
+        * Path of versionable nodes which have been modified during an edition cycle.
+        */
+       private Map<String, Set<String>> checkedInModified = new HashMap<>();
+       private Map<String, Set<String>> checkedOutModified = new HashMap<>();
+
        public JcrSessionAdapter(Repository repository, ProvidedSession contentSession, Subject subject) {
                this.repository = repository;
                this.contentSession = contentSession;
@@ -61,19 +75,7 @@ class JcrSessionAdapter {
 
                Session session = threadSession.get(workspace);
                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);
-                               }
-                       });
+                       session = login(workspace);
                        threadSession.put(workspace, session);
                }
 
@@ -88,4 +90,84 @@ class JcrSessionAdapter {
                return session;
        }
 
+       protected synchronized Session getWriteSession(String workspace) throws RepositoryException {
+               Session session = writeSessions.get(workspace);
+               if (session == null) {
+                       session = login(workspace);
+                       writeSessions.put(workspace, session);
+               } else {
+//                     if ((writeThread != Thread.currentThread()) && session.hasPendingChanges()) {
+//                             throw new IllegalStateException("Session " + contentSession + " is currently being written to");
+//                     }
+//                     writeThread = Thread.currentThread();
+               }
+               return session;
+       }
+
+       public synchronized Node openForEdit(String workspace, String jcrPath) throws RepositoryException {
+               Session session = getWriteSession(workspace);
+               Node node = session.getNode(jcrPath);
+               if (node.isNodeType(NodeType.MIX_SIMPLE_VERSIONABLE)) {
+                       VersionManager versionManager = session.getWorkspace().getVersionManager();
+                       if (versionManager.isCheckedOut(jcrPath)) {
+                               if (!checkedOutModified.containsKey(workspace))
+                                       checkedOutModified.put(workspace, new TreeSet<>());
+                               checkedOutModified.get(workspace).add(jcrPath);
+                       } else {
+                               if (!checkedInModified.containsKey(workspace))
+                                       checkedInModified.put(workspace, new TreeSet<>());
+                               checkedInModified.get(workspace).add(jcrPath);
+                               versionManager.checkout(jcrPath);
+                       }
+               }
+               return node;
+       }
+
+       public synchronized void persist() throws RepositoryException {
+               for (String workspace : writeSessions.keySet()) {
+                       Session session = writeSessions.get(workspace);
+                       if (session == null) {
+//                             assert writeThread == null;
+                               assert !checkedOutModified.containsKey(workspace);
+                               assert !checkedInModified.containsKey(workspace);
+                               return; // nothing to do
+                       }
+                       session.save();
+                       VersionManager versionManager = session.getWorkspace().getVersionManager();
+                       if (checkedOutModified.containsKey(workspace))
+                               for (String jcrPath : checkedOutModified.get(workspace)) {
+                                       versionManager.checkpoint(jcrPath);
+                               }
+                       if (checkedInModified.containsKey(workspace))
+                               for (String jcrPath : checkedInModified.get(workspace)) {
+                                       versionManager.checkin(jcrPath);
+                               }
+                       Jcr.logout(session);
+               }
+
+               for (Map<String, Session> m : threadSessions.values())
+                       for (Session session : m.values())
+                               session.refresh(true);
+//                     writeThread = null;
+               writeSessions.clear();
+               checkedOutModified.clear();
+               checkedInModified.clear();
+       }
+
+       protected Session login(String workspace) {
+               return 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);
+                       }
+               });
+       }
+
 }