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.sql.ResultSet;
25  import java.sql.SQLException;
26  import java.sql.Statement;
27  import java.util.ArrayList;
28  import java.util.List;
29  import java.util.Map.Entry;
30  import java.util.UUID;
31  
32  import org.efaps.admin.datamodel.Attribute;
33  import org.efaps.admin.datamodel.SQLTable;
34  import org.efaps.admin.datamodel.Type;
35  import org.efaps.db.transaction.ConnectionResource;
36  import org.efaps.db.wrapper.SQLSelect;
37  import org.efaps.util.EFapsException;
38  import org.efaps.util.cache.CacheReloadException;
39  
40  
41  /**
42   * Query is used as a nested query for an attribute.
43   *
44   * @author The eFaps Team
45   * @version $Id$
46   */
47  public class AttributeQuery
48      extends AbstractObjectQuery<Object>
49  {
50  
51      /**
52       * Attribute this query will return the value for.
53       */
54      private final Attribute attribute;
55  
56      /**
57       * Constructor setting the type by his UUID.
58       * @param _typeUUI UUID of the Type the query is based on
59       * @throws CacheReloadException on error
60       */
61      public AttributeQuery(final UUID _typeUUI)
62          throws CacheReloadException
63      {
64          this(Type.get(_typeUUI));
65      }
66  
67      /**
68       * Constructor setting the type.
69       *
70       * @param _type TYpe the query is based on
71       */
72      public AttributeQuery(final Type _type)
73      {
74          this(_type, _type.getAttribute("ID"));
75      }
76  
77      /**
78       * Constructor setting the type by his UUID.
79       *
80       * @param _typeUUI UUID of the Type the query is based on
81       * @param _attribute attribute the value is wanted for
82       * @throws CacheReloadException on error
83       */
84      public AttributeQuery(final UUID _typeUUI,
85                            final Attribute _attribute)
86          throws CacheReloadException
87      {
88          this(Type.get(_typeUUI), _attribute);
89      }
90  
91      /**
92       * Constructor setting the type by his UUID.
93       *
94       * @param _typeUUI UUID of the Type the query is based on
95       * @param _attributeName name of the attribute the value is wanted for
96       * @throws CacheReloadException on error
97       */
98      public AttributeQuery(final UUID _typeUUI,
99                            final String _attributeName)
100         throws CacheReloadException
101     {
102         this(Type.get(_typeUUI), Type.get(_typeUUI).getAttribute(_attributeName));
103     }
104 
105     /**
106      * Constructor setting the type.
107      * @param _type         TYpe the query is based on
108      * @param _attribute    attribute the value is wanted for
109      */
110     public AttributeQuery(final Type _type,
111                           final Attribute _attribute)
112     {
113         super(_type);
114         this.attribute = _attribute == null ?  _type.getAttribute("ID") : _attribute;
115     }
116 
117     /**
118      * Getter method for the instance variable {@link #attribute}.
119      *
120      * @return value of instance variable {@link #attribute}
121      */
122     public Attribute getAttribute()
123     {
124         return this.attribute;
125     }
126 
127     /**
128      * Execute the Query.
129      * @return this
130      * @throws EFapsException
131      * TODO Accesscheck
132      */
133     @Override
134     public List<Object> execute()
135         throws EFapsException
136     {
137         return executeWithoutAccessCheck();
138     }
139 
140     /**
141      * The instance method executes the query without an access check.
142      *
143      * @return true if the query contains values, else false
144      * @throws EFapsException on error
145      */
146     @Override
147     public List<Object> executeWithoutAccessCheck()
148         throws EFapsException
149     {
150         executeOneCompleteStmt(getSQLStatement());
151         return getValues();
152     }
153 
154     /**
155      * Create the SQL statement.
156      * @return StringBuilder containing the statement
157      * @throws EFapsException on error
158      */
159     public String getSQLStatement()
160         throws EFapsException
161     {
162         prepareQuery();
163         final SQLSelect select = new SQLSelect()
164             .column(getSqlTable2Index().get(this.attribute.getTable()), this.attribute.getSqlColNames().get(0))
165             .from(getBaseType().getMainTable().getSqlTable(), 0);
166 
167         // add child tables
168         if (getSqlTable2Index().size() > 0) {
169             for (final Entry<SQLTable, Integer> entry : getSqlTable2Index().entrySet()) {
170                 if (entry.getValue() > 0) {
171                     select.leftJoin(entry.getKey().getSqlTable(), entry.getValue(), "ID", 0, "ID");
172                 }
173             }
174         }
175         select.addSection(getWhere());
176         select.addSection(getOrderBy());
177         select.addSection(getLimit());
178 
179         if (AbstractObjectQuery.LOG.isDebugEnabled()) {
180             AbstractObjectQuery.LOG.debug(select.getSQL());
181         }
182         return select.getSQL();
183     }
184 
185     /**
186      * {@inheritDoc}
187      */
188     @Override
189     protected void prepareQuery()
190         throws EFapsException
191     {
192         super.prepareQuery();
193         // to be sure that the table the attribute is in, is part of the indexed tables
194         getIndex4SqlTable(this.attribute.getTable());
195     }
196 
197     /**
198      * Execute the actual statement against the database.
199      * @param _complStmt        Statment to be executed
200      * @return true if executed with success
201      * @throws EFapsException on error
202      */
203     protected boolean executeOneCompleteStmt(final String _complStmt)
204         throws EFapsException
205     {
206         final boolean ret = false;
207         ConnectionResource con = null;
208         try {
209             con = Context.getThreadContext().getConnectionResource();
210             if (AbstractObjectQuery.LOG.isDebugEnabled()) {
211                 AbstractObjectQuery.LOG.debug(_complStmt.toString());
212             }
213 
214             final Statement stmt = con.getConnection().createStatement();
215 
216             final ResultSet rs = stmt.executeQuery(_complStmt.toString());
217             new ArrayList<Instance>();
218             while (rs.next()) {
219                 getValues().add(rs.getObject(1));
220             }
221             rs.close();
222             stmt.close();
223             con.commit();
224         } catch (final SQLException e) {
225             throw new EFapsException(AttributeQuery.class, "executeOneCompleteStmt", e);
226         } finally {
227             if (con != null && con.isOpened()) {
228                 con.abort();
229             }
230         }
231         return ret;
232     }
233 }