1   /*
2    * Copyright 2003 - 2013 The eFaps Team
3    *
4    * Licensed under the Apache License, Version 2.0 (the "License");
5    * you may not use this file except in compliance with the License.
6    * You may obtain a copy of the License at
7    *
8    *     http://www.apache.org/licenses/LICENSE-2.0
9    *
10   * Unless required by applicable law or agreed to in writing, software
11   * distributed under the License is distributed on an "AS IS" BASIS,
12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13   * See the License for the specific language governing permissions and
14   * limitations under the License.
15   *
16   * Revision:        $Rev$
17   * Last Changed:    $Date$
18   * Last Changed By: $Author$
19   */
20  
21  
22  package org.efaps.db;
23  
24  import java.util.ArrayList;
25  import java.util.Collections;
26  import java.util.HashMap;
27  import java.util.HashSet;
28  import java.util.Iterator;
29  import java.util.LinkedHashSet;
30  import java.util.List;
31  import java.util.Map;
32  import java.util.Set;
33  import java.util.UUID;
34  import java.util.regex.Matcher;
35  import java.util.regex.Pattern;
36  
37  import org.efaps.admin.datamodel.Attribute;
38  import org.efaps.admin.datamodel.Classification;
39  import org.efaps.admin.datamodel.Dimension.UoM;
40  import org.efaps.admin.datamodel.IBitEnum;
41  import org.efaps.admin.datamodel.IEnum;
42  import org.efaps.admin.datamodel.Status;
43  import org.efaps.admin.datamodel.Type;
44  import org.efaps.ci.CIAttribute;
45  import org.efaps.ci.CIType;
46  import org.efaps.db.search.AbstractQPart;
47  import org.efaps.db.search.QAnd;
48  import org.efaps.db.search.QAttribute;
49  import org.efaps.db.search.QOr;
50  import org.efaps.db.search.QOrderAsc;
51  import org.efaps.db.search.QOrderDesc;
52  import org.efaps.db.search.compare.AbstractQAttrCompare;
53  import org.efaps.db.search.compare.QClassEqual;
54  import org.efaps.db.search.compare.QEqual;
55  import org.efaps.db.search.compare.QGreater;
56  import org.efaps.db.search.compare.QIn;
57  import org.efaps.db.search.compare.QIs;
58  import org.efaps.db.search.compare.QIsNot;
59  import org.efaps.db.search.compare.QLess;
60  import org.efaps.db.search.compare.QMatch;
61  import org.efaps.db.search.compare.QNotEqual;
62  import org.efaps.db.search.compare.QNotIn;
63  import org.efaps.db.search.section.QOrderBySection;
64  import org.efaps.db.search.section.QWhereSection;
65  import org.efaps.db.search.value.AbstractQValue;
66  import org.efaps.db.search.value.QBitValue;
67  import org.efaps.db.search.value.QBooleanValue;
68  import org.efaps.db.search.value.QClassValue;
69  import org.efaps.db.search.value.QDateTimeValue;
70  import org.efaps.db.search.value.QNullValue;
71  import org.efaps.db.search.value.QNumberValue;
72  import org.efaps.db.search.value.QSQLValue;
73  import org.efaps.db.search.value.QStringValue;
74  import org.efaps.util.EFapsException;
75  import org.efaps.util.cache.CacheReloadException;
76  import org.joda.time.DateTime;
77  import org.slf4j.Logger;
78  import org.slf4j.LoggerFactory;
79  
80  
81  /**
82   * TODO comment!
83   *
84   * @author The eFaps Team
85   * @version $Id$
86   */
87  public class QueryBuilder
88  {
89      /**
90       * Logging instance used in this class.
91       */
92      private static final Logger LOG = LoggerFactory.getLogger(QueryBuilder.class);
93  
94      /**
95       * Pattern to get the attribute from a select.
96       */
97      private static final Pattern ATTRPATTERN = Pattern.compile("(?<=attribute\\[)([A-Z, a-z])*(?=\\])");
98  
99      /**
100      * Pattern to get the attribute from a select.
101      */
102     private static final Pattern LINKTOPATTERN = Pattern.compile("(?<=linkto\\[)([A-Z, a-z])*(?=\\])");
103 
104     /**
105      * List of compares that will be included in this query.
106      */
107     private final List<AbstractQAttrCompare> compares = new ArrayList<>();
108 
109     /**
110      * List of parts that will be included in this order of this query.
111      */
112     private final List<AbstractQPart> orders = new ArrayList<>();
113 
114     /**
115      * QueryBuilders that will make a AttrQuery.
116      */
117     private final Map<List<String>, QueryBuilder> attrQueryBldrs = new HashMap<>();
118 
119     /**
120      * UUID of the type used for generated instance query.
121      */
122     private UUID typeUUID;
123 
124     /**
125      * List of type that should be included.
126      */
127     private final Set<UUID> types = new LinkedHashSet<UUID>();
128 
129     /**
130      * Query this QueryBuilder will return.
131      */
132     private AbstractObjectQuery<?> query;
133 
134     /**
135      * Is this QueryBuilder using or instead of and.
136      */
137     private boolean or = false;
138 
139     /**
140      * List for the query to be executed, defaults to none.
141      */
142     private int limit = -1;
143 
144     /**
145      * Should the child types be also be included in this search?
146      */
147     private boolean includeChildTypes = true;
148 
149     /**
150      * Name of the Attribute that links to this AttributeQuery.
151      */
152     private String linkAttributeName;
153 
154     /**
155      * @param _typeUUID     uuid of the type this query is based on
156      */
157     public QueryBuilder(final UUID _typeUUID)
158     {
159         this.typeUUID = _typeUUID;
160     }
161 
162     /**
163      * @param _type  type this query is based on
164      */
165     public QueryBuilder(final Type _type)
166     {
167         this(_type.getUUID());
168     }
169 
170     /**
171      * @param _ciType  ciType this query is based on
172      */
173     public QueryBuilder(final CIType _ciType)
174     {
175         this(_ciType.getType());
176     }
177 
178     /**
179      * Add a type to the QueryBuilder. Search for the common parent
180      * and use it as baseType.
181      * @param _uuid uudi of the types to be added to the QueryBuilder
182      * @throws EFapsException on error
183      */
184     public void addType(final UUID... _uuid)
185         throws EFapsException
186     {
187         final Set<Type> typesTmp = new HashSet<Type>();
188         for (final UUID uuid : _uuid) {
189             typesTmp.add(Type.get(uuid));
190         }
191         addType(typesTmp.toArray(new Type[typesTmp.size()]));
192     }
193 
194     /**
195      * Add a type to the QueryBuilder. Search for the common parent
196      * and use it as baseType.
197      * @param _ciType CIType of the types to be added to the QueryBuilder
198      * @throws EFapsException on error
199      */
200     public void addType(final CIType... _ciType)
201         throws EFapsException
202     {
203         final Set<Type> typesTmp = new HashSet<Type>();
204         for (final CIType ciType : _ciType) {
205             typesTmp.add(ciType.getType());
206         }
207         addType(typesTmp.toArray(new Type[typesTmp.size()]));
208     }
209 
210     /**
211      * Add a type to the QueryBuilder. Search for the common parent
212      * and use it as baseType.
213      * @param _type types to be added to the QueryBuilder
214      * @throws EFapsException on error
215      */
216     public void addType(final Type... _type)
217         throws EFapsException
218     {
219         final List<Type> allType = new ArrayList<Type>();
220         if (this.types.isEmpty()) {
221             allType.add(Type.get(this.typeUUID));
222         }
223         for (final UUID type : this.types) {
224             allType.add(Type.get(type));
225         }
226         Collections.addAll(allType, _type);
227 
228         //make for every type a list of types up to the parent
229         final List<List<Type>> typeLists = new ArrayList<List<Type>>();
230         for (final Type type : allType) {
231             final List<Type> typesTmp = new ArrayList<Type>();
232             typeLists.add(typesTmp);
233             Type tmpType = type;
234             while (tmpType != null) {
235                 typesTmp.add(tmpType);
236                 tmpType = tmpType.getParentType();
237             }
238         }
239 
240         final Set<Type> common = new LinkedHashSet<Type>();
241         if (!typeLists.isEmpty()) {
242             final Iterator<List<Type>> iterator = typeLists.iterator();
243             common.addAll(iterator.next());
244             while (iterator.hasNext()) {
245                 common.retainAll(iterator.next());
246             }
247         }
248         if (common.isEmpty()) {
249             throw new EFapsException(QueryBuilder.class, "noCommon", allType);
250         } else {
251             // first common type
252             this.typeUUID = common.iterator().next().getUUID();
253             for (final Type type : allType) {
254                 this.types.add(type.getUUID());
255             }
256         }
257         // special case handling
258         if (this.types.size() == 1 && this.types.iterator().next().equals(this.typeUUID)) {
259             this.types.clear();
260         }
261     }
262 
263     /**
264      * @param _ciAttr Name of the attribute
265      * @param _values    value to be included in the where
266      * @return QEqual
267      * @throws EFapsException on error
268      */
269     public QEqual addWhereAttrEqValue(final CIAttribute _ciAttr,
270                                       final Object... _values)
271         throws EFapsException
272     {
273         return addWhereAttrEqValue(_ciAttr.name, _values);
274     }
275 
276     /**
277      * @param _attrName Name of the attribute
278      * @param _values    value to be included in the where
279      * @return QEqual
280      * @throws EFapsException on error
281      */
282     public QEqual addWhereAttrEqValue(final String _attrName,
283                                       final Object... _values)
284         throws EFapsException
285     {
286         final QEqual equal = new QEqual(new QAttribute(_attrName));
287         this.compares.add(equal);
288         for (final Object value : _values) {
289             equal.addValue(getValue(value));
290         }
291         return equal;
292     }
293 
294     /**
295      * @param _select   Select statement
296      * @param _values   value to be included in the where
297      * @return QEqual
298      * @throws EFapsException on error
299      */
300     public QEqual addWhereSelectEqValue(final String _select,
301                                         final Object... _values)
302         throws EFapsException
303     {
304         final String attribute = getAttr4Select(_select);
305         final QueryBuilder queryBldr = getAttrQueryBuilder(_select);
306         final QEqual equal = new QEqual(new QAttribute(attribute));
307         queryBldr.getCompares().add(equal);
308         for (final Object value : _values) {
309             equal.addValue(getValue(value));
310         }
311         return equal;
312     }
313 
314     /**
315      * @param _attr     attribute
316      * @param _values   value to be included in the where
317      * @return QEqual
318      * @throws EFapsException on error
319      */
320     public QEqual addWhereAttrEqValue(final Attribute _attr,
321                                       final Object... _values)
322         throws EFapsException
323     {
324         final QEqual equal = new QEqual(new QAttribute(_attr));
325         this.compares.add(equal);
326         for (final Object value : _values) {
327             equal.addValue(getValue(value));
328         }
329         return equal;
330     }
331 
332     /**
333      * @param _ciAttr Name of the attribute
334      * @param _values    value to be included in the where
335      * @return QEqual
336      * @throws EFapsException on error
337      */
338     public QNotEqual addWhereAttrNotEqValue(final CIAttribute _ciAttr,
339                                             final Object... _values)
340         throws EFapsException
341     {
342         return addWhereAttrNotEqValue(_ciAttr.name, _values);
343     }
344 
345     /**
346      * @param _attrName Name of the attribute
347      * @param _values    value to be included in the where
348      * @return QEqual
349      * @throws EFapsException on error
350      */
351     public QNotEqual addWhereAttrNotEqValue(final String _attrName,
352                                             final Object... _values)
353         throws EFapsException
354     {
355         final QNotEqual equal = new QNotEqual(new QAttribute(_attrName));
356         this.compares.add(equal);
357         for (final Object value : _values) {
358             equal.addValue(getValue(value));
359         }
360         return equal;
361     }
362 
363     /**
364      * @param _attr     attribute
365      * @param _values   value to be included in the where
366      * @return QEqual
367      * @throws EFapsException on error
368      */
369     public QNotEqual addWhereAttrNotEqValue(final Attribute _attr,
370                                             final Object... _values)
371         throws EFapsException
372     {
373         final QNotEqual equal = new QNotEqual(new QAttribute(_attr));
374         this.compares.add(equal);
375         for (final Object value : _values) {
376             equal.addValue(getValue(value));
377         }
378         return equal;
379     }
380 
381     /**
382      * @param _ciAttr   CIAttribute of the attribute
383      * @param _value    value to be included in the where
384      * @return QLess
385      * @throws EFapsException on error
386      */
387     public QLess addWhereAttrLessValue(final CIAttribute _ciAttr,
388                                        final Object _value)
389         throws EFapsException
390     {
391         return addWhereAttrLessValue(_ciAttr.name, _value);
392     }
393 
394     /**
395      * @param _attrName name of the attribute
396      * @param _value    value to be included in the where
397      * @return QLess
398      * @throws EFapsException on error
399      */
400     public QLess addWhereAttrLessValue(final String _attrName,
401                                        final Object _value)
402         throws EFapsException
403     {
404         final QLess ret = new QLess(new QAttribute(_attrName), getValue(_value));
405         this.compares.add(ret);
406         return ret;
407     }
408 
409     /**
410      * @param _attr     attribute
411      * @param _value    value to be included in the where
412      * @return QLess
413      * @throws EFapsException on error
414      */
415     public QLess addWhereAttrLessValue(final Attribute _attr,
416                                        final Object _value)
417         throws EFapsException
418     {
419         final QLess ret = new QLess(new QAttribute(_attr), getValue(_value));
420         this.compares.add(ret);
421         return ret;
422     }
423 
424     /**
425      * @param _select   Select statement
426      * @param _value    value to be included in the where
427      * @return QGreater
428      * @throws EFapsException on error
429      */
430     public QLess addWhereSelectLessValue(final String _select,
431                                          final Object _value)
432         throws EFapsException
433     {
434         final String attribute = getAttr4Select(_select);
435         final QueryBuilder queryBldr = getAttrQueryBuilder(_select);
436         final QLess ret = new QLess(new QAttribute(attribute), getValue(_value));
437         queryBldr.getCompares().add(ret);
438         return ret;
439     }
440 
441     /**
442      * @param _ciAttr   CIAttribute of the attribute
443      * @param _value    value to be included in the where
444      * @return QLess
445      * @throws EFapsException on error
446      */
447     public QGreater addWhereAttrGreaterValue(final CIAttribute _ciAttr,
448                                              final Object _value)
449         throws EFapsException
450     {
451         return addWhereAttrGreaterValue(_ciAttr.name, _value);
452     }
453 
454     /**
455      * @param _attrName name of the attribute
456      * @param _value    value to be included in the where
457      * @return QGreater
458      * @throws EFapsException on error
459      */
460     public QGreater addWhereAttrGreaterValue(final String _attrName,
461                                              final Object _value)
462         throws EFapsException
463     {
464         final QGreater ret = new QGreater(new QAttribute(_attrName), getValue(_value));
465         this.compares.add(ret);
466         return ret;
467     }
468 
469     /**
470      * @param _attr     attribute
471      * @param _value    value to be included in the where
472      * @return QGreater
473      * @throws EFapsException on error
474      */
475     public QGreater addWhereAttrGreaterValue(final Attribute _attr,
476                                              final Object _value)
477         throws EFapsException
478     {
479         final QGreater ret = new QGreater(new QAttribute(_attr), getValue(_value));
480         this.compares.add(ret);
481         return ret;
482     }
483 
484     /**
485      * @param _select   Select statement
486      * @param _value    value to be included in the where
487      * @return QGreater
488      * @throws EFapsException on error
489      */
490     public QGreater addWhereSelectGreaterValue(final String _select,
491                                                final Object _value)
492         throws EFapsException
493     {
494         final String attribute = getAttr4Select(_select);
495         final QueryBuilder queryBldr = getAttrQueryBuilder(_select);
496         final QGreater ret = new QGreater(new QAttribute(attribute), getValue(_value));
497         queryBldr.getCompares().add(ret);
498         return ret;
499     }
500 
501     /**
502      * @param _ciAttr   CIAttribute of the attribute
503      * @param _value    value to be included in the where
504      * @return QLess
505      * @throws EFapsException on error
506      */
507     public QMatch addWhereAttrMatchValue(final CIAttribute _ciAttr,
508                                          final Object _value)
509         throws EFapsException
510     {
511         return addWhereAttrMatchValue(_ciAttr.name, _value);
512     }
513 
514     /**
515      * @param _attr     attribute
516      * @param _value    value to be included in the where
517      * @return QMatch
518      * @throws EFapsException on error
519      */
520     public QMatch addWhereAttrMatchValue(final Attribute _attr,
521                                          final Object _value)
522         throws EFapsException
523     {
524         final QMatch ret = new QMatch(new QAttribute(_attr), getValue(_value));
525         this.compares.add(ret);
526         return ret;
527     }
528 
529     /**
530      * @param _attrName name of the attribute
531      * @param _value    value to be included in the where
532      * @return QMatch
533      * @throws EFapsException on error
534      */
535     public QMatch addWhereAttrMatchValue(final String _attrName,
536                                          final Object _value)
537         throws EFapsException
538     {
539         final QMatch ret = new QMatch(new QAttribute(_attrName), getValue(_value));
540         this.compares.add(ret);
541         return ret;
542     }
543 
544     /**
545      * @param _classes    value to be included in the where
546      * @return QClassEqual
547      * @throws EFapsException on error
548      */
549     public QClassEqual addWhereClassification(final Classification... _classes)
550         throws EFapsException
551     {
552         final QClassEqual ret = new QClassEqual();
553         for (final Classification clazz : _classes) {
554             ret.addValue(new QClassValue(clazz));
555         }
556         this.compares.add(ret);
557         return ret;
558     }
559 
560     /**
561      * @param _ciAttr Name of the attribute
562      * @param _query    the query
563      * @return QEqual
564      * @throws EFapsException on error
565      */
566     public QIn addWhereAttrInQuery(final CIAttribute _ciAttr,
567                                    final AttributeQuery _query)
568         throws EFapsException
569     {
570         return addWhereAttrInQuery(_ciAttr.name, _query);
571     }
572 
573     /**
574      * @param _attrName Name of the attribute
575      * @param _query    the query
576      * @return QEqual
577      * @throws EFapsException on error
578      */
579     public QIn addWhereAttrInQuery(final String _attrName,
580                                    final AttributeQuery _query)
581         throws EFapsException
582     {
583         final QIn in = new QIn(new QAttribute(_attrName), new QSQLValue(_query.getSQLStatement()));
584         this.compares.add(in);
585         return in;
586     }
587 
588     /**
589      * @param _attr     attribute
590      * @param _query    the query
591      * @return QEqual
592      * @throws EFapsException on error
593      */
594     public QIn addWhereAttrEqValue(final Attribute _attr,
595                                       final AttributeQuery _query)
596         throws EFapsException
597     {
598         final QIn in = new QIn(new QAttribute(_attr), new QSQLValue(_query.getSQLStatement()));
599         this.compares.add(in);
600         return in;
601     }
602 
603     /**
604      * @param _ciAttr Name of the attribute
605      * @param _query    the query
606      * @return QEqual
607      * @throws EFapsException on error
608      */
609     public QNotIn addWhereAttrNotInQuery(final CIAttribute _ciAttr,
610                                          final AttributeQuery _query)
611         throws EFapsException
612     {
613         return addWhereAttrNotInQuery(_ciAttr.name, _query);
614     }
615 
616     /**
617      * @param _attrName Name of the attribute
618      * @param _query    the query
619      * @return QEqual
620      * @throws EFapsException on error
621      */
622     public QNotIn addWhereAttrNotInQuery(final String _attrName,
623                                       final AttributeQuery _query)
624         throws EFapsException
625     {
626         final QNotIn in = new QNotIn(new QAttribute(_attrName), new QSQLValue(_query.getSQLStatement()));
627         this.compares.add(in);
628         return in;
629     }
630 
631     /**
632      * @param _attr     attribute
633      * @param _query    the query
634      * @return QEqual
635      * @throws EFapsException on error
636      */
637     public QNotIn addWhereAttrNotInQuery(final Attribute _attr,
638                                          final AttributeQuery _query)
639         throws EFapsException
640     {
641         final QNotIn in = new QNotIn(new QAttribute(_attr), new QSQLValue(_query.getSQLStatement()));
642         this.compares.add(in);
643         return in;
644     }
645 
646     /**
647      * @param _ciAttr Name of the attribute
648      * @return QEqual
649      * @throws EFapsException on error
650      */
651     public QIs addWhereAttrIsNull(final CIAttribute _ciAttr)
652         throws EFapsException
653     {
654         return addWhereAttrIsNull(_ciAttr.name);
655     }
656 
657 
658     /**
659      * @param _attrName Name of the attribute
660      * @return QEqual
661      * @throws EFapsException on error
662      */
663     public QIs addWhereAttrIsNull(final String _attrName)
664         throws EFapsException
665     {
666         final QIs in = new QIs(new QAttribute(_attrName), new QNullValue());
667         this.compares.add(in);
668         return in;
669     }
670 
671     /**
672      * @param _attr     attribute
673      * @return QEqual
674      * @throws EFapsException on error
675      */
676     public QIs addWhereAttrIsNull(final Attribute _attr)
677         throws EFapsException
678     {
679         final QIs in = new QIs(new QAttribute(_attr), new QNullValue());
680         this.compares.add(in);
681         return in;
682     }
683 
684     /**
685      * @param _ciAttr Name of the attribute
686      * @return QEqual
687      * @throws EFapsException on error
688      */
689     public QIsNot addWhereAttrNotIsNull(final CIAttribute _ciAttr)
690         throws EFapsException
691     {
692         return addWhereAttrNotIsNull(_ciAttr.name);
693     }
694 
695     /**
696      * @param _attrName Name of the attribute
697      * @return QEqual
698      * @throws EFapsException on error
699      */
700     public QIsNot addWhereAttrNotIsNull(final String _attrName)
701         throws EFapsException
702     {
703         final QIsNot in = new QIsNot(new QAttribute(_attrName), new QNullValue());
704         this.compares.add(in);
705         return in;
706     }
707 
708     /**
709      * @param _attr     attribute
710      * @return QEqual
711      * @throws EFapsException on error
712      */
713     public QIsNot addWhereAttrNotIsNull(final Attribute _attr)
714         throws EFapsException
715     {
716         final QIsNot in = new QIsNot(new QAttribute(_attr), new QNullValue());
717         this.compares.add(in);
718         return in;
719     }
720 
721     /**
722      * @param _ciAttr CIAttribute to be orderd by.
723      * @return QOrderBySection
724      */
725     public QOrderAsc addOrderByAttributeAsc(final CIAttribute _ciAttr)
726     {
727         return addOrderByAttributeAsc(_ciAttr.name);
728     }
729 
730     /**
731      * @param _attrName Name of the Attributes to be orderd by.
732      * @return QOrderBySection
733      */
734     public QOrderAsc addOrderByAttributeAsc(final String _attrName)
735     {
736         final QOrderAsc asc = new QOrderAsc(new QAttribute(_attrName));
737         this.orders.add(asc);
738         return asc;
739     }
740 
741     /**
742      * @param _attr Attribute to be orderd by.
743      * @return QOrderBySection
744      */
745     public QOrderAsc addOrderByAttributeAsc(final Attribute _attr)
746     {
747         final QOrderAsc asc = new QOrderAsc(new QAttribute(_attr));
748         this.orders.add(asc);
749         return asc;
750     }
751 
752     /**
753      * @param _ciAttr CIAttribute to be orderd by.
754      * @return QOrderBySection
755      */
756     public QOrderDesc addOrderByAttributeDesc(final CIAttribute _ciAttr)
757     {
758         return addOrderByAttributeDesc(_ciAttr.name);
759     }
760 
761     /**
762      * @param _attrName Name of the Attributes to be orderd by.
763      * @return QOrderBySection
764      */
765     public QOrderDesc addOrderByAttributeDesc(final String _attrName)
766     {
767         final QOrderDesc desc = new QOrderDesc(new QAttribute(_attrName));
768         this.orders.add(desc);
769         return desc;
770     }
771 
772     /**
773      * @param _attr Attribute to be orderd by.
774      * @return QOrderBySection
775      */
776     public QOrderDesc addOrderByAttributeDesc(final Attribute _attr)
777     {
778         final QOrderDesc desc = new QOrderDesc(new QAttribute(_attr));
779         this.orders.add(desc);
780         return desc;
781     }
782 
783     /**
784      * Get the QAbstractValue for a value.
785      * @param _value    value the QAbstractValue is wanted for
786      * @return  QAbstractValue
787      * @throws EFapsException on error
788      */
789     private AbstractQValue getValue(final Object _value)
790         throws EFapsException
791     {
792         AbstractQValue ret = null;
793         if (_value == null) {
794             ret = new QNullValue();
795         } else if (_value instanceof Number) {
796             ret = new QNumberValue((Number) _value);
797         } else if (_value instanceof String) {
798             ret = new QStringValue((String) _value);
799         } else if (_value instanceof DateTime) {
800             ret = new QDateTimeValue((DateTime) _value);
801         } else if (_value instanceof Boolean) {
802             ret = new QBooleanValue((Boolean) _value);
803         } else if (_value instanceof Status) {
804             ret = new QNumberValue(((Status) _value).getId());
805         } else if (_value instanceof Instance) {
806             if (!((Instance) _value).isValid()) {
807                 QueryBuilder.LOG.error("the given Instance was not valid and cannot be used as filter criteria",
808                                 _value);
809                 throw new EFapsException(QueryBuilder.class, "invalid Instance given");
810             }
811             ret = new QNumberValue(((Instance) _value).getId());
812         } else if (_value instanceof UoM) {
813             ret = new QNumberValue(((UoM) _value).getId());
814         } else if (_value instanceof IBitEnum) {
815             ret = new QBitValue((IBitEnum) _value);
816         } else if (_value instanceof IEnum) {
817             ret = new QNumberValue(((IEnum) _value).getInt());
818         } else if (_value instanceof AbstractQValue) {
819             ret = (AbstractQValue) _value;
820         } else {
821             throw new EFapsException(QueryBuilder.class, "notsuported");
822         }
823         return ret;
824     }
825 
826     /**
827      * Getter method for the instance variable {@link #or}.
828      *
829      * @return value of instance variable {@link #or}
830      */
831     public boolean isOr()
832     {
833         return this.or;
834     }
835 
836     /**
837      * Setter method for instance variable {@link #or}.
838      *
839      * @param _or value for instance variable {@link #or}
840      * @return this
841      */
842     public QueryBuilder setOr(final boolean _or)
843     {
844         this.or = _or;
845         return this;
846     }
847 
848     /**
849      * Getter method for the instance variable {@link #limit}.
850      *
851      * @return value of instance variable {@link #limit}
852      */
853     public int getLimit()
854     {
855         return this.limit;
856     }
857 
858     /**
859      * Setter method for instance variable {@link #limit}.
860      *
861      * @param _limit value for instance variable {@link #limit}
862      */
863     public void setLimit(final int _limit)
864     {
865         this.limit = _limit;
866     }
867 
868     /**
869      * Getter method for the instance variable {@link #typeUUID}.
870      *
871      * @return value of instance variable {@link #typeUUID}
872      */
873     public final UUID getTypeUUID()
874     {
875         return this.typeUUID;
876     }
877 
878     /**
879      * Get the base type.
880      *
881      * @return the basetype of this QueryBuilder
882      * @throws CacheReloadException on error
883      */
884     public final Type getType()
885         throws CacheReloadException
886     {
887         return Type.get(this.typeUUID);
888     }
889 
890     /**
891      * Get the constructed query.
892      * @return the query
893      */
894     public InstanceQuery getQuery()
895     {
896         if (this.query == null) {
897             try {
898                 this.query = new InstanceQuery(this.typeUUID);
899                 this.query.setIncludeChildTypes(isIncludeChildTypes());
900                 prepareQuery();
901             } catch (final EFapsException e) {
902                 QueryBuilder.LOG.error("Could not open InstanceQuery for uuid: {}", this.typeUUID);
903             }
904         }
905         return (InstanceQuery) this.query;
906     }
907 
908     /**
909      * Get the constructed query.
910      * @param _key key to the Query Cache
911      * @return the query
912      */
913     public CachedInstanceQuery getCachedQuery(final String _key)
914     {
915         if (this.query == null) {
916             try {
917                 this.query = new CachedInstanceQuery(_key, this.typeUUID);
918                 this.query.setIncludeChildTypes(isIncludeChildTypes());
919                 prepareQuery();
920             } catch (final EFapsException e) {
921                 QueryBuilder.LOG.error("Could not open InstanceQuery for uuid: {}", this.typeUUID);
922             }
923         }
924         return (CachedInstanceQuery) this.query;
925     }
926 
927     /**
928      * Get the constructed query.
929      * @return the query
930      */
931     public CachedInstanceQuery getCachedQuery4Request()
932     {
933         if (this.query == null) {
934             try {
935                 this.query = CachedInstanceQuery.get4Request(this.typeUUID);
936                 this.query.setIncludeChildTypes(isIncludeChildTypes());
937                 prepareQuery();
938             } catch (final EFapsException e) {
939                 QueryBuilder.LOG.error("Could not open InstanceQuery for uuid: {}", this.typeUUID);
940             }
941         }
942         return (CachedInstanceQuery) this.query;
943     }
944 
945     /**
946      * Method to get an Attribute Query.
947      * @param _attribute attribute the value is wanted for,
948      *        if null the id attribute will be used automatically
949      * @return Attribute Query
950      */
951     public AttributeQuery getAttributeQuery(final CIAttribute _attribute)
952     {
953         return this.getAttributeQuery(_attribute.name);
954     }
955 
956     /**
957      * Method to get an Attribute Query.
958      * @param _attributeName name of the attribute the value is wanted for,
959      *        if null the id attribute will be used automatically
960      * @return Attribute Query
961      */
962     public AttributeQuery getAttributeQuery(final String _attributeName)
963     {
964         if (this.query == null) {
965             try {
966                 this.query = new AttributeQuery(this.typeUUID, _attributeName);
967                 prepareQuery();
968             } catch (final EFapsException e) {
969                 QueryBuilder.LOG.error("Could not open AttributeQuery for uuid: {}", this.typeUUID);
970             }
971         }
972         return (AttributeQuery) this.query;
973     }
974 
975     /**
976      * Method to get an Attribute Query in case of a Select where criteria.
977      *
978      * @return Attribute Query
979      * @throws EFapsException on error
980      */
981     protected AttributeQuery getAttributeQuery()
982         throws EFapsException
983     {
984         AttributeQuery ret = this.getAttributeQuery((String) null);
985         // check if in the linkto chain is one before this one
986         if (!this.attrQueryBldrs.isEmpty()) {
987             final QueryBuilder queryBldr = this.attrQueryBldrs.values().iterator().next();
988             queryBldr.addWhereAttrInQuery(queryBldr.getLinkAttributeName(), ret);
989             ret = queryBldr.getAttributeQuery();
990         }
991         return ret;
992     }
993 
994     /**
995      * Prepare the Query.
996      * @throws EFapsException on error
997      */
998     private void prepareQuery()
999         throws EFapsException
1000     {
1001         for (final QueryBuilder queryBldr : this.attrQueryBldrs.values()) {
1002             final AttributeQuery attrQuery = queryBldr.getAttributeQuery();
1003             this.addWhereAttrInQuery(queryBldr.getLinkAttributeName(), attrQuery);
1004         }
1005 
1006         if (!this.types.isEmpty()) {
1007             // force the include
1008             this.query.setIncludeChildTypes(true);
1009             final Type baseType = Type.get(this.typeUUID);
1010             final QEqual eqPart = new QEqual(new QAttribute(baseType.getTypeAttribute()));
1011 
1012             for (final UUID type : this.types) {
1013                 eqPart.addValue(new QNumberValue(Type.get(type).getId()));
1014             }
1015             this.compares.add(eqPart);
1016         }
1017 
1018         if (!this.compares.isEmpty()) {
1019             final QAnd and = this.or ? new QOr() : new QAnd();
1020             for (final AbstractQAttrCompare compare : this.compares) {
1021                 and.addPart(compare);
1022             }
1023             this.query.setWhere(new QWhereSection(and));
1024         }
1025         if (!this.orders.isEmpty()) {
1026             final QOrderBySection orderBy = new QOrderBySection(
1027                             this.orders.toArray(new AbstractQPart[this.orders.size()]));
1028             this.query.setOrderBy(orderBy);
1029         }
1030         if (this.limit > 0) {
1031             this.query.setLimit(this.limit);
1032         }
1033     }
1034 
1035     /**
1036      * Method to get a MultiPrintQuery.
1037      * @return MultiPrintQuery based on the InstanceQuery
1038      * @throws EFapsException on error
1039      */
1040     public MultiPrintQuery getPrint()
1041         throws EFapsException
1042     {
1043         return new MultiPrintQuery(getQuery().execute());
1044     }
1045 
1046     /**
1047      * Method to get a CachedMultiPrintQuery.
1048      * @param _key key used for Caching
1049      * @return MultiPrintQuery based on the InstanceQuery
1050      * @throws EFapsException on error
1051      */
1052     public CachedMultiPrintQuery getCachedPrint(final String _key)
1053         throws EFapsException
1054     {
1055         return new CachedMultiPrintQuery(getCachedQuery(_key).execute(), _key);
1056     }
1057 
1058     /**
1059      * Method to get a CachedMultiPrintQuery.
1060      * @return MultiPrintQuery based on the InstanceQuery
1061      * @throws EFapsException on error
1062      */
1063     public CachedMultiPrintQuery getCachedPrint4Request()
1064         throws EFapsException
1065     {
1066         return CachedMultiPrintQuery.get4Request(getCachedQuery4Request().execute());
1067     }
1068 
1069     /**
1070      * Getter method for the instance variable {@link #includeChildTypes}.
1071      *
1072      * @return value of instance variable {@link #includeChildTypes}
1073      */
1074     public boolean isIncludeChildTypes()
1075     {
1076         return this.includeChildTypes;
1077     }
1078 
1079     /**
1080      * Setter method for instance variable {@link #includeChildTypes}.
1081      *
1082      * @param _includeChildTypes value for instance variable {@link #includeChildTypes}
1083      */
1084     public void setIncludeChildTypes(final boolean _includeChildTypes)
1085     {
1086         this.includeChildTypes = _includeChildTypes;
1087     }
1088 
1089     /**
1090      * @param _select select the attribute is wanted for
1091      * @return name of the attribute
1092      */
1093     protected String getAttr4Select(final String _select)
1094     {
1095         final Matcher matcher = ATTRPATTERN.matcher(_select);
1096         String ret = "";
1097         if (matcher.find()) {
1098             ret = matcher.group();
1099         }
1100         return ret;
1101     }
1102 
1103     /**
1104      * @param _select   select the QueryBuilder is wanted for
1105      * @return QueryBuilder
1106      * @throws CacheReloadException on error
1107      */
1108     protected QueryBuilder getAttrQueryBuilder(final String _select)
1109         throws CacheReloadException
1110     {
1111         final Matcher matcher = LINKTOPATTERN.matcher(_select);
1112         final List<String> linktos = new ArrayList<>();
1113         while (matcher.find()) {
1114             linktos.add(matcher.group());
1115         }
1116 
1117         if (!this.attrQueryBldrs.containsKey(linktos)) {
1118             Type currentType = Type.get(this.typeUUID);
1119             QueryBuilder queryBldr = this;
1120             for (final Iterator<String> iterator = linktos.iterator(); iterator.hasNext();) {
1121                 final String string = iterator.next();
1122                 currentType = currentType.getAttribute(string).getLink();
1123                 final QueryBuilder queryBldrTmp = new QueryBuilder(currentType);
1124                 queryBldrTmp.setLinkAttributeName(string);
1125                 queryBldr.getAttrQueryBldrs().put(linktos, queryBldrTmp);
1126                 queryBldr = queryBldrTmp;
1127             }
1128         }
1129         return this.attrQueryBldrs.get(linktos);
1130     }
1131 
1132     /**
1133      * Getter method for the instance variable {@link #compares}.
1134      *
1135      * @return value of instance variable {@link #compares}
1136      */
1137     protected List<AbstractQAttrCompare> getCompares()
1138     {
1139         return this.compares;
1140     }
1141 
1142     /**
1143      * Getter method for the instance variable {@link #attrQueryBldrs}.
1144      *
1145      * @return value of instance variable {@link #attrQueryBldrs}
1146      */
1147     protected Map<List<String>, QueryBuilder> getAttrQueryBldrs()
1148     {
1149         return this.attrQueryBldrs;
1150     }
1151 
1152     /**
1153      * Getter method for the instance variable {@link #linkAttributeName}.
1154      *
1155      * @return value of instance variable {@link #linkAttributeName}
1156      */
1157     protected String getLinkAttributeName()
1158     {
1159         return this.linkAttributeName;
1160     }
1161 
1162     /**
1163      * Setter method for instance variable {@link #linkAttributeName}.
1164      *
1165      * @param _linkAttributeName value for instance variable {@link #linkAttributeName}
1166      */
1167     protected void setLinkAttributeName(final String _linkAttributeName)
1168     {
1169         this.linkAttributeName = _linkAttributeName;
1170     }
1171 }