package aQute.remote.agent;
import java.io.Closeable;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.ServiceLoader;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.atomic.AtomicBoolean;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleException;
import org.osgi.framework.FrameworkEvent;
import org.osgi.framework.FrameworkListener;
import org.osgi.framework.launch.Framework;
import org.osgi.framework.launch.FrameworkFactory;
import aQute.remote.api.Agent;
import aQute.remote.api.Supervisor;
import aQute.remote.util.Link;
/**
* This class collaborates with the Envoy part of this design. After the envoy
* has installed the -runpath it will reflectively call this class to create a
* framework and run an {@link AgentServer}.
*/
public class AgentDispatcher {
//
// We keep a descriptor for each created framework by its name.
//
static List<Descriptor> descriptors = new CopyOnWriteArrayList<Descriptor>();
static class Descriptor implements Closeable {
AtomicBoolean closed = new AtomicBoolean(false);
List<AgentServer> servers = new CopyOnWriteArrayList<AgentServer>();
Framework framework;
Map<String,Object> configuration;
File storage;
File shaCache;
String name;
public List<BundleActivator> activators = new ArrayList<BundleActivator>();
@Override
public void close() throws IOException {
if (closed.getAndSet(true))
return;
for (AgentServer as : servers) {
try {
as.close();
} catch (Exception e) {
// ignore
}
}
for (BundleActivator ba : activators)
try {
ba.stop(framework.getBundleContext());
} catch (Exception e) {
// ignore
}
try {
framework.stop();
} catch (BundleException e) {
// ignore
}
}
}
/**
* Create a new framework. This is reflectively called from the Envoy
*/
public static Descriptor createFramework(String name, Map<String,Object> configuration, final File storage,
final File shacache) throws Exception {
//
// Use the service loader for loading a framework
//
ClassLoader loader = AgentServer.class.getClassLoader();
ServiceLoader<FrameworkFactory> sl = ServiceLoader.load(FrameworkFactory.class, loader);
FrameworkFactory ff = null;
for (FrameworkFactory fff : sl) {
ff = fff;
// break;
}
if (ff == null)
throw new IllegalArgumentException("No framework on runpath");
//
// Create the framework
//
@SuppressWarnings({
"unchecked", "rawtypes"
})
Framework framework = ff.newFramework((Map) configuration);
framework.init();
framework.getBundleContext().addFrameworkListener(new FrameworkListener() {
@Override
public void frameworkEvent(FrameworkEvent event) {
// System.err.println("FW Event " + event);
}
});
framework.start();
Descriptor d = new Descriptor();
//
// create a new descriptor. This is returned
// to the envoy side as an Object and we will
// get this back later in toAgent. The envoy
// maintains a list of name -> framework
//
d.framework = framework;
d.shaCache = shacache;
d.storage = storage;
d.configuration = configuration;
d.name = name;
String embedded = (String) configuration.get("biz.aQute.remote.embedded");
if (embedded != null && !(embedded = embedded.trim()).isEmpty()) {
String activators[] = embedded.trim().split("\\s*,\\s*");
for (String activator : activators)
try {
Class< ? > activatorClass = loader.loadClass(activator);
if (BundleActivator.class.isAssignableFrom(activatorClass)) {
// TODO check immediate
BundleActivator ba = (BundleActivator) activatorClass.getConstructor().newInstance();
ba.start(framework.getBundleContext());
d.activators.add(ba);
}
} catch (Exception e) {
// TODO
System.out.println("IGNORED");
e.printStackTrace();
}
}
return d;
}
/**
* Create a new agent on an existing framework.
*/
public static void toAgent(final Descriptor descriptor, DataInputStream in, DataOutputStream out) {
//
// Check if the framework is active
if (descriptor.framework.getState() != Bundle.ACTIVE) {
throw new IllegalStateException("Framework " + descriptor.name + " is not active. (Stopped?)");
}
//
// Get the bundle context
//
BundleContext context = descriptor.framework.getBundleContext();
AgentServer as = new AgentServer(descriptor.name, context, descriptor.shaCache) {
//
// Override the close se we can remote it from the list
//
public void close() throws IOException {
descriptor.servers.remove(this);
super.close();
}
};
//
// Link up
//
Link<Agent,Supervisor> link = new Link<Agent,Supervisor>(Supervisor.class, as, in, out);
as.setLink(link);
link.open();
}
/**
* Close
*/
public static void close() throws IOException {
for (Descriptor descriptor : descriptors) {
descriptor.close();
}
for (Descriptor descriptor : descriptors) {
try {
descriptor.framework.waitForStop(2000);
} catch (InterruptedException e) {
// ignore
}
}
}
}