package org.gcube.informationsystem.model.knowledge; import java.util.AbstractMap.SimpleEntry; import java.util.Arrays; import java.util.Collection; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; import java.util.Set; import org.gcube.informationsystem.base.reference.AccessType; import org.gcube.informationsystem.base.reference.entities.EntityElement; import org.gcube.informationsystem.base.reference.relations.RelationElement; import org.gcube.informationsystem.model.reference.entities.Facet; import org.gcube.informationsystem.model.reference.entities.Resource; import org.gcube.informationsystem.model.reference.relations.ConsistsOf; import org.gcube.informationsystem.model.reference.relations.IsRelatedTo; import org.gcube.informationsystem.model.reference.relations.Relation; import org.gcube.informationsystem.tree.Node; import org.gcube.informationsystem.tree.Tree; import org.gcube.informationsystem.types.PropertyTypeName; import org.gcube.informationsystem.types.TypeMapper; import org.gcube.informationsystem.types.impl.properties.PropertyDefinitionImpl; import org.gcube.informationsystem.types.reference.Type; import org.gcube.informationsystem.types.reference.entities.FacetType; import org.gcube.informationsystem.types.reference.entities.ResourceType; import org.gcube.informationsystem.types.reference.properties.LinkedEntity; import org.gcube.informationsystem.types.reference.properties.PropertyDefinition; import org.gcube.informationsystem.types.reference.relations.ConsistsOfType; import org.gcube.informationsystem.types.reference.relations.IsRelatedToType; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * @author Luca Frosini (ISTI - CNR) */ public class ModelKnowledge> { private static final Logger logger = LoggerFactory.getLogger(ModelKnowledge.class); protected TI typeInformation; protected Map> trees; protected UsageKnowledge> propertyUsage; protected Map> erTypesUsage; protected Map locate; public ModelKnowledge(TI typeInformation) { this.typeInformation = typeInformation; reset(); } protected void reset() { this.trees = new HashMap<>(); this.erTypesUsage = new HashMap<>(); this.locate = new HashMap<>(); AccessType[] modelTypes = AccessType.getModelTypes(); for(AccessType accessType : modelTypes) { /* * T t = typeInformation.getRoot(accessType); * Tree tree = new Tree<>(t, typeInformation); */ Tree tree = new Tree<>(typeInformation); trees.put(accessType, tree); if(accessType == AccessType.PROPERTY) { /* * In this case we get the type which uses such a property * and the property definition. * In this way we have a complete overview of the usage of the * property type */ propertyUsage = new UsageKnowledge<>(accessType); }else { UsageKnowledge usageKnowledge = new UsageKnowledge(accessType); erTypesUsage.put(accessType, usageKnowledge); } } } protected void addUsage(LinkedEntity linkedEntity, UsageKnowledge relationUsage, UsageKnowledge targetEntityUsage) { if (linkedEntity != null) { UsageKnowledge resourceUsage = erTypesUsage.get(AccessType.RESOURCE); String source = linkedEntity.getSource(); resourceUsage.add(source, linkedEntity); String relation = linkedEntity.getRelation(); relationUsage.add(relation, linkedEntity); String target = linkedEntity.getTarget(); targetEntityUsage.add(target, linkedEntity); } } protected void addAllUsage(Collection linkedEntities, UsageKnowledge relationUsage, UsageKnowledge targetEntityUsage) { if(linkedEntities!=null) { for(LinkedEntity le : linkedEntities) { addUsage(le, relationUsage, targetEntityUsage); } } } protected void addPropertyUsage(T t, Set properties) { if(properties==null || properties.size()==0) { return; } String typeName = typeInformation.getIdentifier(t); for(PropertyDefinition propertyDefinition : properties) { PropertyTypeName propertyTypeName = ((PropertyDefinitionImpl) propertyDefinition).getPropertyTypeName(); if(propertyTypeName.isGenericType()) { SimpleEntry entry = new SimpleEntry<>(typeName, propertyDefinition); propertyUsage.add(propertyTypeName.getGenericClassName(), entry); } } } protected void addEntityMetadataUsage(T t) { Type type = TypeMapper.createTypeDefinition(EntityElement.class); addPropertyUsage(t, type.getProperties()); } protected void addRelationMetadataUsage(T t) { Type type = TypeMapper.createTypeDefinition(RelationElement.class); addPropertyUsage(t, type.getProperties()); } protected void addPropagationConstraintUsage(T t) { Type type = TypeMapper.createTypeDefinition(Relation.class); addPropertyUsage(t, type.getProperties()); } public void addAllType(Collection types) { Set toRetry = new HashSet<>(); for(T t : types) { logger.trace("Going to add {}", typeInformation.getIdentifier(t)); try { addType(t); }catch (RuntimeException e) { toRetry.add(t); } } if(types.size()==toRetry.size()) { throw new RuntimeException("Unable to find parent for " + toRetry.toString()); } if(toRetry.size()>0) { addAllType(toRetry); } } public void addType(T t) { AccessType accessType = typeInformation.getAccessType(t); String typeName = typeInformation.getIdentifier(t); if(locate.get(typeName)!=null) { logger.trace("The type {} was already added to the ModelKnowledge", typeName); return; } Tree tree = trees.get(accessType); tree.addNode(t); locate.put(typeName, accessType); UsageKnowledge resourceUsage = erTypesUsage.get(AccessType.RESOURCE); UsageKnowledge facetUsage = erTypesUsage.get(AccessType.FACET); UsageKnowledge isRelatedToUsage = erTypesUsage.get(AccessType.IS_RELATED_TO); UsageKnowledge consistsOfUsage = erTypesUsage.get(AccessType.CONSISTS_OF); switch (accessType) { case PROPERTY: // Nothing to do break; case RESOURCE: ResourceType resourceType = (ResourceType) t; addAllUsage(resourceType.getFacets(), consistsOfUsage, facetUsage); addAllUsage(resourceType.getResources(), isRelatedToUsage, resourceUsage); /* * Metadata is defined in parent type i.e. EntityElement. * We want to have a reference to all Base type */ if(typeName.compareTo(Resource.NAME)==0) { addEntityMetadataUsage(t); } break; case FACET: FacetType facetType = (FacetType) t; /* * Metadata is defined in parent type i.e. EntityElement. * We want to have a reference to all Base type */ if(typeName.compareTo(Facet.NAME)==0) { addEntityMetadataUsage(t); } addPropertyUsage(t, facetType.getProperties()); break; case IS_RELATED_TO: IsRelatedToType isRelatedToType = (IsRelatedToType) t; /* * Metadata is defined in parent type i.e. RelationElement. * We want to have a reference to all Base type */ if(typeName.compareTo(IsRelatedTo.NAME)==0) { addRelationMetadataUsage(t); addPropagationConstraintUsage(t); } addPropertyUsage(t, isRelatedToType.getProperties()); break; case CONSISTS_OF: ConsistsOfType consistsOfType = (ConsistsOfType) t; /* * Metadata is defined in parent type i.e. RelationElement. * We want to have a reference to all Base type */ if(typeName.compareTo(ConsistsOf.NAME)==0) { addRelationMetadataUsage(t); addPropagationConstraintUsage(t); } addPropertyUsage(t, consistsOfType.getProperties()); break; default: break; } } public Tree getTree(AccessType accessType) { return trees.get(accessType); } public UsageKnowledge getModelTypesUsage(AccessType accessType) { List modelTypes = Arrays.asList(AccessType.getModelTypes()); if(!modelTypes.contains(accessType)) { throw new RuntimeException("Only ModelTypes are allowed, i.e. " + modelTypes.toString()); } if(accessType == AccessType.PROPERTY) { return propertyUsage; }else { return erTypesUsage.get(accessType); } } public UsageKnowledge getERTypesUsage(AccessType accessType) { List erTypes = Arrays.asList(AccessType.getERTypes()); if(!erTypes.contains(accessType)) { throw new RuntimeException("Only ERTypes are allowed, i.e. " + erTypes.toString()); } return erTypesUsage.get(accessType); } public UsageKnowledge> getPropertyUsage(){ return propertyUsage; } public UsageKnowledge getResourceUsage() { return erTypesUsage.get(AccessType.RESOURCE); } public UsageKnowledge getFacetUsage() { return erTypesUsage.get(AccessType.FACET); } public UsageKnowledge getIsRelatedToUsage() { return erTypesUsage.get(AccessType.IS_RELATED_TO); } public UsageKnowledge getConsistsOfUsage() { return erTypesUsage.get(AccessType.CONSISTS_OF); } /** * Return the type if it is contained in the Knowledge * @param typeName the type we are looking for * @return the Type * @throws RuntimeException */ public T getTypeByName(String typeName) throws RuntimeException { return getNodeByName(typeName).getNodeElement(); } /** * Return the node fro the type if it is contained in the Knowledge * @param typeName the type we are looking for * @return the Type * @throws RuntimeException */ public Node getNodeByName(String typeName) throws RuntimeException { AccessType accessType = locate.get(typeName); if(accessType==null) { throw new RuntimeException("The type " + typeName + " is not contained in the Knowledge"); } Tree tree = trees.get(accessType); return tree.getNodeByIdentifier(typeName); } }