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