1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.chemistry.opencmis.jcr.query;
21
22 import org.apache.chemistry.opencmis.commons.definitions.TypeDefinition;
23 import org.apache.chemistry.opencmis.commons.exceptions.CmisInvalidArgumentException;
24 import org.apache.chemistry.opencmis.jcr.JcrTypeManager;
25 import org.apache.chemistry.opencmis.server.support.query.CmisQueryWalker;
26 import org.apache.chemistry.opencmis.server.support.query.QueryObject;
27 import org.apache.chemistry.opencmis.server.support.query.QueryObject.SortSpec;
28 import org.apache.chemistry.opencmis.server.support.query.QueryUtil;
29
30 import java.util.List;
31
32
33
34
35
36
37
38
39
40 public abstract class QueryTranslator {
41 private final JcrTypeManager typeManager;
42 private final EvaluatorXPath evaluator;
43 private QueryObject queryObject;
44
45
46
47
48
49
50
51 protected QueryTranslator(JcrTypeManager typeManager) {
52 this.typeManager = typeManager;
53 evaluator = new EvaluatorXPath() {
54
55 @Override
56 protected String jcrPathFromId(String id) {
57 return QueryTranslator.this.jcrPathFromId(id);
58 }
59
60 @Override
61 protected String jcrPathFromCol(String name) {
62 return QueryTranslator.this.jcrPathFromCol(queryObject.getMainFromName(), name);
63 }
64 };
65 }
66
67
68
69
70
71 public QueryObject getQueryObject() {
72 return queryObject;
73 }
74
75
76
77
78
79
80
81 public String translateToXPath(String statement) {
82 QueryUtil queryUtil = new QueryUtil();
83 queryObject = new QueryObject(typeManager);
84 ParseTreeWalker<XPathBuilder> parseTreeWalker = new ParseTreeWalker<XPathBuilder>(evaluator);
85 CmisQueryWalker walker = queryUtil.traverseStatementAndCatchExc(statement, queryObject, parseTreeWalker);
86 walker.setDoFullTextParse(false);
87 XPathBuilder parseResult = parseTreeWalker.getResult();
88 TypeDefinition fromType = getFromName(queryObject);
89
90 String pathExpression = buildPathExpression(fromType, getFolderPredicate(parseResult));
91 String elementTest = buildElementTest(fromType);
92 String predicates = buildPredicates(fromType, getCondition(parseResult));
93 String orderByClause = buildOrderByClause(fromType, queryObject.getOrderBys());
94 return "/jcr:root" + pathExpression + elementTest + predicates + orderByClause;
95 }
96
97
98
99
100
101
102
103
104
105
106 protected abstract String jcrPathFromId(String id);
107
108
109
110
111
112
113
114
115
116 protected abstract String jcrPathFromCol(TypeDefinition fromType, String name);
117
118
119
120
121
122
123
124
125 protected abstract String jcrTypeName(TypeDefinition fromType);
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146 protected abstract String jcrTypeCondition(TypeDefinition fromType);
147
148
149
150
151
152
153
154
155 protected String buildPathExpression(TypeDefinition fromType, String folderPredicate) {
156 return folderPredicate == null ? "//" : folderPredicate;
157 }
158
159
160
161
162
163
164
165 protected String buildElementTest(TypeDefinition fromType) {
166 return "element(*," + jcrTypeName(fromType) + ")";
167 }
168
169
170
171
172
173
174
175
176
177
178 protected String buildPredicates(TypeDefinition fromType, String condition) {
179 String typeCondition = jcrTypeCondition(fromType);
180
181 if (typeCondition == null) {
182 return condition == null ? "" : "[" + condition + "]";
183 }
184 else if (condition == null) {
185 return "[" + typeCondition + "]";
186 }
187 else {
188 return "[" + typeCondition + " and " + condition + "]";
189 }
190 }
191
192
193
194
195
196
197
198
199 protected String buildOrderByClause(TypeDefinition fromType, List<SortSpec> orderBys) {
200 StringBuilder orderSpecs = new StringBuilder();
201
202 for (SortSpec orderBy : orderBys) {
203 String selector = jcrPathFromCol(fromType, orderBy.getSelector().getName());
204 boolean ascending = orderBy.isAscending();
205
206 if (orderSpecs.length() > 0) {
207 orderSpecs.append(',');
208 }
209
210 orderSpecs
211 .append(selector)
212 .append(' ')
213 .append(ascending ? "ascending" : "descending");
214 }
215
216 return orderSpecs.length() > 0
217 ? "order by " + orderSpecs
218 : "";
219 }
220
221
222
223 private static String getFolderPredicate(XPathBuilder parseResult) {
224 if (parseResult == null) {
225 return null;
226 }
227
228 String folderPredicate = null;
229 for (XPathBuilder p : parseResult.folderPredicates()) {
230 if (folderPredicate == null) {
231 folderPredicate = p.xPath();
232 }
233 else {
234 throw new CmisInvalidArgumentException("Query may only contain a single folder predicate");
235 }
236 }
237
238
239 if (folderPredicate != null &&
240 !Boolean.FALSE.equals(parseResult.eval(false))) {
241 throw new CmisInvalidArgumentException("Folder predicate " + folderPredicate + " is not affirmative.");
242 }
243
244 return folderPredicate;
245 }
246
247 private static TypeDefinition getFromName(QueryObject queryObject) {
248 if (queryObject.getTypes().size() != 1) {
249 throw new CmisInvalidArgumentException("From must contain one single reference");
250 }
251 return queryObject.getMainFromName();
252 }
253
254 private static String getCondition(XPathBuilder parseResult) {
255
256
257 return parseResult == null || Boolean.TRUE.equals(parseResult.eval(true)) ? null : parseResult.xPath();
258 }
259
260 }