/**
* Copyright (c) 2000-present Liferay, Inc. All rights reserved.
*
* This library is free software; you can redistribute it and/or modify it under
* the terms of the GNU Lesser General Public License as published by the Free
* Software Foundation; either version 2.1 of the License, or (at your option)
* any later version.
*
* This library is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
* details.
*/
package com.liferay.portal.kernel.dao.orm;
import com.liferay.portal.kernel.concurrent.ThreadPoolExecutor;
import com.liferay.portal.kernel.exception.PortalException;
import com.liferay.portal.kernel.exception.SystemException;
import com.liferay.portal.kernel.executor.PortalExecutorManagerUtil;
import com.liferay.portal.kernel.model.BaseModel;
import com.liferay.portal.kernel.search.Indexer;
import com.liferay.portal.kernel.service.BaseLocalService;
import com.liferay.portal.kernel.transaction.Propagation;
import com.liferay.portal.kernel.transaction.TransactionConfig;
import com.liferay.portal.kernel.transaction.TransactionInvokerUtil;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.Callable;
import java.util.concurrent.Future;
/**
* @author Brian Wing Shun Chan
* @author Shuyang Zhou
*/
public class DefaultActionableDynamicQuery implements ActionableDynamicQuery {
public static final TransactionConfig REQUIRES_NEW_TRANSACTION_CONFIG;
static {
TransactionConfig.Builder builder = new TransactionConfig.Builder();
builder.setPropagation(Propagation.REQUIRES_NEW);
builder.setRollbackForClasses(
PortalException.class, SystemException.class);
REQUIRES_NEW_TRANSACTION_CONFIG = builder.build();
}
@Override
public AddCriteriaMethod getAddCriteriaMethod() {
return _addCriteriaMethod;
}
@Override
public AddOrderCriteriaMethod getAddOrderCriteriaMethod() {
return _addOrderCriteriaMethod;
}
@Override
public PerformActionMethod<?> getPerformActionMethod() {
return _performActionMethod;
}
@Override
public PerformCountMethod getPerformCountMethod() {
return _performCountMethod;
}
@Override
public boolean isParallel() {
return _parallel;
}
@Override
public void performActions() throws PortalException {
try {
long previousPrimaryKey = -1;
while (true) {
long lastPrimaryKey = doPerformActions(previousPrimaryKey);
if (lastPrimaryKey < 0) {
return;
}
intervalCompleted(previousPrimaryKey, lastPrimaryKey);
previousPrimaryKey = lastPrimaryKey;
}
}
finally {
actionsCompleted();
}
}
@Override
public long performCount() throws PortalException {
if (_performCountMethod != null) {
return _performCountMethod.performCount();
}
DynamicQuery dynamicQuery = DynamicQueryFactoryUtil.forClass(
_modelClass, _classLoader);
addDefaultCriteria(dynamicQuery);
addCriteria(dynamicQuery);
return (Long)executeDynamicQuery(
_dynamicQueryCountMethod, dynamicQuery, getCountProjection());
}
@Override
public void setAddCriteriaMethod(AddCriteriaMethod addCriteriaMethod) {
_addCriteriaMethod = addCriteriaMethod;
}
@Override
public void setAddOrderCriteriaMethod(
AddOrderCriteriaMethod addOrderCriteriaMethod) {
_addOrderCriteriaMethod = addOrderCriteriaMethod;
}
@Override
public void setBaseLocalService(BaseLocalService baseLocalService) {
_baseLocalService = baseLocalService;
Class<?> clazz = _baseLocalService.getClass();
try {
_dynamicQueryMethod = clazz.getMethod(
"dynamicQuery", DynamicQuery.class);
_dynamicQueryCountMethod = clazz.getMethod(
"dynamicQueryCount", DynamicQuery.class, Projection.class);
}
catch (NoSuchMethodException nsme) {
throw new SystemException(nsme);
}
}
/**
* @deprecated As of 7.0.0, replaced by {@link #setModelClass(Class)}
*/
@Deprecated
@Override
public void setClass(Class<?> modelClass) {
_modelClass = modelClass;
}
@Override
public void setClassLoader(ClassLoader classLoader) {
_classLoader = classLoader;
}
@Override
public void setCompanyId(long companyId) {
_companyId = companyId;
}
@Override
public void setGroupId(long groupId) {
_groupId = groupId;
}
@Override
public void setGroupIdPropertyName(String groupIdPropertyName) {
_groupIdPropertyName = groupIdPropertyName;
}
@Override
public void setInterval(int interval) {
_interval = interval;
}
@Override
public void setModelClass(Class<?> modelClass) {
_modelClass = modelClass;
}
@Override
public void setParallel(boolean parallel) {
_parallel = parallel;
}
@Override
public void setPerformActionMethod(
PerformActionMethod<?> performActionMethod) {
_performActionMethod = performActionMethod;
}
@Override
public void setPerformCountMethod(PerformCountMethod performCountMethod) {
_performCountMethod = performCountMethod;
}
@Override
public void setPrimaryKeyPropertyName(String primaryKeyPropertyName) {
_primaryKeyPropertyName = primaryKeyPropertyName;
}
@Override
public void setTransactionConfig(TransactionConfig transactionConfig) {
_transactionConfig = transactionConfig;
}
/**
* @throws PortalException
*/
protected void actionsCompleted() throws PortalException {
}
protected void addCriteria(DynamicQuery dynamicQuery) {
if (_addCriteriaMethod != null) {
_addCriteriaMethod.addCriteria(dynamicQuery);
}
}
protected void addDefaultCriteria(DynamicQuery dynamicQuery) {
if (_companyId > 0) {
Property property = PropertyFactoryUtil.forName("companyId");
dynamicQuery.add(property.eq(_companyId));
}
if (_groupId > 0) {
Property property = PropertyFactoryUtil.forName(
_groupIdPropertyName);
dynamicQuery.add(property.eq(_groupId));
}
}
protected void addOrderCriteria(DynamicQuery dynamicQuery) {
if (_addOrderCriteriaMethod != null) {
_addOrderCriteriaMethod.addOrderCriteria(dynamicQuery);
}
else {
dynamicQuery.addOrder(
OrderFactoryUtil.asc(_primaryKeyPropertyName));
}
}
protected long doPerformActions(long previousPrimaryKey)
throws PortalException {
final DynamicQuery dynamicQuery = DynamicQueryFactoryUtil.forClass(
_modelClass, _classLoader);
Property property = PropertyFactoryUtil.forName(
_primaryKeyPropertyName);
dynamicQuery.add(property.gt(previousPrimaryKey));
dynamicQuery.setLimit(0, _interval);
addDefaultCriteria(dynamicQuery);
addCriteria(dynamicQuery);
addOrderCriteria(dynamicQuery);
Callable<Long> callable = new Callable<Long>() {
@Override
public Long call() throws Exception {
List<Object> objects = (List<Object>)executeDynamicQuery(
_dynamicQueryMethod, dynamicQuery);
if (objects.isEmpty()) {
return -1L;
}
if (_parallel) {
List<Future<Void>> futures = new ArrayList<>(
objects.size());
for (final Object object : objects) {
futures.add(
_threadPoolExecutor.submit(
new Callable<Void>() {
@Override
public Void call() throws PortalException {
performAction(object);
return null;
}
}));
}
for (Future<Void> future : futures) {
future.get();
}
}
else {
for (Object object : objects) {
performAction(object);
}
}
if (objects.size() < _interval) {
return -1L;
}
BaseModel<?> baseModel = (BaseModel<?>)objects.get(
objects.size() - 1);
return (Long)baseModel.getPrimaryKeyObj();
}
};
TransactionConfig transactionConfig = getTransactionConfig();
try {
if (transactionConfig == null) {
return callable.call();
}
else {
return TransactionInvokerUtil.invoke(
transactionConfig, callable);
}
}
catch (Throwable t) {
if (t instanceof PortalException) {
throw (PortalException)t;
}
if (t instanceof SystemException) {
throw (SystemException)t;
}
throw new SystemException(t);
}
}
protected Object executeDynamicQuery(
Method dynamicQueryMethod, Object... arguments)
throws PortalException {
try {
return dynamicQueryMethod.invoke(_baseLocalService, arguments);
}
catch (InvocationTargetException ite) {
Throwable throwable = ite.getCause();
if (throwable instanceof PortalException) {
throw (PortalException)throwable;
}
else if (throwable instanceof SystemException) {
throw (SystemException)throwable;
}
throw new SystemException(ite);
}
catch (Exception e) {
throw new SystemException(e);
}
}
protected long getCompanyId() {
return _companyId;
}
protected Projection getCountProjection() {
return ProjectionFactoryUtil.rowCount();
}
protected int getInterval() {
return _interval;
}
protected Class<?> getModelClass() {
return _modelClass;
}
protected TransactionConfig getTransactionConfig() {
return _transactionConfig;
}
@SuppressWarnings("unused")
protected void intervalCompleted(long startPrimaryKey, long endPrimaryKey)
throws PortalException {
}
protected void performAction(Object object) throws PortalException {
if (_performActionMethod != null) {
_performActionMethod.performAction(object);
}
}
private AddCriteriaMethod _addCriteriaMethod;
private AddOrderCriteriaMethod _addOrderCriteriaMethod;
private BaseLocalService _baseLocalService;
private ClassLoader _classLoader;
private long _companyId;
private Method _dynamicQueryCountMethod;
private Method _dynamicQueryMethod;
private long _groupId;
private String _groupIdPropertyName = "groupId";
private int _interval = Indexer.DEFAULT_INTERVAL;
private Class<?> _modelClass;
private boolean _parallel;
@SuppressWarnings("rawtypes")
private PerformActionMethod _performActionMethod;
private PerformCountMethod _performCountMethod;
private String _primaryKeyPropertyName;
private final ThreadPoolExecutor _threadPoolExecutor =
PortalExecutorManagerUtil.getPortalExecutor(
DefaultActionableDynamicQuery.class.getName());
private TransactionConfig _transactionConfig;
}