001    /**
002     * Copyright (c) 2000-2013 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.service.persistence.impl;
016    
017    import com.liferay.portal.NoSuchModelException;
018    import com.liferay.portal.kernel.dao.db.DB;
019    import com.liferay.portal.kernel.dao.db.DBFactoryUtil;
020    import com.liferay.portal.kernel.dao.orm.Dialect;
021    import com.liferay.portal.kernel.dao.orm.DynamicQuery;
022    import com.liferay.portal.kernel.dao.orm.ORMException;
023    import com.liferay.portal.kernel.dao.orm.OrderFactoryUtil;
024    import com.liferay.portal.kernel.dao.orm.Projection;
025    import com.liferay.portal.kernel.dao.orm.ProjectionFactoryUtil;
026    import com.liferay.portal.kernel.dao.orm.Session;
027    import com.liferay.portal.kernel.dao.orm.SessionFactory;
028    import com.liferay.portal.kernel.exception.SystemException;
029    import com.liferay.portal.kernel.log.Log;
030    import com.liferay.portal.kernel.log.LogFactoryUtil;
031    import com.liferay.portal.kernel.util.ListUtil;
032    import com.liferay.portal.kernel.util.OrderByComparator;
033    import com.liferay.portal.kernel.util.StringBundler;
034    import com.liferay.portal.kernel.util.StringPool;
035    import com.liferay.portal.model.BaseModel;
036    import com.liferay.portal.model.ModelListener;
037    import com.liferay.portal.model.ModelWrapper;
038    import com.liferay.portal.service.ServiceContext;
039    import com.liferay.portal.service.ServiceContextThreadLocal;
040    import com.liferay.portal.service.persistence.BasePersistence;
041    
042    import java.io.Serializable;
043    
044    import java.sql.Connection;
045    
046    import java.util.Collections;
047    import java.util.List;
048    import java.util.Set;
049    
050    import javax.sql.DataSource;
051    
052    /**
053     * The base implementation for all persistence classes. This class should never
054     * need to be used directly.
055     *
056     * <p>
057     * Caching information and settings can be found in
058     * <code>portal.properties</code>
059     * </p>
060     *
061     * @author Brian Wing Shun Chan
062     * @author Shuyang Zhou
063     */
064    public class BasePersistenceImpl<T extends BaseModel<T>>
065            implements BasePersistence<T>, SessionFactory {
066    
067            public static final String COUNT_COLUMN_NAME = "COUNT_VALUE";
068    
069            @Override
070            public void clearCache() {
071            }
072    
073            @Override
074            public void clearCache(List<T> model) {
075            }
076    
077            @Override
078            public void clearCache(T model) {
079            }
080    
081            @Override
082            public void closeSession(Session session) {
083                    _sessionFactory.closeSession(session);
084            }
085    
086            @Override
087            public long countWithDynamicQuery(DynamicQuery dynamicQuery)
088                    throws SystemException {
089    
090                    return countWithDynamicQuery(
091                            dynamicQuery, ProjectionFactoryUtil.rowCount());
092            }
093    
094            @Override
095            public long countWithDynamicQuery(
096                            DynamicQuery dynamicQuery, Projection projection)
097                    throws SystemException {
098    
099                    if (projection == null) {
100                            projection = ProjectionFactoryUtil.rowCount();
101                    }
102    
103                    dynamicQuery.setProjection(projection);
104    
105                    List<Long> results = findWithDynamicQuery(dynamicQuery);
106    
107                    if (results.isEmpty()) {
108                            return 0;
109                    }
110                    else {
111                            return (results.get(0)).longValue();
112                    }
113            }
114    
115            @Override
116            @SuppressWarnings("unused")
117            public T fetchByPrimaryKey(Serializable primaryKey) throws SystemException {
118                    throw new UnsupportedOperationException();
119            }
120    
121            @Override
122            @SuppressWarnings("unused")
123            public T findByPrimaryKey(Serializable primaryKey)
124                    throws NoSuchModelException, SystemException {
125    
126                    throw new UnsupportedOperationException();
127            }
128    
129            @Override
130            @SuppressWarnings("rawtypes")
131            public List findWithDynamicQuery(DynamicQuery dynamicQuery)
132                    throws SystemException {
133    
134                    Session session = null;
135    
136                    try {
137                            session = openSession();
138    
139                            dynamicQuery.compile(session);
140    
141                            return dynamicQuery.list();
142                    }
143                    catch (Exception e) {
144                            throw processException(e);
145                    }
146                    finally {
147                            closeSession(session);
148                    }
149            }
150    
151            @Override
152            @SuppressWarnings("rawtypes")
153            public List findWithDynamicQuery(
154                            DynamicQuery dynamicQuery, int start, int end)
155                    throws SystemException {
156    
157                    Session session = null;
158    
159                    try {
160                            session = openSession();
161    
162                            dynamicQuery.setLimit(start, end);
163    
164                            dynamicQuery.compile(session);
165    
166                            return dynamicQuery.list();
167                    }
168                    catch (Exception e) {
169                            throw processException(e);
170                    }
171                    finally {
172                            closeSession(session);
173                    }
174            }
175    
176            @Override
177            @SuppressWarnings("rawtypes")
178            public List findWithDynamicQuery(
179                            DynamicQuery dynamicQuery, int start, int end,
180                            OrderByComparator orderByComparator)
181                    throws SystemException {
182    
183                    OrderFactoryUtil.addOrderByComparator(dynamicQuery, orderByComparator);
184    
185                    return findWithDynamicQuery(dynamicQuery, start, end);
186            }
187    
188            @Override
189            public void flush() throws SystemException {
190                    try {
191                            Session session = _sessionFactory.getCurrentSession();
192    
193                            if (session != null) {
194                                    session.flush();
195                            }
196                    }
197                    catch (Exception e) {
198                            throw processException(e);
199                    }
200            }
201    
202            @Override
203            public Session getCurrentSession() throws ORMException {
204                    return _sessionFactory.getCurrentSession();
205            }
206    
207            @Override
208            public DataSource getDataSource() {
209                    return _dataSource;
210            }
211    
212            public DB getDB() {
213                    return _db;
214            }
215    
216            @Override
217            public Dialect getDialect() {
218                    return _dialect;
219            }
220    
221            @Override
222            public ModelListener<T>[] getListeners() {
223                    return listeners;
224            }
225    
226            @Override
227            public Session openNewSession(Connection connection) throws ORMException {
228                    return _sessionFactory.openNewSession(connection);
229            }
230    
231            @Override
232            public Session openSession() throws ORMException {
233                    return _sessionFactory.openSession();
234            }
235    
236            @Override
237            public SystemException processException(Exception e) {
238                    if (!(e instanceof ORMException)) {
239                            _log.error("Caught unexpected exception " + e.getClass().getName());
240                    }
241    
242                    if (_log.isDebugEnabled()) {
243                            _log.debug(e, e);
244                    }
245    
246                    return new SystemException(e);
247            }
248    
249            @Override
250            public void registerListener(ModelListener<T> listener) {
251                    List<ModelListener<T>> listenersList = ListUtil.fromArray(listeners);
252    
253                    listenersList.add(listener);
254    
255                    listeners = listenersList.toArray(
256                            new ModelListener[listenersList.size()]);
257            }
258    
259            @Override
260            @SuppressWarnings("unused")
261            public T remove(Serializable primaryKey)
262                    throws NoSuchModelException, SystemException {
263    
264                    throw new UnsupportedOperationException();
265            }
266    
267            @Override
268            public T remove(T model) throws SystemException {
269                    if (model instanceof ModelWrapper) {
270                            ModelWrapper<T> modelWrapper = (ModelWrapper<T>)model;
271    
272                            model = modelWrapper.getWrappedModel();
273                    }
274    
275                    for (ModelListener<T> listener : listeners) {
276                            listener.onBeforeRemove(model);
277                    }
278    
279                    model = removeImpl(model);
280    
281                    for (ModelListener<T> listener : listeners) {
282                            listener.onAfterRemove(model);
283                    }
284    
285                    return model;
286            }
287    
288            @Override
289            public void setDataSource(DataSource dataSource) {
290                    _dataSource = dataSource;
291            }
292    
293            public void setSessionFactory(SessionFactory sessionFactory) {
294                    _sessionFactory = sessionFactory;
295                    _dialect = _sessionFactory.getDialect();
296                    _db = DBFactoryUtil.getDB(_dialect);
297            }
298    
299            @Override
300            public void unregisterListener(ModelListener<T> listener) {
301                    List<ModelListener<T>> listenersList = ListUtil.fromArray(listeners);
302    
303                    listenersList.remove(listener);
304    
305                    listeners = listenersList.toArray(
306                            new ModelListener[listenersList.size()]);
307            }
308    
309            @Override
310            public T update(T model) throws SystemException {
311                    if (model instanceof ModelWrapper) {
312                            ModelWrapper<T> modelWrapper = (ModelWrapper<T>)model;
313    
314                            model = modelWrapper.getWrappedModel();
315                    }
316    
317                    boolean isNew = model.isNew();
318    
319                    for (ModelListener<T> listener : listeners) {
320                            if (isNew) {
321                                    listener.onBeforeCreate(model);
322                            }
323                            else {
324                                    listener.onBeforeUpdate(model);
325                            }
326                    }
327    
328                    model = updateImpl(model);
329    
330                    for (ModelListener<T> listener : listeners) {
331                            if (isNew) {
332                                    listener.onAfterCreate(model);
333                            }
334                            else {
335                                    listener.onAfterUpdate(model);
336                            }
337                    }
338    
339                    return model;
340            }
341    
342            /**
343             * @deprecated As of 6.2.0, replaced by {@link #update(BaseModel)}}
344             */
345            @Override
346            public T update(T model, boolean merge) throws SystemException {
347                    if (model instanceof ModelWrapper) {
348                            ModelWrapper<T> modelWrapper = (ModelWrapper<T>)model;
349    
350                            model = modelWrapper.getWrappedModel();
351                    }
352    
353                    boolean isNew = model.isNew();
354    
355                    for (ModelListener<T> listener : listeners) {
356                            if (isNew) {
357                                    listener.onBeforeCreate(model);
358                            }
359                            else {
360                                    listener.onBeforeUpdate(model);
361                            }
362                    }
363    
364                    model = updateImpl(model, merge);
365    
366                    for (ModelListener<T> listener : listeners) {
367                            if (isNew) {
368                                    listener.onAfterCreate(model);
369                            }
370                            else {
371                                    listener.onAfterUpdate(model);
372                            }
373                    }
374    
375                    return model;
376            }
377    
378            /**
379             * @deprecated As of 6.2.0, replaced by {@link #update(BaseModel,
380             *             ServiceContext)}}
381             */
382            @Override
383            public T update(T model, boolean merge, ServiceContext serviceContext)
384                    throws SystemException {
385    
386                    return update(model, serviceContext);
387            }
388    
389            @Override
390            public T update(T model, ServiceContext serviceContext)
391                    throws SystemException {
392    
393                    try {
394                            ServiceContextThreadLocal.pushServiceContext(serviceContext);
395    
396                            update(model);
397    
398                            return model;
399                    }
400                    finally {
401                            ServiceContextThreadLocal.popServiceContext();
402                    }
403            }
404    
405            protected static String removeConjunction(String sql) {
406                    int pos = sql.indexOf(" AND ");
407    
408                    if (pos != -1) {
409                            sql = sql.substring(0, pos);
410                    }
411    
412                    return sql;
413            }
414    
415            protected void appendOrderByComparator(
416                    StringBundler query, String entityAlias,
417                    OrderByComparator orderByComparator) {
418    
419                    appendOrderByComparator(query, entityAlias, orderByComparator, false);
420            }
421    
422            protected void appendOrderByComparator(
423                    StringBundler query, String entityAlias,
424                    OrderByComparator orderByComparator, boolean sqlQuery) {
425    
426                    query.append(ORDER_BY_CLAUSE);
427    
428                    String[] orderByFields = orderByComparator.getOrderByFields();
429    
430                    for (int i = 0; i < orderByFields.length; i++) {
431                            query.append(entityAlias);
432                            query.append(orderByFields[i]);
433    
434                            if (sqlQuery) {
435                                    Set<String> badColumnNames = getBadColumnNames();
436    
437                                    if (badColumnNames.contains(orderByFields[i])) {
438                                            query.append(StringPool.UNDERLINE);
439                                    }
440                            }
441    
442                            if ((i + 1) < orderByFields.length) {
443                                    if (orderByComparator.isAscending(orderByFields[i])) {
444                                            query.append(ORDER_BY_ASC_HAS_NEXT);
445                                    }
446                                    else {
447                                            query.append(ORDER_BY_DESC_HAS_NEXT);
448                                    }
449                            }
450                            else {
451                                    if (orderByComparator.isAscending(orderByFields[i])) {
452                                            query.append(ORDER_BY_ASC);
453                                    }
454                                    else {
455                                            query.append(ORDER_BY_DESC);
456                                    }
457                            }
458                    }
459            }
460    
461            protected Set<String> getBadColumnNames() {
462                    return Collections.emptySet();
463            }
464    
465            protected ClassLoader getClassLoader() {
466                    Class<?> clazz = getClass();
467    
468                    return clazz.getClassLoader();
469            }
470    
471            /**
472             * Removes the model instance from the database. {@link #update(BaseModel,
473             * boolean)} depends on this method to implement the remove operation; it
474             * only notifies the model listeners.
475             *
476             * @param  model the model instance to remove
477             * @return the model instance that was removed
478             * @throws SystemException if a system exception occurred
479             */
480            protected T removeImpl(T model) throws SystemException {
481                    throw new UnsupportedOperationException();
482            }
483    
484            /**
485             * Updates the model instance in the database or adds it if it does not yet
486             * exist. {@link #remove(BaseModel)} depends on this method to implement the
487             * update operation; it only notifies the model listeners.
488             *
489             * @param  model the model instance to update
490             * @return the model instance that was updated
491             * @throws SystemException if a system exception occurred
492             */
493            protected T updateImpl(T model) throws SystemException {
494                    throw new UnsupportedOperationException();
495            }
496    
497            /**
498             * @deprecated As of 6.2.0, replaced by {@link #updateImpl(BaseModel)}
499             */
500            protected T updateImpl(T model, boolean merge) throws SystemException {
501                    return updateImpl(model);
502            }
503    
504            protected static final Object[] FINDER_ARGS_EMPTY = new Object[0];
505    
506            protected static final String ORDER_BY_ASC = " ASC";
507    
508            protected static final String ORDER_BY_ASC_HAS_NEXT = " ASC, ";
509    
510            protected static final String ORDER_BY_CLAUSE = " ORDER BY ";
511    
512            protected static final String ORDER_BY_DESC = " DESC";
513    
514            protected static final String ORDER_BY_DESC_HAS_NEXT = " DESC, ";
515    
516            protected static final String WHERE_AND = " AND ";
517    
518            protected static final String WHERE_GREATER_THAN = " >= ? ";
519    
520            protected static final String WHERE_GREATER_THAN_HAS_NEXT = " >= ? AND ";
521    
522            protected static final String WHERE_LESSER_THAN = " <= ? ";
523    
524            protected static final String WHERE_LESSER_THAN_HAS_NEXT = " <= ? AND ";
525    
526            protected static final String WHERE_OR = " OR ";
527    
528            protected ModelListener<T>[] listeners = new ModelListener[0];
529    
530            private static Log _log = LogFactoryUtil.getLog(BasePersistenceImpl.class);
531    
532            private DataSource _dataSource;
533            private DB _db;
534            private Dialect _dialect;
535            private SessionFactory _sessionFactory;
536    
537    }