package org.molgenis.data.semanticsearch.service.impl;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import com.google.common.collect.Multimap;
import org.molgenis.data.DataService;
import org.molgenis.data.Entity;
import org.molgenis.data.UnknownEntityException;
import org.molgenis.data.meta.model.*;
import org.molgenis.data.meta.model.Package;
import org.molgenis.data.semantic.LabeledResource;
import org.molgenis.data.semantic.Relation;
import org.molgenis.data.semantic.SemanticTag;
import org.molgenis.data.semanticsearch.repository.TagRepository;
import org.molgenis.data.semanticsearch.service.TagService;
import org.molgenis.data.support.QueryImpl;
import org.molgenis.security.core.runas.RunAsSystem;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import static java.util.Objects.requireNonNull;
import static java.util.stream.StreamSupport.stream;
import static org.molgenis.data.meta.model.AttributeMetadata.ATTRIBUTE_META_DATA;
import static org.molgenis.data.meta.model.EntityTypeMetadata.ATTRIBUTES;
import static org.molgenis.data.meta.model.EntityTypeMetadata.ENTITY_TYPE_META_DATA;
import static org.molgenis.data.meta.model.PackageMetadata.PACKAGE;
/**
* Service to tag metadata with simple
* String terms.
*/
public class UntypedTagService implements TagService<LabeledResource, LabeledResource>
{
private static final Logger LOG = LoggerFactory.getLogger(UntypedTagService.class);
private final DataService dataService;
private final TagRepository tagRepository;
public UntypedTagService(DataService dataService, TagRepository tagRepository)
{
this.dataService = requireNonNull(dataService);
this.tagRepository = requireNonNull(tagRepository);
}
private Entity findAttributeEntity(EntityType entityType, String attributeName)
{
Entity entityTypeEntity = dataService.findOneById(ENTITY_TYPE_META_DATA, entityType.getName());
Optional<Entity> result = stream(entityTypeEntity.getEntities(ATTRIBUTES).spliterator(), false)
.filter(att -> attributeName.equals(att.getString(AttributeMetadata.NAME))).findFirst();
return result.isPresent() ? result.get() : null;
}
private Entity findEntity(EntityType emd)
{
return dataService.findOneById(ENTITY_TYPE_META_DATA, emd.getName());
}
@Override
public void removeAttributeTag(EntityType entityType,
SemanticTag<Attribute, LabeledResource, LabeledResource> removeTag)
{
Attribute attribute = removeTag.getSubject();
Entity attributeEntity = findAttributeEntity(entityType, attribute.getName());
List<Entity> tags = new ArrayList<Entity>();
for (Entity tagEntity : attributeEntity.getEntities(AttributeMetadata.TAGS))
{
SemanticTag<Attribute, LabeledResource, LabeledResource> tag = SemanticTag.asTag(attribute, tagEntity);
if (!removeTag.equals(tag))
{
tags.add(tagEntity);
}
}
attributeEntity.set(AttributeMetadata.TAGS, tags);
dataService.update(ATTRIBUTE_META_DATA, attributeEntity);
}
@Override
@RunAsSystem
public Multimap<Relation, LabeledResource> getTagsForAttribute(EntityType entityType, Attribute attribute)
{
Entity entity = findAttributeEntity(entityType, attribute.getName());
if (entity == null) return ArrayListMultimap.<Relation, LabeledResource>create();
Multimap<Relation, LabeledResource> tags = ArrayListMultimap.<Relation, LabeledResource>create();
for (Entity tagEntity : entity.getEntities(AttributeMetadata.TAGS))
{
SemanticTag<Attribute, LabeledResource, LabeledResource> tag = SemanticTag.asTag(attribute, tagEntity);
tags.put(tag.getRelation(), tag.getObject());
}
return tags;
}
@Override
@RunAsSystem
public Iterable<SemanticTag<EntityType, LabeledResource, LabeledResource>> getTagsForEntity(EntityType entityType)
{
List<SemanticTag<EntityType, LabeledResource, LabeledResource>> result = new ArrayList<SemanticTag<EntityType, LabeledResource, LabeledResource>>();
Entity entity = findEntity(entityType);
if (entity == null)
{
LOG.warn("No known entity with name " + entityType.getName() + ".");
}
else
{
for (Entity tagEntity : entity.getEntities(EntityTypeMetadata.TAGS))
{
result.add(SemanticTag.asTag(entityType, tagEntity));
}
}
return result;
}
@Override
public void addAttributeTag(EntityType entityType, SemanticTag<Attribute, LabeledResource, LabeledResource> tag)
{
Entity entity = findAttributeEntity(entityType, tag.getSubject().getName());
List<Entity> tags = new ArrayList<Entity>();
for (Entity tagEntity : entity.getEntities(AttributeMetadata.TAGS))
{
tags.add(tagEntity);
}
tags.add(getTagEntity(tag));
entity.set(AttributeMetadata.TAGS, tags);
dataService.update(ATTRIBUTE_META_DATA, entity);
}
@Override
public void addEntityTag(SemanticTag<EntityType, LabeledResource, LabeledResource> tag)
{
Entity entity = findEntity(tag.getSubject());
if (entity == null)
{
throw new UnknownEntityException("Unknown entity [" + tag.getSubject().getName() + "]");
}
ImmutableList<SemanticTag<EntityType, LabeledResource, LabeledResource>> existingTags = ImmutableList.<SemanticTag<EntityType, LabeledResource, LabeledResource>>copyOf(
getTagsForEntity(tag.getSubject()));
if (existingTags.contains(tag))
{
LOG.debug("Tag already present");
return;
}
ImmutableList.Builder<Entity> builder = ImmutableList.<Entity>builder();
builder.addAll(entity.getEntities(EntityTypeMetadata.TAGS));
builder.add(getTagEntity(tag));
entity.set(EntityTypeMetadata.TAGS, builder.build());
dataService.update(ENTITY_TYPE_META_DATA, entity);
}
public Entity getTagEntity(SemanticTag<?, LabeledResource, LabeledResource> tag)
{
return tagRepository.getTagEntity(tag.getObject().getIri(), tag.getObject().getLabel(), tag.getRelation(),
tag.getCodeSystem().getIri());
}
@Override
@RunAsSystem
public Iterable<SemanticTag<Package, LabeledResource, LabeledResource>> getTagsForPackage(Package p)
{
Entity packageEntity = dataService
.findOne(PACKAGE, new QueryImpl<Entity>().eq(PackageMetadata.FULL_NAME, p.getName()));
if (packageEntity == null)
{
throw new UnknownEntityException("Unknown package [" + p.getName() + "]");
}
List<SemanticTag<Package, LabeledResource, LabeledResource>> tags = Lists.newArrayList();
for (Entity tagEntity : packageEntity.getEntities(PackageMetadata.TAGS))
{
tags.add(SemanticTag.asTag(p, tagEntity));
}
return tags;
}
@Override
public void removeEntityTag(SemanticTag<EntityType, LabeledResource, LabeledResource> tag)
{
throw new UnsupportedOperationException("not yet implemented");
}
@Override
public void removeAllTagsFromEntity(String entityName)
{
throw new UnsupportedOperationException();
}
}