package net.mms_projects.copy_it.app;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.lang.reflect.Field;
import java.net.URL;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import net.mms_projects.copy_it.Activatable;
import net.mms_projects.copy_it.ApplicationLock;
import net.mms_projects.copy_it.ApplicationLock.LockException;
import net.mms_projects.copy_it.ClipboardManager;
import net.mms_projects.copy_it.Config;
import net.mms_projects.copy_it.EnvironmentIntegration;
import net.mms_projects.copy_it.FileStreamBuilder;
import net.mms_projects.copy_it.FunctionalityManager;
import net.mms_projects.copy_it.PathBuilder;
import net.mms_projects.copy_it.QueueFunctionality;
import net.mms_projects.copy_it.SettingsListener;
import net.mms_projects.copy_it.SyncListener;
import net.mms_projects.copy_it.SyncManager;
import net.mms_projects.copy_it.SyncingThread;
import net.mms_projects.copy_it.api.ServerApi;
import net.mms_projects.copy_it.api.endpoints.ClipboardContentEndpoint;
import net.mms_projects.copy_it.clipboard_services.AwtService;
import net.mms_projects.copy_it.functionality.SyncClipboardBinding;
import net.mms_projects.copy_it.integration.DefaultLinuxIntegration;
import net.mms_projects.copy_it.integration.SwtIntegration;
import net.mms_projects.copy_it.integration.UnityIntegration;
import net.mms_projects.copy_it.integration.WindowsIntegration;
import net.mms_projects.copy_it.linux.DesktopEnvironment;
import net.mms_projects.copy_it.listeners.EnabledListener;
import net.mms_projects.copy_it.sync_services.ApiService;
import net.mms_projects.copy_it.sync_services.TestService;
import net.mms_projects.copy_it.ui.ShellUi;
import net.mms_projects.copy_it.ui.SingleCommandUi;
import net.mms_projects.copy_it.ui.SwtInterface;
import net.mms_projects.copy_it.ui.UserInterfaceImplementation;
import net.mms_projects.utils.OSValidator;
import org.apache.commons.io.FileUtils;
import org.freedesktop.Notifications;
import org.freedesktop.dbus.DBusConnection;
import org.freedesktop.dbus.UInt32;
import org.freedesktop.dbus.Variant;
import org.freedesktop.dbus.exceptions.DBusException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class CopyItDesktop extends CopyIt {
static public DBusConnection dbusConnection;
static private boolean nativeLoadingInitialized;
private final Logger log = LoggerFactory.getLogger(this.getClass());
protected Config settings;
/**
* @param args
*/
public static void main(String[] args) {
CopyItDesktop app = new CopyItDesktop();
app.run(args);
}
public static String getVersion() {
String version = "";
if (CopyItDesktop.class.getPackage().getSpecificationVersion() != null) {
version += CopyItDesktop.class.getPackage()
.getSpecificationVersion();
} else {
version += "0.0.1";
}
if (CopyItDesktop.getBuildNumber() != 0) {
version += "-" + CopyItDesktop.getBuildNumber();
}
return version;
}
public static int getBuildNumber() {
try {
return Integer.parseInt(CopyItDesktop.class.getPackage()
.getImplementationVersion());
} catch (NumberFormatException e) {
return 0;
}
}
public static File exportResource(String resource) {
Logger log = LoggerFactory.getLogger(CopyItDesktop.class);
if (!CopyItDesktop.nativeLoadingInitialized) {
System.setProperty(
"java.library.path",
System.getProperty("java.library.path")
+ System.getProperty("path.separator")
+ PathBuilder.getCacheDirectory().getAbsolutePath());
log.trace("Set the library path to: {}",
System.getProperty("java.library.path"));
Field fieldSysPath = null;
try {
fieldSysPath = ClassLoader.class.getDeclaredField("sys_paths");
fieldSysPath.setAccessible(true);
fieldSysPath.set(null, null);
} catch (SecurityException e2) {
// TODO Auto-generated catch block
e2.printStackTrace();
} catch (NoSuchFieldException e2) {
// TODO Auto-generated catch block
e2.printStackTrace();
} catch (IllegalArgumentException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
CopyItDesktop.nativeLoadingInitialized = true;
}
log.debug("Exporting resource {}", resource);
URL inputUrl = CopyItDesktop.class.getResource("/" + resource);
File dest = new File(PathBuilder.getCacheDirectory(), resource);
if (inputUrl == null) {
log.warn(
"No input resource available while exporting resource {}. Ignoring it.",
resource);
return null;
}
try {
FileUtils.copyURLToFile(inputUrl, dest);
} catch (IOException e1) {
log.warn("Could not copy resource. This might cause issues.", e1);
}
return dest;
}
public void run(String[] args) {
final FunctionalityManager<Activatable> functionalityManager = new FunctionalityManager<Activatable>();
log.info("The application is launched");
this.settings = new Config();
try {
this.settings.setFileStreamBuilder(new StreamBuilder());
} catch (IOException e) {
e.printStackTrace();
System.exit(1);
}
this.settings.loadProperties();
ExecutorService executor = Executors.newSingleThreadExecutor(Executors
.defaultThreadFactory());
final ClipboardManager clipboardManager = new ClipboardManager();
clipboardManager.setExecutor(executor);
final SyncManager syncManager = new SyncManager();
syncManager.setExecutor(executor);
ServerApi api = new ServerApi();
api.deviceId = (settings.get("device.id") != null) ? UUID
.fromString(settings.get("device.id")) : null;
api.devicePassword = settings.get("device.password");
TestService testService = new TestService(syncManager);
final ApiService apiService = new ApiService(syncManager,
new ClipboardContentEndpoint(api));
final SyncingThread syncThread = new SyncingThread(syncManager,
new ClipboardContentEndpoint(api));
SettingsListener apiServiceListener = new SettingsListener() {
@Override
public void onChange(String key, String value) {
ServerApi api = new ServerApi();
api.deviceId = UUID.fromString(settings.get("device.id"));
api.devicePassword = settings.get("device.password");
ClipboardContentEndpoint endpoint = new ClipboardContentEndpoint(
api);
apiService.setEndpoint(endpoint);
syncThread.setEndpoint(endpoint);
}
};
this.settings.addListener("device.id", apiServiceListener);
this.settings.addListener("device.password", apiServiceListener);
syncManager.addPushService(apiService);
syncManager.addPullService(apiService);
syncManager.addPushService(testService);
syncManager.addPullingService(syncThread);
syncManager.addPullingService(testService);
syncManager.addListener(new SyncListener() {
@Override
public void onRemoteContentChange(String content, Date date) {
log.debug("The following content was pulled: {}", content);
}
});
Activatable pollingActivatable = new Activatable() {
private boolean enabled;
private List<EnabledListener> enabledListeners = new ArrayList<EnabledListener>();
@Override
public void setEnabled(boolean enabled) {
if (enabled) {
this.enable();
} else {
this.disable();
}
}
@Override
public boolean isEnabled() {
return this.enabled;
}
@Override
public void enable() {
this.enabled = true;
syncManager.activatePolling();
clipboardManager.activatePolling();
log.debug("The sync manager and clipboard manager have been enabled");
for (EnabledListener listener : this.enabledListeners) {
listener.onEnabled();
}
}
@Override
public void disable() {
this.enabled = false;
syncManager.deactivatePolling();
clipboardManager.deactivatePolling();
log.debug("The sync manager and clipboard manager have been disabled");
for (EnabledListener listener : this.enabledListeners) {
listener.onDisabled();
}
}
@Override
public void addEnabledListener(EnabledListener listener) {
this.enabledListeners.add(listener);
}
};
pollingActivatable.addEnabledListener(new EnabledListener() {
@Override
public void onEnabled() {
settings.set("sync.polling.enabled", true);
}
@Override
public void onDisabled() {
settings.set("sync.polling.enabled", false);
}
});
functionalityManager.addFunctionality("polling", pollingActivatable);
functionalityManager.setEnabled("polling",
this.settings.getBoolean("sync.polling.enabled"));
// this.settings.addListener("sync.polling.enabled",
// new SettingsListener() {
// @Override
// public void onChange(String key, String value) {
// if (Boolean.parseBoolean(value)) {
// syncManager.activatePolling();
// clipboardManager.activatePolling();
// log.debug("The sync manager and clipboard manager have been enabled");
// } else {
//
// }
// }
// });
if (OSValidator.isUnix()) {
this.exportResource("libunix-java.so");
try {
CopyItDesktop.dbusConnection = DBusConnection
.getConnection(DBusConnection.SESSION);
} catch (DBusException e1) {
// TODO Auto-generated catch block
log.error(
"Ahh could not connect to D-Bus. All kinds of explosions n'stuff. Fix it!",
e1);
e1.printStackTrace();
System.exit(1);
}
}
final ApplicationLock appLock = new ApplicationLock(
PathBuilder.getConfigDirectory());
if (appLock.isRunning()) {
String message = "An instance is already running. ";
if (OSValidator.isUnix()) {
try {
Notifications notify = CopyItDesktop.dbusConnection
.getRemoteObject("org.freedesktop.Notifications",
"/org/freedesktop/Notifications",
Notifications.class);
Map<String, Variant<Byte>> hints = new HashMap<String, Variant<Byte>>();
hints.put("urgency", new Variant<Byte>((byte) 2));
notify.Notify("CopyIt", new UInt32(0), "", "CopyIt",
message, new LinkedList<String>(), hints, -1);
} catch (DBusException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
log.info(message);
System.exit(0);
} else {
try {
appLock.lock();
} catch (LockException e) {
e.printStackTrace();
System.exit(1);
}
Runtime.getRuntime().addShutdownHook(new Thread() {
@Override
public void run() {
appLock.unlock();
}
});
}
EnvironmentIntegration environmentIntegration = null;
if (OSValidator.isUnix()) {
switch (DesktopEnvironment.getDesktopEnvironment()) {
case Unity:
UnityIntegration environmentIntegrationUnity = new UnityIntegration(
CopyItDesktop.dbusConnection, functionalityManager,
syncManager, clipboardManager);
environmentIntegration = environmentIntegrationUnity;
break;
default:
environmentIntegration = new DefaultLinuxIntegration(
CopyItDesktop.dbusConnection, functionalityManager,
syncManager, clipboardManager);
break;
}
} else if (OSValidator.isWindows()) {
environmentIntegration = new WindowsIntegration(
functionalityManager, syncManager, clipboardManager);
}
if (environmentIntegration == null) {
environmentIntegration = new SwtIntegration(functionalityManager,
syncManager, clipboardManager);
}
System.out.println(environmentIntegration);
UserInterfaceImplementation uiImplementation = null;
if (args.length > 0) {
AwtService awtService = new AwtService(clipboardManager);
clipboardManager.addPasteService(awtService);
clipboardManager.addCopyService(awtService);
if ("cli".equalsIgnoreCase(args[0])) {
uiImplementation = new ShellUi(this.settings, syncManager,
clipboardManager);
} else {
uiImplementation = new SingleCommandUi(this.settings,
syncManager, clipboardManager, args[0]);
}
} else {
uiImplementation = new SwtInterface(settings, functionalityManager,
environmentIntegration, syncManager, clipboardManager);
}
environmentIntegration.setUserInterfaceImplementation(uiImplementation);
environmentIntegration.setup();
SyncClipboardBinding syncClipboardBinding = new SyncClipboardBinding(
environmentIntegration, syncManager, clipboardManager);
syncManager.addListener(syncClipboardBinding);
clipboardManager.addListener(syncClipboardBinding);
functionalityManager.addFunctionality("sync-clipboard-binding",
syncClipboardBinding);
QueueFunctionality queueFunctionality = new QueueFunctionality(
uiImplementation);
queueFunctionality.setEnabled(this.settings
.getBoolean("sync.queue.enabled"));
queueFunctionality.addEnabledListener(new EnabledListener() {
@Override
public void onEnabled() {
settings.set("sync.queue.enabled", true);
}
@Override
public void onDisabled() {
settings.set("sync.queue.enabled", false);
}
});
functionalityManager.addFunctionality("queue", queueFunctionality);
syncManager.addListener(queueFunctionality);
uiImplementation.open();
this.settings.saveProperties();
if (OSValidator.isUnix()) {
CopyItDesktop.dbusConnection.disconnect();
}
executor.shutdown();
}
class StreamBuilder extends FileStreamBuilder {
private File settingsFile;
public StreamBuilder() throws IOException {
this.settingsFile = new File(PathBuilder.getConfigDirectory(),
"options.properties");
if (!this.settingsFile.exists()) {
log.info("No settings file. Creating it.");
this.settingsFile.createNewFile();
}
}
@Override
public FileInputStream getInputStream() throws IOException {
return new FileInputStream(this.settingsFile);
}
@Override
public FileOutputStream getOutputStream() throws IOException {
return new FileOutputStream(this.settingsFile);
}
}
}