Improve JCR ACR search
authorMathieu Baudier <mbaudier@argeo.org>
Fri, 28 Apr 2023 03:38:06 +0000 (05:38 +0200)
committerMathieu Baudier <mbaudier@argeo.org>
Fri, 28 Apr 2023 03:38:06 +0000 (05:38 +0200)
org.argeo.cms.jcr/src/org/argeo/cms/jcr/acr/BasicSearchToQom.java [new file with mode: 0644]
org.argeo.cms.jcr/src/org/argeo/cms/jcr/acr/JcrContentProvider.java
org.argeo.cms.jcr/src/org/argeo/cms/jcr/acr/search/JcrBasicSearch.java [deleted file]

diff --git a/org.argeo.cms.jcr/src/org/argeo/cms/jcr/acr/BasicSearchToQom.java b/org.argeo.cms.jcr/src/org/argeo/cms/jcr/acr/BasicSearchToQom.java
new file mode 100644 (file)
index 0000000..99b8392
--- /dev/null
@@ -0,0 +1,112 @@
+package org.argeo.cms.jcr.acr;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import javax.jcr.RepositoryException;
+import javax.jcr.Session;
+import javax.jcr.query.QueryManager;
+import javax.jcr.query.qom.DynamicOperand;
+import javax.jcr.query.qom.QueryObjectModel;
+import javax.jcr.query.qom.QueryObjectModelConstants;
+import javax.jcr.query.qom.QueryObjectModelFactory;
+import javax.jcr.query.qom.Selector;
+import javax.jcr.query.qom.StaticOperand;
+import javax.xml.namespace.QName;
+
+import org.apache.jackrabbit.commons.query.sql2.QOMFormatter;
+import org.argeo.api.acr.NamespaceUtils;
+import org.argeo.api.acr.search.BasicSearch;
+import org.argeo.api.acr.search.Constraint;
+import org.argeo.api.acr.search.ContentFilter;
+import org.argeo.api.acr.search.ContentFilter.Eq;
+import org.argeo.api.acr.search.ContentFilter.IsContentClass;
+import org.argeo.api.acr.search.ContentFilter.Not;
+import org.argeo.api.cms.CmsLog;
+
+/** Convert an ACR basic search to a JCR query. */
+class BasicSearchToQom {
+       private final static CmsLog log = CmsLog.getLog(BasicSearchToQom.class);
+
+       private Session session;
+       private QueryManager queryManager;
+       private BasicSearch basicSearch;
+       QueryObjectModelFactory factory;
+
+       QName contentClass = null;
+
+       String selectorName = "content";
+
+       public BasicSearchToQom(Session session, BasicSearch basicSearch, String relPath) throws RepositoryException {
+               this.session = session;
+               this.queryManager = session.getWorkspace().getQueryManager();
+               this.basicSearch = basicSearch;
+               factory = queryManager.getQOMFactory();
+       }
+
+       public QueryObjectModel createQuery() throws RepositoryException {
+               ContentFilter<?> where = basicSearch.getWhere();
+               // scan for content classes
+               // TODO deal with complex cases of multiple types
+
+               javax.jcr.query.qom.Constraint qomConstraint = toQomConstraint(where);
+               if (contentClass == null)
+                       throw new IllegalArgumentException("No content class specified");
+
+               Selector source = factory.selector(NamespaceUtils.toPrefixedName(contentClass), selectorName);
+
+               QueryObjectModel qom = factory.createQuery(source, qomConstraint, null, null);
+               if (log.isDebugEnabled()) {
+                       String sql2 = QOMFormatter.format(qom);
+                       log.debug("JCR query:\n" + sql2 + "\n");
+               }
+               return qom;
+       }
+
+       private javax.jcr.query.qom.Constraint toQomConstraint(Constraint constraint) throws RepositoryException {
+               javax.jcr.query.qom.Constraint qomConstraint;
+               if (constraint instanceof ContentFilter<?> where) {
+                       List<Constraint> constraints = new ArrayList<>();
+                       for (Constraint c : where.getConstraints()) {
+                               if (c instanceof IsContentClass icc) {
+                                       if (icc.getContentClasses().length > 1 || contentClass != null)
+                                               throw new IllegalArgumentException("Multiple content class is not supported");
+                                       contentClass = icc.getContentClasses()[0];
+                               } else {
+                                       constraints.add(c);
+                               }
+                       }
+
+                       if (constraints.isEmpty()) {
+                               qomConstraint = null;
+                       } else if (constraints.size() == 1) {
+                               qomConstraint = toQomConstraint(constraints.get(0));
+                       } else {
+                               javax.jcr.query.qom.Constraint currQomConstraint = toQomConstraint(constraints.get(0));
+                               for (int i = 1; i < constraints.size(); i++) {
+                                       Constraint c = constraints.get(i);
+                                       if (where.isUnion()) {
+                                               currQomConstraint = factory.or(currQomConstraint, toQomConstraint(c));
+                                       } else {
+                                               currQomConstraint = factory.and(currQomConstraint, toQomConstraint(c));
+                                       }
+                               }
+                               qomConstraint = currQomConstraint;
+                       }
+
+               } else if (constraint instanceof Eq comp) {
+                       DynamicOperand dynamicOperand = factory.propertyValue(selectorName,
+                                       NamespaceUtils.toPrefixedName(comp.getProp()));
+                       // TODO better convert attribute value
+                       StaticOperand staticOperand = factory
+                                       .literal(session.getValueFactory().createValue(comp.getValue().toString()));
+                       qomConstraint = factory.comparison(dynamicOperand, QueryObjectModelConstants.JCR_OPERATOR_EQUAL_TO,
+                                       staticOperand);
+               } else if (constraint instanceof Not not) {
+                       qomConstraint = factory.not(toQomConstraint(not.getNegated()));
+               } else {
+                       throw new IllegalArgumentException("Constraint " + constraint.getClass() + " is not supported");
+               }
+               return qomConstraint;
+       }
+}
index 3622399813a25ace31d0310d7fdf6a1f873fdafa..bc4aa5be418b33c966e87e95eb2a955bd2670996 100644 (file)
@@ -27,7 +27,6 @@ import org.argeo.api.acr.spi.ProvidedSession;
 import org.argeo.api.cms.CmsConstants;
 import org.argeo.cms.acr.ContentUtils;
 import org.argeo.cms.jcr.CmsJcrUtils;
-import org.argeo.cms.jcr.acr.search.JcrBasicSearch;
 import org.argeo.jcr.JcrException;
 import org.argeo.jcr.JcrUtils;
 
@@ -149,7 +148,7 @@ public class JcrContentProvider implements ContentProvider, NamespaceContext {
        public Spliterator<Content> search(ProvidedSession session, BasicSearch search, String relPath) {
                try {
                        Session jcrSession = getJcrSession(session, jcrWorkspace);
-                       JcrBasicSearch jcrBasicSearch = new JcrBasicSearch(jcrSession, search, relPath);
+                       BasicSearchToQom jcrBasicSearch = new BasicSearchToQom(jcrSession, search, relPath);
                        Query query = jcrBasicSearch.createQuery();
                        QueryResult queryResult = query.execute();
                        return new QueryResultSpliterator(session, queryResult.getNodes());
diff --git a/org.argeo.cms.jcr/src/org/argeo/cms/jcr/acr/search/JcrBasicSearch.java b/org.argeo.cms.jcr/src/org/argeo/cms/jcr/acr/search/JcrBasicSearch.java
deleted file mode 100644 (file)
index 14bb584..0000000
+++ /dev/null
@@ -1,101 +0,0 @@
-package org.argeo.cms.jcr.acr.search;
-
-import java.util.ArrayList;
-import java.util.List;
-
-import javax.jcr.RepositoryException;
-import javax.jcr.Session;
-import javax.jcr.query.Query;
-import javax.jcr.query.QueryManager;
-import javax.jcr.query.qom.DynamicOperand;
-import javax.jcr.query.qom.QueryObjectModelConstants;
-import javax.jcr.query.qom.QueryObjectModelFactory;
-import javax.jcr.query.qom.Selector;
-import javax.jcr.query.qom.StaticOperand;
-import javax.xml.namespace.QName;
-
-import org.argeo.api.acr.NamespaceUtils;
-import org.argeo.api.acr.search.BasicSearch;
-import org.argeo.api.acr.search.Constraint;
-import org.argeo.api.acr.search.ContentFilter;
-import org.argeo.api.acr.search.ContentFilter.Eq;
-import org.argeo.api.acr.search.ContentFilter.IsContentClass;
-import org.argeo.api.acr.search.ContentFilter.Not;
-
-public class JcrBasicSearch {
-       private Session session;
-       private QueryManager queryManager;
-       private BasicSearch basicSearch;
-       QueryObjectModelFactory factory;
-
-       QName contentClass = null;
-
-       String selectorName = "content";
-
-       public JcrBasicSearch(Session session, BasicSearch basicSearch, String relPath) throws RepositoryException {
-               this.queryManager = session.getWorkspace().getQueryManager();
-               this.basicSearch = basicSearch;
-               factory = queryManager.getQOMFactory();
-       }
-
-       public Query createQuery() throws RepositoryException {
-               ContentFilter<?> where = basicSearch.getWhere();
-               // scan for content classes
-               // TODO deal with complex cases of multiple types
-
-               javax.jcr.query.qom.Constraint qomConstraint = toQomConstraint(where);
-               if (contentClass == null)
-                       throw new IllegalArgumentException("No content class specified");
-
-               Selector source = factory.selector(NamespaceUtils.toPrefixedName(contentClass), selectorName);
-
-               return factory.createQuery(source, qomConstraint, null, null);
-       }
-
-       private javax.jcr.query.qom.Constraint toQomConstraint(Constraint constraint) throws RepositoryException {
-               javax.jcr.query.qom.Constraint qomConstraint;
-               if (constraint instanceof ContentFilter<?> where) {
-                       List<Constraint> constraints = new ArrayList<>();
-                       for (Constraint c : where.getConstraints()) {
-                               if (c instanceof IsContentClass icc) {
-                                       if (icc.getContentClasses().length > 1 || contentClass != null)
-                                               throw new IllegalArgumentException("Multiple content class is not supported");
-                                       contentClass = icc.getContentClasses()[0];
-                               } else {
-                                       constraints.add(c);
-                               }
-                       }
-
-                       if (constraints.isEmpty()) {
-                               qomConstraint = null;
-                       } else if (constraints.size() == 1) {
-                               qomConstraint = toQomConstraint(constraints.get(0));
-                       } else {
-                               javax.jcr.query.qom.Constraint currQomConstraint = toQomConstraint(constraints.get(0));
-                               for (int i = 1; i < constraints.size(); i++) {
-                                       Constraint c = constraints.get(i);
-                                       if (where.isUnion()) {
-                                               currQomConstraint = factory.or(currQomConstraint, toQomConstraint(c));
-                                       } else {
-                                               currQomConstraint = factory.and(currQomConstraint, toQomConstraint(c));
-                                       }
-                               }
-                               qomConstraint = currQomConstraint;
-                       }
-
-               } else if (constraint instanceof Eq comp) {
-                       DynamicOperand dynamicOperand = factory.propertyValue(selectorName,
-                                       NamespaceUtils.toPrefixedName(comp.getProp()));
-                       // TODO better convert attribute value
-                       StaticOperand staticOperand = factory
-                                       .literal(session.getValueFactory().createValue(comp.getValue().toString()));
-                       qomConstraint = factory.comparison(dynamicOperand, QueryObjectModelConstants.JCR_OPERATOR_EQUAL_TO,
-                                       staticOperand);
-               } else if (constraint instanceof Not not) {
-                       qomConstraint = factory.not(toQomConstraint(not.getNegated()));
-               } else {
-                       throw new IllegalArgumentException("Constraint " + constraint.getClass() + " is not supported");
-               }
-               return qomConstraint;
-       }
-}