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<Document>();
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 PerformActionMethod getPerformActionMethod() {
077                    return _performActionMethod;
078            }
079    
080            @Override
081            public PerformCountMethod getPerformCountMethod() {
082                    return _performCountMethod;
083            }
084    
085            @Override
086            public void performActions() throws PortalException {
087                    long previousPrimaryKey = -1;
088    
089                    while (true) {
090                            long lastPrimaryKey = doPerformActions(previousPrimaryKey);
091    
092                            if (lastPrimaryKey < 0) {
093                                    return;
094                            }
095    
096                            intervalCompleted(previousPrimaryKey, lastPrimaryKey);
097    
098                            previousPrimaryKey = lastPrimaryKey;
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                            _clazz, _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 setBaseLocalService(BaseLocalService baseLocalService) {
126                    _baseLocalService = baseLocalService;
127    
128                    Class<?> clazz = _baseLocalService.getClass();
129    
130                    try {
131                            _dynamicQueryMethod = clazz.getMethod(
132                                    "dynamicQuery", DynamicQuery.class);
133                            _dynamicQueryCountMethod = clazz.getMethod(
134                                    "dynamicQueryCount", DynamicQuery.class, Projection.class);
135                    }
136                    catch (NoSuchMethodException nsme) {
137                            throw new SystemException(nsme);
138                    }
139            }
140    
141            @Override
142            public void setClass(Class<?> clazz) {
143                    _clazz = clazz;
144            }
145    
146            @Override
147            public void setClassLoader(ClassLoader classLoader) {
148                    _classLoader = classLoader;
149            }
150    
151            @Override
152            public void setCommitImmediately(boolean commitImmediately) {
153                    _commitImmediately = commitImmediately;
154            }
155    
156            @Override
157            public void setCompanyId(long companyId) {
158                    _companyId = companyId;
159            }
160    
161            @Override
162            public void setGroupId(long groupId) {
163                    _groupId = groupId;
164            }
165    
166            @Override
167            public void setGroupIdPropertyName(String groupIdPropertyName) {
168                    _groupIdPropertyName = groupIdPropertyName;
169            }
170    
171            @Override
172            public void setInterval(int interval) {
173                    _interval = interval;
174            }
175    
176            @Override
177            public void setPerformActionMethod(
178                    PerformActionMethod performActionMethod) {
179    
180                    _performActionMethod = performActionMethod;
181            }
182    
183            @Override
184            public void setPerformCountMethod(PerformCountMethod performCountMethod) {
185                    _performCountMethod = performCountMethod;
186            }
187    
188            @Override
189            public void setPrimaryKeyPropertyName(String primaryKeyPropertyName) {
190                    _primaryKeyPropertyName = primaryKeyPropertyName;
191            }
192    
193            @Override
194            public void setSearchEngineId(String searchEngineId) {
195                    _searchEngineId = searchEngineId;
196            }
197    
198            @Override
199            public void setTransactionAttribute(
200                    TransactionAttribute transactionAttribute) {
201    
202                    _transactionAttribute = transactionAttribute;
203            }
204    
205            protected void addCriteria(DynamicQuery dynamicQuery) {
206                    if (_addCriteriaMethod != null) {
207                            _addCriteriaMethod.addCriteria(dynamicQuery);
208                    }
209            }
210    
211            protected void addDefaultCriteria(DynamicQuery dynamicQuery) {
212                    if (_companyId > 0) {
213                            Property property = PropertyFactoryUtil.forName("companyId");
214    
215                            dynamicQuery.add(property.eq(_companyId));
216                    }
217    
218                    if (_groupId > 0) {
219                            Property property = PropertyFactoryUtil.forName(
220                                    _groupIdPropertyName);
221    
222                            dynamicQuery.add(property.eq(_groupId));
223                    }
224            }
225    
226            protected void addDocuments(Collection<Document> documents)
227                    throws PortalException {
228    
229                    if (_documents == null) {
230                            _documents = new ArrayList<Document>();
231                    }
232    
233                    _documents.addAll(documents);
234    
235                    if (_documents.size() >= _interval) {
236                            indexInterval();
237                    }
238            }
239    
240            protected long doPerformActions(long previousPrimaryKey)
241                    throws PortalException {
242    
243                    final DynamicQuery dynamicQuery = DynamicQueryFactoryUtil.forClass(
244                            _clazz, _classLoader);
245    
246                    Property property = PropertyFactoryUtil.forName(
247                            _primaryKeyPropertyName);
248    
249                    dynamicQuery.add(property.gt(previousPrimaryKey));
250    
251                    dynamicQuery.addOrder(OrderFactoryUtil.asc(_primaryKeyPropertyName));
252    
253                    dynamicQuery.setLimit(0, _interval);
254    
255                    addDefaultCriteria(dynamicQuery);
256    
257                    addCriteria(dynamicQuery);
258    
259                    Callable<Long> callable = new Callable<Long>() {
260    
261                            @Override
262                            public Long call() throws Exception {
263                                    List<Object> objects = (List<Object>)executeDynamicQuery(
264                                            _dynamicQueryMethod, dynamicQuery);
265    
266                                    if (objects.isEmpty()) {
267                                            return -1L;
268                                    }
269    
270                                    for (Object object : objects) {
271                                            performAction(object);
272                                    }
273    
274                                    if (objects.size() < _interval) {
275                                            return -1L;
276                                    }
277    
278                                    BaseModel<?> baseModel = (BaseModel<?>)objects.get(
279                                            objects.size() - 1);
280    
281                                    return (Long)baseModel.getPrimaryKeyObj();
282                            }
283    
284                    };
285    
286                    TransactionAttribute transactionAttribute = getTransactionAttribute();
287    
288                    try {
289                            if (transactionAttribute == null) {
290                                    return callable.call();
291                            }
292                            else {
293                                    return TransactionInvokerUtil.invoke(
294                                            transactionAttribute, callable);
295                            }
296                    }
297                    catch (Throwable t) {
298                            if (t instanceof PortalException) {
299                                    throw (PortalException)t;
300                            }
301    
302                            if (t instanceof SystemException) {
303                                    throw (SystemException)t;
304                            }
305    
306                            throw new SystemException(t);
307                    }
308                    finally {
309                            indexInterval();
310                    }
311            }
312    
313            protected Object executeDynamicQuery(
314                            Method dynamicQueryMethod, Object... arguments)
315                    throws PortalException {
316    
317                    try {
318                            return dynamicQueryMethod.invoke(_baseLocalService, arguments);
319                    }
320                    catch (InvocationTargetException ite) {
321                            Throwable throwable = ite.getCause();
322    
323                            if (throwable instanceof PortalException) {
324                                    throw (PortalException)throwable;
325                            }
326                            else if (throwable instanceof SystemException) {
327                                    throw (SystemException)throwable;
328                            }
329    
330                            throw new SystemException(ite);
331                    }
332                    catch (Exception e) {
333                            throw new SystemException(e);
334                    }
335            }
336    
337            protected Projection getCountProjection() {
338                    return ProjectionFactoryUtil.rowCount();
339            }
340    
341            protected String getSearchEngineId() {
342                    return _searchEngineId;
343            }
344    
345            protected TransactionAttribute getTransactionAttribute() {
346                    return _transactionAttribute;
347            }
348    
349            protected void indexInterval() throws PortalException {
350                    if ((_documents == null) || _documents.isEmpty()) {
351                            return;
352                    }
353    
354                    if (Validator.isNull(_searchEngineId)) {
355                            _searchEngineId = SearchEngineUtil.getSearchEngineId(_documents);
356                    }
357    
358                    SearchEngineUtil.updateDocuments(
359                            _searchEngineId, _companyId, new ArrayList<Document>(_documents),
360                            _commitImmediately);
361    
362                    _documents.clear();
363            }
364    
365            @SuppressWarnings("unused")
366            protected void intervalCompleted(long startPrimaryKey, long endPrimaryKey)
367                    throws PortalException {
368            }
369    
370            protected void performAction(Object object) throws PortalException {
371                    if (_performActionMethod != null) {
372                            _performActionMethod.performAction(object);
373                    }
374            }
375    
376            private AddCriteriaMethod _addCriteriaMethod;
377            private BaseLocalService _baseLocalService;
378            private ClassLoader _classLoader;
379            private Class<?> _clazz;
380            private boolean _commitImmediately;
381            private long _companyId;
382            private Collection<Document> _documents;
383            private Method _dynamicQueryCountMethod;
384            private Method _dynamicQueryMethod;
385            private long _groupId;
386            private String _groupIdPropertyName = "groupId";
387            private int _interval = Indexer.DEFAULT_INTERVAL;
388            private PerformActionMethod _performActionMethod;
389            private PerformCountMethod _performCountMethod;
390            private String _primaryKeyPropertyName;
391            private String _searchEngineId;
392            private TransactionAttribute _transactionAttribute;
393    
394    }