1   /*
2    * Copyright 2003 - 2014 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  package org.efaps.db.print;
22  
23  import java.sql.SQLException;
24  import java.util.ArrayList;
25  import java.util.Iterator;
26  import java.util.List;
27  import java.util.Map;
28  import java.util.regex.Matcher;
29  import java.util.regex.Pattern;
30  
31  import org.apache.commons.lang3.builder.ToStringBuilder;
32  import org.efaps.admin.datamodel.Attribute;
33  import org.efaps.admin.datamodel.AttributeSet;
34  import org.efaps.admin.datamodel.Type;
35  import org.efaps.db.AbstractPrintQuery;
36  import org.efaps.db.Instance;
37  import org.efaps.db.print.value.AbstractValueSelect;
38  import org.efaps.db.print.value.AttributeValueSelect;
39  import org.efaps.db.print.value.BaseValueSelect;
40  import org.efaps.db.print.value.ClassificationValueSelect;
41  import org.efaps.db.print.value.EsjpValueSelect;
42  import org.efaps.db.print.value.FormatValueSelect;
43  import org.efaps.db.print.value.IDValueSelect;
44  import org.efaps.db.print.value.InstanceValueSelect;
45  import org.efaps.db.print.value.KeyValueSelect;
46  import org.efaps.db.print.value.LabelValueSelect;
47  import org.efaps.db.print.value.LengthValueSelect;
48  import org.efaps.db.print.value.NameValueSelect;
49  import org.efaps.db.print.value.OIDValueSelect;
50  import org.efaps.db.print.value.StatusValueSelect;
51  import org.efaps.db.print.value.TypeValueSelect;
52  import org.efaps.db.print.value.UUIDValueSelect;
53  import org.efaps.db.print.value.UoMValueSelect;
54  import org.efaps.db.print.value.ValueValueSelect;
55  import org.efaps.db.wrapper.SQLSelect;
56  import org.efaps.util.EFapsException;
57  import org.efaps.util.cache.CacheReloadException;
58  import org.slf4j.Logger;
59  import org.slf4j.LoggerFactory;
60  
61  
62  /**
63   * This class is used as a part of one complete statement to be executed
64   * against the eFaps database. It will normally return the object for one
65   * attribute. The OneSelect can consist from only one attribute or of a
66   * series of PrintQuery.ISelectPart
67   *
68   * @author The eFaps Team
69   * @version $Id$
70   */
71  public class OneSelect
72  {
73      /**
74       * Logging instance used in this class.
75       */
76      private static final Logger LOG = LoggerFactory.getLogger(OneSelect.class);
77  
78      /**
79       * The select this OneSelect belongs to.
80       */
81      private final String selectStmt;
82  
83      /**
84       * List of select parts.
85       */
86      private final List<ISelectPart> selectParts = new ArrayList<ISelectPart>();
87  
88      /**
89       * FromSelect this OneSelect belong to.
90       */
91      private LinkFromSelect fromSelect;
92  
93      /**
94       * List of objects retrieved from the ResultSet returned
95       * from the eFaps database. It represent one row in a result set.
96       */
97      private final List<Object> objectList = new ArrayList<Object>();
98  
99  
100     /**
101      * List of ids retrieved from the ResultSet returned
102      * from the eFaps database. It represent one row in a result set.
103      */
104     private final List<Long> idList = new ArrayList<Long>();
105 
106     /**
107      * If this OneSelect is a FromSelect the relation Ids are stored in this
108      * List.
109      */
110     private final List<Long> relIdList = new ArrayList<Long>();
111 
112     /**
113      * table index for this table. It will finally contain the index of
114      * the table the attribute belongs to.
115      */
116     private int tableIndex;
117 
118     /**
119      * PrintQuery this ONeSelct belongs to.
120      */
121     private final AbstractPrintQuery query;
122 
123     /**
124      * Iterator for the objects.
125      */
126     private Iterator<Object> objectIterator;
127 
128     /**
129      * Iterator for the ids.
130      */
131     private Iterator<Long> idIterator;
132 
133     /**
134      * current id.
135      */
136     private Long currentId;
137 
138     /**
139      * Currecnt object.
140      */
141     private Object currentObject;
142 
143     /**
144      * Valueselect of this oneselect.
145      */
146     private AbstractValueSelect valueSelect;
147 
148     /**
149      * @param _query        PrintQuery this OneSelect belongs to
150      * @param _selectStmt selectStatement this OneSelect belongs to
151      */
152     public OneSelect(final AbstractPrintQuery _query,
153                      final String _selectStmt)
154     {
155         this.query = _query;
156         this.selectStmt = _selectStmt;
157     }
158 
159     /**
160      * @param _query    AbstractPrintQuery this OneSelect belongs to
161      * @param _attr     attribute to be used in this OneSelect
162      */
163     public OneSelect(final AbstractPrintQuery _query,
164                      final Attribute _attr)
165     {
166         this.query = _query;
167         this.selectStmt = null;
168         this.valueSelect =  new AttributeValueSelect(this, _attr);
169     }
170 
171     /**
172      * Getter method for instance variable {@link #valueSelect}.
173      *
174      * @return value of instance variable {@link #valueSelect}
175      */
176     public AbstractValueSelect getValueSelect()
177     {
178         return this.valueSelect;
179     }
180 
181     /**
182      * Setter method for instance variable {@link #valueSelect}.
183      *
184      * @param _valueSelect value for instance variable {@link #valueSelect}
185      */
186     public void setValueSelect(final AbstractValueSelect _valueSelect)
187     {
188         this.valueSelect = _valueSelect;
189     }
190 
191     /**
192      * Getter method for instance variable {@link #selectStmt}.
193      *
194      * @return value of instance variable {@link #selectStmt}
195      */
196     public String getSelectStmt()
197     {
198         return this.selectStmt;
199     }
200 
201     /**
202      * Getter method for instance variable {@link #selectParts}.
203      *
204      * @return value of instance variable {@link #selectParts}
205      */
206     public List<ISelectPart> getSelectParts()
207     {
208         return this.selectParts;
209     }
210 
211     /**
212      * Setter method for instance variable {@link #attribute}.
213      * @param _attribute Attribute to set
214      */
215     public void setAttribute(final Attribute _attribute)
216     {
217         this.valueSelect = new AttributeValueSelect(this, _attribute);
218     }
219 
220     /**
221      * Add an Object for this OneSelect.
222      *
223      * @param _row Objects from the eFaps database
224      * @throws SQLException on error
225      */
226     public void addObject(final Object[] _row)
227         throws SQLException
228     {
229         // store the ids also
230         this.idList.add((Long) _row[0]);
231 
232         if (getFromSelect() != null) {
233             final int column = "id".equals(this.valueSelect.getValueType())
234                             ? this.valueSelect.getColIndexs().get(0) : 2;
235             this.relIdList.add((Long) _row[column - 1]);
236         }
237         Object object = null;
238         AbstractValueSelect tmpValueSelect;
239         if (this.valueSelect == null) {
240             tmpValueSelect = this.fromSelect.getMainOneSelect().getValueSelect();
241         } else {
242             tmpValueSelect = this.valueSelect;
243         }
244         if (tmpValueSelect.getParentSelectPart() != null) {
245             tmpValueSelect.getParentSelectPart().addObject(_row);
246         }
247 
248         if (tmpValueSelect.getColIndexs().size() > 1) {
249             final Object[] objArray = new Object[tmpValueSelect.getColIndexs().size()];
250             int i = 0;
251             for (final Integer colIndex : tmpValueSelect.getColIndexs()) {
252                 objArray[i] = _row[colIndex - 1];
253                 i++;
254             }
255             object = objArray;
256         } else if (tmpValueSelect.getColIndexs().size() > 0) {
257             object = _row[tmpValueSelect.getColIndexs().get(0) - 1];
258         }
259         this.objectList.add(object);
260     }
261 
262     /**
263      * Add a classification name evaluated from an
264      * <code>class[CLASSIFICATIONNAME]</code> part of an select statement.
265      * @param _classificationName   name of the classification
266      * @throws CacheReloadException on error
267      */
268     public void addClassificationSelectPart(final String _classificationName)
269         throws CacheReloadException
270     {
271         this.selectParts.add(new ClassSelectPart(_classificationName));
272     }
273 
274     /**
275      * Add the name of the attribute the link must go to, evaluated from an
276      * <code>linkTo[ATTRIBUTENAME]</code> part of an select statement.
277      * @param _linkTo   name of the attribute the link must go to
278      */
279     public void addLinkToSelectPart(final String _linkTo)
280     {
281         Type type;
282         // if a previous select exists it is based on the previous select,
283         // else it is based on the basic table
284         if (this.selectParts.size() > 0) {
285             type = this.selectParts.get(this.selectParts.size() - 1).getType();
286         } else {
287             type = this.query.getMainType();
288         }
289         final LinkToSelectPart linkto = new LinkToSelectPart(_linkTo, type);
290         this.selectParts.add(linkto);
291     }
292 
293     /**
294      * Add the select part to connect the general store.
295      */
296     public void addFileSelectPart()
297     {
298         Type type;
299         // if a previous select exists it is based on the previous select,
300         // else it is based on the basic table
301         if (this.selectParts.size() > 0) {
302             type = this.selectParts.get(this.selectParts.size() - 1).getType();
303         } else {
304             type = this.query.getMainType();
305         }
306         final FileSelectPart linkto = new FileSelectPart(type);
307         this.selectParts.add(linkto);
308     }
309 
310     /**
311      * Add the select part to connect the general instances.
312      */
313     public void addGenInstSelectPart()
314     {
315         Type type;
316         // if a previous select exists it is based on the previous select,
317         // else it is based on the basic table
318         if (this.selectParts.size() > 0) {
319             type = this.selectParts.get(this.selectParts.size() - 1).getType();
320         } else {
321             type = this.query.getMainType();
322         }
323         final GenInstSelectPart linkto = new GenInstSelectPart(type);
324         this.selectParts.add(linkto);
325     }
326 
327     /**
328      * Add the name of the attribute the link must go to, evaluated from an
329      * <code>attributeSet[ATTRIBUTESETNAME]</code> part of an select statement.
330      * @param _attributeSet   name of the attribute the link must go to
331      */
332     public void addAttributeSetSelectPart(final String _attributeSet)
333     {
334         Type type;
335         // if a previous select exists it is based on the previous select,
336         // else it is based on the basic table
337         if (this.selectParts.size() > 0) {
338             type = this.selectParts.get(this.selectParts.size() - 1).getType();
339         } else {
340             type = this.query.getMainType();
341         }
342 
343         try {
344             final AttributeSet set = AttributeSet.find(type.getName(), _attributeSet);
345             final String linkFrom = set.getName() + "#" + set.getAttributeName();
346             this.fromSelect = new LinkFromSelect(linkFrom, getQuery().isCacheEnabled() ? getQuery().getKey() : null);
347         } catch (final CacheReloadException e) {
348             OneSelect.LOG.error("Could not find AttributeSet for Type: {}, attribute: {}", type.getName(),
349                             _attributeSet);
350         }
351     }
352 
353     /**
354      * Add the name of the type and attribute the link comes from,
355      * evaluated from an <code>linkTo[TYPENAME#ATTRIBUTENAME]</code>
356      * part of an select statement.
357      * @param _linkFrom   name of the attribute the link comes from
358      * @throws CacheReloadException on erro
359      */
360     public void addLinkFromSelectPart(final String _linkFrom)
361         throws CacheReloadException
362     {
363         this.fromSelect = new LinkFromSelect(_linkFrom, getQuery().isCacheEnabled() ? getQuery().getKey() : null);
364     }
365 
366     /**
367      * Method used to append to the from part of an SQL statement.
368      *
369      * @param _select   SQL select wrapper
370      * @throws EFapsException on error
371      */
372     public void append2SQLFrom(final SQLSelect _select)
373         throws EFapsException
374     {
375         // for attributes it must be evaluated if the attribute is inside a child table
376         if (this.valueSelect != null && "attribute".equals(this.valueSelect.getValueType())) {
377             Type type;
378             if (this.selectParts.size() > 0) {
379                 type = this.selectParts.get(this.selectParts.size() - 1).getType();
380             } else {
381                 type = this.query.getMainType();
382             }
383             Attribute attr = this.valueSelect.getAttribute();
384             if (attr == null) {
385                 attr = type.getAttribute(((AttributeValueSelect) this.valueSelect).getAttrName());
386             }
387             // if the attr is still null that means that the type does not have this attribute, so last
388             // chance to find the attribute is to search in the child types
389             if (attr == null) {
390                 for (final Type childType : type.getChildTypes()) {
391                     attr = childType.getAttribute(((AttributeValueSelect) this.valueSelect).getAttrName());
392                     if (attr != null) {
393                         ((AttributeValueSelect) this.valueSelect).setAttribute(attr);
394                         break;
395                     }
396                 }
397             }
398             if (attr != null && attr.getTable() != null && !attr.getTable().equals(type.getMainTable())) {
399                 final ChildTableSelectPart childtable = new ChildTableSelectPart(type, attr.getTable());
400                 this.selectParts.add(childtable);
401             }
402         }
403         for (final ISelectPart sel : this.selectParts) {
404             this.tableIndex = sel.join(this, _select, this.tableIndex);
405         }
406     }
407 
408     /**
409      * Method used to append to the select part of an SQL statement.
410      *
411      * @param _select       SQL select statement
412      * @param _colIndex     actual column index
413      * @return number of columns added in this part of the SQL statement
414      * @throws EFapsException on error
415      */
416     public int append2SQLSelect(final SQLSelect _select,
417                                 final int _colIndex)
418         throws EFapsException
419     {
420         Type type;
421         if (this.selectParts.size() > 0) {
422             type = this.selectParts.get(this.selectParts.size() - 1).getType();
423         } else {
424             type = this.query.getMainType();
425         }
426         int ret;
427         if (this.valueSelect == null) {
428             ret = this.fromSelect.getMainOneSelect().getValueSelect().append2SQLSelect(type, _select, this.tableIndex,
429                                                                                        _colIndex);
430         } else {
431             ret = this.valueSelect.append2SQLSelect(type, _select, this.tableIndex, _colIndex);
432         }
433 
434         return ret;
435     }
436 
437     /**
438      * Method used to append to the where part of an SQL statement.
439      *
440      * @param _select   SQL select wrapper
441      */
442     public void append2SQLWhere(final SQLSelect _select)
443     {
444         for (final ISelectPart part : this.selectParts) {
445             part.add2Where(this, _select);
446         }
447     }
448 
449     /**
450      * Method to analyse the select statement. Meaning the the different
451      * select parts will be added to {@link #selectParts}.
452      * @throws EFapsException on error
453      */
454     public void analyzeSelectStmt()
455         throws EFapsException
456     {
457         final Pattern mainPattern = Pattern.compile("[a-z]+\\[.+?\\]|[a-z]+");
458         final Pattern attrPattern = Pattern.compile("(?<=\\[)[0-9a-zA-Z_]*(?=\\])");
459         final Pattern esjpPattern = Pattern.compile("(?<=\\[)[\\w\\d\\s,.\"]*(?=\\])");
460         final Pattern linkfomPat = Pattern.compile("(?<=\\[)[0-9a-zA-Z_#:]*(?=\\])");
461         final Pattern formatPat = Pattern.compile("(?<=\\[).*(?=\\])");
462 
463         final Matcher mainMatcher = mainPattern.matcher(this.selectStmt);
464 
465         OneSelect currentSelect = this;
466         while (mainMatcher.find()) {
467             final String part = mainMatcher.group();
468             if (part.startsWith("class[")) {
469                 final Matcher matcher = attrPattern.matcher(part);
470                 if (matcher.find()) {
471                     currentSelect.addClassificationSelectPart(matcher.group());
472                 }
473             } else if (part.startsWith("linkto")) {
474                 final Matcher matcher = attrPattern.matcher(part);
475                 if (matcher.find()) {
476                     currentSelect.addLinkToSelectPart(matcher.group());
477                 }
478             } else if (part.startsWith("attributeset")) {
479                 final Matcher matcher = attrPattern.matcher(part);
480                 if (matcher.find()) {
481                     currentSelect.addValueSelect(new IDValueSelect(currentSelect));
482                     currentSelect.addAttributeSetSelectPart(matcher.group());
483                     currentSelect = currentSelect.fromSelect.getMainOneSelect();
484                 }
485             } else if (part.startsWith("attribute")) {
486                 final Matcher matcher = attrPattern.matcher(part);
487                 if (matcher.find()) {
488                     currentSelect.addValueSelect(new AttributeValueSelect(currentSelect, matcher.group()));
489                 }
490             } else if (part.startsWith("linkfrom")) {
491                 final Matcher matcher = linkfomPat.matcher(part);
492                 if (matcher.find()) {
493                     currentSelect.addValueSelect(new IDValueSelect(currentSelect));
494                     currentSelect.addLinkFromSelectPart(matcher.group());
495                     currentSelect = currentSelect.fromSelect.getMainOneSelect();
496                 }
497             } else if (part.startsWith("format")) {
498                 final Matcher matcher = formatPat.matcher(part);
499                 if (matcher.find()) {
500                     currentSelect.addValueSelect(new FormatValueSelect(currentSelect, matcher.group()));
501                 }
502             } else if (part.startsWith("esjp[")) {
503                 final Matcher matcher = esjpPattern.matcher(part);
504                 if (matcher.find()) {
505                     currentSelect.addValueSelect(new EsjpValueSelect(currentSelect, matcher.group()));
506                 }
507             } else
508                 switch (part) {
509                     case "oid":
510                         currentSelect.addValueSelect(new OIDValueSelect(currentSelect));
511                         break;
512                     case "type":
513                         currentSelect.addValueSelect(new TypeValueSelect(currentSelect));
514                         break;
515                     case "instance":
516                         currentSelect.addValueSelect(new InstanceValueSelect(currentSelect));
517                         break;
518                     case "label":
519                         currentSelect.addValueSelect(new LabelValueSelect(currentSelect));
520                         break;
521                     case "id":
522                         currentSelect.addValueSelect(new IDValueSelect(currentSelect));
523                         break;
524                     case "uuid":
525                         currentSelect.addValueSelect(new UUIDValueSelect(currentSelect));
526                         break;
527                     case "name":
528                         currentSelect.addValueSelect(new NameValueSelect(currentSelect));
529                         break;
530                     case "class":
531                         currentSelect.addValueSelect(new ClassificationValueSelect(currentSelect));
532                         break;
533                     case "value":
534                         currentSelect.addValueSelect(new ValueValueSelect(currentSelect));
535                         break;
536                     case "base":
537                         currentSelect.addValueSelect(new BaseValueSelect(currentSelect));
538                         break;
539                     case "uom":
540                         currentSelect.addValueSelect(new UoMValueSelect(currentSelect));
541                         break;
542                     case "file":
543                         currentSelect.addFileSelectPart();
544                         break;
545                     case "length":
546                         currentSelect.addValueSelect(new LengthValueSelect(currentSelect));
547                         break;
548                     case "status":
549                         currentSelect.addValueSelect(new StatusValueSelect(currentSelect));
550                         break;
551                     case "key":
552                         currentSelect.addValueSelect(new KeyValueSelect(currentSelect));
553                         break;
554                     default:
555                         break;
556                 }
557         }
558     }
559 
560     /**
561      * @param _valueSelect AbstractValueSelect to add
562      * @throws EFapsException on error
563      */
564     private void addValueSelect(final AbstractValueSelect _valueSelect)
565         throws EFapsException
566     {
567         if (this.valueSelect != null) {
568             this.valueSelect.addChildValueSelect(_valueSelect);
569         } else if (this.fromSelect != null && !(this.query instanceof LinkFromSelect)) {
570             this.fromSelect.getMainOneSelect().addValueSelect(_valueSelect);
571         } else {
572             this.valueSelect = _valueSelect;
573         }
574     }
575 
576     /**
577      * Get an object from a "n to 1" Relation.Therefore the given object
578      * is used to filter only the valid values from the by the Database
579      * returned objects.
580      * @param _object Object used as filter (must be an <code>Long</code> Id)
581      * @return  Object
582      * @throws EFapsException on error
583      */
584     private Object getObject(final Object _object)
585         throws EFapsException
586     {
587         final Object ret;
588         // inside a fromobject the correct value must be set
589         if (this.fromSelect != null && _object instanceof Number) {
590             final List<Object> tmpList = new ArrayList<Object>();
591             final Long id = ((Number) _object).longValue();
592             final Iterator<Long> relIter = this.relIdList.iterator();
593             final Iterator<Object> objIter = this.objectList.iterator();
594             while (relIter.hasNext()) {
595                 final Long rel = relIter.next();
596                 final Object obj = objIter.next();
597                 if (rel.equals(id)) {
598                     tmpList.add(obj);
599                 }
600             }
601             ret = this.valueSelect.getValue(tmpList);
602         } else {
603             ret = this.getObject();
604         }
605         return ret;
606     }
607 
608     /**
609      * Method to get the Object for this OneSelect.
610      * @return  object for this OneSelect
611      * @throws EFapsException on error
612      */
613     public Object getObject()
614         throws EFapsException
615     {
616         Object ret = null;
617         if (this.valueSelect == null) {
618             // if the fromSelect has data
619             if (this.fromSelect.hasResult()) {
620                 // and there are more than one id the current object must not be null
621                 if (this.idList.size() > 1 && this.currentObject != null) {
622                     ret = this.fromSelect.getMainOneSelect().getObject(this.currentObject);
623                 // or if there is only one id the first objectvalue must not be null
624                 } else if (this.idList.size() == 1 && this.objectList.get(0) != null) {
625                     ret = this.fromSelect.getMainOneSelect().getObject(this.currentObject);
626                 }
627             }
628         } else {
629             // if the currentObject is not null it means that the values are
630             // retrieved by iteration through the object list
631             if (this.currentId != null) {
632                 ret = this.valueSelect.getValue(this.currentObject);
633             } else {
634                 ret = this.valueSelect.getValue(this.objectList);
635             }
636         }
637         return ret;
638     }
639 
640     /**
641      * Method returns the instances this OneSelect has returned.
642      *
643      * @return Collection of Instances
644      * @throws EFapsException on error
645      */
646     @SuppressWarnings("unchecked")
647     public List<Instance> getInstances()
648         throws EFapsException
649     {
650         final List<Instance> ret = new ArrayList<Instance>();
651         // no value select means, that the from select must be asked
652         if (this.valueSelect == null) {
653             ret.addAll(this.fromSelect.getMainOneSelect().getInstances());
654         } else {
655             // if an oid select was given the oid is evaluated
656             if ("oid".equals(this.valueSelect.getValueType())) {
657                 for (final Object object : this.objectList) {
658                     final Instance inst = Instance.get((String) this.valueSelect.getValue(object));
659                     if (inst.isValid()) {
660                         ret.add(inst);
661                     }
662                 }
663             } else {
664                 List<Long> idTmp;
665                 if (this.valueSelect.getParentSelectPart() != null
666                                 && this.valueSelect.getParentSelectPart() instanceof LinkToSelectPart) {
667                     idTmp = (List<Long>) this.valueSelect.getParentSelectPart().getObject();
668                 } else {
669                     idTmp = this.idList;
670                 }
671                 for (final Long id : idTmp) {
672                     if (id != null) {
673                         ret.add(Instance.get(this.valueSelect.getAttribute().getParent(), String.valueOf(id)));
674                     }
675                 }
676             }
677         }
678         return ret;
679     }
680 
681     /**
682      * Getter method for instance variable {@link #attribute}.
683      *
684      * @return value of instance variable {@link #attribute}
685      */
686     public Attribute getAttribute()
687     {
688         Attribute ret;
689         if (this.valueSelect == null) {
690             ret = this.fromSelect.getMainOneSelect().getAttribute();
691         } else {
692             ret = this.valueSelect.getAttribute();
693         }
694         return ret;
695     }
696 
697     /**
698      * Getter method for instance variable {@link #fromSelect}.
699      *
700      * @return value of instance variable {@link #fromSelect}
701      */
702     public LinkFromSelect getFromSelect()
703     {
704         return this.fromSelect;
705     }
706 
707     /**
708      * Setter method for instance variable {@link #fromSelect}.
709      *
710      * @param _fromSelect value for instance variable {@link #fromSelect}
711      */
712     public void setFromSelect(final LinkFromSelect _fromSelect)
713     {
714         this.fromSelect = _fromSelect;
715     }
716 
717     /**
718      * Method to determine if this OneSelect does return more than one value.
719      * @param _object Object used as filter (must be an <code>Long</code> Id)
720      * @return true if more than one value is returned, else false
721      * @throws EFapsException on error
722      */
723     private boolean isMultiple(final Object _object)
724         throws EFapsException
725     {
726         boolean ret;
727         if (_object instanceof Long && this.fromSelect != null) {
728             final Object object = this.getObject(_object);
729             if (object instanceof List<?>) {
730                 ret = true;
731             } else {
732                 ret = false;
733             }
734         } else {
735             ret = this.isMultiple();
736         }
737         return ret;
738     }
739 
740     /**
741      * Method to determine if this OneSelect does return more than one value.
742      * @return true if more than one value is returned, else false
743      * @throws EFapsException on error
744      */
745     public boolean isMultiple()
746         throws EFapsException
747     {
748         boolean ret;
749         if (this.valueSelect == null) {
750             ret = this.fromSelect.getMainOneSelect().isMultiple(this.currentObject);
751         } else {
752             ret = this.objectList.size() > 1;
753         }
754         return ret;
755     }
756 
757     /**
758      * Get a new table index and add the table to the map of existing table
759      * indexes. The method calls in case that this OneSelect is related
760      * to a FromSelect the method
761      * {@link org.efaps.db.PrintQuery.FromSelect#getNewTableIndex(String, Integer)},
762      * else in PrintQuery the method
763      * {@link org.efaps.db.PrintQuery#getNewTableIndex(String, Integer)}.
764      *
765      * @param _tableName    tablename the index is wanted for
766      * @param _column       name of the column, used for the relation
767      * @param _relIndex     relation the table is used in
768      * @param _clazzId      optional id of the classification
769      * @return new index for the table
770      */
771     public Integer getNewTableIndex(final String _tableName,
772                                     final String _column,
773                                     final Integer _relIndex,
774                                     final Long _clazzId)
775     {
776         int ret;
777         if (this.valueSelect == null && this.fromSelect != null) {
778             ret = this.fromSelect.getNewTableIndex(_tableName, _column, _relIndex, _clazzId);
779         } else {
780             ret = this.query.getNewTableIndex(_tableName, _column, _relIndex, _clazzId);
781         }
782         return ret;
783     }
784 
785     /**
786      * Method to get an table index from {@link #sqlTable2Index}.
787      * Get a new table index and add the table to the map of existing table
788      * indexes. The method calls in case that this OneSelect is related
789      * to a FromSelect the method
790      * {@link org.efaps.db.PrintQuery.FromSelect#getTableIndex(String, Integer)},
791      * else in PrintQuery the method
792      * {@link org.efaps.db.PrintQuery#getTableIndex(String, Integer)}
793      * @param _tableName tablename the index is wanted for
794      * @param _column       name of the column, used for the relation
795      * @param _relIndex     relation the table is used in
796      * @param _clazzId      optional id of the classification
797      * @return index of the table or null if not found
798      */
799     public Integer getTableIndex(final String _tableName,
800                                  final String _column,
801                                  final int _relIndex,
802                                  final Long _clazzId)
803     {
804         Integer ret;
805         if (this.valueSelect == null && this.fromSelect != null) {
806             ret = this.fromSelect.getTableIndex(_tableName, _column, _relIndex, _clazzId);
807         } else {
808             ret = this.query.getTableIndex(_tableName, _column, _relIndex, _clazzId);
809         }
810         return ret;
811     }
812 
813     /**
814      * @return true if next, else false
815      * @throws EFapsException on error
816      */
817     public boolean next()
818         throws EFapsException
819     {
820         boolean ret = false;
821         if (this.objectIterator == null) {
822             this.objectIterator = this.objectList.iterator();
823         }
824         if (this.idIterator == null) {
825             this.idIterator = this.idList.iterator();
826         }
827         if (this.objectIterator.hasNext()) {
828             this.currentObject = this.objectIterator.next();
829             this.currentId = this.idIterator.next();
830             ret = true;
831             for (final ISelectPart part : getSelectParts()) {
832                 part.next();
833             }
834         }
835         return ret;
836     }
837 
838     /**
839      * Getter method for the instance variable {@link #query}.
840      *
841      * @return value of instance variable {@link #query}
842      */
843     public AbstractPrintQuery getQuery()
844     {
845         return this.query;
846     }
847 
848     /**
849      * Getter method for the instance variable {@link #objectList}.
850      *
851      * @return value of instance variable {@link #objectList}
852      */
853     public List<Object> getObjectList()
854     {
855         return this.objectList;
856     }
857 
858     /**
859      * Method sorts the object and idList.
860      * @param _targetList   list of instances
861      * @param _currentList  list if instances how it is sorted now
862      */
863     public void sortByInstanceList(final List<Instance> _targetList,
864                                    final Map<Instance, Integer> _currentList)
865     {
866         final List<Long> idListNew = new ArrayList<Long>();
867         final List<Object> objectListNew = new ArrayList<Object>();
868         for (final Instance instance : _targetList) {
869             if (_currentList.containsKey(instance)) {
870                 final Integer i = _currentList.get(instance);
871                 idListNew.add(this.idList.get(i));
872                 objectListNew.add(this.objectList.get(i));
873             }
874         }
875         this.idList.clear();
876         this.idList.addAll(idListNew);
877         this.objectList.clear();
878         this.objectList.addAll(objectListNew);
879     }
880 
881     @Override
882     public String toString()
883     {
884         return ToStringBuilder.reflectionToString(this);
885     }
886 }