Improve ACR
[lgpl/argeo-commons.git] / org.argeo.cms / src / org / argeo / cms / acr / ContentUtils.java
index d0ce5d1535bcf954242533f0a4d2febafdf16b55..e1fbcb1a9f440157b818a5c12dc8cf264be75c11 100644 (file)
@@ -1,22 +1,43 @@
 package org.argeo.cms.acr;
 
 import java.io.PrintStream;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.StringJoiner;
 import java.util.function.BiConsumer;
 
+import javax.security.auth.login.LoginContext;
+import javax.security.auth.login.LoginException;
 import javax.xml.namespace.QName;
 
 import org.argeo.api.acr.Content;
+import org.argeo.api.acr.ContentRepository;
+import org.argeo.api.acr.ContentSession;
+import org.argeo.api.acr.CrName;
+import org.argeo.api.cms.CmsAuth;
+import org.argeo.cms.CmsUserManager;
+import org.argeo.osgi.useradmin.UserDirectory;
+import org.argeo.util.CurrentSubject;
+import org.osgi.service.useradmin.Role;
 
+/** Utilities and routines around {@link Content}. */
 public class ContentUtils {
        public static void traverse(Content content, BiConsumer<Content, Integer> doIt) {
-               traverse(content, doIt, 0);
+               traverse(content, doIt, (Integer) null);
        }
 
-       public static void traverse(Content content, BiConsumer<Content, Integer> doIt, int currentDepth) {
+       public static void traverse(Content content, BiConsumer<Content, Integer> doIt, Integer maxDepth) {
+               doTraverse(content, doIt, 0, maxDepth);
+       }
+
+       private static void doTraverse(Content content, BiConsumer<Content, Integer> doIt, int currentDepth,
+                       Integer maxDepth) {
                doIt.accept(content, currentDepth);
+               if (maxDepth != null && currentDepth == maxDepth)
+                       return;
                int nextDepth = currentDepth + 1;
                for (Content child : content) {
-                       traverse(child, doIt, nextDepth);
+                       doTraverse(child, doIt, nextDepth, maxDepth);
                }
        }
 
@@ -37,24 +58,115 @@ public class ContentUtils {
                }
        }
 
-       
-
 //     public static <T> boolean isString(T t) {
 //             return t instanceof String;
 //     }
 
+       public static final char SLASH = '/';
+       public static final String ROOT_SLASH = "" + SLASH;
+       public static final String EMPTY = "";
+
        /**
         * Split a path (with '/' separator) in an array of length 2, the first part
         * being the parent path (which could be either absolute or relative), the
-        * second one being the last segment, (guaranteed to be with '/').
+        * second one being the last segment, (guaranteed to be without a '/').
         */
        public static String[] getParentPath(String path) {
-               int parentIndex = path.lastIndexOf('/');
-               // TODO make it more robust
-               return new String[] { parentIndex != 0 ? path.substring(0, parentIndex) : "/",
+               if (path == null)
+                       throw new IllegalArgumentException("Path cannot be null");
+               if (path.length() == 0)
+                       throw new IllegalArgumentException("Path cannot be empty");
+               checkDoubleSlash(path);
+               int parentIndex = path.lastIndexOf(SLASH);
+               if (parentIndex == path.length() - 1) {// trailing '/'
+                       path = path.substring(0, path.length() - 1);
+                       parentIndex = path.lastIndexOf(SLASH);
+               }
+
+               if (parentIndex == -1) // no '/'
+                       return new String[] { EMPTY, path };
+
+               return new String[] { parentIndex != 0 ? path.substring(0, parentIndex) : "" + SLASH,
                                path.substring(parentIndex + 1) };
        }
 
+       public static String toPath(List<String> segments) {
+               // TODO checks
+               StringJoiner sj = new StringJoiner("/");
+               segments.forEach((s) -> sj.add(s));
+               return sj.toString();
+       }
+
+       public static List<String> toPathSegments(String path) {
+               List<String> res = new ArrayList<>();
+               if (EMPTY.equals(path) || ROOT_SLASH.equals(path))
+                       return res;
+               collectPathSegments(path, res);
+               return res;
+       }
+
+       private static void collectPathSegments(String path, List<String> segments) {
+               String[] parent = getParentPath(path);
+               if (EMPTY.equals(parent[1])) // root
+                       return;
+               segments.add(0, parent[1]);
+               if (EMPTY.equals(parent[0])) // end
+                       return;
+               collectPathSegments(parent[0], segments);
+       }
+
+       public static void checkDoubleSlash(String path) {
+               if (path.contains(SLASH + "" + SLASH))
+                       throw new IllegalArgumentException("Path " + path + " contains //");
+       }
+
+       public static Content roleToContent(CmsUserManager userManager, ContentSession contentSession, Role role) {
+               UserDirectory userDirectory = userManager.getDirectory(role);
+               String path = CmsContentRepository.DIRECTORY_BASE + SLASH + userDirectory.getName() + SLASH
+                               + userDirectory.getRolePath(role);
+               Content content = contentSession.get(path);
+               return content;
+       }
+
+       /*
+        * CONSUMER UTILS
+        */
+
+       public static Content createCollections(ContentSession session, String path) {
+               if (session.exists(path)) {
+                       Content content = session.get(path);
+                       if (!content.isContentClass(CrName.collection.qName())) {
+                               throw new IllegalStateException("Content " + path + " already exists, but is not a collection");
+                       } else {
+                               return content;
+                       }
+               } else {
+                       String[] parentPath = getParentPath(path);
+                       Content parent = createCollections(session, parentPath[0]);
+                       Content content = parent.add(parentPath[1], CrName.collection.qName());
+                       return content;
+               }
+       }
+
+       public static ContentSession openDataAdminSession(ContentRepository repository) {
+               LoginContext loginContext;
+               try {
+                       loginContext = CmsAuth.DATA_ADMIN.newLoginContext();
+                       loginContext.login();
+               } catch (LoginException e1) {
+                       throw new RuntimeException("Could not login as data admin", e1);
+               } finally {
+               }
+
+               ClassLoader currentCl = Thread.currentThread().getContextClassLoader();
+               try {
+                       Thread.currentThread().setContextClassLoader(ContentUtils.class.getClassLoader());
+                       return CurrentSubject.callAs(loginContext.getSubject(), () -> repository.get());
+               } finally {
+                       Thread.currentThread().setContextClassLoader(currentCl);
+               }
+       }
+
        /** Singleton. */
        private ContentUtils() {