001    /**
002     * Copyright (c) 2000-2012 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.portal.dao.orm.jpa;
016    
017    import com.liferay.portal.kernel.dao.orm.ORMException;
018    import com.liferay.portal.kernel.dao.orm.SQLQuery;
019    import com.liferay.portal.kernel.dao.orm.Type;
020    import com.liferay.portal.kernel.util.ListUtil;
021    import com.liferay.portal.kernel.util.StringBundler;
022    import com.liferay.portal.kernel.util.StringPool;
023    import com.liferay.portal.kernel.util.UnmodifiableList;
024    
025    import java.lang.reflect.Field;
026    
027    import java.util.ArrayList;
028    import java.util.Collection;
029    import java.util.Collections;
030    import java.util.List;
031    import java.util.Map;
032    import java.util.concurrent.ConcurrentHashMap;
033    import java.util.regex.Pattern;
034    
035    /**
036     * @author Prashant Dighe
037     * @author Brian Wing Shun Chan
038     * @author Shuyang Zhou
039     */
040    public class SQLQueryImpl extends QueryImpl implements SQLQuery {
041    
042            public SQLQueryImpl(
043                    SessionImpl sessionImpl, String queryString, boolean strictName) {
044    
045                    super(sessionImpl, queryString, strictName);
046    
047                    sqlQuery = true;
048            }
049    
050            public SQLQuery addEntity(String alias, Class<?> entityClass) {
051                    String columnAliases = null;
052    
053                    try {
054                            String[] columnNames = _getColumns(entityClass);
055    
056                            if (columnNames.length == 0) {
057                                    columnAliases = StringPool.BLANK;
058                            }
059                            else {
060                                    StringBundler sb = new StringBundler(
061                                            columnNames.length * 4 - 1);
062    
063                                    int i = 0;
064    
065                                    for (String column : columnNames) {
066                                            sb.append(alias);
067                                            sb.append(StringPool.PERIOD);
068                                            sb.append(column);
069    
070                                            if ((i + 1) < columnNames.length) {
071                                                    sb.append(StringPool.COMMA_AND_SPACE);
072                                            }
073    
074                                            i++;
075                                    }
076    
077                                    columnAliases = sb.toString();
078                            }
079                    }
080                    catch (Exception e) {
081                            throw new ORMException(e.getMessage());
082                    }
083    
084                    String escapedAlias = Pattern.quote("{" + alias + ".*}");
085    
086                    queryString = queryString.replaceAll(escapedAlias, columnAliases);
087    
088                    this.entityClass = entityClass;
089    
090                    return this;
091            }
092    
093            public SQLQuery addScalar(String columnAlias, Type type) {
094                    columnAlias = columnAlias.toLowerCase();
095    
096                    String q = queryString.toLowerCase();
097    
098                    int fromIndex = q.indexOf("from");
099    
100                    if (fromIndex == -1) {
101                            return this;
102                    }
103    
104                    String selectExpression = q.substring(0, fromIndex);
105    
106                    String[] selectTokens = selectExpression.split(StringPool.COMMA);
107    
108                    for (int pos = 0; pos < selectTokens.length; pos++) {
109                            String s = selectTokens[pos];
110    
111                            if (s.indexOf(columnAlias) != -1) {
112                                    _scalars.add(pos);
113    
114                                    _scalarTypes.add(type);
115                            }
116                    }
117    
118                    return this;
119            }
120    
121            @Override
122            public List<?> list(boolean copy, boolean unmodifiable)
123                    throws ORMException {
124    
125                    try {
126                            List<?> list = sessionImpl.list(
127                                    queryString, positionalParameterMap, namedParameterMap,
128                                    strictName, firstResult, maxResults, flushModeType,
129                                    lockModeType, sqlQuery, entityClass);
130    
131                            if ((entityClass == null) && !list.isEmpty()) {
132                                    list = _transformList(list);
133                            }
134    
135                            if (unmodifiable) {
136                                    list = new UnmodifiableList<Object>(list);
137                            }
138                            else if (copy) {
139                                    list = ListUtil.copy(list);
140                            }
141    
142                            return list;
143                    }
144                    catch (Exception e) {
145                            throw ExceptionTranslator.translate(e);
146                    }
147            }
148    
149            @Override
150            public Object uniqueResult() throws ORMException {
151                    try {
152                            Object object = sessionImpl.uniqueResult(
153                                    queryString, positionalParameterMap, namedParameterMap,
154                                    strictName, firstResult, maxResults, flushModeType,
155                                    lockModeType, sqlQuery, entityClass);
156    
157                            if (object instanceof Collection<?>) {
158                                    Collection<Object> collection = (Collection<Object>)object;
159    
160                                    if (collection.size() == 1) {
161                                            object = collection.iterator().next();
162                                    }
163                            }
164    
165                            if (_scalars.size() == 1) {
166                                    object = _transformType(object, _scalarTypes.get(0));
167                            }
168    
169                            return object;
170                    }
171                    catch (Exception e) {
172                            throw ExceptionTranslator.translate(e);
173                    }
174            }
175    
176            private String[] _getColumns(Class<?> entityClass) throws Exception {
177                    String[] columns = _entityColumns.get(entityClass);
178    
179                    if (columns != null) {
180                            return columns;
181                    }
182    
183                    Field field = entityClass.getField("TABLE_COLUMNS");
184    
185                    Object[][] tableColumns = (Object[][])field.get(null);
186    
187                    columns = new String[tableColumns.length];
188    
189                    int i = 0;
190    
191                    for (Object[] row : tableColumns) {
192                            String name = (String)row[0];
193    
194                            columns[i++] = name.toUpperCase();
195                    }
196    
197                    _entityColumns.put(entityClass, columns);
198    
199                    return columns;
200            }
201    
202            private List<?> _transformList(List<?> list) throws Exception {
203                    if (!_scalars.isEmpty()) {
204                            Collections.sort(_scalars);
205    
206                            if (list.get(0) instanceof Collection<?>) {
207                                    List<Object> newList = new ArrayList<Object>();
208    
209                                    for (Collection<Object> collection :
210                                                    (List<Collection<Object>>)list) {
211    
212                                            Object[] array = collection.toArray();
213    
214                                            if (_scalars.size() > 1) {
215                                                    Object[] values = new Object[_scalars.size()];
216    
217                                                    for (int i = 0; i < _scalars.size(); i++) {
218                                                            values[i] = array[_scalars.get(i)];
219                                                    }
220    
221                                                    newList.add(values);
222                                            }
223                                            else {
224                                                    newList.add(array[_scalars.get(0)]);
225                                            }
226                                    }
227    
228                                    list = newList;
229                            }
230                            else if (list.get(0) instanceof Object[]) {
231                                    List<Object> newList = new ArrayList<Object>();
232    
233                                    for (Object[] array : (List<Object[]>)list) {
234                                            if (_scalars.size() > 1) {
235                                                    Object[] values = new Object[_scalars.size()];
236    
237                                                    for (int i = 0; i < _scalars.size(); i++) {
238                                                            values[i] = array[_scalars.get(i)];
239                                                    }
240    
241                                                    newList.add(values);
242                                            }
243                                            else {
244                                                    newList.add(array[_scalars.get(0)]);
245                                            }
246                                    }
247    
248                                    list = newList;
249                            }
250                            else if ((_scalars.size() == 1)) {
251                                    List<Object> newList = new ArrayList<Object>();
252    
253                                    for (Object value : list) {
254                                            value = _transformType(value, _scalarTypes.get(0));
255    
256                                            newList.add(value);
257                                    }
258    
259                                    list = newList;
260                            }
261                    }
262                    else if (list.get(0) instanceof Collection<?>) {
263                            List<Object> newList = new ArrayList<Object>();
264    
265                            for (Collection<Object> collection :
266                                            (List<Collection<Object>>)list) {
267    
268                                    if (collection.size() == 1) {
269                                            newList.add(collection.iterator().next());
270                                    }
271                                    else {
272                                            newList.add(collection.toArray());
273                                    }
274                            }
275    
276                            list = newList;
277                    }
278    
279                    return list;
280            }
281    
282            private Object _transformType(Object object, Type type) {
283                    Object result = object;
284    
285                    if (type.equals(Type.LONG)) {
286                            if (object instanceof Integer) {
287                                    result = new Long((((Integer)object).longValue()));
288                            }
289                    }
290                    else if (type.equals(Type.STRING)) {
291                            result = object.toString();
292                    }
293                    else {
294                            throw new UnsupportedOperationException(
295                                    "Type conversion from " + object.getClass().getName() + " to " +
296                                            type + " is not supported");
297                    }
298    
299                    return result;
300            }
301    
302            private static Map<Class<?>, String[]> _entityColumns =
303                    new ConcurrentHashMap<Class<?>, String[]>();
304    
305            private List<Integer> _scalars = new ArrayList<Integer>();
306            private List<Type> _scalarTypes = new ArrayList<Type>();
307    
308    }