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