blob: 829c695c4812ff12ab24b409789dc346841b451d [file] [log] [blame]
/*********************************************************************
* Copyright (c) 2013 Boeing
*
* This program and the accompanying materials are made
* available under the terms of the Eclipse Public License 2.0
* which is available at https://www.eclipse.org/legal/epl-2.0/
*
* SPDX-License-Identifier: EPL-2.0
*
* Contributors:
* Boeing - initial API and implementation
**********************************************************************/
package org.eclipse.osee.orcs.db.internal.search.engines;
import static org.eclipse.osee.framework.core.enums.CoreAttributeTypes.Name;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.function.Consumer;
import org.eclipse.osee.framework.core.OrcsTokenService;
import org.eclipse.osee.framework.core.data.ApplicabilityId;
import org.eclipse.osee.framework.core.data.ArtifactId;
import org.eclipse.osee.framework.core.data.ArtifactToken;
import org.eclipse.osee.framework.core.data.ArtifactTypeToken;
import org.eclipse.osee.framework.core.data.AttributeTypeGeneric;
import org.eclipse.osee.framework.core.data.AttributeTypeToken;
import org.eclipse.osee.framework.core.data.Branch;
import org.eclipse.osee.framework.core.data.BranchToken;
import org.eclipse.osee.framework.core.data.TransactionId;
import org.eclipse.osee.framework.core.enums.LoadLevel;
import org.eclipse.osee.framework.core.enums.ModificationType;
import org.eclipse.osee.framework.core.enums.RelationSide;
import org.eclipse.osee.framework.core.executor.CancellableCallable;
import org.eclipse.osee.framework.jdk.core.type.HashCollection;
import org.eclipse.osee.framework.jdk.core.type.Id;
import org.eclipse.osee.framework.jdk.core.type.OseeCoreException;
import org.eclipse.osee.framework.resource.management.IResourceManager;
import org.eclipse.osee.jdbc.JdbcClient;
import org.eclipse.osee.jdbc.JdbcStatement;
import org.eclipse.osee.orcs.OrcsSession;
import org.eclipse.osee.orcs.QueryType;
import org.eclipse.osee.orcs.core.ds.ApplicabilityDsQuery;
import org.eclipse.osee.orcs.core.ds.ArtifactData;
import org.eclipse.osee.orcs.core.ds.KeyValueStore;
import org.eclipse.osee.orcs.core.ds.LoadDataHandler;
import org.eclipse.osee.orcs.core.ds.LoadDataHandlerAdapter;
import org.eclipse.osee.orcs.core.ds.OptionsUtil;
import org.eclipse.osee.orcs.core.ds.QueryData;
import org.eclipse.osee.orcs.core.ds.QueryEngine;
import org.eclipse.osee.orcs.core.ds.criteria.CriteriaAttributeKeywords;
import org.eclipse.osee.orcs.data.ArtifactReadable;
import org.eclipse.osee.orcs.data.ArtifactReadableImpl;
import org.eclipse.osee.orcs.data.TransactionReadable;
import org.eclipse.osee.orcs.db.internal.loader.SqlObjectLoader;
import org.eclipse.osee.orcs.db.internal.search.QueryCallableFactory;
import org.eclipse.osee.orcs.db.internal.search.QuerySqlContext;
import org.eclipse.osee.orcs.db.internal.search.QuerySqlContextFactory;
import org.eclipse.osee.orcs.db.internal.sql.SelectiveArtifactSqlWriter;
import org.eclipse.osee.orcs.db.internal.sql.SqlHandlerFactory;
import org.eclipse.osee.orcs.db.internal.sql.join.SqlJoinFactory;
import org.eclipse.osee.orcs.search.QueryFactory;
import org.eclipse.osee.orcs.search.TupleQuery;
/**
* @author Roberto E. Escobar
*/
public class QueryEngineImpl implements QueryEngine {
private final QueryCallableFactory artifactQueryEngineFactory;
private final QuerySqlContextFactory branchSqlContextFactory;
private final QuerySqlContextFactory txSqlContextFactory;
private final QueryCallableFactory allQueryEngineFactory;
private final JdbcClient jdbcClient;
private final SqlJoinFactory sqlJoinFactory;
private final SqlObjectLoader sqlObjectLoader;
private final KeyValueStore keyValue;
private final SqlHandlerFactory handlerFactory;
private final OrcsTokenService tokenService;
private final IResourceManager resourceManager;
public QueryEngineImpl(QueryCallableFactory artifactQueryEngineFactory, QuerySqlContextFactory branchSqlContextFactory, QuerySqlContextFactory txSqlContextFactory, QueryCallableFactory allQueryEngineFactory, JdbcClient jdbcClient, SqlJoinFactory sqlJoinFactory, SqlHandlerFactory handlerFactory, SqlObjectLoader sqlObjectLoader, OrcsTokenService tokenService, KeyValueStore keyValue, IResourceManager resourceManager) {
this.artifactQueryEngineFactory = artifactQueryEngineFactory;
this.branchSqlContextFactory = branchSqlContextFactory;
this.txSqlContextFactory = txSqlContextFactory;
this.allQueryEngineFactory = allQueryEngineFactory;
this.jdbcClient = jdbcClient;
this.sqlJoinFactory = sqlJoinFactory;
this.sqlObjectLoader = sqlObjectLoader;
this.tokenService = tokenService;
this.keyValue = keyValue;
this.handlerFactory = handlerFactory;
this.resourceManager = resourceManager;
}
@Override
public int getArtifactCount(QueryData queryData) {
if (isPostProcessRequired(queryData)) {
return artifactQueryEngineFactory.getArtifactCount(queryData);
}
QueryData rootQueryData = queryData.getRootQueryData();
return new SelectiveArtifactSqlWriter(sqlJoinFactory, jdbcClient, rootQueryData).getCount(handlerFactory);
}
private boolean isPostProcessRequired(QueryData queryData) {
return queryData.hasCriteriaType(CriteriaAttributeKeywords.class);
}
@Override
public void runArtifactQuery(QueryData queryData, LoadDataHandler handler) throws Exception {
artifactQueryEngineFactory.createQuery(null, queryData, handler).call();
queryData.reset();
}
@Override
public int getBranchCount(QueryData queryData) {
return getCount(branchSqlContextFactory, queryData);
}
@Override
public void runBranchQuery(QueryData queryData, List<? super Branch> branches) {
QuerySqlContext queryContext = branchSqlContextFactory.createQueryContext(null, queryData, QueryType.SELECT);
sqlObjectLoader.loadBranches(branches, queryContext);
queryData.reset();
}
@Override
public int getTxCount(QueryData queryData) {
return getCount(txSqlContextFactory, queryData);
}
private int getCount(QuerySqlContextFactory sqlContextFactory, QueryData queryData) {
QuerySqlContext queryContext = sqlContextFactory.createQueryContext(null, queryData, QueryType.COUNT);
int count = sqlObjectLoader.getCount(queryContext);
queryData.reset();
return count;
}
@Override
public void runTxQuery(QueryData queryData, List<? super TransactionReadable> txs) {
QuerySqlContext queryContext = txSqlContextFactory.createQueryContext(null, queryData, QueryType.SELECT);
sqlObjectLoader.loadTransactions(txs, queryContext);
queryData.reset();
}
@Override
public CancellableCallable<Integer> createQuery(OrcsSession session, QueryData queryData, LoadDataHandler handler) {
return allQueryEngineFactory.createQuery(session, queryData, handler);
}
@Override
public TupleQuery createTupleQuery() {
return new TupleQueryImpl(jdbcClient, sqlJoinFactory, keyValue, tokenService);
}
@Override
public List<ArtifactToken> asArtifactTokens(QueryData queryData) {
List<ArtifactToken> tokens = new ArrayList<>(100);
selectiveArtifactLoad(queryData,
stmt -> tokens.add(ArtifactToken.valueOf(stmt.getLong("art_id"), stmt.getString("value"),
queryData.getBranch(), tokenService.getArtifactTypeOrCreate(stmt.getLong("art_type_id")))));
return tokens;
}
@Override
public Map<ArtifactId, ArtifactReadable> asArtifactMap(QueryData queryData, QueryFactory queryFactory) {
HashMap<ArtifactId, ArtifactReadable> artifacts = new HashMap<>(500);
loadArtifactsInto(queryData, queryFactory, a -> artifacts.put(a, a));
return artifacts;
}
@Override
public List<ArtifactReadable> asArtifacts(QueryData queryData, QueryFactory queryFactory) {
List<ArtifactReadable> artifacts = new ArrayList<>(500);
loadArtifactsInto(queryData, queryFactory, a -> artifacts.add(a));
return artifacts;
}
private void loadArtifactsInto(QueryData queryData, QueryFactory queryFactory, Consumer<ArtifactReadable> artifactConsumer) {
HashMap<ArtifactId, ArtifactReadable> artifactMap = new HashMap<>(500);
Consumer<JdbcStatement> jdbcConsumer = stmt -> {
Long artId = stmt.getLong("art_id");
ArtifactReadableImpl artifact = (ArtifactReadableImpl) artifactMap.get(ArtifactId.valueOf(artId));
if (artifact == null) {
artifact = createArtifact(stmt, artId, stmt.getLong("art_type_id"), queryData, queryFactory);
artifactMap.put(artifact, artifact);
if (stmt.getLong("top") == 1) {
artifactConsumer.accept(artifact);
}
}
Long typeId = stmt.getLong("type_id");
Long otherArtId = stmt.getLong("other_art_id");
String value = stmt.getString("value");
String uri = stmt.getString("uri");
if (otherArtId == 0) {
AttributeTypeGeneric<?> attributeType = tokenService.getAttributeTypeOrCreate(typeId);
Attribute<?> attribute =
new Attribute<>(stmt.getLong("attr_id"), attributeType, value, uri, resourceManager);
artifact.putAttributeValue(attributeType, attribute);
} else {
Long otherArtType = stmt.getLong("other_art_type_id");
RelationSide side = value.equals("A") ? RelationSide.SIDE_A : RelationSide.SIDE_B;
ArtifactReadableImpl otherArtifact = (ArtifactReadableImpl) artifactMap.get(ArtifactId.valueOf(otherArtId));
if (otherArtifact == null) {
otherArtifact = createArtifact(stmt, otherArtId, otherArtType, queryData, queryFactory);
artifactMap.put(otherArtifact, otherArtifact);
}
artifact.putRelation(tokenService.getRelationTypeOrCreate(typeId), side, otherArtifact);
}
};
selectiveArtifactLoad(queryData, jdbcConsumer);
}
private ArtifactReadableImpl createArtifact(JdbcStatement stmt, Long artId, Long artifactTypeId, QueryData queryData, QueryFactory queryFactory) {
TransactionId txId = TransactionId.valueOf(stmt.getLong("transaction_id"));
ModificationType modType = ModificationType.valueOf(stmt.getInt("mod_type"));
ArtifactTypeToken artifactType = tokenService.getArtifactTypeOrCreate(artifactTypeId);
ApplicabilityId applic = ApplicabilityId.valueOf(stmt.getLong("app_id"));
return new ArtifactReadableImpl(artId, artifactType, BranchToken.create(queryData.getBranch(), "unknown"),
queryData.getView(), applic, txId, modType, queryFactory);
}
@Override
public List<Map<String, Object>> asArtifactMaps(QueryData queryData) {
List<Map<String, Object>> maps = new ArrayList<>(500);
HashCollection<AttributeTypeToken, Object> attributes = new HashCollection<>();
Long[] artifactId = new Long[] {Id.SENTINEL};
Long[] applicability = new Long[] {Id.SENTINEL};
ArtifactTypeToken[] artifactType = new ArtifactTypeToken[] {ArtifactTypeToken.SENTINEL};
Consumer<JdbcStatement> consumer = stmt -> {
Long newArtId = stmt.getLong("art_id");
if (artifactId[0].equals(Id.SENTINEL)) {
artifactId[0] = newArtId;
applicability[0] = stmt.getLong("app_id");
artifactType[0] = tokenService.getArtifactTypeOrCreate(stmt.getLong("art_type_id"));
} else if (!artifactId[0].equals(newArtId)) {
maps.add(createFieldMap(artifactType[0], artifactId[0], applicability[0], attributes));
attributes.clear();
artifactId[0] = newArtId;
applicability[0] = stmt.getLong("app_id");
artifactType[0] = tokenService.getArtifactTypeOrCreate(stmt.getLong("art_type_id"));
}
attributes.put(tokenService.getAttributeTypeOrCreate(stmt.getLong("type_id")), stmt.getString("value"));
};
selectiveArtifactLoad(queryData, consumer);
if (!artifactId[0].equals(Id.SENTINEL)) {
maps.add(createFieldMap(artifactType[0], artifactId[0], applicability[0], attributes));
}
return maps;
}
private Map<String, Object> createFieldMap(ArtifactTypeToken artifactType, Long artifactId, Long applicability, HashCollection<AttributeTypeToken, Object> attributes) {
Map<String, Object> map = new LinkedHashMap<>();
map.put("Name", attributes.getValues(Name));
map.put("Artifact Type", artifactType.getIdString());
map.put("Artifact Id", artifactId.toString());
map.put("Applicability Id", applicability.toString());
List<AttributeTypeToken> attributeTypes = new ArrayList<>(attributes.keySet());
Collections.sort(attributeTypes);
for (AttributeTypeToken attributeType : attributeTypes) {
List<Object> attributeValues = attributes.getValues(attributeType);
if (attributeValues.size() == 1) {
map.put(attributeType.getName(), attributeValues.get(0));
} else {
map.put(attributeType.getName(), attributeValues);
}
}
return map;
}
@Override
public Map<ArtifactId, ArtifactToken> asArtifactTokenMap(QueryData queryData) {
Map<ArtifactId, ArtifactToken> tokens = new HashMap<>(10000);
Consumer<JdbcStatement> consumer = stmt -> {
ArtifactToken token = ArtifactToken.valueOf(stmt.getLong("art_id"), stmt.getString("value"),
queryData.getBranch(), tokenService.getArtifactTypeOrCreate(stmt.getLong("art_type_id")));
tokens.put(token, token);
};
selectiveArtifactLoad(queryData, consumer);
return tokens;
}
@Override
public List<ArtifactId> asArtifactIds(QueryData queryData) {
List<ArtifactId> ids = new ArrayList<>(100);
if (isPostProcessRequired(queryData)) {
LoadDataHandlerAdapter handler = new LoadDataHandlerAdapter() {
@Override
public void onData(ArtifactData data) {
ids.add(data);
}
};
OptionsUtil.setLoadLevel(queryData.getOptions(), LoadLevel.ARTIFACT_AND_ATTRIBUTE_DATA);
try {
runArtifactQuery(queryData, handler);
return ids;
} catch (Exception ex) {
OseeCoreException.wrapAndThrow(ex);
}
}
selectiveArtifactLoad(queryData, stmt -> ids.add(ArtifactId.valueOf(stmt.getLong("art_id"))));
return ids;
}
private void selectiveArtifactLoad(QueryData queryData, Consumer<JdbcStatement> consumer) {
QueryData rootQueryData = queryData.getRootQueryData();
new SelectiveArtifactSqlWriter(sqlJoinFactory, jdbcClient, rootQueryData).runSql(consumer, handlerFactory);
}
@Override
public ApplicabilityDsQuery createApplicabilityDsQuery() {
return new ApplicabilityDsQueryImpl(jdbcClient, sqlJoinFactory);
}
}