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