blob: 9dd024cf8c3d6b2df4e95463b251db9aff7bf0e6 [file] [log] [blame]
/*******************************************************************************
* Copyright (c) 2009,2010 IBM Corporation and others.
* All rights reserved. This program and the accompanying materials
* are made available under the terms of the Eclipse Public License v1.0
* which accompanies this distribution, and is available at
* http://www.eclipse.org/legal/epl-v10.html
*
* Contributors:
* IBM Corporation - initial API and implementation
*******************************************************************************/
package org.eclipse.stem.definitions;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.SortedSet;
import java.util.TreeSet;
import org.eclipse.core.resources.IContainer;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.IResource;
import org.eclipse.emf.common.util.EList;
import org.eclipse.emf.common.util.EMap;
import org.eclipse.emf.common.util.URI;
import org.eclipse.stem.core.STEMURI;
import org.eclipse.stem.core.Utility;
import org.eclipse.stem.core.common.Identifiable;
import org.eclipse.stem.core.graph.Edge;
import org.eclipse.stem.core.graph.Graph;
import org.eclipse.stem.core.graph.LabelValue;
import org.eclipse.stem.core.graph.Node;
import org.eclipse.stem.core.model.Model;
import org.eclipse.stem.definitions.labels.CommonBorderRelationshipLabelValue;
import org.eclipse.stem.definitions.labels.RelativePhysicalRelationshipLabel;
import org.eclipse.stem.definitions.labels.RelativePhysicalRelationshipLabelValue;
/**
* Utility to extract node keys from a project
*/
public class LocationUtility {
static Map<String, Set<String>> [] treeISOKeyMaps = new Map[4];
static Map<String, URI> isoKeyURIMap = new HashMap<String, URI>();
static List<Model> processedModels = new ArrayList<Model>();
static boolean loaded = false;
public static void reset() {treeISOKeyMaps = new Map[4];isoKeyURIMap.clear();processedModels.clear();loaded=false;}
public static Set<String> getKeys(IProject project, int level, String parent) {
if(!loaded) {
for(int i=0;i<4;++i) treeISOKeyMaps[i] = new HashMap<String, Set<String>>();
IContainer modelFolder = project.getFolder("models");
IResource[] models = null;
try {
models = modelFolder.members();
} catch(Exception e) {
e.printStackTrace();
}
if (models != null) {
for(IResource r:models) {
// ignore system files
if(r.getName().startsWith(".")) continue;
try {
URI uri = URI.createURI(r.getLocationURI().toString());
Identifiable id = Utility.getIdentifiable(uri);
if(id instanceof Model) processModel((Model)id);
} catch(Exception e) {
// Skip bad file
}
}
}
IContainer graphsFolder = project.getFolder("graphs");
IResource[] graphs = null;
try {
graphs = graphsFolder.members();
} catch(Exception e) {
e.printStackTrace();
}
if (graphs != null) {
for(IResource r:graphs) {
// ignore system files
if(r.getName().startsWith(".")) continue;
try {
URI uri = URI.createURI(r.getLocationURI().toString());
Identifiable id = Utility.getIdentifiable(uri);
if(id instanceof Graph) processGraph((Graph)id);
} catch(Exception e) {
// Skip bad file
}
}
}
loaded = true;
}
Set<String>result = null;
if(parent != null) result = treeISOKeyMaps[level-1].get(parent);
else result = treeISOKeyMaps[level].keySet();
if(result!= null)
return result;
return new HashSet<String>(); // return empty array
}
private static void processModel(Model m) {
processedModels.add(m);
// First get sub models
for(Model m2:m.getModels())
if(!processedModels.contains(m2)) processModel(m2);
// To the graphs in the model
EList<Graph>graphs = m.getGraphs();
for(Graph g:graphs)
processGraph(g);
}
private static void processGraph(Graph g) {
// Do the edges first to get the hierarchy
for(Edge e:g.getEdges().values()) {
if(e.getLabel().getCurrentValue() instanceof RelativePhysicalRelationshipLabelValue) {
int sourceLevel = Utility.keyLevel(e.getNodeAURI().lastSegment());
int targetLevel = Utility.keyLevel(e.getNodeBURI().lastSegment());
String sourceKey = e.getNodeAURI().lastSegment();
String targetKey = e.getNodeBURI().lastSegment();
if(treeISOKeyMaps[sourceLevel].containsKey(sourceKey))
treeISOKeyMaps[sourceLevel].get(sourceKey).add(targetKey);
else {
SortedSet<String>nl = new TreeSet<String>();
treeISOKeyMaps[sourceLevel].put(sourceKey, nl);
nl.add(targetKey);
}
if(!treeISOKeyMaps[targetLevel].containsKey(targetKey)) {
// Add with empty child set
TreeSet<String>nl = new TreeSet<String>();
treeISOKeyMaps[targetLevel].put(targetKey, nl);
}
isoKeyURIMap.put(sourceKey, e.getNodeAURI());
isoKeyURIMap.put(targetKey, e.getNodeBURI());
}
}
// Now find dangling nodes
EMap<URI, Node> map = g.getNodes();
for(URI u:map.keySet()) {
int l = Utility.keyLevel(u.lastSegment());
if(l == -1) continue; // no world
String key = u.lastSegment();
if(!treeISOKeyMaps[l].containsKey(key)) {
TreeSet<String>nl = new TreeSet<String>();
treeISOKeyMaps[l].put(key, nl);
isoKeyURIMap.put(key, u);
}
}
}
/**
* Place the edges from the graph in a Map keyed by the URI of the edge.
* This avoids duplicates in case same graph exists in multiple models
* @param project
* @return
*/
public static Set<Edge> getCommonBorderEdges(IProject project, URI location) {
Map<String,Edge> cbEdges = new HashMap<String,Edge>();
IContainer modelFolder = project.getFolder("models");
IResource[] models = null;
try {
models = modelFolder.members();
} catch(Exception e) {
e.printStackTrace();
}
if (models != null) {
for(IResource r:models) {
// ignore system files
if(r.getName().startsWith(".")) continue;
try {
URI uri = URI.createURI(r.getLocationURI().toString());
Identifiable id = Utility.getIdentifiable(uri);
Graph g = ((Model)id).getCanonicalGraph(STEMURI.createURI(""), null, null);
if(id instanceof Model) cbEdges.putAll(getGraphCommonBorderEdges(g, location));
} catch(Exception e) {
// Skip bad file
}
}
}
// Only do the edges in the graphs folder if the user hasn't specified a
// location, since we need to resolve the URI's to support locations
if(location == null || location.toString().trim().equals("")) {
IContainer graphsFolder = project.getFolder("graphs");
IResource[] graphs = null;
try {
graphs = graphsFolder.members();
} catch(Exception e) {
e.printStackTrace();
}
if (graphs != null) {
for(IResource r:graphs) {
// ignore system files
if(r.getName().startsWith(".")) continue;
try {
URI uri = URI.createURI(r.getLocationURI().toString());
Identifiable id = Utility.getIdentifiable(uri);
if(id instanceof Graph) cbEdges.putAll(getGraphCommonBorderEdges((Graph)id, location));
} catch(Exception e) {
// Skip bad file
}
}
}
}
Set<Edge> retVal = new HashSet<Edge>();
retVal.addAll(cbEdges.values());
return retVal;
}
/***
* Place the edges from the graph in a Map keyed by the URI of the edge.
* This avoids duplicates in case same graph exists in multiple models
* @param g
*/
private static Map<String,Edge> getGraphCommonBorderEdges(Graph g, URI location) {
Map<String,Edge> cbEdges = new HashMap<String,Edge>();
for(Edge e:g.getEdges().values()) {
if(e.getLabel().getCurrentValue() instanceof CommonBorderRelationshipLabelValue) {
String uriKey = e.getURI().lastSegment();
if(location != null && !location.toString().trim().equals("")
&& isSelfOrChild(e.getA(), location.lastSegment()) && isSelfOrChild(e.getB(), location.lastSegment()))
cbEdges.put(uriKey,e);
else if(location == null || location.toString().trim().equals(""))
cbEdges.put(uriKey,e);
}
}
return cbEdges;
}//getGraphCommonBorderEdges
/**
* Retrieve all nodes in a project
* @param project
* @param location The parent location
* @return Set<Node> All nodes in parent and children
*/
public static Set<Node> getNodes(IProject project, URI location) {
Set<Node> allNodes = new HashSet<Node>();
IContainer modelFolder = project.getFolder("models");
IResource[] models = null;
try {
models = modelFolder.members();
} catch(Exception e) {
e.printStackTrace();
}
if (models != null) {
for(IResource r:models) {
// ignore system files
if(r.getName().startsWith(".")) continue;
try {
URI uri = URI.createURI(r.getLocationURI().toString());
Model mod = (Model)Utility.getIdentifiable(uri);
Graph g = mod.getCanonicalGraph(STEMURI.createURI(""), null, null);
addGraphNodes(g, allNodes, location);
} catch(Exception e) {
// Skip bad file
}
}
}
return allNodes;
}
/***
* Retrieve all nodes for the location in the graph
* @param g
* @param allNodes Results are stored here
* @param location The location, or null if all nodes should be retrieved
*/
private static void addGraphNodes(Graph g, Set<Node>allNodes, URI location) {
for(Node n:g.getNodes().values()) {
String uriKey = n.getURI().lastSegment();
if(location != null && !location.toString().trim().equals("")
&& isSelfOrChild(n, location.lastSegment()) &&
!containsNodeURI(n.getURI(), allNodes))
allNodes.add(n);
else if(location == null || location.toString().trim().equals("") && ! allNodes.contains(n)
&& !containsNodeURI(n.getURI(), allNodes))
allNodes.add(n);
}
}//getGraphCommonBorderEdges
private static boolean containsNodeURI(URI uri, Set<Node>nodes) {
for(Node n:nodes) if(n.getURI().equals(uri)) return true;
return false;
}
public static URI getURIFromISOKey(String key) {
return isoKeyURIMap.get(key);
}
protected static boolean isSelfOrChild(Node n, String parent) {
if(n.getURI().lastSegment().equals(parent)) return true;
return hasParent(n, parent);
}
protected static boolean hasParent(Node n, String key) {
for(Edge e:n.getEdges()) {
// Make sure it's a physical containment edge
boolean phys = e.getLabel() instanceof RelativePhysicalRelationshipLabel;
if(!phys)
continue;
if(e.getA().getURI().lastSegment().equals(key)) return true;
else if(Utility.keyLevel(e.getA().getURI().lastSegment()) < Utility.keyLevel(n.getURI().lastSegment()))
return hasParent(e.getA(), key);
}
return false;
}
/**
* finds all the child nodes of a parent (direct children and children of children etc...)
* and returns them in a set.
* Child is defined by a containment relationship
* @param parent
*/
public static Set<Node> getAllChildren(Node parent) {
Set<Node> allChildren = new HashSet<Node>();
Set<Node> toDoSet = getChildSet(parent);
toDoSet.remove(parent);
Set<Node> directChildren = new HashSet<Node>();
while(toDoSet.size() >=1) {
directChildren.addAll(toDoSet);
Iterator<Node> iter = directChildren.iterator();
while(iter!=null && iter.hasNext()) {
Node next = iter.next();
allChildren.add(next);
Set<Node> nextSet = getChildSet(next);
nextSet.removeAll(allChildren);
toDoSet.addAll(nextSet);
}
toDoSet.removeAll(directChildren);
directChildren.clear();
}
return allChildren;
}
/**
* finds all the direct child nodes of a parent and returns them in a set.
* Child is defined by a containment relationship
* @param parent
*/
public static Set<Node> getChildSet(Node parent) {
Set<Node> children = new HashSet<Node>();
if(parent == null) return children;
String parentID = parent.getURI().lastSegment();
//RelativePhysicalRelationshipLabelValue
EList<Edge> allEdges = parent.getEdges();
for (int i = 0; i < allEdges.size(); i ++) {
Edge e = allEdges.get(i);
LabelValue lv = e.getLabel().getCurrentValue();
if(lv instanceof RelativePhysicalRelationshipLabelValue) {
RelativePhysicalRelationshipLabelValue containment = (RelativePhysicalRelationshipLabelValue)lv;
Node neighborNode = e.getOtherNode(parent);
String neighborID= neighborNode.getURI().lastSegment();
// is it really a child
if(neighborID.length() > parentID.length() || parentID.equals("ZZZ")) {
//yes
children.add(neighborNode);
}// is child
}// is containment relationship
}// for all edges
//just to be sure
children.remove(parent);
return children;
}
}