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