001    /**
002     * Copyright (c) 2000-present 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.NullSafeStringComparator;
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.ModelListenerRegistrationUtil;
038    import com.liferay.portal.model.ModelWrapper;
039    import com.liferay.portal.service.ServiceContext;
040    import com.liferay.portal.service.ServiceContextThreadLocal;
041    import com.liferay.portal.service.persistence.BasePersistence;
042    
043    import java.io.Serializable;
044    
045    import java.sql.Connection;
046    
047    import java.util.Collections;
048    import java.util.Comparator;
049    import java.util.List;
050    import java.util.Map;
051    import java.util.Set;
052    
053    import javax.sql.DataSource;
054    
055    /**
056     * The base implementation for all persistence classes. This class should never
057     * need to be used directly.
058     *
059     * <p>
060     * Caching information and settings can be found in
061     * <code>portal.properties</code>
062     * </p>
063     *
064     * @author Brian Wing Shun Chan
065     * @author Shuyang Zhou
066     * @author Peter Fellwock
067     */
068    public class BasePersistenceImpl<T extends BaseModel<T>>
069            implements BasePersistence<T>, SessionFactory {
070    
071            public static final String COUNT_COLUMN_NAME = "COUNT_VALUE";
072    
073            @Override
074            public void clearCache() {
075            }
076    
077            @Override
078            public void clearCache(List<T> model) {
079            }
080    
081            @Override
082            public void clearCache(T model) {
083            }
084    
085            @Override
086            public void closeSession(Session session) {
087                    _sessionFactory.closeSession(session);
088            }
089    
090            @Override
091            public long countWithDynamicQuery(DynamicQuery dynamicQuery) {
092                    return countWithDynamicQuery(
093                            dynamicQuery, ProjectionFactoryUtil.rowCount());
094            }
095    
096            @Override
097            public long countWithDynamicQuery(
098                    DynamicQuery dynamicQuery, Projection projection) {
099    
100                    if (projection == null) {
101                            projection = ProjectionFactoryUtil.rowCount();
102                    }
103    
104                    dynamicQuery.setProjection(projection);
105    
106                    List<Long> results = findWithDynamicQuery(dynamicQuery);
107    
108                    if (results.isEmpty()) {
109                            return 0;
110                    }
111                    else {
112                            return (results.get(0)).longValue();
113                    }
114            }
115    
116            @Override
117            public T fetchByPrimaryKey(Serializable primaryKey) {
118                    throw new UnsupportedOperationException();
119            }
120    
121            @Override
122            public Map<Serializable, T> fetchByPrimaryKeys(
123                    Set<Serializable> primaryKeys) {
124    
125                    throw new UnsupportedOperationException();
126            }
127    
128            @Override
129            @SuppressWarnings("unused")
130            public T findByPrimaryKey(Serializable primaryKey)
131                    throws NoSuchModelException {
132    
133                    throw new UnsupportedOperationException();
134            }
135    
136            @Override
137            public <V> List<V> findWithDynamicQuery(DynamicQuery dynamicQuery) {
138                    Session session = null;
139    
140                    try {
141                            session = openSession();
142    
143                            dynamicQuery.compile(session);
144    
145                            return dynamicQuery.list();
146                    }
147                    catch (Exception e) {
148                            throw processException(e);
149                    }
150                    finally {
151                            closeSession(session);
152                    }
153            }
154    
155            @Override
156            public <V> List<V> findWithDynamicQuery(
157                    DynamicQuery dynamicQuery, int start, int end) {
158    
159                    Session session = null;
160    
161                    try {
162                            session = openSession();
163    
164                            dynamicQuery.setLimit(start, end);
165    
166                            dynamicQuery.compile(session);
167    
168                            return dynamicQuery.list();
169                    }
170                    catch (Exception e) {
171                            throw processException(e);
172                    }
173                    finally {
174                            closeSession(session);
175                    }
176            }
177    
178            @Override
179            public <V> List<V> findWithDynamicQuery(
180                    DynamicQuery dynamicQuery, int start, int end,
181                    OrderByComparator<V> orderByComparator) {
182    
183                    OrderFactoryUtil.addOrderByComparator(dynamicQuery, orderByComparator);
184    
185                    return findWithDynamicQuery(dynamicQuery, start, end);
186            }
187    
188            @Override
189            public void flush() {
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 ModelListenerRegistrationUtil.getModelListeners(getModelClass());
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                    ModelListenerRegistrationUtil.register(listener);
257            }
258    
259            @Override
260            @SuppressWarnings("unused")
261            public T remove(Serializable primaryKey) throws NoSuchModelException {
262                    throw new UnsupportedOperationException();
263            }
264    
265            @Override
266            public T remove(T model) {
267                    if (model instanceof ModelWrapper) {
268                            ModelWrapper<T> modelWrapper = (ModelWrapper<T>)model;
269    
270                            model = modelWrapper.getWrappedModel();
271                    }
272    
273                    ModelListener<T>[] listeners = getListeners();
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                    ModelListenerRegistrationUtil.unregister(listener);
302            }
303    
304            @Override
305            public T update(T model) {
306                    if (model instanceof ModelWrapper) {
307                            ModelWrapper<T> modelWrapper = (ModelWrapper<T>)model;
308    
309                            model = modelWrapper.getWrappedModel();
310                    }
311    
312                    boolean isNew = model.isNew();
313    
314                    ModelListener<T>[] listeners = getListeners();
315    
316                    for (ModelListener<T> listener : listeners) {
317                            if (isNew) {
318                                    listener.onBeforeCreate(model);
319                            }
320                            else {
321                                    listener.onBeforeUpdate(model);
322                            }
323                    }
324    
325                    model = updateImpl(model);
326    
327                    for (ModelListener<T> listener : listeners) {
328                            if (isNew) {
329                                    listener.onAfterCreate(model);
330                            }
331                            else {
332                                    listener.onAfterUpdate(model);
333                            }
334                    }
335    
336                    return model;
337            }
338    
339            /**
340             * @deprecated As of 6.2.0, replaced by {@link #update(BaseModel)}}
341             */
342            @Deprecated
343            @Override
344            public T update(T model, boolean merge) {
345                    if (model instanceof ModelWrapper) {
346                            ModelWrapper<T> modelWrapper = (ModelWrapper<T>)model;
347    
348                            model = modelWrapper.getWrappedModel();
349                    }
350    
351                    boolean isNew = model.isNew();
352    
353                    ModelListener<T>[] listeners = getListeners();
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            @Deprecated
383            @Override
384            public T update(T model, boolean merge, ServiceContext serviceContext) {
385                    return update(model, serviceContext);
386            }
387    
388            @Override
389            public T update(T model, ServiceContext serviceContext) {
390                    try {
391                            ServiceContextThreadLocal.pushServiceContext(serviceContext);
392    
393                            update(model);
394    
395                            return model;
396                    }
397                    finally {
398                            ServiceContextThreadLocal.popServiceContext();
399                    }
400            }
401    
402            protected static String removeConjunction(String sql) {
403                    int pos = sql.indexOf(" AND ");
404    
405                    if (pos != -1) {
406                            sql = sql.substring(0, pos);
407                    }
408    
409                    return sql;
410            }
411    
412            protected void appendOrderByComparator(
413                    StringBundler query, String entityAlias,
414                    OrderByComparator<T> orderByComparator) {
415    
416                    appendOrderByComparator(query, entityAlias, orderByComparator, false);
417            }
418    
419            protected void appendOrderByComparator(
420                    StringBundler query, String entityAlias,
421                    OrderByComparator<T> orderByComparator, boolean sqlQuery) {
422    
423                    query.append(ORDER_BY_CLAUSE);
424    
425                    String[] orderByFields = orderByComparator.getOrderByFields();
426    
427                    for (int i = 0; i < orderByFields.length; i++) {
428                            query.append(entityAlias);
429                            query.append(orderByFields[i]);
430    
431                            if (sqlQuery) {
432                                    Set<String> badColumnNames = getBadColumnNames();
433    
434                                    if (badColumnNames.contains(orderByFields[i])) {
435                                            query.append(StringPool.UNDERLINE);
436                                    }
437                            }
438    
439                            if ((i + 1) < orderByFields.length) {
440                                    if (orderByComparator.isAscending(orderByFields[i])) {
441                                            query.append(ORDER_BY_ASC_HAS_NEXT);
442                                    }
443                                    else {
444                                            query.append(ORDER_BY_DESC_HAS_NEXT);
445                                    }
446                            }
447                            else {
448                                    if (orderByComparator.isAscending(orderByFields[i])) {
449                                            query.append(ORDER_BY_ASC);
450                                    }
451                                    else {
452                                            query.append(ORDER_BY_DESC);
453                                    }
454                            }
455                    }
456            }
457    
458            protected Set<String> getBadColumnNames() {
459                    return Collections.emptySet();
460            }
461    
462            protected ClassLoader getClassLoader() {
463                    Class<?> clazz = getClass();
464    
465                    return clazz.getClassLoader();
466            }
467    
468            /**
469             * Removes the model instance from the database. {@link #update(BaseModel,
470             * boolean)} depends on this method to implement the remove operation; it
471             * only notifies the model listeners.
472             *
473             * @param  model the model instance to remove
474             * @return the model instance that was removed
475             */
476            protected T removeImpl(T model) {
477                    throw new UnsupportedOperationException();
478            }
479    
480            protected void setModelClass(Class<T> modelClass) {
481                    _modelClass = modelClass;
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             */
492            protected T updateImpl(T model) {
493                    throw new UnsupportedOperationException();
494            }
495    
496            /**
497             * @deprecated As of 6.2.0, replaced by {@link #updateImpl(BaseModel)}
498             */
499            @Deprecated
500            protected T updateImpl(T model, boolean merge) {
501                    return updateImpl(model);
502            }
503    
504            protected static final Object[] FINDER_ARGS_EMPTY = new Object[0];
505    
506            protected static final Comparator<String> NULL_SAFE_STRING_COMPARATOR =
507                    new NullSafeStringComparator();
508    
509            protected static final String ORDER_BY_ASC = " ASC";
510    
511            protected static final String ORDER_BY_ASC_HAS_NEXT = " ASC, ";
512    
513            protected static final String ORDER_BY_CLAUSE = " ORDER BY ";
514    
515            protected static final String ORDER_BY_DESC = " DESC";
516    
517            protected static final String ORDER_BY_DESC_HAS_NEXT = " DESC, ";
518    
519            protected static final String WHERE_AND = " AND ";
520    
521            protected static final String WHERE_GREATER_THAN = " >= ? ";
522    
523            protected static final String WHERE_GREATER_THAN_HAS_NEXT = " >= ? AND ";
524    
525            protected static final String WHERE_LESSER_THAN = " <= ? ";
526    
527            protected static final String WHERE_LESSER_THAN_HAS_NEXT = " <= ? AND ";
528    
529            protected static final String WHERE_OR = " OR ";
530    
531            /**
532             * @deprecated As of 7.0.0, with no direct replacement
533             */
534            @Deprecated
535            protected ModelListener<T>[] listeners = new ModelListener[0];
536    
537            private static final Log _log = LogFactoryUtil.getLog(
538                    BasePersistenceImpl.class);
539    
540            private DataSource _dataSource;
541            private DB _db;
542            private Dialect _dialect;
543            private Class<T> _modelClass;
544            private SessionFactory _sessionFactory;
545    
546    }