001
014
015 package com.liferay.portal.kernel.repository.cmis.search;
016
017 import com.liferay.portal.kernel.exception.SystemException;
018 import com.liferay.portal.kernel.search.BooleanClause;
019 import com.liferay.portal.kernel.search.BooleanClauseOccur;
020 import com.liferay.portal.kernel.search.BooleanQuery;
021 import com.liferay.portal.kernel.search.Field;
022 import com.liferay.portal.kernel.search.Query;
023 import com.liferay.portal.kernel.search.QueryConfig;
024 import com.liferay.portal.kernel.search.QueryTerm;
025 import com.liferay.portal.kernel.search.SearchContext;
026 import com.liferay.portal.kernel.search.SearchException;
027 import com.liferay.portal.kernel.search.Sort;
028 import com.liferay.portal.kernel.search.TermQuery;
029 import com.liferay.portal.kernel.search.TermRangeQuery;
030 import com.liferay.portal.kernel.search.WildcardQuery;
031 import com.liferay.portal.kernel.util.ArrayUtil;
032 import com.liferay.portal.kernel.util.GetterUtil;
033 import com.liferay.portal.kernel.util.StringBundler;
034 import com.liferay.portal.kernel.util.Validator;
035 import com.liferay.portal.model.RepositoryEntry;
036 import com.liferay.portal.model.User;
037 import com.liferay.portal.service.RepositoryEntryLocalServiceUtil;
038 import com.liferay.portal.service.UserLocalServiceUtil;
039
040 import java.util.HashMap;
041 import java.util.HashSet;
042 import java.util.List;
043 import java.util.Map;
044 import java.util.Set;
045
046
049 public class BaseCmisSearchQueryBuilder implements CMISSearchQueryBuilder {
050
051 @Override
052 public String buildQuery(SearchContext searchContext, Query query)
053 throws SearchException {
054
055 StringBundler sb = new StringBundler();
056
057 sb.append("SELECT cmis:objectId");
058
059 QueryConfig queryConfig = searchContext.getQueryConfig();
060
061 if (queryConfig.isScoreEnabled()) {
062 sb.append(", SCORE() AS HITS");
063 }
064
065 sb.append(" FROM cmis:document");
066
067 CMISConjunction cmisConjunction = new CMISConjunction();
068
069 traverseQuery(cmisConjunction, query, queryConfig);
070
071 if (!cmisConjunction.isEmpty()) {
072 sb.append(" WHERE ");
073 sb.append(cmisConjunction.toQueryFragment());
074 }
075
076 Sort[] sorts = searchContext.getSorts();
077
078 if (queryConfig.isScoreEnabled() || ArrayUtil.isNotEmpty(sorts)) {
079 sb.append(" ORDER BY ");
080 }
081
082 if (ArrayUtil.isNotEmpty(sorts)) {
083 int i = 0;
084
085 for (Sort sort : sorts) {
086 String fieldName = sort.getFieldName();
087
088 if (!isSupportedField(fieldName)) {
089 continue;
090 }
091
092 if (i > 0) {
093 sb.append(", ");
094 }
095
096 sb.append(getCmisField(fieldName));
097
098 if (sort.isReverse()) {
099 sb.append(" DESC");
100 }
101 else {
102 sb.append(" ASC");
103 }
104
105 i++;
106 }
107 }
108 else if (queryConfig.isScoreEnabled()) {
109 sb.append("HITS DESC");
110 }
111
112 return sb.toString();
113 }
114
115 protected CMISCriterion buildFieldExpression(
116 String field, String value,
117 CMISSimpleExpressionOperator cmisSimpleExpressionOperator,
118 QueryConfig queryConfig)
119 throws SearchException {
120
121 CMISCriterion cmisCriterion = null;
122
123 boolean wildcard =
124 CMISSimpleExpressionOperator.LIKE == cmisSimpleExpressionOperator;
125
126 if (field.equals(Field.CONTENT)) {
127 value = CMISParameterValueUtil.formatParameterValue(
128 field, value, false, queryConfig);
129
130 cmisCriterion = new CMISContainsExpression(value);
131 }
132 else if (field.equals(Field.FOLDER_ID)) {
133 long folderId = GetterUtil.getLong(value);
134
135 try {
136 RepositoryEntry repositoryEntry =
137 RepositoryEntryLocalServiceUtil.fetchRepositoryEntry(
138 folderId);
139
140 if (repositoryEntry != null) {
141 String objectId = repositoryEntry.getMappedId();
142
143 objectId = CMISParameterValueUtil.formatParameterValue(
144 field, objectId, wildcard, queryConfig);
145
146 if (queryConfig.isSearchSubfolders()) {
147 cmisCriterion = new CMISInTreeExpression(objectId);
148 }
149 else {
150 cmisCriterion = new CMISInFolderExpression(objectId);
151 }
152 }
153 }
154 catch (SystemException se) {
155 throw new SearchException(
156 "Unable to determine folder {folderId=" + folderId + "}",
157 se);
158 }
159 }
160 else if (field.equals(Field.USER_ID)) {
161 try {
162 long userId = GetterUtil.getLong(value);
163
164 User user = UserLocalServiceUtil.getUserById(userId);
165
166 String screenName = CMISParameterValueUtil.formatParameterValue(
167 field, user.getScreenName(), wildcard, queryConfig);
168
169 cmisCriterion = new CMISSimpleExpression(
170 getCmisField(field), screenName,
171 cmisSimpleExpressionOperator);
172 }
173 catch (Exception e) {
174 if (e instanceof SearchException) {
175 throw (SearchException)e;
176 }
177
178 throw new SearchException(
179 "Unable to determine user {" + field + "=" + value + "}",
180 e);
181 }
182 }
183 else {
184 value = CMISParameterValueUtil.formatParameterValue(
185 field, value, wildcard, queryConfig);
186
187 cmisCriterion = new CMISSimpleExpression(
188 getCmisField(field), value, cmisSimpleExpressionOperator);
189 }
190
191 return cmisCriterion;
192 }
193
194 protected String getCmisField(String field) {
195 return _cmisFields.get(field);
196 }
197
198 protected boolean isSupportedField(String field) {
199 return _supportedFields.contains(field);
200 }
201
202 protected boolean isSupportsFullText(QueryConfig queryConfig) {
203 String capabilityQuery = (String)queryConfig.getAttribute(
204 "capabilityQuery");
205
206 if (Validator.isNull(capabilityQuery)) {
207 return false;
208 }
209
210 if (capabilityQuery.equals("bothcombined") ||
211 capabilityQuery.equals("fulltextonly")) {
212
213 return true;
214 }
215
216 return false;
217 }
218
219 protected boolean isSupportsOnlyFullText(QueryConfig queryConfig) {
220 String capabilityQuery = (String)queryConfig.getAttribute(
221 "capabilityQuery");
222
223 if (Validator.isNull(capabilityQuery)) {
224 return false;
225 }
226
227 if (capabilityQuery.equals("fulltextonly")) {
228 return true;
229 }
230
231 return false;
232 }
233
234 protected void traverseQuery(
235 CMISJunction criterion, Query query, QueryConfig queryConfig)
236 throws SearchException {
237
238 if (query instanceof BooleanQuery) {
239 BooleanQuery booleanQuery = (BooleanQuery)query;
240
241 List<BooleanClause> booleanClauses = booleanQuery.clauses();
242
243 CMISConjunction anyCMISConjunction = new CMISConjunction();
244 CMISConjunction notCMISConjunction = new CMISConjunction();
245 CMISDisjunction cmisDisjunction = new CMISDisjunction();
246
247 for (BooleanClause booleanClause : booleanClauses) {
248 CMISJunction cmisJunction = cmisDisjunction;
249
250 BooleanClauseOccur booleanClauseOccur =
251 booleanClause.getBooleanClauseOccur();
252
253 if (booleanClauseOccur.equals(BooleanClauseOccur.MUST)) {
254 cmisJunction = anyCMISConjunction;
255 }
256 else if (booleanClauseOccur.equals(
257 BooleanClauseOccur.MUST_NOT)) {
258
259 cmisJunction = notCMISConjunction;
260 }
261
262 Query booleanClauseQuery = booleanClause.getQuery();
263
264 traverseQuery(cmisJunction, booleanClauseQuery, queryConfig);
265 }
266
267 if (!anyCMISConjunction.isEmpty()) {
268 criterion.add(anyCMISConjunction);
269 }
270
271 if (!cmisDisjunction.isEmpty()) {
272 criterion.add(cmisDisjunction);
273 }
274
275 if (!notCMISConjunction.isEmpty()) {
276 criterion.add(new CMISNotExpression(notCMISConjunction));
277 }
278 }
279 else if (query instanceof TermQuery) {
280 TermQuery termQuery = (TermQuery)query;
281
282 QueryTerm queryTerm = termQuery.getQueryTerm();
283
284 if (!isSupportedField(queryTerm.getField())) {
285 return;
286 }
287
288 CMISCriterion cmisExpression = buildFieldExpression(
289 queryTerm.getField(), queryTerm.getValue(),
290 CMISSimpleExpressionOperator.EQ, queryConfig);
291
292 if (cmisExpression != null) {
293 boolean add = true;
294
295 if ((cmisExpression instanceof CMISContainsExpression) &&
296 !isSupportsFullText(queryConfig)) {
297
298 add = false;
299 }
300 else if (!((cmisExpression instanceof CMISContainsExpression) ||
301 (cmisExpression instanceof CMISInFolderExpression) ||
302 (cmisExpression instanceof CMISInTreeExpression)) &&
303 isSupportsOnlyFullText(queryConfig)) {
304
305 add = false;
306 }
307
308 if (add) {
309 criterion.add(cmisExpression);
310 }
311 }
312 }
313 else if (query instanceof TermRangeQuery) {
314 TermRangeQuery termRangeQuery = (TermRangeQuery)query;
315
316 if (!isSupportedField(termRangeQuery.getField())) {
317 return;
318 }
319
320 String fieldName = termRangeQuery.getField();
321
322 String cmisField = getCmisField(fieldName);
323 String cmisLowerTerm = CMISParameterValueUtil.formatParameterValue(
324 fieldName, termRangeQuery.getLowerTerm(), false, queryConfig);
325 String cmisUpperTerm = CMISParameterValueUtil.formatParameterValue(
326 fieldName, termRangeQuery.getUpperTerm(), false, queryConfig);
327
328 CMISCriterion cmisCriterion = new CMISBetweenExpression(
329 cmisField, cmisLowerTerm, cmisUpperTerm,
330 termRangeQuery.includesLower(), termRangeQuery.includesUpper());
331
332 criterion.add(cmisCriterion);
333 }
334 else if (query instanceof WildcardQuery) {
335 WildcardQuery wildcardQuery = (WildcardQuery)query;
336
337 QueryTerm queryTerm = wildcardQuery.getQueryTerm();
338
339 if (!isSupportedField(queryTerm.getField())) {
340 return;
341 }
342
343 CMISCriterion cmisCriterion = buildFieldExpression(
344 queryTerm.getField(), queryTerm.getValue(),
345 CMISSimpleExpressionOperator.LIKE, queryConfig);
346
347 if (cmisCriterion != null) {
348 boolean add = true;
349
350 if ((cmisCriterion instanceof CMISContainsExpression) &&
351 !isSupportsFullText(queryConfig)) {
352
353 add = false;
354 }
355 else if (!((cmisCriterion instanceof CMISContainsExpression) ||
356 (cmisCriterion instanceof CMISInFolderExpression) ||
357 (cmisCriterion instanceof CMISInTreeExpression)) &&
358 isSupportsOnlyFullText(queryConfig)) {
359
360 add = false;
361 }
362
363 if (add) {
364 criterion.add(cmisCriterion);
365 }
366 }
367 }
368 }
369
370 private static Map<String, String> _cmisFields;
371 private static Set<String> _supportedFields;
372
373 static {
374 _cmisFields = new HashMap<String, String>();
375
376 _cmisFields.put(Field.CREATE_DATE, "cmis:creationDate");
377 _cmisFields.put(Field.MODIFIED_DATE, "cmis:lastModificationDate");
378 _cmisFields.put(Field.NAME, "cmis:name");
379 _cmisFields.put(Field.TITLE, "cmis:name");
380 _cmisFields.put(Field.USER_ID, "cmis:createdBy");
381 _cmisFields.put(Field.USER_NAME, "cmis:createdBy");
382
383 _supportedFields = new HashSet<String>();
384
385 _supportedFields.add(Field.CONTENT);
386 _supportedFields.add(Field.CREATE_DATE);
387 _supportedFields.add(Field.FOLDER_ID);
388 _supportedFields.add(Field.MODIFIED_DATE);
389 _supportedFields.add(Field.NAME);
390 _supportedFields.add(Field.TITLE);
391 _supportedFields.add(Field.USER_ID);
392 _supportedFields.add(Field.USER_NAME);
393 }
394
395 }