package aQute.remote.plugin;
import java.io.File;
import java.io.IOException;
import java.net.InetAddress;
import java.net.Socket;
import java.util.ArrayList;
import java.util.Collection;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.TimeUnit;
import aQute.bnd.build.RunSession;
import aQute.bnd.osgi.Constants;
import aQute.remote.api.Agent;
/**
* A session is a connection to a remote framework. It is possible to have many
* sessions at the same time. This object maintains the state of the connection
* and provides means to cancel the connection.
*/
public class RunSessionImpl implements RunSession {
private LauncherSupervisor supervisor;
private RemoteProjectLauncherPlugin launcher;
private RunRemoteDTO dto;
private Map<String,Object> properties;
public CountDownLatch started = new CountDownLatch(1);
private Appendable stderr;
private Appendable stdout;
private int shell = -4711;
public static int jdb = 16043;
public RunSessionImpl(RemoteProjectLauncherPlugin launcher, RunRemoteDTO dto, Map<String,Object> properties)
throws Exception {
this.launcher = launcher;
this.properties = properties;
this.dto = dto;
if (dto.agent <= 0)
dto.agent = Agent.DEFAULT_PORT;
if (dto.host == null)
dto.host = "localhost";
if (dto.jdb <= 0)
dto.jdb = jdb++;
if (dto.timeout <= 0)
dto.timeout = 5000;
}
@Override
public String getName() {
return dto.name;
}
@Override
public String getLabel() {
return dto.name + " – " + dto.host + ":" + dto.agent;
}
@Override
public int getJdb() {
return dto.jdb;
}
@Override
public void stderr(Appendable app) throws Exception {
stderr = app;
if (supervisor != null)
supervisor.setStderr(app);
}
@Override
public void stdout(Appendable app) throws Exception {
stdout = app;
if (supervisor != null)
supervisor.setStdout(app);
}
@Override
public void stdin(String input) throws Exception {
if (supervisor != null)
supervisor.getAgent().stdin(input);
}
@Override
public int launch() throws Exception {
try {
supervisor = new LauncherSupervisor();
supervisor.connect(dto.host, dto.agent);
Agent agent = supervisor.getAgent();
if (agent.isEnvoy())
installFramework(agent, dto, properties);
if (stdout != null)
supervisor.setStdout(stdout);
if (stderr != null)
supervisor.setStderr(stderr);
started.countDown();
update(dto);
int exitCode = supervisor.join();
return exitCode;
} catch (Exception e) {
started.countDown();
throw e;
}
}
@Override
public void cancel() throws Exception {
supervisor.abort();
}
@Override
public Map<String,Object> getProperties() {
return properties;
}
private boolean installFramework(Agent agent, RunRemoteDTO dto, Map<String,Object> properties) throws Exception {
List<String> onpath = new ArrayList<String>(launcher.getRunpath());
Map<String,String> runpath = getBundles(onpath, Constants.RUNPATH);
return agent.createFramework(dto.name, runpath.values(), properties);
}
void update(Map<String,String> newer) throws Exception {
supervisor.getAgent().update(newer);
}
int join() throws InterruptedException {
return supervisor.join();
}
public void close() throws IOException {
supervisor.close();
}
Map<String,String> getBundles(Collection<String> collection, String header) throws Exception {
Map<String,String> newer = new LinkedHashMap<String,String>();
for (String c : collection) {
File f = new File(c);
String sha = supervisor.addFile(f);
newer.put(c, sha);
}
return newer;
}
void update(RunRemoteDTO dto) throws Exception {
Map<String,String> newer = getBundles(launcher.getRunBundles(), Constants.RUNBUNDLES);
if (shell != dto.shell) {
supervisor.getAgent().redirect(dto.shell);
shell = dto.shell;
}
supervisor.getAgent().update(newer);
}
@Override
public int getExitCode() {
return supervisor.getExitCode();
}
@Override
public void waitTillStarted(long ms) throws InterruptedException {
started.await(ms, TimeUnit.MILLISECONDS);
}
@Override
public String getHost() {
return dto.host;
}
@Override
public long getTimeout() {
return dto.timeout;
}
@Override
public int getAgent() {
return dto.agent;
}
@Override
public boolean validate(Callable<Boolean> isCancelled) throws Exception {
boolean result = true;
if (getAgent() <= 0 || getAgent() > 65535) {
launcher.error("Agent port %s not in a valid IP range (0-65535)", getAgent());
result = false;
}
InetAddress in;
try {
in = InetAddress.getByName(getHost());
} catch (Exception e) {
launcher.exception(e, "Cannot find host %s", getHost());
return false; // no use to continue from here
}
if (isCancelled.call())
return false;
if (!in.isReachable(5000)) {
launcher.error("Host not reachable %s", getHost());
return false;
}
while (!isCancelled.call())
try {
Socket s = new Socket(getHost(), getAgent());
s.close();
break;
} catch (Exception e) {
// Ignore
try {
Thread.sleep(500);
} catch (InterruptedException e1) {}
}
return result;
}
}