io.mindmaps.graph.internal.RelationImpl Maven / Gradle / Ivy
/*
* MindmapsDB - A Distributed Semantic Database
* Copyright (C) 2016 Mindmaps Research Ltd
*
* MindmapsDB is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* MindmapsDB is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with MindmapsDB. If not, see .
*/
package io.mindmaps.graph.internal;
import io.mindmaps.util.Schema;
import io.mindmaps.util.ErrorMessage;
import io.mindmaps.exception.ConceptException;
import io.mindmaps.concept.Instance;
import io.mindmaps.concept.Relation;
import io.mindmaps.concept.RelationType;
import io.mindmaps.concept.RoleType;
import org.apache.tinkerpop.gremlin.structure.Direction;
import org.apache.tinkerpop.gremlin.structure.Vertex;
import java.util.*;
/**
* A relation represents and instance of a relation type which concept how different entities relate to one another.
*/
class RelationImpl extends InstanceImpl implements Relation {
RelationImpl(Vertex v, RelationType type, AbstractMindmapsGraph mindmapsGraph) {
super(v, type, mindmapsGraph);
}
/**
*
* @return All the castings this relation is connected with
*/
public Set getMappingCasting() {
Set castings = new HashSet<>();
getOutgoingNeighbours(Schema.EdgeLabel.CASTING).forEach(casting -> castings.add(casting.asCasting()));
return castings;
}
/**
* Sets the internal hash in order to perform a faster lookup
* @param roleMap The roles and their corresponding role players
*/
public void setHash(Map roleMap){
if(roleMap == null || roleMap.isEmpty())
setUniqueProperty(Schema.ConceptProperty.INDEX, "RelationBaseId_" + getBaseIdentifier() + UUID.randomUUID().toString());
else
setUniqueProperty(Schema.ConceptProperty.INDEX, generateNewHash(type(), roleMap));
}
/**
*
* @param relationType The type of this relation
* @param roleMap The roles and their corresponding role players
* @return A unique hash identifying this relation
*/
public static String generateNewHash(RelationType relationType, Map roleMap){
SortedSet sortedRoleIds = new TreeSet<>(roleMap.keySet());
String hash = "RelationType_" + relationType.getId().replace("_", "\\_") + "_Relation";
for(RoleType role: sortedRoleIds){
hash = hash + "_" + role.getId().replace("_", "\\_") ;
Instance instance = roleMap.get(role);
if(instance != null){
hash = hash + "_" + instance.getId().replace("_", "\\_") ;
}
}
return hash;
}
/**
*
* @return A list of all the Instances involved in the relationships and the Role Types which they play.
*/
@Override
public Map rolePlayers() {
Set castings = getMappingCasting();
HashMap roleMap = new HashMap<>();
//Gets roles based on all roles of the relation type
type().hasRoles().forEach(roleType -> roleMap.put(roleType, null));
//Get roles based on availiable castings
castings.forEach(casting -> roleMap.put(casting.getRole(), casting.getRolePlayer()));
return roleMap;
}
/**
*
* @return A list of the Instances which scope this Relation
*/
@Override
public Set scopes() {
HashSet scopes = new HashSet<>();
getOutgoingNeighbours(Schema.EdgeLabel.HAS_SCOPE).forEach(concept -> scopes.add(concept.asInstance()));
return scopes;
}
/**
*
* @param instance A new instance which can scope this Relation
* @return The Relation itself
*/
@Override
public Relation scope(Instance instance) {
putEdge(instance, Schema.EdgeLabel.HAS_SCOPE);
return this;
}
/**
* Expands this Relation to include a new role player which is playing a specific role.
* @param roleType The role of the new role player.
* @param instance The new role player.
* @return The Relation itself
*/
@Override
public Relation putRolePlayer(RoleType roleType, Instance instance) {
if(roleType == null){
throw new IllegalArgumentException(ErrorMessage.ROLE_IS_NULL.getMessage(instance));
}
if(mindmapsGraph.isBatchLoadingEnabled()) {
return addNewRolePlayer(null, roleType, instance);
} else {
Map roleMap = rolePlayers();
roleMap.put(roleType, instance);
Relation otherRelation = mindmapsGraph.getRelation(type(), roleMap);
if(otherRelation == null){
return addNewRolePlayer(roleMap, roleType, instance);
}
if(!this.equals(otherRelation)){
throw new ConceptException(ErrorMessage.RELATION_EXISTS.getMessage(otherRelation));
} else {
return this;
}
}
}
/**
* Adds a new role player to this relation
* @param roleType The role of the new role player.
* @param instance The new role player.
* @return The Relation itself
*/
private Relation addNewRolePlayer(Map roleMap, RoleType roleType, Instance instance){
if(instance != null)
mindmapsGraph.putCasting((RoleTypeImpl) roleType, (InstanceImpl) instance, this);
if(mindmapsGraph.isBatchLoadingEnabled()){
setHash(null);
} else {
setHash(roleMap);
}
return this;
}
/**
* @param scope A concept which is currently scoping this concept.
* @return The Relation itself
*/
@Override
public Relation deleteScope(Instance scope) throws ConceptException {
deleteEdgeTo(Schema.EdgeLabel.HAS_SCOPE, scope);
return this;
}
/**
* When a relation is deleted this cleans up any solitary casting and resources.
*/
public void cleanUp() {
boolean performDeletion = true;
Collection rolePlayers = rolePlayers().values();
// tracking
rolePlayers.forEach(r -> {
if(r != null)
getMindmapsGraph().getConceptLog().putConcept((ConceptImpl) r);
});
this.getMappingCasting().forEach(c -> getMindmapsGraph().getConceptLog().putConcept(c));
for(Instance instance : rolePlayers){
if(instance != null && (instance.getId() != null )){
performDeletion = false;
}
}
if(performDeletion){
delete();
}
}
/**
* Deletes the concept as a Relation
*/
@Override
public void innerDelete() {
scopes().forEach(this::deleteScope);
Set castings = getMappingCasting();
for (CastingImpl casting: castings) {
InstanceImpl, ?> instance = casting.getRolePlayer();
if(instance != null) {
for (EdgeImpl edge : instance.getEdgesOfType(Direction.BOTH, Schema.EdgeLabel.SHORTCUT)) {
if(edge.getProperty(Schema.EdgeProperty.RELATION_ID).equals(getId())){
edge.delete();
}
}
}
}
super.innerDelete();
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy