1   /**
2    * Copyright (c) 2000-2010 Liferay, Inc. All rights reserved.
3    *
4    * This library is free software; you can redistribute it and/or modify it under
5    * the terms of the GNU Lesser General Public License as published by the Free
6    * Software Foundation; either version 2.1 of the License, or (at your option)
7    * any later version.
8    *
9    * This library is distributed in the hope that it will be useful, but WITHOUT
10   * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
11   * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
12   * details.
13   */
14  
15  package com.liferay.portal.dao.orm.jpa;
16  
17  import com.liferay.portal.kernel.dao.orm.ORMException;
18  import com.liferay.portal.kernel.dao.orm.SQLQuery;
19  import com.liferay.portal.kernel.dao.orm.Type;
20  import com.liferay.portal.kernel.util.ListUtil;
21  import com.liferay.portal.kernel.util.StringBundler;
22  import com.liferay.portal.kernel.util.StringPool;
23  import com.liferay.portal.kernel.util.UnmodifiableList;
24  
25  import java.lang.reflect.Field;
26  
27  import java.util.ArrayList;
28  import java.util.Collection;
29  import java.util.Collections;
30  import java.util.List;
31  import java.util.Map;
32  import java.util.concurrent.ConcurrentHashMap;
33  import java.util.regex.Pattern;
34  
35  /**
36   * <a href="SQLQueryImpl.java.html"><b><i>View Source</i></b></a>
37   *
38   * @author Prashant Dighe
39   * @author Brian Wing Shun Chan
40   */
41  public class SQLQueryImpl extends QueryImpl implements SQLQuery {
42  
43      public SQLQueryImpl(SessionImpl sessionImpl, String queryString) {
44          super(sessionImpl, queryString);
45  
46          sqlQuery = true;
47      }
48  
49      public SQLQuery addEntity(String alias, Class<?> entityClass) {
50          String columnAliases = null;
51  
52          try {
53              String[] columnNames = _getColumns(entityClass);
54  
55              if (columnNames.length == 0) {
56                  columnAliases = StringPool.BLANK;
57              }
58              else {
59                  StringBundler sb = new StringBundler(
60                      columnNames.length * 4 - 1);
61  
62                  int i = 0;
63  
64                  for (String column : columnNames) {
65                      sb.append(alias);
66                      sb.append(StringPool.PERIOD);
67                      sb.append(column);
68  
69                      if ((i + 1) < columnNames.length) {
70                          sb.append(StringPool.COMMA_AND_SPACE);
71                      }
72  
73                      i++;
74                  }
75  
76                  columnAliases = sb.toString();
77              }
78          }
79          catch (Exception e) {
80              throw new ORMException(e.getMessage());
81          }
82  
83          String escapedAlias = Pattern.quote("{" + alias + ".*}");
84  
85          queryString = queryString.replaceAll(escapedAlias, columnAliases);
86  
87          this.entityClass = entityClass;
88  
89          return this;
90      }
91  
92      public SQLQuery addScalar(String columnAlias, Type type) {
93          columnAlias = columnAlias.toLowerCase();
94  
95          String q = queryString.toLowerCase();
96  
97          int fromIndex = q.indexOf("from");
98  
99          if (fromIndex == -1) {
100             return this;
101         }
102 
103         String selectExpression = q.substring(0, fromIndex);
104 
105         String[] selectTokens = selectExpression.split(StringPool.COMMA);
106 
107         for (int pos = 0; pos < selectTokens.length; pos++) {
108             String s = selectTokens[pos];
109 
110             if (s.indexOf(columnAlias) != -1) {
111                 _scalars.add(pos);
112 
113                 _scalarTypes.add(type);
114             }
115         }
116 
117         return this;
118     }
119 
120     public List<?> list(boolean unmodifiable) throws ORMException {
121         try {
122             List<?> list = sessionImpl.list(
123                 queryString, parameterMap, firstResult, maxResults,
124                 flushModeType, sqlQuery, entityClass);
125 
126             if ((entityClass == null) && !list.isEmpty()) {
127                 list = _transformList(list);
128             }
129 
130             if (unmodifiable) {
131                 return new UnmodifiableList<Object>(list);
132             }
133             else {
134                 return ListUtil.copy(list);
135             }
136         }
137         catch (Exception e) {
138             throw ExceptionTranslator.translate(e);
139         }
140     }
141 
142     public Object uniqueResult() throws ORMException {
143         try {
144             Object object =  sessionImpl.uniqueResult(
145                 queryString, parameterMap, firstResult, maxResults,
146                 flushModeType, sqlQuery, entityClass);
147 
148             if (object instanceof Collection<?>) {
149                 Collection<Object> collection = (Collection<Object>)object;
150 
151                 if (collection.size() == 1) {
152                     object = collection.iterator().next();
153                 }
154             }
155 
156             if (_scalars.size() == 1) {
157                 object = _transformType(object, _scalarTypes.get(0));
158             }
159 
160             return object;
161         }
162         catch (Exception e) {
163             throw ExceptionTranslator.translate(e);
164         }
165     }
166 
167     private String[] _getColumns(Class<?> entityClass) throws Exception {
168         String[] columns = _entityColumns.get(entityClass);
169 
170         if (columns != null) {
171             return columns;
172         }
173 
174         Field field = entityClass.getField("TABLE_COLUMNS");
175 
176         Object[][] tableColumns = (Object[][])field.get(null);
177 
178         columns = new String[tableColumns.length];
179 
180         int i = 0;
181 
182         for (Object[] row : tableColumns) {
183             String name = (String)row[0];
184 
185             columns[i++] = name.toUpperCase();
186         }
187 
188         _entityColumns.put(entityClass, columns);
189 
190         return columns;
191     }
192 
193     private List<?> _transformList(List<?> list) throws Exception {
194         if (!_scalars.isEmpty()) {
195             Collections.sort(_scalars);
196 
197             if (list.get(0) instanceof Collection<?>) {
198                 List<Object> newList = new ArrayList<Object>();
199 
200                 for (Collection<Object> collection :
201                         (List<Collection<Object>>)list) {
202 
203                     Object[] array = collection.toArray();
204 
205                     if (_scalars.size() > 1) {
206                         Object[] values = new Object[_scalars.size()];
207 
208                         for (int i = 0; i < _scalars.size(); i++) {
209                             values[i] = array[_scalars.get(i)];
210                         }
211 
212                         newList.add(values);
213                     }
214                     else {
215                         newList.add(array[_scalars.get(0)]);
216                     }
217                 }
218 
219                 list = newList;
220             }
221             else if (list.get(0) instanceof Object[]) {
222                 List<Object> newList = new ArrayList<Object>();
223 
224                 for (Object[] array : (List<Object[]>)list) {
225                     if (_scalars.size() > 1) {
226                         Object[] values = new Object[_scalars.size()];
227 
228                         for (int i = 0; i < _scalars.size(); i++) {
229                             values[i] = array[_scalars.get(i)];
230                         }
231 
232                         newList.add(values);
233                     }
234                     else {
235                         newList.add(array[_scalars.get(0)]);
236                     }
237                 }
238 
239                 list = newList;
240             }
241             else if ((_scalars.size() == 1)) {
242                 List<Object> newList = new ArrayList<Object>();
243 
244                 for (Object value : list) {
245                     value = _transformType(value, _scalarTypes.get(0));
246 
247                     newList.add(value);
248                 }
249 
250                 list = newList;
251             }
252         }
253         else if (list.get(0) instanceof Collection<?>) {
254             List<Object> newList = new ArrayList<Object>();
255 
256             for (Collection<Object> collection :
257                     (List<Collection<Object>>)list) {
258 
259                 if (collection.size() == 1) {
260                     newList.add(collection.iterator().next());
261                 }
262                 else {
263                     newList.add(collection.toArray());
264                 }
265             }
266 
267             list = newList;
268         }
269 
270         return list;
271     }
272 
273     private Object _transformType(Object object, Type type) {
274         Object result = object;
275 
276         if (type.equals(Type.LONG)) {
277             if (object instanceof Integer) {
278                 result = new Long((((Integer)object).longValue()));
279             }
280         }
281         else if (type.equals(Type.STRING)) {
282             result = object.toString();
283         }
284         else {
285             throw new UnsupportedOperationException(
286                 "Type conversion from " + object.getClass().getName() + " to " +
287                     type + " is not supported");
288         }
289 
290         return result;
291     }
292 
293     private static Map<Class<?>, String[]> _entityColumns =
294         new ConcurrentHashMap<Class<?>, String[]>();
295 
296     private List<Integer> _scalars = new ArrayList<Integer>();
297     private List<Type> _scalarTypes = new ArrayList<Type>();
298 
299 }