372 lines
16 KiB
Java
372 lines
16 KiB
Java
package org.opencdmp.elastic.query;
|
|
|
|
import co.elastic.clients.elasticsearch._types.query_dsl.Query;
|
|
import co.elastic.clients.elasticsearch._types.query_dsl.QueryBuilders;
|
|
import gr.cite.commons.web.authz.service.AuthorizationService;
|
|
import gr.cite.tools.data.query.FieldResolver;
|
|
import gr.cite.tools.data.query.OrderingFieldResolver;
|
|
import gr.cite.tools.data.query.QueryFactory;
|
|
import gr.cite.tools.elastic.ElasticConstants;
|
|
import gr.cite.tools.elastic.configuration.ElasticProperties;
|
|
import gr.cite.tools.elastic.mapper.FieldBasedMapper;
|
|
import gr.cite.tools.elastic.query.ElasticField;
|
|
import gr.cite.tools.elastic.query.ElasticFields;
|
|
import gr.cite.tools.elastic.query.ElasticNestedQuery;
|
|
import gr.cite.tools.elastic.query.ElasticQuery;
|
|
import org.opencdmp.authorization.AuthorizationFlags;
|
|
import org.opencdmp.authorization.Permission;
|
|
import org.opencdmp.commons.enums.DmpAccessType;
|
|
import org.opencdmp.commons.enums.DmpStatus;
|
|
import org.opencdmp.commons.enums.DmpVersionStatus;
|
|
import org.opencdmp.commons.scope.tenant.TenantScope;
|
|
import org.opencdmp.commons.scope.user.UserScope;
|
|
import org.opencdmp.elastic.data.DescriptionElasticEntity;
|
|
import org.opencdmp.elastic.data.DmpElasticEntity;
|
|
import org.opencdmp.elastic.data.nested.NestedDescriptionElasticEntity;
|
|
import org.opencdmp.service.elastic.AppElasticProperties;
|
|
import org.opencdmp.service.elastic.ElasticService;
|
|
import org.springframework.beans.factory.annotation.Autowired;
|
|
import org.springframework.beans.factory.config.BeanDefinition;
|
|
import org.springframework.context.annotation.Scope;
|
|
import org.springframework.data.elasticsearch.client.elc.ElasticsearchTemplate;
|
|
import org.springframework.stereotype.Component;
|
|
|
|
import javax.management.InvalidApplicationException;
|
|
import java.io.IOException;
|
|
import java.util.*;
|
|
import java.util.stream.Collectors;
|
|
|
|
@Component
|
|
//Like in C# make it Transient
|
|
@Scope(BeanDefinition.SCOPE_PROTOTYPE)
|
|
public class DmpElasticQuery extends ElasticQuery<DmpElasticEntity, UUID> {
|
|
|
|
private String like;
|
|
private Collection<UUID> ids;
|
|
private Collection<UUID> excludedIds;
|
|
private Collection<DmpStatus> statuses;
|
|
private Collection<DmpVersionStatus> versionStatuses;
|
|
private Collection<DmpAccessType> accessTypes;
|
|
private Collection<Integer> versions;
|
|
private Collection<UUID> groupIds;
|
|
private EnumSet<AuthorizationFlags> authorize = EnumSet.of(AuthorizationFlags.None);
|
|
|
|
|
|
public DmpElasticQuery like(String value) {
|
|
this.like = value;
|
|
return this;
|
|
}
|
|
|
|
public DmpElasticQuery ids(UUID value) {
|
|
this.ids = List.of(value);
|
|
return this;
|
|
}
|
|
|
|
public DmpElasticQuery ids(UUID... value) {
|
|
this.ids = Arrays.asList(value);
|
|
return this;
|
|
}
|
|
|
|
public DmpElasticQuery ids(Collection<UUID> values) {
|
|
this.ids = values;
|
|
return this;
|
|
}
|
|
|
|
public DmpElasticQuery excludedIds(Collection<UUID> values) {
|
|
this.excludedIds = values;
|
|
return this;
|
|
}
|
|
|
|
public DmpElasticQuery excludedIds(UUID value) {
|
|
this.excludedIds = List.of(value);
|
|
return this;
|
|
}
|
|
|
|
public DmpElasticQuery excludedIds(UUID... value) {
|
|
this.excludedIds = Arrays.asList(value);
|
|
return this;
|
|
}
|
|
|
|
public DmpElasticQuery versionStatuses(DmpVersionStatus value) {
|
|
this.versionStatuses = List.of(value);
|
|
return this;
|
|
}
|
|
|
|
public DmpElasticQuery versionStatuses(DmpVersionStatus... value) {
|
|
this.versionStatuses = Arrays.asList(value);
|
|
return this;
|
|
}
|
|
|
|
public DmpElasticQuery versionStatuses(Collection<DmpVersionStatus> values) {
|
|
this.versionStatuses = values;
|
|
return this;
|
|
}
|
|
|
|
public DmpElasticQuery accessTypes(DmpAccessType value) {
|
|
this.accessTypes = List.of(value);
|
|
return this;
|
|
}
|
|
|
|
public DmpElasticQuery accessTypes(DmpAccessType... value) {
|
|
this.accessTypes = Arrays.asList(value);
|
|
return this;
|
|
}
|
|
|
|
public DmpElasticQuery accessTypes(Collection<DmpAccessType> values) {
|
|
this.accessTypes = values;
|
|
return this;
|
|
}
|
|
|
|
public DmpElasticQuery statuses(DmpStatus value) {
|
|
this.statuses = List.of(value);
|
|
return this;
|
|
}
|
|
|
|
public DmpElasticQuery statuses(DmpStatus... value) {
|
|
this.statuses = Arrays.asList(value);
|
|
return this;
|
|
}
|
|
|
|
public DmpElasticQuery statuses(Collection<DmpStatus> values) {
|
|
this.statuses = values;
|
|
return this;
|
|
}
|
|
|
|
public DmpElasticQuery versions(Integer value) {
|
|
this.versions = List.of(value);
|
|
return this;
|
|
}
|
|
|
|
public DmpElasticQuery versions(Integer... value) {
|
|
this.versions = Arrays.asList(value);
|
|
return this;
|
|
}
|
|
|
|
public DmpElasticQuery versions(Collection<Integer> values) {
|
|
this.versions = values;
|
|
return this;
|
|
}
|
|
|
|
public DmpElasticQuery groupIds(UUID value) {
|
|
this.groupIds = List.of(value);
|
|
return this;
|
|
}
|
|
|
|
public DmpElasticQuery groupIds(UUID... value) {
|
|
this.groupIds = Arrays.asList(value);
|
|
return this;
|
|
}
|
|
|
|
public DmpElasticQuery groupIds(Collection<UUID> values) {
|
|
this.groupIds = values;
|
|
return this;
|
|
}
|
|
|
|
public DmpElasticQuery authorize(EnumSet<AuthorizationFlags> values) {
|
|
this.authorize = values;
|
|
return this;
|
|
}
|
|
|
|
private final QueryFactory queryFactory;
|
|
private final AppElasticProperties appElasticProperties;
|
|
private final ElasticService elasticService;
|
|
private final UserScope userScope;
|
|
private final TenantScope tenantScope;
|
|
private final AuthorizationService authService;
|
|
@Autowired
|
|
public DmpElasticQuery(ElasticsearchTemplate elasticsearchTemplate, ElasticProperties elasticProperties, QueryFactory queryFactory, AppElasticProperties appElasticProperties, ElasticService elasticService, UserScope userScope, TenantScope tenantScope, AuthorizationService authService) {
|
|
super(elasticsearchTemplate, elasticProperties);
|
|
this.queryFactory = queryFactory;
|
|
this.appElasticProperties = appElasticProperties;
|
|
this.elasticService = elasticService;
|
|
this.userScope = userScope;
|
|
this.tenantScope = tenantScope;
|
|
this.authService = authService;
|
|
}
|
|
|
|
@Override
|
|
protected Boolean isFalseQuery() {
|
|
return this.isEmpty(this.ids) || this.isEmpty(this.versionStatuses) || this.isEmpty(this.excludedIds) || this.isEmpty(this.accessTypes)|| this.isEmpty(this.statuses);
|
|
}
|
|
|
|
@Override
|
|
protected Class<DmpElasticEntity> entityClass() {
|
|
return DmpElasticEntity.class;
|
|
}
|
|
|
|
private Query applyTenant(List<Query> predicates){
|
|
if (this.tenantScope.isSet()){
|
|
Query tenantQuery;
|
|
if (this.tenantScope.isDefaultTenant()){
|
|
tenantQuery = this.fieldNotExists(this.elasticFieldOf(DmpElasticEntity._tenantId))._toQuery();
|
|
}
|
|
else {
|
|
try {
|
|
tenantQuery = this.or(this.fieldNotExists(this.elasticFieldOf(DmpElasticEntity._tenantId))._toQuery(),
|
|
this.equals(this.elasticFieldOf(DmpElasticEntity._tenantId), this.tenantScope.getTenant()))._toQuery();
|
|
} catch (InvalidApplicationException e) {
|
|
throw new RuntimeException(e);
|
|
}
|
|
}
|
|
if (predicates == null) return tenantQuery;
|
|
else return this.and(tenantQuery, this.or(predicates)._toQuery());
|
|
} else {
|
|
if (predicates != null) return this.or(predicates)._toQuery();
|
|
}
|
|
return null;
|
|
}
|
|
@Override
|
|
protected Query applyAuthZ() {
|
|
|
|
if (this.authorize.contains(AuthorizationFlags.None)) return this.applyTenant(null);
|
|
if (this.authorize.contains(AuthorizationFlags.Permission) && this.authService.authorize(Permission.BrowseDmp)) return this.applyTenant(null);
|
|
UUID userId = null;
|
|
boolean usePublic = this.authorize.contains(AuthorizationFlags.Public);
|
|
if (this.authorize.contains(AuthorizationFlags.DmpAssociated)) userId = this.userScope.getUserIdSafe();
|
|
|
|
List<Query> predicates = new ArrayList<>();
|
|
if (usePublic) {
|
|
predicates.add(this.and(
|
|
this.equals(this.elasticFieldOf(DmpElasticEntity._status), DmpStatus.Finalized.getValue()),
|
|
this.equals(this.elasticFieldOf(DmpElasticEntity._accessType), DmpAccessType.Public.getValue())
|
|
));
|
|
}
|
|
if (userId != null) {
|
|
NestedCollaboratorElasticQuery query = this.queryFactory.query(NestedCollaboratorElasticQuery.class).nestedPath(DmpElasticEntity._collaborators);
|
|
query.userIds(userId);
|
|
predicates.add(this.nestedQuery(query).build()._toQuery());
|
|
}
|
|
if (!predicates.isEmpty()) {
|
|
return this.applyTenant(predicates);
|
|
} else {
|
|
return this.equals(this.elasticFieldOf(DescriptionElasticEntity._id), UUID.randomUUID());
|
|
}
|
|
}
|
|
|
|
@Override
|
|
protected Query applyFilters() {
|
|
List<Query> predicates = new ArrayList<>();
|
|
|
|
if (this.like != null && !this.like.isBlank()) {
|
|
|
|
if (!this.like.startsWith("*")) this.like = "*" + this.like;
|
|
if (!this.like.endsWith("*")) this.like = this.like + "*";
|
|
ElasticFields elasticFields = this.elasticFieldsOf();
|
|
elasticFields.add("*", null, true);
|
|
|
|
predicates.add(this.or(
|
|
this.like(elasticFields, List.of(this.like))._toQuery()
|
|
,
|
|
QueryBuilders.nested().path(DmpElasticEntity._collaborators).query(
|
|
this.like(elasticFields, List.of(this.like))._toQuery()
|
|
).build()._toQuery(),
|
|
QueryBuilders.nested().path(DmpElasticEntity._references).query(
|
|
this.like(elasticFields, List.of(this.like))._toQuery()
|
|
).build()._toQuery(),
|
|
QueryBuilders.nested().path(DmpElasticEntity._descriptions + "." + NestedDescriptionElasticEntity._references).query(
|
|
this.like(elasticFields, List.of(this.like))._toQuery()
|
|
).build()._toQuery(),
|
|
QueryBuilders.nested().path(DmpElasticEntity._descriptions + "." + NestedDescriptionElasticEntity._tags).query(
|
|
this.like(elasticFields, List.of(this.like))._toQuery()
|
|
).build()._toQuery(),
|
|
QueryBuilders.nested().path(DmpElasticEntity._descriptions).query(
|
|
this.like(elasticFields, List.of(this.like))._toQuery()
|
|
).build()._toQuery()
|
|
|
|
)._toQuery());
|
|
}
|
|
if (this.ids != null) {
|
|
predicates.add(this.containsUUID(this.elasticFieldOf(DmpElasticEntity._id), this.ids)._toQuery());
|
|
}
|
|
if (this.groupIds != null) {
|
|
predicates.add(this.containsUUID(this.elasticFieldOf(DmpElasticEntity._groupId), this.groupIds)._toQuery());
|
|
}
|
|
if (this.versions != null) {
|
|
predicates.add(this.contains(this.elasticFieldOf(DmpElasticEntity._version), this.versions.toArray(new Integer[this.versions.size()]))._toQuery());
|
|
}
|
|
if (this.excludedIds != null) {
|
|
predicates.add(this.not(this.containsUUID(this.elasticFieldOf(DmpElasticEntity._id), this.excludedIds)._toQuery())._toQuery());
|
|
}
|
|
if (this.statuses != null) {
|
|
predicates.add(this.contains(this.elasticFieldOf(DmpElasticEntity._status), this.statuses.stream().map(x-> x.getValue()).collect(Collectors.toList()).toArray(new Short[this.statuses.size()]))._toQuery());
|
|
}
|
|
if (this.versionStatuses != null) {
|
|
predicates.add(this.contains(this.elasticFieldOf(DmpElasticEntity._versionStatus), this.versionStatuses.stream().map(x-> x.getValue()).collect(Collectors.toList()).toArray(new Short[this.versionStatuses.size()]))._toQuery());
|
|
}
|
|
if (this.accessTypes != null) {
|
|
predicates.add(this.contains(this.elasticFieldOf(DmpElasticEntity._accessType), this.accessTypes.stream().map(x-> x.getValue()).collect(Collectors.toList()).toArray(new Short[this.accessTypes.size()]))._toQuery());
|
|
}
|
|
|
|
if (!predicates.isEmpty()) {
|
|
return this.and(predicates);
|
|
} else {
|
|
return null;
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public DmpElasticEntity convert(Map<String, Object> rawData, Set<String> columns) {
|
|
DmpElasticEntity mocDoc = new DmpElasticEntity();
|
|
if (columns.contains(DmpElasticEntity._id)) mocDoc.setId(FieldBasedMapper.shallowSafeConversion(rawData.get(DmpElasticEntity._id), UUID.class));
|
|
if (columns.contains(DmpElasticEntity._label)) mocDoc.setLabel(FieldBasedMapper.shallowSafeConversion(rawData.get(DmpElasticEntity._label), String.class));
|
|
if (columns.contains(DmpElasticEntity._description)) mocDoc.setDescription(FieldBasedMapper.shallowSafeConversion(rawData.get(DmpElasticEntity._description), String.class));
|
|
if (columns.contains(DmpElasticEntity._status)) mocDoc.setStatus(FieldBasedMapper.shallowSafeConversion(rawData.get(DmpElasticEntity._status), DmpStatus.class));
|
|
if (columns.contains(DmpElasticEntity._versionStatus)) mocDoc.setVersionStatus(FieldBasedMapper.shallowSafeConversion(rawData.get(DmpElasticEntity._versionStatus), DmpVersionStatus.class));
|
|
if (columns.contains(DmpElasticEntity._version)) mocDoc.setVersion(FieldBasedMapper.shallowSafeConversion(rawData.get(DmpElasticEntity._version), Short.class));
|
|
if (columns.contains(DmpElasticEntity._groupId)) mocDoc.setGroupId(FieldBasedMapper.shallowSafeConversion(rawData.get(DmpElasticEntity._groupId), UUID.class));
|
|
if (columns.contains(DmpElasticEntity._accessType)) mocDoc.setAccessType(FieldBasedMapper.shallowSafeConversion(rawData.get(DmpElasticEntity._accessType), DmpAccessType.class));
|
|
if (columns.contains(DmpElasticEntity._finalizedAt)) mocDoc.setFinalizedAt(FieldBasedMapper.shallowSafeConversion(rawData.get(DmpElasticEntity._finalizedAt), Date.class));
|
|
mocDoc.setCollaborators(this.convertNested(rawData, columns, this.queryFactory.query(NestedCollaboratorElasticQuery.class), DmpElasticEntity._collaborators, null));
|
|
mocDoc.setReferences(this.convertNested(rawData, columns, this.queryFactory.query(NestedReferenceElasticQuery.class), DmpElasticEntity._references, null));
|
|
mocDoc.setDescriptions(this.convertNested(rawData, columns, this.queryFactory.query(NestedDescriptionElasticQuery.class), DmpElasticEntity._descriptions, null));
|
|
return mocDoc;
|
|
}
|
|
|
|
@Override
|
|
protected ElasticField fieldNameOf(FieldResolver item) {
|
|
if (item.match(DmpElasticEntity._id)) return this.elasticFieldOf(DmpElasticEntity._id);
|
|
else if (item.match(DmpElasticEntity._label)) return item instanceof OrderingFieldResolver ? this.elasticFieldOf(DmpElasticEntity._label).subfield(ElasticConstants.SubFields.keyword) : this.elasticFieldOf(DmpElasticEntity._label);
|
|
else if (item.match(DmpElasticEntity._description)) return this.elasticFieldOf(DmpElasticEntity._description);
|
|
else if (item.match(DmpElasticEntity._status)) return this.elasticFieldOf(DmpElasticEntity._status);
|
|
else if (item.match(DmpElasticEntity._version)) return this.elasticFieldOf(DmpElasticEntity._version);
|
|
else if (item.match(DmpElasticEntity._versionStatus)) return this.elasticFieldOf(DmpElasticEntity._versionStatus);
|
|
else if (item.match(DmpElasticEntity._groupId)) return this.elasticFieldOf(DmpElasticEntity._groupId);
|
|
else if (item.match(DmpElasticEntity._finalizedAt)) return this.elasticFieldOf(DmpElasticEntity._finalizedAt);
|
|
else if (item.match(DmpElasticEntity._accessType)) return this.elasticFieldOf(DmpElasticEntity._accessType);
|
|
else if (item.prefix(DmpElasticEntity._collaborators)) return this.queryFactory.query(NestedCollaboratorElasticQuery.class).nestedPath(DmpElasticEntity._collaborators).fieldNameOf(this.extractPrefixed(item, DmpElasticEntity._collaborators));
|
|
else if (item.prefix(DmpElasticEntity._references)) return this.queryFactory.query(NestedReferenceElasticQuery.class).nestedPath(DmpElasticEntity._references).fieldNameOf(this.extractPrefixed(item, DmpElasticEntity._references));
|
|
else if (item.prefix(DmpElasticEntity._descriptions)) return this.queryFactory.query(NestedDescriptionElasticQuery.class).nestedPath(DmpElasticEntity._descriptions).fieldNameOf(this.extractPrefixed(item, DmpElasticEntity._descriptions));
|
|
else return null;
|
|
}
|
|
|
|
@Override
|
|
protected String[] getIndex() {
|
|
List<String> indexNames = new ArrayList<>();
|
|
indexNames.add(this.appElasticProperties.getDmpIndexName());
|
|
try {
|
|
this.elasticService.ensureDescriptionIndex();
|
|
} catch (IOException e) {
|
|
throw new RuntimeException(e);
|
|
}
|
|
return indexNames.toArray(new String[indexNames.size()]);
|
|
}
|
|
|
|
@Override
|
|
protected UUID toKey(String key) {
|
|
return UUID.fromString(key);
|
|
}
|
|
|
|
@Override
|
|
protected ElasticField getKeyField() {
|
|
return this.elasticFieldOf(DmpElasticEntity._id);
|
|
}
|
|
|
|
@Override
|
|
protected ElasticNestedQuery<?, ?, ?> nestedQueryOf(FieldResolver item) {
|
|
if (item.prefix(DmpElasticEntity._collaborators)) return this.queryFactory.query(NestedCollaboratorElasticQuery.class).nestedPath(DmpElasticEntity._collaborators);
|
|
else if (item.prefix(DmpElasticEntity._references)) return this.queryFactory.query(NestedReferenceElasticQuery.class).nestedPath(DmpElasticEntity._references);
|
|
else if (item.prefix(DmpElasticEntity._descriptions)) return this.queryFactory.query(NestedDescriptionElasticQuery.class).nestedPath(DmpElasticEntity._descriptions);
|
|
else return null;
|
|
}
|
|
}
|