parent
cd5f7be740
commit
4e6ad69877
@ -0,0 +1,50 @@
|
|||||||
|
package com.olexyn.ensync;
|
||||||
|
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.util.Date;
|
||||||
|
import java.util.logging.FileHandler;
|
||||||
|
import java.util.logging.Level;
|
||||||
|
import java.util.logging.LogRecord;
|
||||||
|
import java.util.logging.Logger;
|
||||||
|
import java.util.logging.SimpleFormatter;
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
public class LogUtil {
|
||||||
|
|
||||||
|
private static final String format = "[%1$tF %1$tT] [%4$-7s] %5$-120s [%2$s]\n";
|
||||||
|
|
||||||
|
public static Logger get(Class<?> c) {
|
||||||
|
return get(c, Level.INFO);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Logger get(Class<?> c, Level level) {
|
||||||
|
System.setProperty("java.util.logging.SimpleFormatter.format", format);
|
||||||
|
Logger logger = Logger.getLogger(c.getName());
|
||||||
|
try {
|
||||||
|
String dir = System.getProperty("user.dir") + "/log/main.log";
|
||||||
|
FileHandler fh = new FileHandler(dir, true);
|
||||||
|
fh.setFormatter(new SimpleFormatter() {
|
||||||
|
@Override
|
||||||
|
public synchronized String format(LogRecord logRecord) {
|
||||||
|
String msg = logRecord.getMessage();
|
||||||
|
return String.format(format,
|
||||||
|
new Date(logRecord.getMillis()),
|
||||||
|
logRecord.getSourceClassName() + " " + logRecord.getSourceMethodName(),
|
||||||
|
"",
|
||||||
|
logRecord.getLevel().getLocalizedName(),
|
||||||
|
msg
|
||||||
|
);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
logger.addHandler(fh);
|
||||||
|
logger.setLevel(level);
|
||||||
|
} catch (NullPointerException | IOException e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
}
|
||||||
|
return logger;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,49 +0,0 @@
|
|||||||
package com.olexyn.ensync;
|
|
||||||
|
|
||||||
import com.olexyn.ensync.artifacts.MapOfSyncMaps;
|
|
||||||
import com.olexyn.ensync.artifacts.SyncMap;
|
|
||||||
import com.olexyn.ensync.ui.UI;
|
|
||||||
|
|
||||||
import org.json.JSONArray;
|
|
||||||
import org.json.JSONException;
|
|
||||||
import org.json.JSONObject;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.util.HashMap;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.Map;
|
|
||||||
|
|
||||||
|
|
||||||
public class Main {
|
|
||||||
|
|
||||||
final public static Thread UI_THREAD = new Thread(new UI(), "ui");
|
|
||||||
final public static Thread FLOW_THREAD = new Thread(new Flow(), "flow");
|
|
||||||
final private static Tools tools = new Tools();
|
|
||||||
|
|
||||||
public static void main(String[] args) {
|
|
||||||
|
|
||||||
OperationMode operationMode = OperationMode.JSON;
|
|
||||||
|
|
||||||
switch (operationMode) {
|
|
||||||
case JAVA_FX:
|
|
||||||
UI_THREAD.start();
|
|
||||||
break;
|
|
||||||
case JSON:
|
|
||||||
String configPath = System.getProperty("user.dir") + "/src/main/resources/config.json";
|
|
||||||
String configString = tools.fileToString(new File(configPath));
|
|
||||||
JSONObject jsonMapOfSyncMaps = new JSONObject(configString).getJSONObject("jsonMapOfSyncMaps");
|
|
||||||
for (String key : jsonMapOfSyncMaps.keySet()) {
|
|
||||||
SyncMap syncMap = new SyncMap(key);
|
|
||||||
for (Object jsonSyncDirPath : jsonMapOfSyncMaps.getJSONArray(key).toList()) {
|
|
||||||
syncMap.addDirectory(jsonSyncDirPath.toString());
|
|
||||||
}
|
|
||||||
MapOfSyncMaps.get().put(key, syncMap);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
FLOW_THREAD.start();
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,34 @@
|
|||||||
|
package com.olexyn.ensync;
|
||||||
|
|
||||||
|
import com.olexyn.ensync.artifacts.DataRoot;
|
||||||
|
import com.olexyn.ensync.artifacts.SyncBundle;
|
||||||
|
|
||||||
|
import org.json.JSONException;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
import java.io.File;
|
||||||
|
|
||||||
|
|
||||||
|
public class MainApp {
|
||||||
|
|
||||||
|
final public static Thread FLOW_THREAD = new Thread(new Flow(), "flow");
|
||||||
|
final private static Tools tools = new Tools();
|
||||||
|
|
||||||
|
public static void main(String[] args) throws JSONException {
|
||||||
|
|
||||||
|
String configPath = System.getProperty("user.dir") + "/src/main/resources/config.json";
|
||||||
|
String configString = tools.fileToString(new File(configPath));
|
||||||
|
JSONObject dataRoot = new JSONObject(configString).getJSONObject("dataRoot");
|
||||||
|
for (String bundleKey : dataRoot.keySet()) {
|
||||||
|
SyncBundle syncBundle = new SyncBundle(bundleKey);
|
||||||
|
dataRoot.getJSONArray(bundleKey).toList()
|
||||||
|
.forEach(
|
||||||
|
directoryPath -> syncBundle.addDirectory(directoryPath.toString())
|
||||||
|
);
|
||||||
|
|
||||||
|
DataRoot.get().put(bundleKey, syncBundle);
|
||||||
|
}
|
||||||
|
|
||||||
|
FLOW_THREAD.start();
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,7 @@
|
|||||||
|
package com.olexyn.ensync.artifacts;
|
||||||
|
|
||||||
|
public interface Constants {
|
||||||
|
|
||||||
|
String STATE_FILE_NAME = "state.ensync";
|
||||||
|
|
||||||
|
}
|
@ -0,0 +1,19 @@
|
|||||||
|
package com.olexyn.ensync.artifacts
|
||||||
|
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
class StateFile(val targetPath: String) {
|
||||||
|
|
||||||
|
fun getPath(): String {
|
||||||
|
return targetPath + Constants.STATE_FILE_NAME
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun getFile(): File {
|
||||||
|
return File(getPath())
|
||||||
|
}
|
||||||
|
|
||||||
|
fun exists(): Boolean {
|
||||||
|
return getFile().exists();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
@ -1,55 +0,0 @@
|
|||||||
package com.olexyn.ensync.ui;
|
|
||||||
|
|
||||||
|
|
||||||
import com.olexyn.ensync.artifacts.MapOfSyncMaps;
|
|
||||||
import com.olexyn.ensync.artifacts.SyncMap;
|
|
||||||
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Connect the Controller and the Flow
|
|
||||||
*/
|
|
||||||
public class Bridge {
|
|
||||||
|
|
||||||
|
|
||||||
void newCollection(String collectionName) {
|
|
||||||
|
|
||||||
synchronized (MapOfSyncMaps.get()) {
|
|
||||||
MapOfSyncMaps.get().put(collectionName, new SyncMap(collectionName));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void removeCollection(String collectionName) {
|
|
||||||
synchronized (MapOfSyncMaps.get()) {
|
|
||||||
MapOfSyncMaps.get().remove(collectionName);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
void addDirectory(String collectionName, File diretory) {
|
|
||||||
synchronized (MapOfSyncMaps.get()) {
|
|
||||||
MapOfSyncMaps.get().get(collectionName).addDirectory(diretory.getAbsolutePath());
|
|
||||||
}
|
|
||||||
//TODO pause syning when adding
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This works, because a directory, which here is an unique ablsolute path,
|
|
||||||
* is only supposed to present once across entire SYNC.
|
|
||||||
*/
|
|
||||||
void removeDirectory(String directoryAbsolutePath) {
|
|
||||||
//TODO fix ConcurrentModificationException. This will possibly resolve further errors.
|
|
||||||
synchronized (MapOfSyncMaps.get()) {
|
|
||||||
for (var syncMap : MapOfSyncMaps.get().entrySet()) {
|
|
||||||
syncMap.getValue().removeDirectory(directoryAbsolutePath);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,237 +0,0 @@
|
|||||||
package com.olexyn.ensync.ui;
|
|
||||||
|
|
||||||
|
|
||||||
import javafx.fxml.FXML;
|
|
||||||
import javafx.fxml.Initializable;
|
|
||||||
import javafx.scene.Node;
|
|
||||||
import javafx.scene.control.Button;
|
|
||||||
import javafx.scene.control.TextField;
|
|
||||||
import javafx.scene.layout.GridPane;
|
|
||||||
import javafx.scene.text.Text;
|
|
||||||
import javafx.stage.DirectoryChooser;
|
|
||||||
import javafx.stage.Window;
|
|
||||||
|
|
||||||
import java.io.File;
|
|
||||||
import java.net.URL;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.Arrays;
|
|
||||||
import java.util.List;
|
|
||||||
import java.util.ResourceBundle;
|
|
||||||
|
|
||||||
/***
|
|
||||||
* Controller class for JavaFX. Contains the application logic.
|
|
||||||
*/
|
|
||||||
public class Controller implements Initializable {
|
|
||||||
|
|
||||||
|
|
||||||
final static int COLUMN_COUNT = 5; // How many columns should the GridPane have? Adjust if necessary.
|
|
||||||
final static Text SPACE = new Text(""); // Placeholder
|
|
||||||
int collection_count = 0;
|
|
||||||
Bridge bridge = new Bridge();
|
|
||||||
|
|
||||||
@FXML
|
|
||||||
protected GridPane gridPane;
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void initialize(URL url, ResourceBundle resourceBundle) {
|
|
||||||
|
|
||||||
Text end = new Text("");
|
|
||||||
end.setId("end");
|
|
||||||
|
|
||||||
Button newCollectionButton = new Button("New Collection");
|
|
||||||
newCollectionButton.setId("newCollectionButton");
|
|
||||||
newCollectionButton.setOnAction(event -> { this.newCollection();});
|
|
||||||
|
|
||||||
gridPane.add(end, 0, 0);
|
|
||||||
|
|
||||||
List<Node> nodeList = new ArrayList<>(gridPane.getChildren());
|
|
||||||
|
|
||||||
List<Node> payload = Arrays.asList(new Text(""), new Text(""), new Text(""), new Text(""), newCollectionButton);
|
|
||||||
|
|
||||||
|
|
||||||
insertPayload(nodeList, payload, "end", 0);
|
|
||||||
redraw(gridPane, nodeList);
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private void newCollection() {
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
String collectionName = "name" + collection_count++;
|
|
||||||
|
|
||||||
bridge.newCollection(collectionName);
|
|
||||||
|
|
||||||
|
|
||||||
TextField collectionStateTextField = new TextField();
|
|
||||||
collectionStateTextField.setText("STATE");
|
|
||||||
collectionStateTextField.setStyle("-fx-text-fill: green");
|
|
||||||
collectionStateTextField.setDisable(true);
|
|
||||||
collectionStateTextField.setId("collectionStateTextField-" + collectionName);
|
|
||||||
|
|
||||||
Button removeCollectionButton = new Button("Remove Collection");
|
|
||||||
removeCollectionButton.setId("removeCollectionButton-" + collectionName);
|
|
||||||
removeCollectionButton.setOnAction(event -> { this.removeCollection(collectionName);});
|
|
||||||
|
|
||||||
TextField addDirectoryTextField = new TextField();
|
|
||||||
addDirectoryTextField.setId("addDirectoryTextField-" + collectionName);
|
|
||||||
|
|
||||||
Button addDirectoryButton = new Button("Add Directory");
|
|
||||||
addDirectoryButton.setId("addDirectoryButton-" + collectionName);
|
|
||||||
addDirectoryButton.setOnAction(event -> { this.addDirectory(collectionName);});
|
|
||||||
|
|
||||||
|
|
||||||
List<Node> nodeList = new ArrayList<>(gridPane.getChildren());
|
|
||||||
|
|
||||||
List<Node> payload = new ArrayList<>();
|
|
||||||
payload.addAll(Arrays.asList(new Text(""), new Text(""), collectionStateTextField, new Text(""), removeCollectionButton));
|
|
||||||
payload.addAll(Arrays.asList(addDirectoryTextField, new Text(""), new Text(""), new Text(""), addDirectoryButton));
|
|
||||||
|
|
||||||
insertPayload(nodeList, payload, "newCollectionButton", -4);
|
|
||||||
redraw(gridPane, nodeList);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* For the order & number of Nodes see ui-design.png .
|
|
||||||
* Remove the "Remove-Collection-Line" and the consecutive lines until and including the "Add-Directory-Line".
|
|
||||||
* The !=null expression protects from Text("") placeholders, who have id==null.
|
|
||||||
*/
|
|
||||||
private void removeCollection(String collectionName) {
|
|
||||||
|
|
||||||
bridge.removeCollection(collectionName);
|
|
||||||
|
|
||||||
List<Node> nodeList = new ArrayList<>(gridPane.getChildren());
|
|
||||||
|
|
||||||
here:
|
|
||||||
for (Node node : nodeList) {
|
|
||||||
|
|
||||||
if (node.getId() != null && node.getId().equals("removeCollectionButton-" + collectionName)) {
|
|
||||||
int i = nodeList.indexOf(node) - 4;
|
|
||||||
while (i < nodeList.size()) {
|
|
||||||
nodeList.remove(i);
|
|
||||||
|
|
||||||
if (nodeList.get(i).getId() != null && nodeList.get(i).getId().equals("addDirectoryButton-" + collectionName)) {
|
|
||||||
nodeList.remove(i);
|
|
||||||
break here;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
redraw(gridPane, nodeList);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
*
|
|
||||||
*/
|
|
||||||
private void addDirectory(String collectionName) {
|
|
||||||
// TODO throw error if other collection already contains absollutepath
|
|
||||||
Window stage = gridPane.getScene().getWindow();
|
|
||||||
|
|
||||||
final DirectoryChooser directoryChooser = new DirectoryChooser();
|
|
||||||
directoryChooser.setTitle("Select Directory.");
|
|
||||||
directoryChooser.setInitialDirectory(new File(System.getProperty("user.home")));
|
|
||||||
|
|
||||||
File directory = directoryChooser.showDialog(stage);
|
|
||||||
|
|
||||||
if (directory != null) {
|
|
||||||
|
|
||||||
bridge.addDirectory(collectionName, directory);
|
|
||||||
|
|
||||||
TextField directoryPathTextField = new TextField();
|
|
||||||
directoryPathTextField.setText(directory.getAbsolutePath());
|
|
||||||
directoryPathTextField.setDisable(true);
|
|
||||||
directoryPathTextField.setId("directoryPathTextField-" + directory.getAbsolutePath());
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
TextField directoryStateTextField = new TextField();
|
|
||||||
directoryStateTextField.setText("STATE");
|
|
||||||
directoryStateTextField.setStyle("-fx-text-fill: green");
|
|
||||||
directoryStateTextField.setDisable(true);
|
|
||||||
directoryStateTextField.setId("directoryStateTextField-" + directory.getAbsolutePath());
|
|
||||||
|
|
||||||
Button removeDirectoryButton = new Button("Remove");
|
|
||||||
removeDirectoryButton.setId("removeDirectoryButton-" + directory.getAbsolutePath());
|
|
||||||
removeDirectoryButton.setOnAction(event -> { this.removeDirectory(directory.getAbsolutePath());});
|
|
||||||
|
|
||||||
|
|
||||||
List<Node> nodeList = new ArrayList<>(gridPane.getChildren());
|
|
||||||
List<Node> payload = Arrays.asList(directoryPathTextField, new Text(""), directoryStateTextField, new Text(""), removeDirectoryButton);
|
|
||||||
insertPayload(nodeList, payload, "addDirectoryTextField-" + collectionName, 0);
|
|
||||||
redraw(gridPane, nodeList);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Find the Node with @param id.
|
|
||||||
* Insert the contents of the @param payload starting from the last.
|
|
||||||
* This pushes the Node with @param id forward.
|
|
||||||
*/
|
|
||||||
private void insertPayload(List<Node> nodeList, List<Node> payload, String id, int offset) {
|
|
||||||
for (Node node : nodeList) {
|
|
||||||
|
|
||||||
if (node.getId() != null && node.getId().equals(id)) {
|
|
||||||
int i = nodeList.indexOf(node) + offset;
|
|
||||||
|
|
||||||
for (int j = payload.size() - 1; j >= 0; j--) {
|
|
||||||
nodeList.add(i, payload.get(j));
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Clear the gridPane and redraw it with contents of nodeList.
|
|
||||||
*/
|
|
||||||
private void redraw(GridPane gridPane, List<Node> nodeList) {
|
|
||||||
gridPane.getChildren().clear();
|
|
||||||
|
|
||||||
int col = 0, row = 0;
|
|
||||||
|
|
||||||
for (Node node : nodeList) {
|
|
||||||
if (nodeList.indexOf(node) % COLUMN_COUNT == 0) {
|
|
||||||
row++;
|
|
||||||
col = 0;
|
|
||||||
}
|
|
||||||
gridPane.add(node, col, row);
|
|
||||||
col++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
private void removeDirectory(String directoryAbsolutePath) {
|
|
||||||
|
|
||||||
bridge.removeDirectory(directoryAbsolutePath);
|
|
||||||
|
|
||||||
List<Node> nodeList = new ArrayList<>(gridPane.getChildren());
|
|
||||||
|
|
||||||
for (Node node : nodeList) {
|
|
||||||
|
|
||||||
if (node.getId() != null && node.getId().equals("removeDirectoryButton-" +directoryAbsolutePath)) {
|
|
||||||
int i = nodeList.indexOf(node) - 4;
|
|
||||||
for (int j = 0; j < 5; j++) {
|
|
||||||
nodeList.remove(i);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
redraw(gridPane, nodeList);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
@ -1,27 +0,0 @@
|
|||||||
package com.olexyn.ensync.ui;
|
|
||||||
|
|
||||||
import javafx.application.Application;
|
|
||||||
import javafx.fxml.FXMLLoader;
|
|
||||||
import javafx.scene.Parent;
|
|
||||||
import javafx.scene.Scene;
|
|
||||||
import javafx.stage.Stage;
|
|
||||||
|
|
||||||
|
|
||||||
public class UI extends Application implements Runnable {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void start(Stage primaryStage) throws Exception {
|
|
||||||
// in IDEA add ";?.fxml;?.css" to File|Settings|Compiler settings
|
|
||||||
Parent root = FXMLLoader.load(getClass().getResource("/fxml/layout.fxml"));
|
|
||||||
Scene scene = new Scene(root, 500, 500);
|
|
||||||
|
|
||||||
primaryStage.setTitle("EnSync");
|
|
||||||
primaryStage.setScene(scene);
|
|
||||||
primaryStage.show();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void run() {
|
|
||||||
UI.launch();
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,12 +1,8 @@
|
|||||||
{
|
{
|
||||||
"jsonMapOfSyncMaps": {
|
"dataRoot": {
|
||||||
"syncMap1": [
|
"syncMap1": [
|
||||||
"/home/user/test/a",
|
"P:\\ensync-test",
|
||||||
"/home/user/test/b"
|
"C:\\Users\\user\\home\\ensync-test"
|
||||||
],
|
|
||||||
"syncMap2": [
|
|
||||||
"/home/user/test/c",
|
|
||||||
"/home/user/test/d"
|
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in new issue