001    /**
002     * Copyright (c) 2000-2012 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
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.GetterUtil;
032    import com.liferay.portal.kernel.util.StringBundler;
033    import com.liferay.portal.model.RepositoryEntry;
034    import com.liferay.portal.model.User;
035    import com.liferay.portal.service.RepositoryEntryLocalServiceUtil;
036    import com.liferay.portal.service.UserLocalServiceUtil;
037    
038    import java.util.HashMap;
039    import java.util.HashSet;
040    import java.util.List;
041    import java.util.Map;
042    import java.util.Set;
043    
044    /**
045     * @author Mika Koivisto
046     */
047    public class BaseCmisSearchQueryBuilder implements CMISSearchQueryBuilder {
048    
049            public String buildQuery(SearchContext searchContext, Query query)
050                    throws SearchException {
051    
052                    StringBundler sb = new StringBundler();
053    
054                    sb.append("SELECT cmis:objectId");
055    
056                    QueryConfig queryConfig = searchContext.getQueryConfig();
057    
058                    if (queryConfig.isScoreEnabled()) {
059                            sb.append(", SCORE() AS HITS");
060                    }
061    
062                    sb.append(" FROM cmis:document");
063    
064                    CMISConjunction cmisConjunction = new CMISConjunction();
065    
066                    traverseQuery(cmisConjunction, query);
067    
068                    if (!cmisConjunction.isEmpty()) {
069                            sb.append(" WHERE ");
070                            sb.append(cmisConjunction.toQueryFragment());
071                    }
072    
073                    Sort[] sorts = searchContext.getSorts();
074    
075                    if (queryConfig.isScoreEnabled() ||
076                            ((sorts != null) && sorts.length > 0)) {
077    
078                            sb.append(" ORDER BY ");
079                    }
080    
081                    if ((sorts != null) && (sorts.length > 0)) {
082                            int i = 0;
083    
084                            for (Sort sort : sorts) {
085                                    String fieldName = sort.getFieldName();
086    
087                                    if (!isSupportedField(fieldName)) {
088                                            continue;
089                                    }
090    
091                                    if (i > 0) {
092                                            sb.append(", ");
093                                    }
094    
095                                    sb.append(getCmisField(fieldName));
096    
097                                    if (sort.isReverse()) {
098                                            sb.append(" DESC");
099                                    }
100                                    else {
101                                            sb.append(" ASC");
102                                    }
103    
104                                    i++;
105                            }
106                    }
107                    else if (queryConfig.isScoreEnabled()) {
108                            sb.append("HITS DESC");
109                    }
110    
111                    return sb.toString();
112            }
113    
114            protected CMISCriterion buildFieldExpression(
115                            String field, String value,
116                            CMISSimpleExpressionOperator cmisSimpleExpressionOperator)
117                    throws SearchException {
118    
119                    CMISCriterion cmisCriterion = null;
120    
121                    boolean wildcard =
122                            CMISSimpleExpressionOperator.LIKE == cmisSimpleExpressionOperator;
123    
124                    if (field.equals(Field.CONTENT)) {
125                            value = CMISParameterValueUtil.formatParameterValue(field, value);
126    
127                            cmisCriterion = new CMISContainsExpression(value);
128                    }
129                    else if (field.equals(Field.FOLDER_ID)) {
130                            long folderId = GetterUtil.getLong(value);
131    
132                            try {
133                                    RepositoryEntry repositoryEntry =
134                                            RepositoryEntryLocalServiceUtil.fetchRepositoryEntry(
135                                                    folderId);
136    
137                                    if (repositoryEntry != null) {
138                                            String objectId = repositoryEntry.getMappedId();
139    
140                                            objectId = CMISParameterValueUtil.formatParameterValue(
141                                                    field, objectId, wildcard);
142    
143                                            cmisCriterion = new CMISInFolderExpression(objectId);
144                                    }
145                            }
146                            catch (SystemException se) {
147                                    throw new SearchException(
148                                            "Unable to determine folder {folderId=" + folderId + "}",
149                                            se);
150                            }
151                    }
152                    else if (field.equals(Field.USER_ID)) {
153                            try {
154                                    long userId = GetterUtil.getLong(value);
155    
156                                    User user = UserLocalServiceUtil.getUserById(userId);
157    
158                                    String screenName = CMISParameterValueUtil.formatParameterValue(
159                                            field, user.getScreenName(), wildcard);
160    
161                                    cmisCriterion = new CMISSimpleExpression(
162                                            getCmisField(field), screenName,
163                                            cmisSimpleExpressionOperator);
164                            }
165                            catch (Exception e) {
166                                    if (e instanceof SearchException) {
167                                            throw (SearchException)e;
168                                    }
169    
170                                    throw new SearchException(
171                                            "Unable to determine user {" + field + "=" + value + "}",
172                                            e);
173                            }
174                    }
175                    else {
176                            value = CMISParameterValueUtil.formatParameterValue(
177                                    field, value, wildcard);
178    
179                            cmisCriterion = new CMISSimpleExpression(
180                                    getCmisField(field), value, cmisSimpleExpressionOperator);
181                    }
182    
183                    return cmisCriterion;
184            }
185    
186            protected String getCmisField(String field) {
187                    return _cmisFields.get(field);
188            }
189    
190            protected boolean isSupportedField(String field) {
191                    return _supportedFields.contains(field);
192            }
193    
194            protected void traverseQuery(CMISJunction criterion, Query query)
195                    throws SearchException {
196    
197                    if (query instanceof BooleanQuery) {
198                            BooleanQuery booleanQuery = (BooleanQuery)query;
199    
200                            List<BooleanClause> booleanClauses = booleanQuery.clauses();
201    
202                            CMISConjunction anyCMISConjunction = new CMISConjunction();
203                            CMISConjunction notCMISConjunction = new CMISConjunction();
204                            CMISDisjunction cmisDisjunction = new CMISDisjunction();
205    
206                            for (BooleanClause booleanClause : booleanClauses) {
207                                    CMISJunction cmisJunction = cmisDisjunction;
208    
209                                    BooleanClauseOccur booleanClauseOccur =
210                                            booleanClause.getBooleanClauseOccur();
211    
212                                    if (booleanClauseOccur.equals(BooleanClauseOccur.MUST)) {
213                                            cmisJunction = anyCMISConjunction;
214                                    }
215                                    else if (booleanClauseOccur.equals(
216                                                            BooleanClauseOccur.MUST_NOT)) {
217    
218                                            cmisJunction = notCMISConjunction;
219                                    }
220    
221                                    Query booleanClauseQuery = booleanClause.getQuery();
222    
223                                    traverseQuery(cmisJunction, booleanClauseQuery);
224                            }
225    
226                            if (!anyCMISConjunction.isEmpty()) {
227                                    criterion.add(anyCMISConjunction);
228                            }
229    
230                            if (!cmisDisjunction.isEmpty()) {
231                                    criterion.add(cmisDisjunction);
232                            }
233    
234                            if (!notCMISConjunction.isEmpty()) {
235                                    criterion.add(new CMISNotExpression(notCMISConjunction));
236                            }
237                    }
238                    else if (query instanceof TermQuery) {
239                            TermQuery termQuery = (TermQuery)query;
240    
241                            QueryTerm queryTerm = termQuery.getQueryTerm();
242    
243                            if (!isSupportedField(queryTerm.getField())) {
244                                    return;
245                            }
246    
247                            CMISCriterion cmisExpression = buildFieldExpression(
248                                    queryTerm.getField(), queryTerm.getValue(),
249                                    CMISSimpleExpressionOperator.EQ);
250    
251                            if (cmisExpression != null) {
252                                    criterion.add(cmisExpression);
253                            }
254                    }
255                    else if (query instanceof TermRangeQuery) {
256                            TermRangeQuery termRangeQuery = (TermRangeQuery)query;
257    
258                            if (!isSupportedField(termRangeQuery.getField())) {
259                                    return;
260                            }
261    
262                            String fieldName = termRangeQuery.getField();
263    
264                            String cmisField = getCmisField(fieldName);
265                            String cmisLowerTerm = CMISParameterValueUtil.formatParameterValue(
266                                    fieldName, termRangeQuery.getLowerTerm());
267                            String cmisUpperTerm = CMISParameterValueUtil.formatParameterValue(
268                                    fieldName, termRangeQuery.getUpperTerm());
269    
270                            CMISCriterion cmisCriterion = new CMISBetweenExpression(
271                                    cmisField, cmisLowerTerm, cmisUpperTerm,
272                                    termRangeQuery.includesLower(), termRangeQuery.includesUpper());
273    
274                            criterion.add(cmisCriterion);
275                    }
276                    else if (query instanceof WildcardQuery) {
277                            WildcardQuery wildcardQuery = (WildcardQuery)query;
278    
279                            QueryTerm queryTerm = wildcardQuery.getQueryTerm();
280    
281                            if (!isSupportedField(queryTerm.getField())) {
282                                    return;
283                            }
284    
285                            CMISCriterion cmisCriterion = buildFieldExpression(
286                                    queryTerm.getField(), queryTerm.getValue(),
287                                    CMISSimpleExpressionOperator.LIKE);
288    
289                            if (cmisCriterion != null) {
290                                    criterion.add(cmisCriterion);
291                            }
292                    }
293            }
294    
295            private static Map<String, String> _cmisFields;
296            private static Set<String> _supportedFields;
297    
298            static {
299                    _cmisFields = new HashMap<String, String>();
300    
301                    _cmisFields.put(Field.CREATE_DATE, "cmis:creationDate");
302                    _cmisFields.put(Field.MODIFIED_DATE, "cmis:lastModificationDate");
303                    _cmisFields.put(Field.NAME, "cmis:name");
304                    _cmisFields.put(Field.TITLE, "cmis:name");
305                    _cmisFields.put(Field.USER_ID, "cmis:createdBy");
306                    _cmisFields.put(Field.USER_NAME, "cmis:createdBy");
307    
308                    _supportedFields = new HashSet<String>();
309    
310                    _supportedFields.add(Field.CREATE_DATE);
311                    _supportedFields.add(Field.FOLDER_ID);
312                    _supportedFields.add(Field.MODIFIED_DATE);
313                    _supportedFields.add(Field.NAME);
314                    _supportedFields.add(Field.TITLE);
315                    _supportedFields.add(Field.USER_ID);
316                    _supportedFields.add(Field.USER_NAME);
317            }
318    
319    }