Introduce Terms manager service.
authorMathieu Baudier <mbaudier@argeo.org>
Sat, 16 Jan 2021 08:53:52 +0000 (09:53 +0100)
committerMathieu Baudier <mbaudier@argeo.org>
Sat, 16 Jan 2021 08:53:52 +0000 (09:53 +0100)
org.argeo.entity.api/src/org/argeo/entity/TermsManager.java [new file with mode: 0644]
org.argeo.suite.core/OSGI-INF/termsManager.xml [new file with mode: 0644]
org.argeo.suite.core/bnd.bnd
org.argeo.suite.core/src/org/argeo/suite/core/CustomMaintenanceService.java
org.argeo.suite.core/src/org/argeo/suite/core/SuiteTerm.java [new file with mode: 0644]
org.argeo.suite.core/src/org/argeo/suite/core/SuiteTermsManager.java [new file with mode: 0644]
org.argeo.suite.core/src/org/argeo/suite/core/SuiteTypology.java [new file with mode: 0644]

diff --git a/org.argeo.entity.api/src/org/argeo/entity/TermsManager.java b/org.argeo.entity.api/src/org/argeo/entity/TermsManager.java
new file mode 100644 (file)
index 0000000..a2b5951
--- /dev/null
@@ -0,0 +1,8 @@
+package org.argeo.entity;
+
+import java.util.List;
+
+/** Provides optimised access and utilities around terms typologies. */
+public interface TermsManager {
+       List<String> listAllTerms(String typology);
+}
diff --git a/org.argeo.suite.core/OSGI-INF/termsManager.xml b/org.argeo.suite.core/OSGI-INF/termsManager.xml
new file mode 100644 (file)
index 0000000..3e6d4c6
--- /dev/null
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<scr:component xmlns:scr="http://www.osgi.org/xmlns/scr/v1.1.0" activate="init" deactivate="destroy" name="Suite Terms Manager">
+   <implementation class="org.argeo.suite.core.SuiteTermsManager"/>
+   <reference bind="setRepository" cardinality="1..1" interface="javax.jcr.Repository" name="Repository" policy="static" target="(cn=entity)"/>
+   <service>
+      <provide interface="org.argeo.entity.TermsManager"/>
+   </service>
+</scr:component>
index fe905331c9fde8712054aa199ad0bce597db72a4..1b9efff2c6c14579fef4fb407ba8427e589387f9 100644 (file)
@@ -1,6 +1,7 @@
 Bundle-ActivationPolicy: lazy
 
 Service-Component:\
+OSGI-INF/termsManager.xml,\
 OSGI-INF/maintenanceService.xml
 
 Import-Package:\
index 88470323af2bb86a1fccd3d29117c64a471508a5..b6e997af2d1508380f02f047afd9526511c7959d 100644 (file)
@@ -42,6 +42,9 @@ public abstract class CustomMaintenanceService extends AbstractMaintenanceServic
 
        protected void loadTerms(Node termsBase, String name) throws IOException, RepositoryException {
                try {
+                       if (termsBase.hasNode(name))
+                               return;
+
                        String termsLoadPath = getTypologiesLoadBase() + '/' + name + ".xml";
                        URL termsUrl = getClass().getClassLoader().getResource(termsLoadPath);
                        if (termsUrl == null)
diff --git a/org.argeo.suite.core/src/org/argeo/suite/core/SuiteTerm.java b/org.argeo.suite.core/src/org/argeo/suite/core/SuiteTerm.java
new file mode 100644 (file)
index 0000000..0c03dc5
--- /dev/null
@@ -0,0 +1,55 @@
+package org.argeo.suite.core;
+
+import java.util.ArrayList;
+import java.util.List;
+
+/**
+ * A single term. Helper to optimise {@link SuiteTermsManager} implementation.
+ */
+class SuiteTerm {
+       private final String name;
+       private final String relativePath;
+       private final SuiteTypology typology;
+       private final String id;
+
+       private final SuiteTerm parentTerm;
+       private final List<SuiteTerm> subTerms = new ArrayList<>();
+
+       SuiteTerm(SuiteTypology typology, String relativePath, SuiteTerm parentTerm) {
+               this.typology = typology;
+               this.parentTerm = parentTerm;
+               this.relativePath = relativePath;
+               int index = relativePath.lastIndexOf('/');
+               if (index > 0) {
+                       this.name = relativePath.substring(index);
+               } else {
+                       this.name = relativePath;
+               }
+               id = typology.getName() + '/' + relativePath;
+       }
+
+       public String getName() {
+               return name;
+       }
+
+       public String getRelativePath() {
+               return relativePath;
+       }
+
+       SuiteTypology getTypology() {
+               return typology;
+       }
+
+       public String getId() {
+               return id;
+       }
+
+       List<SuiteTerm> getSubTerms() {
+               return subTerms;
+       }
+
+       SuiteTerm getParentTerm() {
+               return parentTerm;
+       }
+
+}
diff --git a/org.argeo.suite.core/src/org/argeo/suite/core/SuiteTermsManager.java b/org.argeo.suite.core/src/org/argeo/suite/core/SuiteTermsManager.java
new file mode 100644 (file)
index 0000000..3c5a59f
--- /dev/null
@@ -0,0 +1,94 @@
+package org.argeo.suite.core;
+
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.List;
+import java.util.Map;
+
+import javax.jcr.Node;
+import javax.jcr.Repository;
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+
+import org.argeo.api.NodeConstants;
+import org.argeo.api.NodeUtils;
+import org.argeo.entity.EntityNames;
+import org.argeo.entity.EntityType;
+import org.argeo.entity.TermsManager;
+import org.argeo.jcr.Jcr;
+import org.argeo.jcr.JcrException;
+
+/** Argeo Suite implementation of terms manager. */
+public class SuiteTermsManager implements TermsManager {
+       private final Map<String, SuiteTerm> terms = new HashMap<>();
+       private final Map<String, SuiteTypology> typologies = new HashMap<>();
+
+       // JCR
+       private Repository repository;
+       private Session adminSession;
+
+       public void init() {
+               adminSession = NodeUtils.openDataAdminSession(repository, NodeConstants.SYS_WORKSPACE);
+       }
+
+       @Override
+       public List<String> listAllTerms(String typology) {
+               List<String> res = new ArrayList<>();
+               SuiteTypology t = getTypology(typology);
+               for (SuiteTerm term : t.getAllTerms()) {
+                       res.add(term.getId());
+               }
+               return res;
+       }
+
+       SuiteTypology getTypology(String typology) {
+               SuiteTypology t = typologies.get(typology);
+               if (t == null) {
+                       Node termsNode = Jcr.getNode(adminSession, "SELECT * FROM [{0}] WHERE NAME()=\"{1}\"",
+                                       EntityType.terms.get(), typology);
+                       t = loadTypology(termsNode);
+               }
+               return t;
+       }
+
+       SuiteTypology loadTypology(Node termsNode) {
+               try {
+                       SuiteTypology typology = new SuiteTypology(termsNode);
+                       for (Node termNode : Jcr.iterate(termsNode.getNodes())) {
+                               if (termNode.isNodeType(EntityType.term.get())) {
+                                       SuiteTerm term = loadTerm(typology, termNode, null);
+                                       if (!term.getSubTerms().isEmpty())
+                                               typology.markNotFlat();
+                                       typology.getSubTerms().add(term);
+                               }
+                       }
+                       typologies.put(typology.getName(), typology);
+                       return typology;
+               } catch (RepositoryException e) {
+                       throw new JcrException("Cannot load typology from " + termsNode, e);
+               }
+       }
+
+       SuiteTerm loadTerm(SuiteTypology typology, Node termNode, SuiteTerm parentTerm) throws RepositoryException {
+               String name = termNode.getProperty(EntityNames.NAME).getString();
+               String relativePath = parentTerm == null ? name : parentTerm.getRelativePath() + '/' + name;
+               SuiteTerm term = new SuiteTerm(typology, relativePath, parentTerm);
+               terms.put(term.getId(), term);
+               for (Node subTermNode : Jcr.iterate(termNode.getNodes())) {
+                       if (termNode.isNodeType(EntityType.term.get())) {
+                               SuiteTerm subTerm = loadTerm(typology, subTermNode, term);
+                               term.getSubTerms().add(subTerm);
+                       }
+               }
+               return term;
+       }
+
+       public void destroy() {
+               Jcr.logout(adminSession);
+       }
+
+       public void setRepository(Repository repository) {
+               this.repository = repository;
+       }
+
+}
diff --git a/org.argeo.suite.core/src/org/argeo/suite/core/SuiteTypology.java b/org.argeo.suite.core/src/org/argeo/suite/core/SuiteTypology.java
new file mode 100644 (file)
index 0000000..e84066c
--- /dev/null
@@ -0,0 +1,64 @@
+package org.argeo.suite.core;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.jcr.Node;
+
+import org.argeo.jcr.Jcr;
+
+/** A typology. Helper to optimise {@link SuiteTermsManager} implementation. */
+class SuiteTypology {
+       private final String name;
+       private final Node node;
+       private boolean isFlat = true;
+
+       private final List<SuiteTerm> subTerms = new ArrayList<>();
+
+       public SuiteTypology(Node node) {
+               this.node = node;
+               this.name = Jcr.getName(this.node);
+       }
+
+       public String getName() {
+               return name;
+       }
+
+       public Node getNode() {
+               return node;
+       }
+
+       void markNotFlat() {
+               if (isFlat)
+                       isFlat = false;
+       }
+
+       public boolean isFlat() {
+               return isFlat;
+       }
+
+       public List<SuiteTerm> getSubTerms() {
+               return subTerms;
+       }
+
+       public List<SuiteTerm> getAllTerms() {
+               if (isFlat)
+                       return subTerms;
+               else {
+                       List<SuiteTerm> terms = new ArrayList<>();
+                       for (SuiteTerm subTerm : subTerms) {
+                               terms.add(subTerm);
+                               collectSubTerms(terms, subTerm);
+                       }
+                       return terms;
+               }
+       }
+
+       private void collectSubTerms(List<SuiteTerm> terms, SuiteTerm term) {
+               for (SuiteTerm subTerm : term.getSubTerms()) {
+                       terms.add(subTerm);
+                       collectSubTerms(terms, subTerm);
+               }
+       }
+
+}