001/*
002 * (C) Copyright 2010 Nuxeo SA (http://nuxeo.com/) and others.
003 *
004 * Licensed under the Apache License, Version 2.0 (the "License");
005 * you may not use this file except in compliance with the License.
006 * You may obtain a copy of the License at
007 *
008 *     http://www.apache.org/licenses/LICENSE-2.0
009 *
010 * Unless required by applicable law or agreed to in writing, software
011 * distributed under the License is distributed on an "AS IS" BASIS,
012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
013 * See the License for the specific language governing permissions and
014 * limitations under the License.
015 *
016 * Contributors:
017 *     Anahide Tchertchian
018 */
019package org.nuxeo.ecm.platform.smart.query;
020
021import java.util.ArrayList;
022import java.util.Date;
023import java.util.List;
024
025import org.apache.commons.lang.StringUtils;
026
027/**
028 * Smart query providing all the needed methods for UI interaction that will make it possible to build a query adding
029 * clauses step by step.
030 * <p>
031 * Specific getters and setters have been defined instead of a generic one for a better resolution of target types.
032 *
033 * @since 5.4
034 * @author Anahide Tchertchian
035 */
036public abstract class IncrementalSmartQuery implements SmartQuery {
037
038    private static final long serialVersionUID = 1L;
039
040    /**
041     * Stores the current existing query part.
042     * <p>
043     * This does not need to be a valid query as it can still be refined after.
044     */
045    protected String existingQueryPart;
046
047    /**
048     * String containing the logical operator at start of the query part to add (for instance 'AND' or 'OR').
049     */
050    protected String logicalOperator;
051
052    /**
053     * Boolean indicating if the query part to add should be negated (for instance by adding the 'NOT' marker before)
054     */
055    protected Boolean addNotOperator;
056
057    /**
058     * Boolean indicating if an open parenthesis should be added prior to the query part to add.
059     */
060    protected Boolean openParenthesis;
061
062    /**
063     * Boolean indicating if an closed parenthesis should be added after the query part to add.
064     */
065    protected Boolean closeParenthesis;
066
067    /**
068     * Marker for layout row selection that will make it possible to display only the widgets defined in this row for
069     * the rest of the query part definition.
070     */
071    protected String selectedRowName;
072
073    /**
074     * String typically representing the search index for the query part to add.
075     */
076    protected String leftExpression;
077
078    /**
079     * String representing the conditional operator to use when building the query part to add (for instance '=',
080     * 'LIKE',...)
081     */
082    protected String conditionalOperator;
083
084    protected Boolean escapeValue;
085
086    /**
087     * Generic set value for the new query part to add.
088     * <p>
089     * Holds the last value set on one of the specific value setters.
090     */
091    protected Object value;
092
093    // provide a separate field for accepted expression values for a good JFS
094    // resolution
095
096    /**
097     * Boolean value binding.
098     */
099    protected Boolean booleanValue;
100
101    /**
102     * String value binding.
103     */
104    protected String stringValue;
105
106    /**
107     * String list value binding.
108     */
109    protected List<String> stringListValue;
110
111    /**
112     * String array value binding.
113     */
114    protected String[] stringArrayValue;
115
116    /**
117     * Date and time value binding.
118     */
119    protected Date datetimeValue;
120
121    /**
122     * Another date and time value binding (useful when using the 'BETWEEN' operator for instance)
123     */
124    protected Date otherDatetimeValue;
125
126    /**
127     * Date value binding
128     */
129    protected Date dateValue;
130
131    /**
132     * Another date value binding (useful when using the 'BETWEEN' operator for instance)
133     */
134    protected Date otherDateValue;
135
136    /**
137     * Integer value binding.
138     */
139    protected Long integerValue;
140
141    /**
142     * Float value binding.
143     */
144    protected Double floatValue;
145
146    public IncrementalSmartQuery(String existingQueryPart) {
147        super();
148        this.existingQueryPart = existingQueryPart;
149    }
150
151    public String getExistingQueryPart() {
152        return existingQueryPart;
153    }
154
155    public void setExistingQueryPart(String existingQueryPart) {
156        this.existingQueryPart = existingQueryPart;
157    }
158
159    /**
160     * Returns true if existing query part is not empty.
161     */
162    public boolean getShowLogicalOperator() {
163        if (existingQueryPart == null || existingQueryPart.trim().length() == 0) {
164            return false;
165        }
166        return true;
167    }
168
169    public String getLogicalOperator() {
170        return logicalOperator;
171    }
172
173    public void setLogicalOperator(String logicalOperator) {
174        this.logicalOperator = logicalOperator;
175    }
176
177    public boolean getShowAddNotOperator() {
178        return true;
179    }
180
181    public Boolean getAddNotOperator() {
182        return addNotOperator;
183    }
184
185    public void setAddNotOperator(Boolean addNotOperator) {
186        this.addNotOperator = addNotOperator;
187    }
188
189    /**
190     * Returns true
191     */
192    public boolean getShowOpenParenthesis() {
193        return true;
194    }
195
196    public Boolean getOpenParenthesis() {
197        return openParenthesis;
198    }
199
200    public void setOpenParenthesis(Boolean openParenthesis) {
201        this.openParenthesis = openParenthesis;
202    }
203
204    /**
205     * Returns true if there are strictly more open parenthesis in the existing query part than closed ones.
206     */
207    public boolean getShowCloseParenthesis() {
208        if (existingQueryPart != null) {
209            int numberOpened = StringUtils.countMatches(existingQueryPart, "(");
210            int numberClosed = StringUtils.countMatches(existingQueryPart, ")");
211            if (numberOpened > numberClosed) {
212                return true;
213            }
214        }
215        return false;
216    }
217
218    public Boolean getCloseParenthesis() {
219        return closeParenthesis;
220    }
221
222    public void setCloseParenthesis(Boolean closeParenthesis) {
223        this.closeParenthesis = closeParenthesis;
224    }
225
226    public String getSelectedRowName() {
227        return selectedRowName;
228    }
229
230    /**
231     * Sets the selected row name.
232     * <p>
233     * Also resets the left expression, conditional operator, and all value bindings, as they may be set to values that
234     * are not relevant in this new row context.
235     */
236    public void setSelectedRowName(String selectedRowName) {
237        this.selectedRowName = selectedRowName;
238        leftExpression = null;
239        conditionalOperator = null;
240        clearValues();
241    }
242
243    // TODO: will be useful if layout tag can use it to filter other rows, see
244    // NXP-5725
245    public List<String> getSelectedRowNames() {
246        List<String> res = new ArrayList<String>();
247        if (selectedRowName != null) {
248            res.add(selectedRowName);
249        }
250        return res;
251    }
252
253    public String getLeftExpression() {
254        return leftExpression;
255    }
256
257    public void setLeftExpression(String leftExpression) {
258        this.leftExpression = leftExpression;
259    }
260
261    public String getConditionalOperator() {
262        return conditionalOperator;
263    }
264
265    /**
266     * Sets the conditional operator.
267     * <p>
268     * Also resets all the value bindings, as they may be set to values that are not relevant in this new conditional
269     * operator context.
270     */
271    public void setConditionalOperator(String conditionalOperator) {
272        this.conditionalOperator = conditionalOperator;
273        clearValues();
274    }
275
276    public Boolean getEscapeValue() {
277        return escapeValue;
278    }
279
280    public void setEscapeValue(Boolean escapeValue) {
281        this.escapeValue = escapeValue;
282    }
283
284    public Object getValue() {
285        return value;
286    }
287
288    public void setValue(Object value) {
289        this.value = value;
290    }
291
292    public Boolean getBooleanValue() {
293        return booleanValue;
294    }
295
296    public void setBooleanValue(Boolean booleanValue) {
297        this.booleanValue = booleanValue;
298        setValue(booleanValue);
299    }
300
301    public String getStringValue() {
302        return stringValue;
303    }
304
305    public void setStringValue(String stringValue) {
306        this.stringValue = stringValue;
307        setValue(stringValue);
308    }
309
310    public List<String> getStringListValue() {
311        return stringListValue;
312    }
313
314    public void setStringListValue(List<String> stringListValue) {
315        this.stringListValue = stringListValue;
316        setValue(stringListValue);
317    }
318
319    public String[] getStringArrayValue() {
320        return stringArrayValue;
321    }
322
323    public void setStringArrayValue(String[] stringArrayValue) {
324        this.stringArrayValue = stringArrayValue;
325        setValue(stringArrayValue);
326    }
327
328    public Date getDatetimeValue() {
329        return datetimeValue;
330    }
331
332    public void setDatetimeValue(Date datetimeValue) {
333        this.datetimeValue = datetimeValue;
334        setValue(datetimeValue);
335    }
336
337    public Date getOtherDatetimeValue() {
338        return otherDatetimeValue;
339    }
340
341    public void setOtherDatetimeValue(Date otherDatetimeValue) {
342        this.otherDatetimeValue = otherDatetimeValue;
343        setValue(otherDatetimeValue);
344    }
345
346    public Date getDateValue() {
347        return dateValue;
348    }
349
350    public void setDateValue(Date dateValue) {
351        this.dateValue = dateValue;
352        setValue(dateValue);
353    }
354
355    public Date getOtherDateValue() {
356        return otherDateValue;
357    }
358
359    public void setOtherDateValue(Date otherDateValue) {
360        this.otherDateValue = otherDateValue;
361        setValue(otherDateValue);
362    }
363
364    public Long getIntegerValue() {
365        return integerValue;
366    }
367
368    public void setIntegerValue(Long integerValue) {
369        this.integerValue = integerValue;
370        setValue(integerValue);
371    }
372
373    public Double getFloatValue() {
374        return floatValue;
375    }
376
377    public void setFloatValue(Double floatValue) {
378        this.floatValue = floatValue;
379        setValue(floatValue);
380    }
381
382    /**
383     * Clears all field values, except the existing quedry part.
384     */
385    protected void clear() {
386        logicalOperator = null;
387        addNotOperator = null;
388        openParenthesis = null;
389        closeParenthesis = null;
390        selectedRowName = null;
391        leftExpression = null;
392        conditionalOperator = null;
393        clearValues();
394    }
395
396    /**
397     * Clears all value bindings.
398     */
399    protected void clearValues() {
400        escapeValue = null;
401        value = null;
402        booleanValue = null;
403        stringValue = null;
404        stringListValue = null;
405        stringArrayValue = null;
406        datetimeValue = null;
407        otherDatetimeValue = null;
408        dateValue = null;
409        otherDateValue = null;
410        integerValue = null;
411        floatValue = null;
412    }
413
414}