/*
* Copyright 2016 Red Hat, Inc. and/or its affiliates.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jbpm.kie.services.impl.query;
import static org.jbpm.services.api.query.QueryResultMapper.COLUMN_DEPLOYMENTID;
import static org.jbpm.services.api.query.QueryResultMapper.COLUMN_EXTERNALID;
import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.dashbuilder.DataSetCore;
import org.dashbuilder.dataprovider.DataSetProviderRegistry;
import org.dashbuilder.dataprovider.sql.SQLDataSetProvider;
import org.dashbuilder.dataset.DataSet;
import org.dashbuilder.dataset.DataSetLookupBuilder;
import org.dashbuilder.dataset.DataSetLookupFactory;
import org.dashbuilder.dataset.DataSetManager;
import org.dashbuilder.dataset.DataSetMetadata;
import org.dashbuilder.dataset.def.DataSetDef;
import org.dashbuilder.dataset.def.DataSetDefFactory;
import org.dashbuilder.dataset.def.DataSetDefRegistry;
import org.dashbuilder.dataset.def.SQLDataSetDefBuilder;
import org.dashbuilder.dataset.filter.ColumnFilter;
import org.jbpm.kie.services.impl.model.ProcessAssetDesc;
import org.jbpm.kie.services.impl.query.persistence.PersistDataSetListener;
import org.jbpm.kie.services.impl.query.persistence.QueryDefinitionEntity;
import org.jbpm.kie.services.impl.query.preprocessor.BusinessAdminTasksPreprocessor;
import org.jbpm.kie.services.impl.query.preprocessor.DeploymentIdsPreprocessor;
import org.jbpm.kie.services.impl.query.preprocessor.PotOwnerTasksPreprocessor;
import org.jbpm.kie.services.impl.security.DeploymentRolesManager;
import org.jbpm.services.api.DeploymentEvent;
import org.jbpm.services.api.DeploymentEventListener;
import org.jbpm.services.api.model.DeployedAsset;
import org.jbpm.services.api.query.QueryAlreadyRegisteredException;
import org.jbpm.services.api.query.QueryNotFoundException;
import org.jbpm.services.api.query.QueryParamBuilder;
import org.jbpm.services.api.query.QueryResultMapper;
import org.jbpm.services.api.query.QueryService;
import org.jbpm.services.api.query.model.QueryDefinition;
import org.jbpm.services.api.query.model.QueryDefinition.Target;
import org.jbpm.services.api.query.model.QueryParam;
import org.jbpm.shared.services.impl.QueryManager;
import org.jbpm.shared.services.impl.TransactionalCommandService;
import org.jbpm.shared.services.impl.commands.QueryNameCommand;
import org.kie.api.runtime.query.AdvancedQueryContext;
import org.kie.api.runtime.query.QueryContext;
import org.kie.internal.identity.IdentityProvider;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;;
public class QueryServiceImpl implements QueryService, DeploymentEventListener {
private static final Logger logger = LoggerFactory.getLogger(QueryServiceImpl.class);
private DataSetDefRegistry dataSetDefRegistry;
private DataSetManager dataSetManager;
private DataSetProviderRegistry providerRegistry;
private IdentityProvider identityProvider;
private TransactionalCommandService commandService;
private DeploymentRolesManager deploymentRolesManager = new DeploymentRolesManager();
public void setDeploymentRolesManager(DeploymentRolesManager deploymentRolesManager) {
this.deploymentRolesManager = deploymentRolesManager;
}
public void setIdentityProvider(IdentityProvider identityProvider) {
this.identityProvider = identityProvider;
}
public void setCommandService(TransactionalCommandService commandService) {
this.commandService = commandService;
}
public void setDataSetDefRegistry(DataSetDefRegistry dataSetDefRegistry) {
this.dataSetDefRegistry = dataSetDefRegistry;
}
public void setProviderRegistry(DataSetProviderRegistry providerRegistry) {
this.providerRegistry = providerRegistry;
}
public void setDataSetManager(DataSetManager dataSetManager) {
this.dataSetManager = dataSetManager;
}
public void init() {
if (dataSetDefRegistry == null && dataSetManager == null && providerRegistry == null) {
dataSetDefRegistry = DataSetCore.get().getDataSetDefRegistry();
dataSetManager = DataSetCore.get().getDataSetManager();
providerRegistry = DataSetCore.get().getDataSetProviderRegistry();
providerRegistry.registerDataProvider(SQLDataSetProvider.get());
dataSetDefRegistry.addListener(new PersistDataSetListener(commandService));
}
// load previously registered query definitions
if (commandService != null) {
List<QueryDefinitionEntity> queries = commandService.execute(new QueryNameCommand<List<QueryDefinitionEntity>>("getQueryDefinitions"));
for (QueryDefinitionEntity entity : queries) {
QueryDefinition definition = entity.toQueryDefinition();
try {
registerQuery(definition);
} catch (QueryAlreadyRegisteredException e) {
logger.debug("Query {} already registered, skipping...", definition.getName());
}
}
}
}
@Override
public void registerQuery(QueryDefinition queryDefinition) throws QueryAlreadyRegisteredException {
if (dataSetDefRegistry.getDataSetDef(queryDefinition.getName()) != null) {
throw new QueryAlreadyRegisteredException("Query" + queryDefinition.getName() + " is already registered");
}
replaceQuery(queryDefinition);
}
@Override
public void replaceQuery(QueryDefinition queryDefinition) {
logger.debug("About to register {} query...", queryDefinition);
if (queryDefinition instanceof SqlQueryDefinition) {
SqlQueryDefinition sqlQueryDefinition = (SqlQueryDefinition) queryDefinition;
SQLDataSetDefBuilder<?> builder = DataSetDefFactory.newSQLDataSetDef().uuid(sqlQueryDefinition.getName()).name(sqlQueryDefinition.getName() + "::" + sqlQueryDefinition.getTarget().toString()).dataSource(sqlQueryDefinition.getSource()).dbSQL(sqlQueryDefinition.getExpression(), true);
DataSetDef sqlDef = builder.buildDef();
dataSetDefRegistry.registerDataSetDef(sqlDef);
if (queryDefinition.getTarget().equals(Target.BA_TASK)) {
dataSetDefRegistry.registerPreprocessor(sqlDef.getUUID(), new BusinessAdminTasksPreprocessor(identityProvider));
} else if (queryDefinition.getTarget().equals(Target.PO_TASK)) {
dataSetDefRegistry.registerPreprocessor(sqlDef.getUUID(), new PotOwnerTasksPreprocessor(identityProvider));
} else if (queryDefinition.getTarget().equals(Target.FILTERED_PROCESS)) {
dataSetDefRegistry.registerPreprocessor(sqlDef.getUUID(), new DeploymentIdsPreprocessor(deploymentRolesManager, identityProvider, COLUMN_EXTERNALID));
} else if (queryDefinition.getTarget().equals(Target.FILTERED_BA_TASK)) {
dataSetDefRegistry.registerPreprocessor(sqlDef.getUUID(), new BusinessAdminTasksPreprocessor(identityProvider));
dataSetDefRegistry.registerPreprocessor(sqlDef.getUUID(), new DeploymentIdsPreprocessor(deploymentRolesManager, identityProvider, COLUMN_DEPLOYMENTID));
} else if (queryDefinition.getTarget().equals(Target.FILTERED_PO_TASK)) {
dataSetDefRegistry.registerPreprocessor(sqlDef.getUUID(), new PotOwnerTasksPreprocessor(identityProvider));
dataSetDefRegistry.registerPreprocessor(sqlDef.getUUID(), new DeploymentIdsPreprocessor(deploymentRolesManager, identityProvider, COLUMN_DEPLOYMENTID));
}
DataSetMetadata metadata = dataSetManager.getDataSetMetadata(sqlDef.getUUID());
for (String columnId : metadata.getColumnIds()) {
sqlDef.addColumn(columnId, metadata.getColumnType(columnId));
}
logger.info("Registered {} query successfully", queryDefinition.getName());
}
}
@Override
public void unregisterQuery(final String uniqueQueryName) throws QueryNotFoundException {
DataSetDef def = dataSetDefRegistry.removeDataSetDef(uniqueQueryName);
if (def == null) {
throw new QueryNotFoundException("Query " + uniqueQueryName + " not found");
}
logger.info("Unregistered {} query successfully", uniqueQueryName);
}
@Override
public <T> T query(String queryName, QueryResultMapper<T> mapper, QueryContext queryContext, QueryParam... filterParams) throws QueryNotFoundException {
return query(queryName, mapper, queryContext, new CoreFunctionQueryParamBuilder(filterParams));
}
@Override
public <T> T query(String queryName, QueryResultMapper<T> mapper, QueryContext queryContext, QueryParamBuilder<?> paramBuilder) throws QueryNotFoundException {
if (dataSetDefRegistry.getDataSetDef(queryName) == null) {
throw new QueryNotFoundException("Query " + queryName + " not found");
}
logger.debug("About to query using {} definition with number of rows {} and starting at {} offset", queryName, queryContext.getCount(), queryContext.getOffset());
DataSetLookupBuilder<?> builder = DataSetLookupFactory.newDataSetLookupBuilder().dataset(queryName).rowNumber(queryContext.getCount()).rowOffset(queryContext.getOffset());
Object filter = paramBuilder.build();
while (filter != null) {
if (filter instanceof ColumnFilter) {
// add filter
builder.filter((ColumnFilter) filter);
} else if (filter instanceof AggregateColumnFilter) {
// add aggregate function
builder.column(((AggregateColumnFilter) filter).getColumnId(), ((AggregateColumnFilter) filter).getType(), ((AggregateColumnFilter) filter).getColumnId());
} else if (filter instanceof GroupColumnFilter) {
// add group function
builder.group(((GroupColumnFilter) filter).getColumnId(), ((GroupColumnFilter) filter).getNewColumnId());
} else if (filter instanceof ExtraColumnFilter) {
// add extra column
builder.column(((ExtraColumnFilter) filter).getColumnId(), ((ExtraColumnFilter) filter).getNewColumnId());
} else {
logger.warn("Unsupported filter '{}' generated by '{}'", filter, paramBuilder);
}
// call builder again in case more parameters are available
filter = paramBuilder.build();
}
// if advanced ordering is used process the ORDER BY clause into order by and sort order pairs
if (queryContext instanceof AdvancedQueryContext && ((AdvancedQueryContext) queryContext).getOrderByClause() != null && !((AdvancedQueryContext) queryContext).getOrderByClause().isEmpty()) {
String[] orderBySortOrderItems = ((AdvancedQueryContext) queryContext).getOrderByClause().split(",");
for (String orderBySortOrderItem : orderBySortOrderItems) {
String[] orderBySortOrder = orderBySortOrderItem.trim().split(" ");
//check that sort order is given. default to 'asc'.
String sortOrder = orderBySortOrder.length == 1 ? "asc" : orderBySortOrder[1].trim();
logger.debug("Applying order by clause '{}' with {}ending sort order", orderBySortOrder[0].trim(), sortOrder);
builder.sort(orderBySortOrder[0].trim(), sortOrder);
}
} else { // use default simple ordering
if (queryContext.getOrderBy() != null) {
String[] oderByItems = queryContext.getOrderBy().split(",");
for (String orderBy : oderByItems) {
logger.debug("Applying order by {} and ascending {}", orderBy, queryContext.isAscending());
builder.sort(orderBy.trim(), queryContext.isAscending() ? "asc" : "desc");
}
}
}
DataSet result = dataSetManager.lookupDataSet(builder.buildLookup());
logger.debug("Query result is {}", result);
T mappedResult = mapper.map(result);
logger.debug("Mapped result is {}", mappedResult);
return mappedResult;
}
@Override
public QueryDefinition getQuery(String uniqueQueryName) throws QueryNotFoundException {
Map<String, Object> params = new HashMap<String, Object>();
params.put("name", uniqueQueryName);
List<QueryDefinitionEntity> queries = commandService.execute(new QueryNameCommand<List<QueryDefinitionEntity>>("getQueryDefinitionByName", params));
if (queries.size() == 1) {
return queries.get(0).toQueryDefinition();
}
throw new QueryNotFoundException("Query " + uniqueQueryName + " not found");
}
@Override
public List<QueryDefinition> getQueries(QueryContext queryContext) {
List<QueryDefinition> result = new ArrayList<QueryDefinition>();
Map<String, Object> params = new HashMap<String, Object>();
applyQueryContext(params, queryContext);
List<QueryDefinitionEntity> queries = commandService.execute(new QueryNameCommand<List<QueryDefinitionEntity>>("getQueryDefinitions", params));
for (QueryDefinitionEntity entity : queries) {
QueryDefinition definition = entity.toQueryDefinition();
result.add(definition);
}
return result;
}
protected void applyQueryContext(Map<String, Object> params, QueryContext queryContext) {
if (queryContext != null) {
params.put("firstResult", queryContext.getOffset());
params.put("maxResults", queryContext.getCount());
if (queryContext.getOrderBy() != null && !queryContext.getOrderBy().isEmpty()) {
params.put(QueryManager.ORDER_BY_KEY, queryContext.getOrderBy());
if (queryContext.isAscending()) {
params.put(QueryManager.ASCENDING_KEY, "true");
} else {
params.put(QueryManager.DESCENDING_KEY, "true");
}
}
}
}
public void onDeploy(DeploymentEvent event) {
Collection<DeployedAsset> assets = event.getDeployedUnit().getDeployedAssets();
List<String> roles = null;
for (DeployedAsset asset : assets) {
if (asset instanceof ProcessAssetDesc) {
if (roles == null) {
roles = ((ProcessAssetDesc) asset).getRoles();
}
}
}
if (roles == null) {
roles = Collections.emptyList();
}
deploymentRolesManager.addRolesForDeployment(event.getDeploymentId(), roles);
}
public void onUnDeploy(DeploymentEvent event) {
deploymentRolesManager.removeRolesForDeployment(event.getDeploymentId());
}
@Override
public void onActivate(DeploymentEvent event) {
// no op
}
@Override
public void onDeactivate(DeploymentEvent event) {
// no op
}
}