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