]> git.argeo.org Git - gpl/argeo-jcr.git/blob - BasicSearchToQom.java
40005d692a7dec987e09aa0b22bab8181530d232
[gpl/argeo-jcr.git] / BasicSearchToQom.java
1 package org.argeo.cms.jcr.acr;
2
3 import static javax.jcr.query.qom.QueryObjectModelConstants.JCR_OPERATOR_EQUAL_TO;
4
5 import java.util.ArrayList;
6 import java.util.List;
7
8 import javax.jcr.Property;
9 import javax.jcr.RepositoryException;
10 import javax.jcr.Session;
11 import javax.jcr.query.QueryManager;
12 import javax.jcr.query.qom.DynamicOperand;
13 import javax.jcr.query.qom.QueryObjectModel;
14 import javax.jcr.query.qom.QueryObjectModelConstants;
15 import javax.jcr.query.qom.QueryObjectModelFactory;
16 import javax.jcr.query.qom.Selector;
17 import javax.jcr.query.qom.StaticOperand;
18 import javax.xml.namespace.QName;
19
20 import org.apache.jackrabbit.commons.query.sql2.QOMFormatter;
21 import org.argeo.api.acr.DName;
22 import org.argeo.api.acr.NamespaceUtils;
23 import org.argeo.api.acr.search.BasicSearch;
24 import org.argeo.api.acr.search.Constraint;
25 import org.argeo.api.acr.search.ContentFilter;
26 import org.argeo.api.acr.search.Eq;
27 import org.argeo.api.acr.search.Gt;
28 import org.argeo.api.acr.search.Gte;
29 import org.argeo.api.acr.search.IsContentClass;
30 import org.argeo.api.acr.search.IsDefined;
31 import org.argeo.api.acr.search.Like;
32 import org.argeo.api.acr.search.Lt;
33 import org.argeo.api.acr.search.Lte;
34 import org.argeo.api.acr.search.Not;
35 import org.argeo.api.acr.search.PropertyValueContraint;
36 import org.argeo.api.cms.CmsLog;
37
38 /** Convert an ACR basic search to a JCR query. */
39 class BasicSearchToQom {
40 private final static CmsLog log = CmsLog.getLog(BasicSearchToQom.class);
41
42 private Session session;
43 private QueryManager queryManager;
44 private BasicSearch basicSearch;
45 private QueryObjectModelFactory factory;
46
47 private String relPath;
48
49 private QName contentClass = null;
50
51 private String selectorName = "content";
52
53 public BasicSearchToQom(Session session, BasicSearch basicSearch, String relPath) throws RepositoryException {
54 this.session = session;
55 this.queryManager = session.getWorkspace().getQueryManager();
56 this.basicSearch = basicSearch;
57 this.relPath = relPath;
58 factory = queryManager.getQOMFactory();
59 }
60
61 public QueryObjectModel createQuery() throws RepositoryException {
62 ContentFilter<?> where = basicSearch.getWhere();
63 // scan for content classes
64 // TODO deal with complex cases of multiple types
65
66 javax.jcr.query.qom.Constraint qomConstraint = toQomConstraint(where);
67 if (contentClass == null)
68 throw new IllegalArgumentException("No content class specified");
69
70 if (relPath != null) {
71 qomConstraint = factory.and(qomConstraint, factory.descendantNode(selectorName, "/" + relPath));
72 }
73
74 Selector source = factory.selector(NamespaceUtils.toPrefixedName(contentClass), selectorName);
75
76 QueryObjectModel qom = factory.createQuery(source, qomConstraint, null, null);
77 if (log.isTraceEnabled()) {
78 String sql2 = QOMFormatter.format(qom);
79 log.trace("JCR query:\n" + sql2 + "\n");
80 }
81 return qom;
82 }
83
84 private javax.jcr.query.qom.Constraint toQomConstraint(Constraint constraint) throws RepositoryException {
85 // javax.jcr.query.qom.Constraint qomConstraint;
86 if (constraint instanceof ContentFilter<?> where) {
87 List<Constraint> constraints = new ArrayList<>();
88 for (Constraint c : where.getConstraints()) {
89 if (c instanceof IsContentClass icc) {
90 if (icc.getContentClasses().length > 1 || contentClass != null)
91 throw new IllegalArgumentException("Multiple content class is not supported");
92 contentClass = icc.getContentClasses()[0];
93 } else {
94 constraints.add(c);
95 }
96 }
97
98 if (constraints.isEmpty()) {
99 return null;
100 } else if (constraints.size() == 1) {
101 return toQomConstraint(constraints.get(0));
102 } else {
103 javax.jcr.query.qom.Constraint currQomConstraint = toQomConstraint(constraints.get(0));
104 // QOM constraint may be null because only content classes where specified
105 while (currQomConstraint == null) {
106 constraints.remove(0);
107 if (constraints.isEmpty())
108 return null;
109 currQomConstraint = toQomConstraint(constraints.get(0));
110 }
111 assert currQomConstraint != null : "currQomConstraint is null : " + constraints.get(0);
112 for (int i = 1; i < constraints.size(); i++) {
113 Constraint c = constraints.get(i);
114 javax.jcr.query.qom.Constraint subQomConstraint = toQomConstraint(c);
115 if (subQomConstraint != null) { // isContentClass leads to null QOM constraint
116 assert subQomConstraint != null : "subQomConstraint";
117 if (where.isUnion()) {
118 currQomConstraint = factory.or(currQomConstraint, subQomConstraint);
119 } else {
120 currQomConstraint = factory.and(currQomConstraint, subQomConstraint);
121 }
122 }
123 }
124 return currQomConstraint;
125 }
126
127 } else if (constraint instanceof PropertyValueContraint comp) {
128 QName prop = comp.getProp();
129 if (DName.creationdate.equals(prop))
130 prop = JcrName.created.qName();
131 else if (DName.getlastmodified.equals(prop))
132 prop = JcrName.lastModified.qName();
133
134 DynamicOperand dynamicOperand = factory.propertyValue(selectorName, NamespaceUtils.toPrefixedName(prop));
135 // TODO better convert attribute value
136 StaticOperand staticOperand = factory
137 .literal(JcrContent.convertSingleObject(session.getValueFactory(), comp.getValue()));
138 javax.jcr.query.qom.Constraint res;
139 if (comp instanceof Eq)
140 res = factory.comparison(dynamicOperand, QueryObjectModelConstants.JCR_OPERATOR_EQUAL_TO,
141 staticOperand);
142 else if (comp instanceof Lt)
143 res = factory.comparison(dynamicOperand, QueryObjectModelConstants.JCR_OPERATOR_LESS_THAN,
144 staticOperand);
145 else if (comp instanceof Lte)
146 res = factory.comparison(dynamicOperand, QueryObjectModelConstants.JCR_OPERATOR_LESS_THAN_OR_EQUAL_TO,
147 staticOperand);
148 else if (comp instanceof Gt)
149 res = factory.comparison(dynamicOperand, QueryObjectModelConstants.JCR_OPERATOR_GREATER_THAN,
150 staticOperand);
151 else if (comp instanceof Gte)
152 res = factory.comparison(dynamicOperand,
153 QueryObjectModelConstants.JCR_OPERATOR_GREATER_THAN_OR_EQUAL_TO, staticOperand);
154 else if (comp instanceof Like)
155 res = factory.comparison(dynamicOperand, QueryObjectModelConstants.JCR_OPERATOR_LIKE, staticOperand);
156 else
157 throw new UnsupportedOperationException("Constraint of type " + comp.getClass() + " is not supported");
158 return res;
159 } else if (constraint instanceof Not not) {
160 return factory.not(toQomConstraint(not.getNegated()));
161 } else if (constraint instanceof IsDefined comp) {
162 QName prop = comp.getProp();
163 if (DName.checkedIn.equals(prop) || DName.checkedOut.equals(prop)) {
164 DynamicOperand dynamicOperand = factory.propertyValue(selectorName, Property.JCR_IS_CHECKED_OUT);
165 StaticOperand staticOperand = factory
166 .literal(session.getValueFactory().createValue(DName.checkedOut.equals(prop)));
167 return factory.comparison(dynamicOperand, JCR_OPERATOR_EQUAL_TO, staticOperand);
168 } else {
169 return factory.propertyExistence(selectorName, NamespaceUtils.toPrefixedName(prop));
170 }
171 } else {
172 throw new IllegalArgumentException("Constraint " + constraint.getClass() + " is not supported");
173 }
174 // return qomConstraint;
175 }
176 }