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 Class<T> getModelClass() {
228                    return _modelClass;
229            }
230    
231            @Override
232            public Session openNewSession(Connection connection) throws ORMException {
233                    return _sessionFactory.openNewSession(connection);
234            }
235    
236            @Override
237            public Session openSession() throws ORMException {
238                    return _sessionFactory.openSession();
239            }
240    
241            @Override
242            public SystemException processException(Exception e) {
243                    if (!(e instanceof ORMException)) {
244                            _log.error("Caught unexpected exception " + e.getClass().getName());
245                    }
246    
247                    if (_log.isDebugEnabled()) {
248                            _log.debug(e, e);
249                    }
250    
251                    return new SystemException(e);
252            }
253    
254            @Override
255            public void registerListener(ModelListener<T> listener) {
256                    List<ModelListener<T>> listenersList = ListUtil.fromArray(listeners);
257    
258                    listenersList.add(listener);
259    
260                    listeners = listenersList.toArray(
261                            new ModelListener[listenersList.size()]);
262            }
263    
264            @Override
265            @SuppressWarnings("unused")
266            public T remove(Serializable primaryKey)
267                    throws NoSuchModelException, SystemException {
268    
269                    throw new UnsupportedOperationException();
270            }
271    
272            @Override
273            public T remove(T model) throws SystemException {
274                    if (model instanceof ModelWrapper) {
275                            ModelWrapper<T> modelWrapper = (ModelWrapper<T>)model;
276    
277                            model = modelWrapper.getWrappedModel();
278                    }
279    
280                    for (ModelListener<T> listener : listeners) {
281                            listener.onBeforeRemove(model);
282                    }
283    
284                    model = removeImpl(model);
285    
286                    for (ModelListener<T> listener : listeners) {
287                            listener.onAfterRemove(model);
288                    }
289    
290                    return model;
291            }
292    
293            @Override
294            public void setDataSource(DataSource dataSource) {
295                    _dataSource = dataSource;
296            }
297    
298            public void setSessionFactory(SessionFactory sessionFactory) {
299                    _sessionFactory = sessionFactory;
300                    _dialect = _sessionFactory.getDialect();
301                    _db = DBFactoryUtil.getDB(_dialect);
302            }
303    
304            @Override
305            public void unregisterListener(ModelListener<T> listener) {
306                    List<ModelListener<T>> listenersList = ListUtil.fromArray(listeners);
307    
308                    listenersList.remove(listener);
309    
310                    listeners = listenersList.toArray(
311                            new ModelListener[listenersList.size()]);
312            }
313    
314            @Override
315            public T update(T model) throws SystemException {
316                    if (model instanceof ModelWrapper) {
317                            ModelWrapper<T> modelWrapper = (ModelWrapper<T>)model;
318    
319                            model = modelWrapper.getWrappedModel();
320                    }
321    
322                    boolean isNew = model.isNew();
323    
324                    for (ModelListener<T> listener : listeners) {
325                            if (isNew) {
326                                    listener.onBeforeCreate(model);
327                            }
328                            else {
329                                    listener.onBeforeUpdate(model);
330                            }
331                    }
332    
333                    model = updateImpl(model);
334    
335                    for (ModelListener<T> listener : listeners) {
336                            if (isNew) {
337                                    listener.onAfterCreate(model);
338                            }
339                            else {
340                                    listener.onAfterUpdate(model);
341                            }
342                    }
343    
344                    return model;
345            }
346    
347            /**
348             * @deprecated As of 6.2.0, replaced by {@link #update(BaseModel)}}
349             */
350            @Override
351            public T update(T model, boolean merge) throws SystemException {
352                    if (model instanceof ModelWrapper) {
353                            ModelWrapper<T> modelWrapper = (ModelWrapper<T>)model;
354    
355                            model = modelWrapper.getWrappedModel();
356                    }
357    
358                    boolean isNew = model.isNew();
359    
360                    for (ModelListener<T> listener : listeners) {
361                            if (isNew) {
362                                    listener.onBeforeCreate(model);
363                            }
364                            else {
365                                    listener.onBeforeUpdate(model);
366                            }
367                    }
368    
369                    model = updateImpl(model, merge);
370    
371                    for (ModelListener<T> listener : listeners) {
372                            if (isNew) {
373                                    listener.onAfterCreate(model);
374                            }
375                            else {
376                                    listener.onAfterUpdate(model);
377                            }
378                    }
379    
380                    return model;
381            }
382    
383            /**
384             * @deprecated As of 6.2.0, replaced by {@link #update(BaseModel,
385             *             ServiceContext)}}
386             */
387            @Override
388            public T update(T model, boolean merge, ServiceContext serviceContext)
389                    throws SystemException {
390    
391                    return update(model, serviceContext);
392            }
393    
394            @Override
395            public T update(T model, ServiceContext serviceContext)
396                    throws SystemException {
397    
398                    try {
399                            ServiceContextThreadLocal.pushServiceContext(serviceContext);
400    
401                            update(model);
402    
403                            return model;
404                    }
405                    finally {
406                            ServiceContextThreadLocal.popServiceContext();
407                    }
408            }
409    
410            protected static String removeConjunction(String sql) {
411                    int pos = sql.indexOf(" AND ");
412    
413                    if (pos != -1) {
414                            sql = sql.substring(0, pos);
415                    }
416    
417                    return sql;
418            }
419    
420            protected void appendOrderByComparator(
421                    StringBundler query, String entityAlias,
422                    OrderByComparator orderByComparator) {
423    
424                    appendOrderByComparator(query, entityAlias, orderByComparator, false);
425            }
426    
427            protected void appendOrderByComparator(
428                    StringBundler query, String entityAlias,
429                    OrderByComparator orderByComparator, boolean sqlQuery) {
430    
431                    query.append(ORDER_BY_CLAUSE);
432    
433                    String[] orderByFields = orderByComparator.getOrderByFields();
434    
435                    for (int i = 0; i < orderByFields.length; i++) {
436                            query.append(entityAlias);
437                            query.append(orderByFields[i]);
438    
439                            if (sqlQuery) {
440                                    Set<String> badColumnNames = getBadColumnNames();
441    
442                                    if (badColumnNames.contains(orderByFields[i])) {
443                                            query.append(StringPool.UNDERLINE);
444                                    }
445                            }
446    
447                            if ((i + 1) < orderByFields.length) {
448                                    if (orderByComparator.isAscending(orderByFields[i])) {
449                                            query.append(ORDER_BY_ASC_HAS_NEXT);
450                                    }
451                                    else {
452                                            query.append(ORDER_BY_DESC_HAS_NEXT);
453                                    }
454                            }
455                            else {
456                                    if (orderByComparator.isAscending(orderByFields[i])) {
457                                            query.append(ORDER_BY_ASC);
458                                    }
459                                    else {
460                                            query.append(ORDER_BY_DESC);
461                                    }
462                            }
463                    }
464            }
465    
466            protected Set<String> getBadColumnNames() {
467                    return Collections.emptySet();
468            }
469    
470            protected ClassLoader getClassLoader() {
471                    Class<?> clazz = getClass();
472    
473                    return clazz.getClassLoader();
474            }
475    
476            /**
477             * Removes the model instance from the database. {@link #update(BaseModel,
478             * boolean)} depends on this method to implement the remove operation; it
479             * only notifies the model listeners.
480             *
481             * @param  model the model instance to remove
482             * @return the model instance that was removed
483             * @throws SystemException if a system exception occurred
484             */
485            protected T removeImpl(T model) throws SystemException {
486                    throw new UnsupportedOperationException();
487            }
488    
489            protected void setModelClass(Class<T> modelClass) {
490                    _modelClass = modelClass;
491            }
492    
493            /**
494             * Updates the model instance in the database or adds it if it does not yet
495             * exist. {@link #remove(BaseModel)} depends on this method to implement the
496             * update operation; it only notifies the model listeners.
497             *
498             * @param  model the model instance to update
499             * @return the model instance that was updated
500             * @throws SystemException if a system exception occurred
501             */
502            protected T updateImpl(T model) throws SystemException {
503                    throw new UnsupportedOperationException();
504            }
505    
506            /**
507             * @deprecated As of 6.2.0, replaced by {@link #updateImpl(BaseModel)}
508             */
509            protected T updateImpl(T model, boolean merge) throws SystemException {
510                    return updateImpl(model);
511            }
512    
513            protected static final Object[] FINDER_ARGS_EMPTY = new Object[0];
514    
515            protected static final String ORDER_BY_ASC = " ASC";
516    
517            protected static final String ORDER_BY_ASC_HAS_NEXT = " ASC, ";
518    
519            protected static final String ORDER_BY_CLAUSE = " ORDER BY ";
520    
521            protected static final String ORDER_BY_DESC = " DESC";
522    
523            protected static final String ORDER_BY_DESC_HAS_NEXT = " DESC, ";
524    
525            protected static final String WHERE_AND = " AND ";
526    
527            protected static final String WHERE_GREATER_THAN = " >= ? ";
528    
529            protected static final String WHERE_GREATER_THAN_HAS_NEXT = " >= ? AND ";
530    
531            protected static final String WHERE_LESSER_THAN = " <= ? ";
532    
533            protected static final String WHERE_LESSER_THAN_HAS_NEXT = " <= ? AND ";
534    
535            protected static final String WHERE_OR = " OR ";
536    
537            protected ModelListener<T>[] listeners = new ModelListener[0];
538    
539            private static Log _log = LogFactoryUtil.getLog(BasePersistenceImpl.class);
540    
541            private DataSource _dataSource;
542            private DB _db;
543            private Dialect _dialect;
544            private Class<T> _modelClass;
545            private SessionFactory _sessionFactory;
546    
547    }