package org.archstudio.myx.fw.equinox;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.archstudio.myx.fw.IMyxBrickLoader;
import org.archstudio.myx.fw.MyxBasicRuntime;
import org.archstudio.myx.fw.MyxBrickLoaderException;
import org.archstudio.myx.fw.MyxUtils;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.Platform;
import org.eclipse.core.runtime.RegistryFactory;
import org.osgi.framework.Bundle;
import com.google.common.base.Functions;
import com.google.common.collect.ArrayListMultimap;
import com.google.common.collect.Collections2;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import com.google.common.collect.Multimap;
import com.google.common.collect.Sets;
/**
* A {@link MyxBasicRuntime} that automatically loads all brick loaders defined by the brickLoader extension points.
*/
public class MyxEquinoxRuntime extends MyxBasicRuntime {
private static final List<Class<IMyxBrickLoader>> brickLoaderClasses = Lists.newArrayList();
static {
try {
// load the brick loader extension points
Map<String, Class<IMyxBrickLoader>> brickLoaderNodes = Maps.newHashMap();
Multimap<String, String> brickLoaderEdges = ArrayListMultimap.create();
for (IConfigurationElement brickLoaderConfigurationElement : RegistryFactory.getRegistry()
.getConfigurationElementsFor("org.archstudio.myx.fw.equinox", "brickLoader")) {
String bundleName = brickLoaderConfigurationElement.getContributor().getName();
Bundle bundle = Platform.getBundle(bundleName);
String id = brickLoaderConfigurationElement.getAttribute("id");
String brickLoaderClassName = brickLoaderConfigurationElement.getAttribute("class");
@SuppressWarnings("unchecked")
Class<IMyxBrickLoader> brickLoaderClass = (Class<IMyxBrickLoader>) bundle
.loadClass(brickLoaderClassName);
brickLoaderNodes.put(id, brickLoaderClass);
for (IConfigurationElement c : brickLoaderConfigurationElement.getChildren("Override")) {
String overrideId = c.getAttribute("brickLoader");
brickLoaderEdges.put(id, overrideId);
}
}
// sort topologically (using algorithm from wikipedia)
List<String> L = Lists.newArrayList();
Set<String> S = Sets.newHashSet(brickLoaderNodes.keySet());
S.removeAll(brickLoaderEdges.values());
while (!S.isEmpty()) {
String n = S.iterator().next();
S.remove(n);
L.add(n);
for (Iterator<String> e = brickLoaderEdges.get(n).iterator(); e.hasNext();) {
String m = e.next();
e.remove();
if (!brickLoaderEdges.containsValue(m)) {
S.add(m);
}
}
}
if (!brickLoaderEdges.isEmpty()) {
throw new IllegalArgumentException("brick loaders contain overrides cycle");
}
brickLoaderClasses.addAll(Collections2.transform(L, Functions.forMap(brickLoaderNodes)));
}
catch (Exception e) {
throw new RuntimeException("Unable to initialize MyxEquinoxRuntime", e);
}
}
public MyxEquinoxRuntime() {
for (Class<IMyxBrickLoader> brickLoaderClass : brickLoaderClasses) {
try {
addBrickLoader(MyxUtils.createName(brickLoaderClass.getName()), brickLoaderClass, null);
}
catch (MyxBrickLoaderException mble) {
throw new RuntimeException("This shouldn't happen.", mble);
}
}
}
}