package org.freeplane.plugin.remote.server;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.management.ManagementFactory;
import java.lang.management.RuntimeMXBean;
import java.util.Date;
import java.util.Hashtable;
import org.apache.commons.io.IOUtils;
import org.eclipse.jgit.api.Git;
import org.eclipse.jgit.api.errors.GitAPIException;
import org.eclipse.jgit.api.errors.NoHeadException;
import org.eclipse.jgit.lib.Repository;
import org.eclipse.jgit.lib.RepositoryCache;
import org.eclipse.jgit.revwalk.RevCommit;
import org.eclipse.jgit.util.FS;
import org.freeplane.core.util.Compat;
import org.freeplane.features.mode.ModeController;
import org.freeplane.features.mode.mindmapmode.MModeController;
import org.freeplane.main.osgi.IModeControllerExtensionProvider;
import org.jboss.netty.channel.ChannelException;
import org.osgi.framework.Bundle;
import org.osgi.framework.BundleActivator;
import org.osgi.framework.BundleContext;
import org.osgi.framework.BundleException;
import uk.org.lidalia.sysoutslf4j.context.SysOutOverSLF4J;
public class Activator implements BundleActivator{
@Override
public void start(BundleContext context) {
//first thing: start logger and redirect out and err
Logger.getLogger();
SysOutOverSLF4J.sendSystemOutAndErrToSLF4J();
final Bundle systemBundle = context.getBundle(0);
logGit();
saveAutoProperties();
registerToFreeplaneStart(context);
registerShutDownHook(context);
generatePIDFile(systemBundle);
}
private void logGit() {
try {
File gitDir = new File(".git");
if (gitDir.exists()){
Repository repo = RepositoryCache.open(RepositoryCache.FileKey.lenient(gitDir, FS.DETECTED), true);
Git git = new Git(repo);
RevCommit commit = git.log().call().iterator().next();
Logger.getLogger().info("Activator.logGit => Latest Commit id '" + commit.getId()+"'");
Logger.getLogger().info("Activator.logGit => Latest commit by '" + commit.getCommitterIdent().getName()+"'");
Logger.getLogger().info("Activator.logGit => Latest commit at " + new Date(commit.getCommitTime() * 1000L));
Logger.getLogger().info("Activator.logGit => Latest commit message '" + commit.getShortMessage()+"'");
repo.close();
} else {
Logger.getLogger().info("Activator.logGit => No local git repos to log. try to find generated git file.");
File gitFile = new File("./resources/gitinfo.properties");
if (gitFile.exists()){
BufferedReader reader = new BufferedReader(new FileReader(gitFile));
Logger.getLogger().info("Activator.logGit => Latest commit info of current build " + reader.readLine());
} else {
Logger.getLogger().info("Activator.logGit => No commit information found.");
}
}
} catch (IOException ex) {
Logger.getLogger().error("Activator.logGit => IOException", ex);
} catch (NoHeadException e) {
Logger.getLogger().error("Activator.logGit => NoHeadException", e);
} catch (GitAPIException e) {
Logger.getLogger().error("Activator.logGit => GitAPIException", e);
}
}
private void registerToFreeplaneStart(final BundleContext context) {
final Hashtable<String, String[]> props = new Hashtable<String, String[]>();
final Bundle systemBundle = context.getBundle(0);
props.put("mode", new String[] { MModeController.MODENAME });
context.registerService(IModeControllerExtensionProvider.class.getName(),
new IModeControllerExtensionProvider() {
public void installExtension(ModeController modeController) {
try {
RemoteController.getInstance();
} catch(ChannelException e) {
Logger.getLogger().error("Activator.registerToFreeplaneStart => Error while starting RemotePlugin!\n",e);
Logger.getLogger().info("Activator.registerToFreeplaneStart => Stop Remote.");
stop(context);
try{systemBundle.stop();} catch(Exception e1) {}
Logger.getLogger().info("Activator.registerToFreeplaneStart => OSGI SystemBundle stopped. Exit.");
System.exit(1);
}
}
}, props);
}
private void registerShutDownHook(BundleContext context) {
final Bundle systemBundle = context.getBundle(0);
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
Logger.getLogger().info("Activator.registerShutDownHook => Shutdown hook called.");
try {
systemBundle.stop();
} catch (BundleException e) {
e.printStackTrace();
}
}
});
}
private void saveAutoProperties() {
//send auto.properties to correct location
final String freeplaneDirectory = Compat.getFreeplaneUserDirectory();
final File userPropertiesFolder = new File(freeplaneDirectory);
final File autoPropertiesFile = new File(userPropertiesFolder, "auto.properties");
Logger.getLogger().info("Activator.start => trying to save auto.properties to '{}'.",autoPropertiesFile.getAbsolutePath());
InputStream in = null;
OutputStream out = null;
try {
in = RemoteController.class.getResourceAsStream("/auto.properties");
out = new FileOutputStream(autoPropertiesFile);
IOUtils.copy(in, out);
} catch (Exception e) {
Logger.getLogger().error("could not save auto.properties. ",e);
} finally {
IOUtils.closeQuietly(in);
IOUtils.closeQuietly(out);
}
}
/**
* The PID-File indicates that the server is currently running.
* Only one server instance can run at a time.
* OSGI-Container will shut down if, a server is already running.
*
*/
private void generatePIDFile(Bundle systemBundle){
RuntimeMXBean rtb = ManagementFactory.getRuntimeMXBean();
String name = rtb.getName();
Integer pid = Integer.parseInt(name.substring(0, name.indexOf("@")));
Logger.getLogger().info("OSGI pid: {}",pid);
FileWriter fileWriter = null;
try {
File pidFile = new File("RUNNING_PID");
Logger.getLogger().info("Activator.generatePIDFile => Path of RUNNING_PID = '{}'",pidFile.getAbsolutePath());
String pidProperty = System.getProperty("ignorePID");
if (pidFile.exists() && (pidProperty == null || pidProperty.isEmpty() || !pidProperty.equals("true"))){
Logger.getLogger().error("Activator.generatePIDFile => RUNNING_PID already exists. Abort start.");
systemBundle.stop();
Logger.getLogger().info("Activator.generatePIDFile => OSGI SystemBundle stopped. Exit.");
System.exit(1);
}
fileWriter = new FileWriter(pidFile);
fileWriter.write(pid.toString());
fileWriter.close();
} catch (IOException ex){
System.err.println(ex.getMessage());
} catch (BundleException e) {
e.printStackTrace();
} finally {
try {
fileWriter.close();
} catch (IOException ex) {
System.err.println(ex.getMessage());
}
}
}
@Override
public void stop(BundleContext context) {
Logger.getLogger().info("Activator.stop => Activator.stop called.");
if (RemoteController.isStarted()){
Logger.getLogger().info("Activator.stop => Stop running Remote.");
RemoteController.stop();
}
try{
Logger.getLogger().info("Activator.stop => Delete RUNNING_PID.");
File file = new File("./RUNNING_PID");
if(!file.delete()){
Logger.getLogger().error("Activator.stop => Error while deleting RUNNING_PID");
} else {
Logger.getLogger().info("Activator.stop => Deleted RUNNING_PID.");
}
}catch(Exception e){
Logger.getLogger().error("Activator.stop => Error while deleting RUNNING_PID",e);
}
}
}