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.kernel.dao.orm;
016    
017    import com.liferay.portal.kernel.concurrent.ThreadPoolExecutor;
018    import com.liferay.portal.kernel.exception.PortalException;
019    import com.liferay.portal.kernel.exception.SystemException;
020    import com.liferay.portal.kernel.executor.PortalExecutorManagerUtil;
021    import com.liferay.portal.kernel.search.Indexer;
022    import com.liferay.portal.kernel.transaction.Propagation;
023    import com.liferay.portal.kernel.transaction.TransactionAttribute;
024    import com.liferay.portal.kernel.transaction.TransactionInvokerUtil;
025    import com.liferay.portal.model.BaseModel;
026    import com.liferay.portal.service.BaseLocalService;
027    
028    import java.lang.reflect.InvocationTargetException;
029    import java.lang.reflect.Method;
030    
031    import java.util.ArrayList;
032    import java.util.List;
033    import java.util.concurrent.Callable;
034    import java.util.concurrent.Future;
035    
036    /**
037     * @author Brian Wing Shun Chan
038     * @author Shuyang Zhou
039     */
040    public class DefaultActionableDynamicQuery implements ActionableDynamicQuery {
041    
042            public static final TransactionAttribute REQUIRES_NEW_TRANSACTION_ATTRIBUTE;
043    
044            static {
045                    TransactionAttribute.Builder builder =
046                            new TransactionAttribute.Builder();
047    
048                    builder.setPropagation(Propagation.REQUIRES_NEW);
049                    builder.setRollbackForClasses(
050                            PortalException.class, SystemException.class);
051    
052                    REQUIRES_NEW_TRANSACTION_ATTRIBUTE = builder.build();
053            }
054    
055            @Override
056            public AddCriteriaMethod getAddCriteriaMethod() {
057                    return _addCriteriaMethod;
058            }
059    
060            @Override
061            public AddOrderCriteriaMethod getAddOrderCriteriaMethod() {
062                    return _addOrderCriteriaMethod;
063            }
064    
065            @Override
066            public PerformActionMethod<?> getPerformActionMethod() {
067                    return _performActionMethod;
068            }
069    
070            @Override
071            public PerformCountMethod getPerformCountMethod() {
072                    return _performCountMethod;
073            }
074    
075            @Override
076            public boolean isParallel() {
077                    return _parallel;
078            }
079    
080            @Override
081            public void performActions() throws PortalException {
082                    try {
083                            long previousPrimaryKey = -1;
084    
085                            while (true) {
086                                    long lastPrimaryKey = doPerformActions(previousPrimaryKey);
087    
088                                    if (lastPrimaryKey < 0) {
089                                            return;
090                                    }
091    
092                                    intervalCompleted(previousPrimaryKey, lastPrimaryKey);
093    
094                                    previousPrimaryKey = lastPrimaryKey;
095                            }
096                    }
097                    finally {
098                            actionsCompleted();
099                    }
100            }
101    
102            @Override
103            public long performCount() throws PortalException {
104                    if (_performCountMethod != null) {
105                            return _performCountMethod.performCount();
106                    }
107    
108                    DynamicQuery dynamicQuery = DynamicQueryFactoryUtil.forClass(
109                            _modelClass, _classLoader);
110    
111                    addDefaultCriteria(dynamicQuery);
112    
113                    addCriteria(dynamicQuery);
114    
115                    return (Long)executeDynamicQuery(
116                            _dynamicQueryCountMethod, dynamicQuery, getCountProjection());
117            }
118    
119            @Override
120            public void setAddCriteriaMethod(AddCriteriaMethod addCriteriaMethod) {
121                    _addCriteriaMethod = addCriteriaMethod;
122            }
123    
124            @Override
125            public void setAddOrderCriteriaMethod(
126                    AddOrderCriteriaMethod addOrderCriteriaMethod) {
127    
128                    _addOrderCriteriaMethod = addOrderCriteriaMethod;
129            }
130    
131            @Override
132            public void setBaseLocalService(BaseLocalService baseLocalService) {
133                    _baseLocalService = baseLocalService;
134    
135                    Class<?> clazz = _baseLocalService.getClass();
136    
137                    try {
138                            _dynamicQueryMethod = clazz.getMethod(
139                                    "dynamicQuery", DynamicQuery.class);
140                            _dynamicQueryCountMethod = clazz.getMethod(
141                                    "dynamicQueryCount", DynamicQuery.class, Projection.class);
142                    }
143                    catch (NoSuchMethodException nsme) {
144                            throw new SystemException(nsme);
145                    }
146            }
147    
148            /**
149             * @deprecated As of 7.0.0, replaced by {@link #setModelClass(Class)}
150             */
151            @Deprecated
152            @Override
153            public void setClass(Class<?> modelClass) {
154                    _modelClass = modelClass;
155            }
156    
157            @Override
158            public void setClassLoader(ClassLoader classLoader) {
159                    _classLoader = classLoader;
160            }
161    
162            @Override
163            public void setCompanyId(long companyId) {
164                    _companyId = companyId;
165            }
166    
167            @Override
168            public void setGroupId(long groupId) {
169                    _groupId = groupId;
170            }
171    
172            @Override
173            public void setGroupIdPropertyName(String groupIdPropertyName) {
174                    _groupIdPropertyName = groupIdPropertyName;
175            }
176    
177            @Override
178            public void setInterval(int interval) {
179                    _interval = interval;
180            }
181    
182            @Override
183            public void setModelClass(Class<?> modelClass) {
184                    _modelClass = modelClass;
185            }
186    
187            @Override
188            public void setParallel(boolean parallel) {
189                    _parallel = parallel;
190            }
191    
192            @Override
193            public void setPerformActionMethod(
194                    PerformActionMethod<?> performActionMethod) {
195    
196                    _performActionMethod = performActionMethod;
197            }
198    
199            @Override
200            public void setPerformCountMethod(PerformCountMethod performCountMethod) {
201                    _performCountMethod = performCountMethod;
202            }
203    
204            @Override
205            public void setPrimaryKeyPropertyName(String primaryKeyPropertyName) {
206                    _primaryKeyPropertyName = primaryKeyPropertyName;
207            }
208    
209            @Override
210            public void setTransactionAttribute(
211                    TransactionAttribute transactionAttribute) {
212    
213                    _transactionAttribute = transactionAttribute;
214            }
215    
216            /**
217             * @throws PortalException
218             */
219            protected void actionsCompleted() throws PortalException {
220            }
221    
222            protected void addCriteria(DynamicQuery dynamicQuery) {
223                    if (_addCriteriaMethod != null) {
224                            _addCriteriaMethod.addCriteria(dynamicQuery);
225                    }
226            }
227    
228            protected void addDefaultCriteria(DynamicQuery dynamicQuery) {
229                    if (_companyId > 0) {
230                            Property property = PropertyFactoryUtil.forName("companyId");
231    
232                            dynamicQuery.add(property.eq(_companyId));
233                    }
234    
235                    if (_groupId > 0) {
236                            Property property = PropertyFactoryUtil.forName(
237                                    _groupIdPropertyName);
238    
239                            dynamicQuery.add(property.eq(_groupId));
240                    }
241            }
242    
243            protected void addOrderCriteria(DynamicQuery dynamicQuery) {
244                    if (_addOrderCriteriaMethod != null) {
245                            _addOrderCriteriaMethod.addOrderCriteria(dynamicQuery);
246                    }
247                    else {
248                            dynamicQuery.addOrder(
249                                    OrderFactoryUtil.asc(_primaryKeyPropertyName));
250                    }
251            }
252    
253            protected long doPerformActions(long previousPrimaryKey)
254                    throws PortalException {
255    
256                    final DynamicQuery dynamicQuery = DynamicQueryFactoryUtil.forClass(
257                            _modelClass, _classLoader);
258    
259                    Property property = PropertyFactoryUtil.forName(
260                            _primaryKeyPropertyName);
261    
262                    dynamicQuery.add(property.gt(previousPrimaryKey));
263    
264                    dynamicQuery.setLimit(0, _interval);
265    
266                    addDefaultCriteria(dynamicQuery);
267    
268                    addCriteria(dynamicQuery);
269    
270                    addOrderCriteria(dynamicQuery);
271    
272                    Callable<Long> callable = new Callable<Long>() {
273    
274                            @Override
275                            public Long call() throws Exception {
276                                    List<Object> objects = (List<Object>)executeDynamicQuery(
277                                            _dynamicQueryMethod, dynamicQuery);
278    
279                                    if (objects.isEmpty()) {
280                                            return -1L;
281                                    }
282    
283                                    if (_parallel) {
284                                            List<Future<Void>> futures = new ArrayList<>(
285                                                    objects.size());
286    
287                                            for (final Object object : objects) {
288                                                    futures.add(
289                                                            _threadPoolExecutor.submit(
290                                                                    new Callable<Void>() {
291    
292                                                                            @Override
293                                                                            public Void call() throws PortalException {
294                                                                                    performAction(object);
295    
296                                                                                    return null;
297                                                                            }
298    
299                                                                    }));
300                                            }
301    
302                                            for (Future<Void> future : futures) {
303                                                    future.get();
304                                            }
305                                    }
306                                    else {
307                                            for (Object object : objects) {
308                                                    performAction(object);
309                                            }
310                                    }
311    
312                                    if (objects.size() < _interval) {
313                                            return -1L;
314                                    }
315    
316                                    BaseModel<?> baseModel = (BaseModel<?>)objects.get(
317                                            objects.size() - 1);
318    
319                                    return (Long)baseModel.getPrimaryKeyObj();
320                            }
321    
322                    };
323    
324                    TransactionAttribute transactionAttribute = getTransactionAttribute();
325    
326                    try {
327                            if (transactionAttribute == null) {
328                                    return callable.call();
329                            }
330                            else {
331                                    return TransactionInvokerUtil.invoke(
332                                            transactionAttribute, callable);
333                            }
334                    }
335                    catch (Throwable t) {
336                            if (t instanceof PortalException) {
337                                    throw (PortalException)t;
338                            }
339    
340                            if (t instanceof SystemException) {
341                                    throw (SystemException)t;
342                            }
343    
344                            throw new SystemException(t);
345                    }
346            }
347    
348            protected Object executeDynamicQuery(
349                            Method dynamicQueryMethod, Object... arguments)
350                    throws PortalException {
351    
352                    try {
353                            return dynamicQueryMethod.invoke(_baseLocalService, arguments);
354                    }
355                    catch (InvocationTargetException ite) {
356                            Throwable throwable = ite.getCause();
357    
358                            if (throwable instanceof PortalException) {
359                                    throw (PortalException)throwable;
360                            }
361                            else if (throwable instanceof SystemException) {
362                                    throw (SystemException)throwable;
363                            }
364    
365                            throw new SystemException(ite);
366                    }
367                    catch (Exception e) {
368                            throw new SystemException(e);
369                    }
370            }
371    
372            protected long getCompanyId() {
373                    return _companyId;
374            }
375    
376            protected Projection getCountProjection() {
377                    return ProjectionFactoryUtil.rowCount();
378            }
379    
380            protected int getInterval() {
381                    return _interval;
382            }
383    
384            protected Class<?> getModelClass() {
385                    return _modelClass;
386            }
387    
388            protected TransactionAttribute getTransactionAttribute() {
389                    return _transactionAttribute;
390            }
391    
392            @SuppressWarnings("unused")
393            protected void intervalCompleted(long startPrimaryKey, long endPrimaryKey)
394                    throws PortalException {
395            }
396    
397            protected void performAction(Object object) throws PortalException {
398                    if (_performActionMethod != null) {
399                            _performActionMethod.performAction(object);
400                    }
401            }
402    
403            private AddCriteriaMethod _addCriteriaMethod;
404            private AddOrderCriteriaMethod _addOrderCriteriaMethod;
405            private BaseLocalService _baseLocalService;
406            private ClassLoader _classLoader;
407            private long _companyId;
408            private Method _dynamicQueryCountMethod;
409            private Method _dynamicQueryMethod;
410            private long _groupId;
411            private String _groupIdPropertyName = "groupId";
412            private int _interval = Indexer.DEFAULT_INTERVAL;
413            private Class<?> _modelClass;
414            private boolean _parallel;
415    
416            @SuppressWarnings("rawtypes")
417            private PerformActionMethod _performActionMethod;
418    
419            private PerformCountMethod _performCountMethod;
420            private String _primaryKeyPropertyName;
421            private final ThreadPoolExecutor _threadPoolExecutor =
422                    PortalExecutorManagerUtil.getPortalExecutor(
423                            DefaultActionableDynamicQuery.class.getName());
424            private TransactionAttribute _transactionAttribute;
425    
426    }