001    /**
002     * Copyright (c) 2000-2013 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.util.Validator;
023    import com.liferay.portal.service.BaseLocalService;
024    
025    import java.lang.reflect.InvocationTargetException;
026    import java.lang.reflect.Method;
027    
028    import java.util.ArrayList;
029    import java.util.Collection;
030    import java.util.List;
031    
032    /**
033     * @author Brian Wing Shun Chan
034     */
035    public abstract class BaseActionableDynamicQuery
036            implements ActionableDynamicQuery {
037    
038            @Override
039            public void performActions() throws PortalException, SystemException {
040                    long count = doPerformCount();
041    
042                    if (count > _interval) {
043                            performActionsInMultipleIntervals();
044                    }
045                    else {
046                            performActionsInSingleInterval();
047                    }
048            }
049    
050            public void performActions(long startPrimaryKey, long endPrimaryKey)
051                    throws PortalException, SystemException {
052    
053                    DynamicQuery dynamicQuery = DynamicQueryFactoryUtil.forClass(
054                            _clazz, _classLoader);
055    
056                    Property property = PropertyFactoryUtil.forName(
057                            _primaryKeyPropertyName);
058    
059                    dynamicQuery.add(property.ge(startPrimaryKey));
060                    dynamicQuery.add(property.lt(endPrimaryKey));
061    
062                    addDefaultCriteria(dynamicQuery);
063    
064                    addCriteria(dynamicQuery);
065    
066                    List<Object> objects = (List<Object>)executeDynamicQuery(
067                            _dynamicQueryMethod, dynamicQuery);
068    
069                    for (Object object : objects) {
070                            performAction(object);
071                    }
072            }
073    
074            @Override
075            public long performCount() throws PortalException, SystemException {
076                    return doPerformCount();
077            }
078    
079            @Override
080            public void setBaseLocalService(BaseLocalService baseLocalService)
081                    throws SystemException {
082    
083                    _baseLocalService = baseLocalService;
084    
085                    Class<?> clazz = _baseLocalService.getClass();
086    
087                    try {
088                            _dynamicQueryMethod = clazz.getMethod(
089                                    "dynamicQuery", DynamicQuery.class);
090                            _dynamicQueryCountMethod = clazz.getMethod(
091                                    "dynamicQueryCount", DynamicQuery.class, Projection.class);
092                    }
093                    catch (NoSuchMethodException nsme) {
094                            throw new SystemException(nsme);
095                    }
096            }
097    
098            @Override
099            public void setClass(Class<?> clazz) {
100                    _clazz = clazz;
101            }
102    
103            @Override
104            public void setClassLoader(ClassLoader classLoader) {
105                    _classLoader = classLoader;
106            }
107    
108            @Override
109            public void setCompanyId(long companyId) {
110                    _companyId = companyId;
111            }
112    
113            @Override
114            public void setGroupId(long groupId) {
115                    _groupId = groupId;
116            }
117    
118            @Override
119            public void setGroupIdPropertyName(String groupIdPropertyName) {
120                    _groupIdPropertyName = groupIdPropertyName;
121            }
122    
123            @Override
124            public void setInterval(int interval) {
125                    _interval = interval;
126            }
127    
128            @Override
129            public void setPrimaryKeyPropertyName(String primaryKeyPropertyName) {
130                    _primaryKeyPropertyName = primaryKeyPropertyName;
131            }
132    
133            @Override
134            public void setSearchEngineId(String searchEngineId) {
135                    _searchEngineId = searchEngineId;
136            }
137    
138            protected void addCriteria(DynamicQuery dynamicQuery) {
139            }
140    
141            protected void addOrderCriteria(DynamicQuery dynamicQuery) {
142            }
143    
144            protected void addDefaultCriteria(DynamicQuery dynamicQuery) {
145                    if (_companyId > 0) {
146                            Property property = PropertyFactoryUtil.forName("companyId");
147    
148                            dynamicQuery.add(property.eq(_companyId));
149                    }
150    
151                    if (_groupId > 0) {
152                            Property property = PropertyFactoryUtil.forName(
153                                    _groupIdPropertyName);
154    
155                            dynamicQuery.add(property.eq(_groupId));
156                    }
157            }
158    
159            protected void addDocument(Document document) throws PortalException {
160                    if (_documents == null) {
161                            _documents = new ArrayList<Document>();
162                    }
163    
164                    _documents.add(document);
165    
166                    if (_documents.size() >= _interval) {
167                            indexInterval();
168                    }
169            }
170    
171            protected void addDocuments(Collection<Document> documents)
172                    throws PortalException {
173    
174                    if (_documents == null) {
175                            _documents = new ArrayList<Document>();
176                    }
177    
178                    _documents.addAll(documents);
179    
180                    if (_documents.size() >= _interval) {
181                            indexInterval();
182                    }
183            }
184    
185            protected long doPerformCount() throws PortalException, SystemException {
186                    DynamicQuery dynamicQuery = DynamicQueryFactoryUtil.forClass(
187                            _clazz, _classLoader);
188    
189                    addDefaultCriteria(dynamicQuery);
190    
191                    addCriteria(dynamicQuery);
192    
193                    return (Long)executeDynamicQuery(
194                            _dynamicQueryCountMethod, dynamicQuery, getCountProjection());
195            }
196    
197            protected Object executeDynamicQuery(
198                            Method dynamicQueryMethod, Object... arguments)
199                    throws PortalException, SystemException {
200    
201                    try {
202                            return dynamicQueryMethod.invoke(_baseLocalService, arguments);
203                    }
204                    catch (InvocationTargetException ite) {
205                            Throwable throwable = ite.getCause();
206    
207                            if (throwable instanceof PortalException) {
208                                    throw (PortalException)throwable;
209                            }
210                            else if (throwable instanceof SystemException) {
211                                    throw (SystemException)throwable;
212                            }
213    
214                            throw new SystemException(ite);
215                    }
216                    catch (Exception e) {
217                            throw new SystemException(e);
218                    }
219            }
220    
221            protected Projection getCountProjection() {
222                    return ProjectionFactoryUtil.rowCount();
223            }
224    
225            protected String getSearchEngineId() {
226                    return _searchEngineId;
227            }
228    
229            protected void indexInterval() throws PortalException {
230                    if ((_documents == null) || _documents.isEmpty()) {
231                            return;
232                    }
233    
234                    if (Validator.isNull(_searchEngineId)) {
235                            SearchEngineUtil.updateDocuments(
236                                    _companyId, new ArrayList<Document>(_documents));
237                    }
238                    else {
239                            SearchEngineUtil.updateDocuments(
240                                    _searchEngineId, _companyId,
241                                    new ArrayList<Document>(_documents));
242                    }
243    
244                    _documents.clear();
245            }
246    
247            @SuppressWarnings("unused")
248            protected void intervalCompleted(long startPrimaryKey, long endPrimaryKey)
249                    throws PortalException, SystemException {
250            }
251    
252            protected abstract void performAction(Object object)
253                    throws PortalException, SystemException;
254    
255            protected void performActionsInMultipleIntervals()
256                    throws PortalException, SystemException {
257    
258                    DynamicQuery dynamicQuery = DynamicQueryFactoryUtil.forClass(
259                            _clazz, _classLoader);
260    
261                    Projection minPrimaryKeyProjection = ProjectionFactoryUtil.min(
262                            _primaryKeyPropertyName);
263                    Projection maxPrimaryKeyProjection = ProjectionFactoryUtil.max(
264                            _primaryKeyPropertyName);
265    
266                    ProjectionList projectionList = ProjectionFactoryUtil.projectionList();
267    
268                    projectionList.add(minPrimaryKeyProjection);
269                    projectionList.add(maxPrimaryKeyProjection);
270    
271                    dynamicQuery.setProjection(projectionList);
272    
273                    addDefaultCriteria(dynamicQuery);
274    
275                    addCriteria(dynamicQuery);
276    
277                    addOrderCriteria(dynamicQuery);
278    
279                    List<Object[]> results = (List<Object[]>)executeDynamicQuery(
280                            _dynamicQueryMethod, dynamicQuery);
281    
282                    Object[] minAndMaxPrimaryKeys = results.get(0);
283    
284                    if ((minAndMaxPrimaryKeys[0] == null) ||
285                            (minAndMaxPrimaryKeys[1] == null)) {
286    
287                            return;
288                    }
289    
290                    long minPrimaryKey = (Long)minAndMaxPrimaryKeys[0];
291                    long maxPrimaryKey = (Long)minAndMaxPrimaryKeys[1];
292    
293                    long startPrimaryKey = minPrimaryKey;
294                    long endPrimaryKey = startPrimaryKey + _interval;
295    
296                    while (startPrimaryKey <= maxPrimaryKey) {
297                            performActions(startPrimaryKey, endPrimaryKey);
298    
299                            indexInterval();
300    
301                            intervalCompleted(startPrimaryKey, endPrimaryKey);
302    
303                            startPrimaryKey = endPrimaryKey;
304                            endPrimaryKey += _interval;
305                    }
306            }
307    
308            protected void performActionsInSingleInterval()
309                    throws PortalException, SystemException {
310    
311                    DynamicQuery dynamicQuery = DynamicQueryFactoryUtil.forClass(
312                            _clazz, _classLoader);
313    
314                    addDefaultCriteria(dynamicQuery);
315    
316                    addCriteria(dynamicQuery);
317    
318                    addOrderCriteria(dynamicQuery);
319    
320                    List<Object> objects = (List<Object>)executeDynamicQuery(
321                            _dynamicQueryMethod, dynamicQuery);
322    
323                    for (Object object : objects) {
324                            performAction(object);
325                    }
326    
327                    indexInterval();
328            }
329    
330            private BaseLocalService _baseLocalService;
331            private ClassLoader _classLoader;
332            private Class<?> _clazz;
333            private long _companyId;
334            private Collection<Document> _documents;
335            private Method _dynamicQueryCountMethod;
336            private Method _dynamicQueryMethod;
337            private long _groupId;
338            private String _groupIdPropertyName = "groupId";
339            private int _interval = Indexer.DEFAULT_INTERVAL;
340            private String _primaryKeyPropertyName;
341            private String _searchEngineId;
342    
343    }