| /******************************************************************************* |
| * Copyright (c) 2018 Aston University. |
| * |
| * This program and the accompanying materials are made available under the |
| * terms of the Eclipse Public License 2.0 which is available at |
| * http://www.eclipse.org/legal/epl-2.0. |
| * |
| * This Source Code may also be made available under the following Secondary |
| * Licenses when the conditions for such availability set forth in the Eclipse |
| * Public License, v. 2.0 are satisfied: GNU General Public License, version 3. |
| * |
| * SPDX-License-Identifier: EPL-2.0 OR GPL-3.0 |
| * |
| * Contributors: |
| * Antonio Garcia-Dominguez - initial API and implementation |
| ******************************************************************************/ |
| package org.eclipse.hawk.greycat; |
| |
| import java.util.Map; |
| import java.util.Set; |
| import java.util.concurrent.CompletableFuture; |
| import java.util.concurrent.ExecutionException; |
| |
| import org.eclipse.hawk.core.graph.IGraphEdge; |
| import org.eclipse.hawk.greycat.GreycatNode.NodeReader; |
| import org.slf4j.Logger; |
| import org.slf4j.LoggerFactory; |
| |
| import greycat.Node; |
| import greycat.Type; |
| |
| /** |
| * "Heavy" edge that can have its own properties. Emulated in Greycat |
| * through documents, like in Orient. |
| */ |
| public class GreycatHeavyEdge implements IGraphEdge { |
| |
| public static GreycatHeavyEdge create(String type, GreycatNode from, GreycatNode to, Map<String, Object> props) { |
| try (NodeReader rStart = from.getNodeReader(); NodeReader rEnd = to.getNodeReader()) { |
| final GreycatNode gHeavyEdgeNode = from.getGraph().createNode(props, NODETYPE); |
| |
| try (GreycatNode.NodeReader rEdge = gHeavyEdgeNode.getNodeReader()) { |
| final Node heavyEdgeNode = rEdge.get(); |
| |
| heavyEdgeNode.set(GreycatHeavyEdge.TYPE_PROP, Type.STRING, type); |
| heavyEdgeNode.addToRelation(GreycatHeavyEdge.START_REL, rStart.get()); |
| heavyEdgeNode.addToRelation(GreycatHeavyEdge.END_REL, rEnd.get()); |
| GreycatNode.addOutgoing(type, rStart, rEdge); |
| GreycatNode.addIncoming(type, rEnd, rEdge); |
| rEdge.markDirty(); |
| } |
| |
| return new GreycatHeavyEdge(gHeavyEdgeNode, type); |
| } |
| } |
| |
| private static final Logger LOGGER = LoggerFactory.getLogger(GreycatHeavyEdge.class); |
| |
| protected static final String NODETYPE = "h_heavyEdge"; |
| protected static final String END_REL = "h_end"; |
| protected static final String START_REL = "h_start"; |
| protected static final String TYPE_PROP = "h_type"; |
| |
| private final GreycatNode node; |
| |
| /** |
| * The type is already known from the in/out edge of the target/source node, but |
| * we keep it in the intermediate node as well in case the user takes advantage |
| * of a node visualizer. |
| */ |
| private final String type; |
| |
| public GreycatHeavyEdge(GreycatNode node, String type) { |
| this.node = node; |
| this.type = type; |
| } |
| |
| @Override |
| public Object getId() { |
| return node.getId(); |
| } |
| |
| @Override |
| public String getType() { |
| return type; |
| } |
| |
| @Override |
| public Set<String> getPropertyKeys() { |
| return node.getPropertyKeys(); |
| } |
| |
| @Override |
| public Object getProperty(String name) { |
| return node.getProperty(name); |
| } |
| |
| @Override |
| public void setProperty(String name, Object value) { |
| node.setProperty(name, value); |
| } |
| |
| @Override |
| public GreycatNode getStartNode() { |
| return getRawTarget(START_REL); |
| } |
| |
| @Override |
| public GreycatNode getEndNode() { |
| return getRawTarget(END_REL); |
| } |
| |
| public GreycatNode getBackingNode() { |
| return node; |
| } |
| |
| @Override |
| public void delete() { |
| final GreycatNode startNode = getStartNode(); |
| final GreycatNode endNode = getEndNode(); |
| |
| try ( |
| NodeReader rEdge = node.getNodeReader(); |
| NodeReader rStart = startNode.getNodeReader(); |
| NodeReader rEnd = endNode.getNodeReader() |
| ) { |
| final String type = getType(); |
| |
| GreycatNode.removeOutgoing(type, rStart, rEdge); |
| GreycatNode.removeIncoming(type, rEnd, rEdge); |
| |
| final Node edgeNode = rEdge.get(); |
| if (edgeNode.timeDephasing() > 0 || node.getAllVersions().size() > 1) { |
| /* There is more than one instant for this edge: end it in the previous timepoint. */ |
| node.travelInTime(node.getTime() - 1).end(); |
| } else { |
| /* There is exactly one version and we are right in its timepoint - just delete the backing node altogether. */ |
| node.delete(); |
| } |
| } catch (Exception e) { |
| LOGGER.error(e.getMessage(), e); |
| } |
| } |
| |
| @Override |
| public void removeProperty(String name) { |
| node.removeProperty(name); |
| } |
| |
| protected GreycatNode getRawTarget(final String relationName) { |
| try (NodeReader reader = node.getNodeReader()) { |
| CompletableFuture<GreycatNode> result = new CompletableFuture<>(); |
| reader.get().traverse(relationName, (Node[] targets) -> { |
| final Node target = targets[0]; |
| final GreycatNode newNode = node.getGraph().lookup( |
| target.world(), target.time(), target.id()); |
| for (Node t : targets) { |
| t.free(); |
| } |
| result.complete(newNode); |
| }); |
| |
| return result.get(); |
| } catch (InterruptedException | ExecutionException e) { |
| LOGGER.error(e.getMessage(), e); |
| return null; |
| } |
| } |
| |
| @Override |
| public int hashCode() { |
| final int prime = 31; |
| int result = 1; |
| result = prime * result + ((node == null) ? 0 : node.hashCode()); |
| return result; |
| } |
| |
| @Override |
| public boolean equals(Object obj) { |
| if (this == obj) |
| return true; |
| if (obj == null) |
| return false; |
| if (getClass() != obj.getClass()) |
| return false; |
| GreycatHeavyEdge other = (GreycatHeavyEdge) obj; |
| if (node == null) { |
| if (other.node != null) |
| return false; |
| } else if (!node.equals(other.node)) |
| return false; |
| return true; |
| } |
| |
| @Override |
| public String toString() { |
| return "GreycatHeavyEdge [node=" + node + ", getStartNode()=" + getStartNode() + ", getEndNode()=" |
| + getEndNode() + "]"; |
| } |
| |
| } |