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