--- /dev/null
+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;
+ }
+
+}
--- /dev/null
+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;
+ }
+
+}
--- /dev/null
+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);
+ }
+ }
+
+}