package org.simantics.district.route.internal; import java.util.ArrayList; import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Set; import java.util.UUID; import java.util.stream.Collectors; import org.eclipse.osgi.util.NLS; import org.simantics.Simantics; import org.simantics.databoard.Bindings; import org.simantics.databoard.util.ObjectUtils; import org.simantics.db.ReadGraph; import org.simantics.db.Resource; import org.simantics.db.WriteGraph; import org.simantics.db.common.request.ObjectsWithType; import org.simantics.db.common.request.ResourceRead; import org.simantics.db.common.request.UniqueRead; import org.simantics.db.common.utils.ListUtils; import org.simantics.db.common.utils.NameUtils; import org.simantics.db.exception.DatabaseException; import org.simantics.db.layer0.QueryIndexUtils; import org.simantics.db.layer0.request.PossibleActiveModel; import org.simantics.db.layer0.util.RemoverUtil; import org.simantics.district.network.ontology.DistrictNetworkResource; import org.simantics.district.route.Waypoint; import org.simantics.district.route.ontology.RouteResource; import org.simantics.layer0.Layer0; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * @author Tuukka Lehtonen */ public class RoutePersistence { private static final Logger LOGGER = LoggerFactory.getLogger(RoutePersistence.class); public static Resource getRouteFolder(ReadGraph graph, Resource model) throws DatabaseException { List diagrams = QueryIndexUtils.searchByType(graph, model, RouteResource.getInstance(graph).RouteFolder); if (diagrams.size() > 0) return diagrams.get(0); return null; } public static Resource getOrCreateRouteFolder(WriteGraph graph, Resource model) throws DatabaseException { Resource rf = getRouteFolder(graph, model); if (rf == null) { Layer0 L0 = Layer0.getInstance(graph); RouteResource RR = RouteResource.getInstance(graph); rf = graph.newResource(); graph.claim(rf, L0.InstanceOf, null, RR.RouteFolder); graph.claimLiteral(rf, L0.HasName, L0.NameOf, L0.String, UUID.randomUUID().toString(), Bindings.STRING); graph.claim(model, L0.ConsistsOf, L0.PartOf, rf); } return rf; } public static Resource createRoute(WriteGraph graph, Resource model, String label, List waypoints) throws DatabaseException { Resource rf = getOrCreateRouteFolder(graph, model); RouteResource RR = RouteResource.getInstance(graph); Layer0 L0 = Layer0.getInstance(graph); Resource route = ListUtils.create(graph, RR.Route, waypoints); graph.claim(rf, L0.ConsistsOf, L0.PartOf, route); graph.claimLiteral(route, L0.HasName, UUID.randomUUID().toString(), Bindings.STRING); graph.claimLiteral(route, L0.HasLabel, label, Bindings.STRING); LOGGER.info("Persisted route {} with label {} and waypoints {}", route, label, waypoints); return route; } public static void updateRoute(WriteGraph graph, Resource route, String label, List waypoints) throws DatabaseException { RouteResource RR = RouteResource.getInstance(graph); Layer0 L0 = Layer0.getInstance(graph); String existingLabel = graph.getPossibleRelatedValue(route, L0.HasLabel, Bindings.STRING); if (!ObjectUtils.objectEquals(existingLabel, label)) { graph.claimLiteral(route, L0.HasLabel, label, Bindings.STRING); } List existingWaypoints = ListUtils.toList(graph, route); if (!existingWaypoints.equals(waypoints)) { // TODO: optimize this ListUtils.removeElements(graph, route, new HashSet<>(existingWaypoints)); ListUtils.createExisting(graph, RR.Route, waypoints); } LOGGER.info("Updated route {} with label {} and waypoints {}", route, label, waypoints); } public static void removeRoute(WriteGraph graph, Resource route) throws DatabaseException { RemoverUtil.remove(graph, route); } public static Waypoint toWaypoint(ReadGraph graph, Resource waypoint) throws DatabaseException { DistrictNetworkResource DN = DistrictNetworkResource.getInstance(graph); Set types = graph.getTypes(waypoint); String name = NameUtils.getSafeName(graph, waypoint); if (types.contains(DN.Vertex)) { String address = graph.getPossibleRelatedValue(waypoint, DN.Vertex_HasAddress, Bindings.STRING); String label = address != null ? NLS.bind("Node {0} - {1}", name, address).trim() : NLS.bind("Node {0}", name, address).trim(); return new WaypointImpl(waypoint, label); } else if (types.contains(DN.Edge)) { return new WaypointImpl(waypoint, NLS.bind("Edge {0}", name)); } LOGGER.warn("Tried to convert unrecognized resource {} to a route waypoint", waypoint); return null; } public static List toWaypoints(ReadGraph graph, List waypoints) throws DatabaseException { List result = new ArrayList<>(); for (Resource wpr : waypoints) { Waypoint wp = toWaypoint(graph, wpr); if (wp != null) result.add(wp); } return result; } public static List findRoutes(ReadGraph graph, Resource model) throws DatabaseException { Resource rf = model != null ? getRouteFolder(graph, model) : null; if (rf == null) return Collections.emptyList(); Layer0 L0 = Layer0.getInstance(graph); RouteResource RR = RouteResource.getInstance(graph); List routes = new ArrayList<>(); for (Resource route : graph.syncRequest(new ObjectsWithType(rf, L0.ConsistsOf, RR.Route))) { RouteImpl ri = new RouteImpl(graph.getRelatedValue(route, L0.HasLabel, Bindings.STRING)) .backend(route) .modelEntity(model) .waypoints(toWaypoints(graph, ListUtils.toList(graph, route))); routes.add(ri); } return routes; } public static class ModelRoutesRequest extends ResourceRead> { public ModelRoutesRequest(Resource model) { super(model); } @Override public List perform(ReadGraph graph) throws DatabaseException { return findRoutes(graph, resource); } } public static class ActiveModelRoutesRequest extends UniqueRead> { @Override public List perform(ReadGraph graph) throws DatabaseException { return findRoutes(graph, graph.syncRequest(new PossibleActiveModel(Simantics.getProjectResource()))); } } public static List toResources(List waypoints) { return waypoints.stream() .map(Waypoint::getObject) .collect(Collectors.toList()); } }