changeset 1528:e44b9395ae5b

Rust properties parser generalized to be reusable * rust-launcher/src/dirs_paths_helper.rs: new file, including get_xdg_config_dir, deployment.properties and similar originally from jvm_from_properties.rs * rust-launcher/src/main.rs: adapted to re-factored state * rust-launcher/src/os_access.rs: added and for Linux implemented get_system_config_javadir, get_user_config_dir * rust-launcher/src/property_from_file.rs: renamed from jvm_from_properties_file and generalized * rust-launcher/src/property_from_files_resolver.rs: renamed from jvm_from_files_resolver and generalized * rust-launcher/src/utils.rs: adapted to renamed JRE_PROPERTY_NAME from PROPERTY_NAME
author Jiri Vanek <jvanek@redhat.com>
date Fri, 30 Nov 2018 19:04:42 +0100
parents 612ff5eded4f
children 9bac379fb97e
files ChangeLog rust-launcher/src/dirs_paths_helper.rs rust-launcher/src/jvm_from_properties.rs rust-launcher/src/jvm_from_properties_resolver.rs rust-launcher/src/main.rs rust-launcher/src/os_access.rs rust-launcher/src/property_from_file.rs rust-launcher/src/property_from_files_resolver.rs rust-launcher/src/utils.rs
diffstat 9 files changed, 581 insertions(+), 536 deletions(-) [+]
line wrap: on
line diff
--- a/ChangeLog	Wed Nov 28 12:35:38 2018 +0100
+++ b/ChangeLog	Fri Nov 30 19:04:42 2018 +0100
@@ -1,3 +1,14 @@
+2018-11-30  Jiri Vanek <jvanek@redhat.com>
+
+	Rust properties parser generalized to be reusable
+	* rust-launcher/src/dirs_paths_helper.rs: new file, including get_xdg_config_dir, deployment.properties and similar
+	originally from jvm_from_properties.rs
+	* rust-launcher/src/main.rs: adapted to re-factored state
+	* rust-launcher/src/os_access.rs: added and for Linux implemented get_system_config_javadir, get_user_config_dir
+	* rust-launcher/src/property_from_file.rs: renamed from jvm_from_properties_file and generalized
+	* rust-launcher/src/property_from_files_resolver.rs: renamed from jvm_from_files_resolver and generalized
+	* rust-launcher/src/utils.rs: adapted to renamed JRE_PROPERTY_NAME from PROPERTY_NAME
+
 2018-11-28  Jiri Vanek <jvanek@redhat.com>
 
 	deployment.config now support generic url instead just file
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rust-launcher/src/dirs_paths_helper.rs	Fri Nov 30 19:04:42 2018 +0100
@@ -0,0 +1,95 @@
+use os_access;
+
+use std;
+use std::env;
+
+pub static ICEDTEA_WEB: &'static str = "icedtea-web";
+pub static DEPLOYMENT_PROPERTIES: &'static str = "deployment.properties";
+
+pub fn get_home() -> Option<std::path::PathBuf> {
+    match env::home_dir() {
+        Some(p) => Some(p),
+        None => None
+    }
+}
+
+pub fn get_xdg_config_dir() -> Option<std::path::PathBuf> {
+    match env::var("XDG_CONFIG_HOME") {
+        Ok(war) => {
+            Some(std::path::PathBuf::from(war))
+        }
+        Err(_) => {
+            match get_home() {
+                Some(mut p) => {
+                    p.push(".config");
+                    Some(p)
+                }
+                None => None
+            }
+        }
+    }
+}
+
+pub fn append_deployment_file(dir: Option<std::path::PathBuf>) -> Option<std::path::PathBuf> {
+    match dir {
+        Some(mut p) => {
+            p.push(DEPLOYMENT_PROPERTIES);
+            Some(p)
+        }
+        None => None
+    }
+}
+
+
+pub fn get_itw_config_file(os: &os_access::Os) -> Option<std::path::PathBuf> {
+    append_deployment_file(os.get_user_config_dir())
+}
+
+pub fn get_itw_legacy_config_file(os: &os_access::Os) -> Option<std::path::PathBuf> {
+    append_deployment_file(os.get_legacy_user_config_dir())
+}
+
+
+pub fn get_itw_legacy_global_config_file(os: &os_access::Os) -> Option<std::path::PathBuf> {
+    append_deployment_file(os.get_legacy_system_config_javadir())
+}
+
+pub fn get_itw_global_config_file(os: &os_access::Os) -> Option<std::path::PathBuf> {
+    append_deployment_file(os.get_system_config_javadir())
+}
+
+
+/*tests*/
+#[cfg(test)]
+mod tests {
+    use os_access;
+
+    #[test]
+    fn check_config_files_paths() {
+        let os = os_access::Linux::new(false);
+        let p3 = super::get_itw_config_file(&os);
+        let p4 = super::get_itw_legacy_config_file(&os);
+        let p5 = super::get_itw_legacy_global_config_file(&os);
+        let p6 = super::get_itw_global_config_file(&os);
+        assert_ne!(None, p3);
+        assert_ne!(None, p4);
+        assert_ne!(None, p5);
+        assert_ne!(None, p6);
+        println!("{}", p3.clone().expect("unwrap failed").display());
+        println!("{}", p4.clone().expect("unwrap failed").display());
+        println!("{}", p5.clone().expect("unwrap failed").display());
+        println!("{}", p6.clone().expect("unwrap failed").display());
+        assert_eq!(true, p3.clone().expect("unwrap failed").display().to_string().contains("icedtea-web"));
+        assert_eq!(true, p3.clone().expect("unwrap failed").display().to_string().ends_with("deployment.properties"));
+        assert_eq!(true, p4.clone().expect("unwrap failed").display().to_string().contains(".icedtea"));
+        assert_eq!(true, p4.clone().expect("unwrap failed").display().to_string().ends_with("deployment.properties"));
+        assert_eq!(true, p5.clone().expect("unwrap failed").display().to_string().contains("etc"));
+        assert_eq!(true, p5.clone().expect("unwrap failed").display().to_string().contains(".java"));
+        assert_eq!(true, p5.clone().expect("unwrap failed").display().to_string().contains(".deploy"));
+        assert_eq!(true, p5.clone().expect("unwrap failed").display().to_string().ends_with("deployment.properties"));
+        assert_eq!(true, p5.clone().expect("unwrap failed").display().to_string().contains("etc"));
+        assert_eq!(true, p5.clone().expect("unwrap failed").display().to_string().contains(".java"));
+        assert_eq!(true, p5.clone().expect("unwrap failed").display().to_string().contains("deployment"));
+        assert_eq!(true, p6.clone().expect("unwrap failed").display().to_string().ends_with("deployment.properties"));
+    }
+}
--- a/rust-launcher/src/jvm_from_properties.rs	Wed Nov 28 12:35:38 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,305 +0,0 @@
-use property;
-
-use std;
-use std::env;
-use std::string::String;
-use std::fs::File;
-
-static ICEDTEA_WEB: &'static str = "icedtea-web";
-pub static DEPLOYMENT_PROPERTIES: &'static str = "deployment.properties";
-pub static PROPERTY_NAME: &'static str = "deployment.jre.dir";
-
-fn is_file(path: &std::path::PathBuf) -> bool {
-    let mdr = path.metadata();
-    match mdr {
-        Ok(md) => md.is_file(),
-        Err(_e) => false
-    }
-}
-
-fn get_home() -> Option<std::path::PathBuf> {
-    match env::home_dir() {
-        Some(p) => Some(p),
-        None => None
-    }
-}
-
-fn get_config_dir() -> Option<std::path::PathBuf> {
-    match env::var("XDG_CONFIG_HOME") {
-        Ok(war) => {
-            Some(std::path::PathBuf::from(war))
-        }
-        Err(_e) => {
-            match get_home() {
-                Some(mut p) => {
-                    p.push(".config");
-                    Some(p)
-                }
-                None => None
-            }
-        }
-    }
-}
-
-pub fn get_itw_config_dir() -> Option<std::path::PathBuf> {
-    match get_config_dir() {
-        Some(mut p) => {
-            p.push(ICEDTEA_WEB);
-            Some(p)
-        }
-        None => None
-    }
-}
-
-
-pub fn get_itw_legacy_config_dir() -> Option<std::path::PathBuf> {
-    match get_home() {
-        Some(mut p) => {
-            p.push(".icedtea");
-            Some(p)
-        }
-        None => None
-    }
-}
-
-
-pub fn get_itw_config_file() -> Option<std::path::PathBuf> {
-    match get_itw_config_dir() {
-        Some(mut p) => {
-            p.push(DEPLOYMENT_PROPERTIES);
-            Some(p)
-        }
-        None => None
-    }
-}
-
-pub fn get_itw_legacy_config_file() -> Option<std::path::PathBuf> {
-    match get_itw_legacy_config_dir() {
-        Some(mut p) => {
-            p.push(DEPLOYMENT_PROPERTIES);
-            Some(p)
-        }
-        None => None
-    }
-}
-
-
-pub fn get_itw_legacy_global_config_file() -> Option<std::path::PathBuf> {
-    let mut path = std::path::PathBuf::from("/etc/.java/.deploy");
-    path.push(DEPLOYMENT_PROPERTIES);
-    Some(path)
-}
-
-pub fn get_itw_global_config_file() -> Option<std::path::PathBuf> {
-    let mut path = std::path::PathBuf::from("/etc/.java/deployment");
-    path.push(DEPLOYMENT_PROPERTIES);
-    Some(path)
-}
-
-
-pub fn check_file_for_property_jredir(file: File) -> Option<String> {
-    check_file_for_property(file, PROPERTY_NAME)
-}
-
-fn check_file_for_property(file: File, key: &str) -> Option<String> {
-    let p = property::Property::load(file, key);
-    match p {
-        None => { None }
-        Some(property) => {
-            Some(property.value)
-        }
-    }
-}
-
-
-pub fn get_jre_from_file(file: Option<std::path::PathBuf>) -> Option<String> {
-    match file {
-        None => None,
-        Some(path) => {
-            get_jre_from_file_direct(path)
-        }
-    }
-}
-
-fn get_jre_from_file_direct(path: std::path::PathBuf) -> Option<String> {
-    if !path.exists() {
-        None
-    } else if !is_file(&path) {
-        return None;
-    } else {
-        let fileresult = File::open(path);
-        match fileresult {
-            Err(_fe) => None,
-            Ok(file) => {
-                let result = check_file_for_property_jredir(file);
-                result
-            }
-        }
-    }
-}
-
-pub fn verify_jdk_string(file: &String) -> bool {
-    verify_jdk_path(&std::path::PathBuf::from(file))
-}
-
-fn verify_jdk_path(ffile: &std::path::PathBuf) -> bool {
-    let mut file = ffile.clone();
-    file.push("bin");
-    file.push("java");
-    if !file.exists() {
-        false
-    } else if !is_file(&file) {
-        false
-    } else {
-        true
-    }
-}
-
-/*tests*/
-#[cfg(test)]
-mod tests {
-    use std;
-    use std::fs::File;
-    use utils::tests_utils as tu;
-
-
-    #[test]
-    fn is_not_file_() {
-        let r = super::is_file(&std::path::PathBuf::from("/definitely/not/existing/file"));
-        assert_eq!(false, r);
-    }
-
-    #[test]
-    fn is_file_() {
-        let dir = tu::create_tmp_file();
-        let r = super::is_file(&dir);
-        tu::debuggable_remove_file(&dir);
-        assert_eq!(true, r);
-    }
-
-    #[test]
-    fn check_file_for_property_jredir_not_found() {
-        let path = tu::create_tmp_file();
-        let f = File::open(&path);
-        let prop = super::check_file_for_property_jredir(f.expect("file was not opened"));
-        tu::debuggable_remove_file(&path);
-        assert_eq!(None, prop);
-    }
-
-    #[test]
-    fn check_file_for_property_jredir() {
-        let path = tu::create_tmp_propfile_with_content();
-        let f = File::open(&path);
-        let prop = super::check_file_for_property_jredir(f.expect("file was not opened"));
-        tu::debuggable_remove_file(&path);
-        assert_eq!("/some/jre", prop.expect("property was supposed to be loaded"));
-    }
-
-
-    #[test]
-    fn check_file_for_property_not_found() {
-        let path = tu::create_tmp_propfile_with_content();
-        let f = File::open(&path);
-        let k = "not_existing_key";
-        let prop = super::check_file_for_property(f.expect("file was not opened"), k);
-        tu::debuggable_remove_file(&path);
-        assert_eq!(None, prop);
-    }
-
-    #[test]
-    fn check_file_for_property_item_exists() {
-        let path = tu::create_tmp_propfile_with_content();
-        let f = File::open(&path);
-        let k = "key2";
-        let prop = super::check_file_for_property(f.expect("file was not opened"), k);
-        tu::debuggable_remove_file(&path);
-        assert_eq!("val2", prop.expect("property was supposed to be loaded"));
-    }
-
-    #[test]
-    fn get_jre_from_file_exists() {
-        let path = tu::create_tmp_propfile_with_content();
-        let prop = super::get_jre_from_file(Some(path.clone()));
-        tu::debuggable_remove_file(&path);
-        assert_eq!("/some/jre", prop.expect("property was supposed to be loaded"));
-    }
-
-    #[test]
-    fn get_jre_from_file_not_found() {
-        let path = tu::create_tmp_file();
-        let prop = super::get_jre_from_file(Some(path.clone()));
-        tu::debuggable_remove_file(&path);
-        assert_eq!(None, prop);
-    }
-
-
-    #[test]
-    fn get_jre_from_file_notexists() {
-        let path = tu::create_tmp_file();
-        tu::debuggable_remove_file(&path);
-        let prop = super::get_jre_from_file(Some(path));
-        assert_eq!(None, prop);
-    }
-
-    #[test]
-    fn get_jre_from_file_none() {
-        let prop = super::get_jre_from_file(None);
-        assert_eq!(None, prop);
-    }
-
-    #[test]
-    fn verify_jdk_string_verify_jdk_path_jdk_ok() {
-        let master_dir = tu::fake_jre(true);
-        let vs = super::verify_jdk_string(&master_dir.display().to_string());
-        let vp = super::verify_jdk_path(&master_dir);
-        tu::debuggable_remove_dir(&master_dir);
-        assert_eq!(true, vs);
-        assert_eq!(true, vp);
-    }
-
-    #[test]
-    fn verify_jdk_string_verify_jdk_path_jdk_bad() {
-        let master_dir = tu::fake_jre(false);
-        let vs = super::verify_jdk_string(&master_dir.display().to_string());
-        let vp = super::verify_jdk_path(&master_dir);
-        tu::debuggable_remove_dir(&master_dir);
-        assert_eq!(false, vs);
-        assert_eq!(false, vp);
-    }
-
-    #[test]
-    fn check_config_files_paths() {
-        let p1 = super::get_itw_config_dir();
-        let p2 = super::get_itw_legacy_config_dir();
-        let p3 = super::get_itw_config_file();
-        let p4 = super::get_itw_legacy_config_file();
-        let p5 = super::get_itw_legacy_global_config_file();
-        let p6 = super::get_itw_global_config_file();
-        assert_ne!(None, p1);
-        assert_ne!(None, p2);
-        assert_ne!(None, p3);
-        assert_ne!(None, p4);
-        assert_ne!(None, p5);
-        assert_ne!(None, p6);
-        println!("{}", p1.clone().expect("unwrap failed").display());
-        println!("{}", p2.clone().expect("unwrap failed").display());
-        println!("{}", p3.clone().expect("unwrap failed").display());
-        println!("{}", p4.clone().expect("unwrap failed").display());
-        println!("{}", p5.clone().expect("unwrap failed").display());
-        println!("{}", p6.clone().expect("unwrap failed").display());
-        assert_eq!(true, p1.clone().expect("unwrap failed").display().to_string().contains("icedtea-web"));
-        assert_eq!(true, p2.clone().expect("unwrap failed").display().to_string().contains(".icedtea"));
-        assert_eq!(true, p3.clone().expect("unwrap failed").display().to_string().contains("icedtea-web"));
-        assert_eq!(true, p3.clone().expect("unwrap failed").display().to_string().ends_with("deployment.properties"));
-        assert_eq!(true, p4.clone().expect("unwrap failed").display().to_string().contains(".icedtea"));
-        assert_eq!(true, p4.clone().expect("unwrap failed").display().to_string().ends_with("deployment.properties"));
-        assert_eq!(true, p5.clone().expect("unwrap failed").display().to_string().contains("etc"));
-        assert_eq!(true, p5.clone().expect("unwrap failed").display().to_string().contains(".java"));
-        assert_eq!(true, p5.clone().expect("unwrap failed").display().to_string().contains(".deploy"));
-        assert_eq!(true, p5.clone().expect("unwrap failed").display().to_string().ends_with("deployment.properties"));
-        assert_eq!(true, p5.clone().expect("unwrap failed").display().to_string().contains("etc"));
-        assert_eq!(true, p5.clone().expect("unwrap failed").display().to_string().contains(".java"));
-        assert_eq!(true, p5.clone().expect("unwrap failed").display().to_string().contains("deployment"));
-        assert_eq!(true, p6.clone().expect("unwrap failed").display().to_string().ends_with("deployment.properties"));
-    }
-}
--- a/rust-launcher/src/jvm_from_properties_resolver.rs	Wed Nov 28 12:35:38 2018 +0100
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,221 +0,0 @@
-use hardcoded_paths;
-use jvm_from_properties;
-use os_access;
-
-use std;
-use std::string::String;
-use std::fmt::Write;
-
-pub fn try_jdk_from_properties(logger: &os_access::Os) -> Option<String> {
-    let array: [Option<std::path::PathBuf>; 4] = [
-        jvm_from_properties::get_itw_config_file(),
-        jvm_from_properties::get_itw_legacy_config_file(),
-        jvm_from_properties::get_itw_legacy_global_config_file(),
-        jvm_from_properties::get_itw_global_config_file()
-    ];
-    try_jdk_from_properties_files(logger, &array)
-}
-
-fn try_jdk_from_properties_files(logger: &os_access::Os, array: &[Option<std::path::PathBuf>]) -> Option<String> {
-    for jdk in array {
-        let mut info1 = String::new();
-        write!(&mut info1, "{} ", "itw-rust-debug: checking jre in:").expect("unwrap failed");
-        write!(&mut info1, "{}", jdk.clone().unwrap_or(std::path::PathBuf::from("None")).display()).expect("unwrap failed");
-        logger.log(&info1);
-        match jvm_from_properties::get_jre_from_file(jdk.clone()) {
-            Some(path) => {
-                let mut info2 = String::new();
-                write!(&mut info2, "{} ", "itw-rust-debug: located").expect("unwrap failed");
-                write!(&mut info2, "{}", path).expect("unwrap failed");
-                write!(&mut info2, " in file {}", jdk.clone().expect("file should be already verified").display()).expect("unwrap failed");
-                logger.log(&info2);
-                if jvm_from_properties::verify_jdk_string(&path) {
-                    return Some(path);
-                } else {
-                    //the only output out of verbose mode
-                    let mut res = String::new();
-                    write!(&mut res, "{}", "Your custom JRE ").expect("unwrap failed");
-                    write!(&mut res, "{}", path).expect("unwrap failed");
-                    write!(&mut res, "{}", " read from ").expect("unwrap failed");
-                    write!(&mut res, "{}", jdk.clone().expect("jre path should be loaded").display()).expect("unwrap failed");
-                    write!(&mut res, "{}", " under key ").expect("unwrap failed");
-                    write!(&mut res, "{}", jvm_from_properties::PROPERTY_NAME).expect("unwrap failed");
-                    write!(&mut res, "{}", " is not valid. Trying other config files, then using default (").expect("unwrap failed");
-                    write!(&mut res, "{}", hardcoded_paths::get_java()).expect("unwrap failed");
-                    write!(&mut res, "{}", ", ").expect("unwrap failed");
-                    write!(&mut res, "{}", hardcoded_paths::get_jre()).expect("unwrap failed");
-                    write!(&mut res, "{}", ", registry or JAVA_HOME) in attempt to start. Please fix this.").expect("unwrap failed");
-                    logger.info(&res);
-                }
-            }
-            None => {
-                logger.log("itw-rust-debug: property not located or file inaccessible");
-            }
-        }
-    }
-    None
-}
-
-/*tests*/
-/*To print the diagnostic output use `cargo test -- --nocapture
-`*/
-#[cfg(test)]
-mod tests {
-    use std;
-    use os_access;
-    use std::cell::RefCell;
-    use utils::tests_utils as tu;
-    //if you wont to investigate files used for testing
-    // use cargo test -- --nocapture to see  files which needs delete
-    static DELETE_TEST_FILES: bool = true;
-
-    pub struct TestLogger {
-        vec: RefCell<Vec<String>>,
-    }
-
-    impl TestLogger {
-        fn get_log(&self) -> String {
-            let joined = self.vec.borrow_mut().join("; ");
-            joined
-        }
-    }
-
-    impl os_access::Os for TestLogger {
-        fn log(&self, s: &str) {
-            let ss = String::from(s);
-            self.vec.borrow_mut().push(ss);
-        }
-
-        fn info(&self, s: &str) {
-            let ss = String::from(s);
-            self.vec.borrow_mut().push(ss);
-        }
-
-        fn get_registry_jdk(&self) -> Option<std::path::PathBuf> {
-            None
-        }
-
-        fn spawn_java_process(&self, jre_dir: &std::path::PathBuf, args: &Vec<String>) -> std::process::Child {
-            panic!("not implemented");
-        }
-    }
-
-    #[test]
-    fn try_jdk_from_properties_files_4nothing() {
-        let array: [Option<std::path::PathBuf>; 4] = [
-            None,
-            None,
-            None,
-            None
-        ];
-        let os = TestLogger { vec: RefCell::new(Vec::new()) };
-        let r = super::try_jdk_from_properties_files(&os, &array);
-        println!("{}", &os.get_log());
-        assert_eq!(None, r);
-    }
-
-    #[test]
-    fn try_jdk_from_properties_files_4nonexisting() {
-        let array: [Option<std::path::PathBuf>; 4] = [
-            Some(std::path::PathBuf::from("Nonexisting file 1")),
-            Some(std::path::PathBuf::from("Nonexisting file 2")),
-            Some(std::path::PathBuf::from("Nonexisting file 3")),
-            Some(std::path::PathBuf::from("Nonexisting file 4")),
-        ];
-        let os = TestLogger { vec: RefCell::new(Vec::new()) };
-        let r = super::try_jdk_from_properties_files(&os, &array);
-        println!("{}", &os.get_log());
-        assert_eq!(None, r);
-    }
-
-    fn clean_fake_files(array: &[Option<std::path::PathBuf>]) {
-        for jdk in array {
-            match jdk.clone() {
-                Some(path) => {
-                    if DELETE_TEST_FILES {
-                        tu::debuggable_remove_file(&path);
-                    } else {
-                        println!("file {} intentionally not deleted!", path.display());
-                    }
-                }
-                None => {}
-            }
-        }
-    }
-
-    #[test]
-    fn try_jdk_from_properties_files_4empty() {
-        let array: [Option<std::path::PathBuf>; 4] = [
-            Some(std::path::PathBuf::from(tu::create_tmp_file())),
-            Some(std::path::PathBuf::from(tu::create_tmp_file())),
-            Some(std::path::PathBuf::from(tu::create_tmp_file())),
-            Some(std::path::PathBuf::from(tu::create_tmp_file())),
-        ];
-        let os = TestLogger { vec: RefCell::new(Vec::new()) };
-        let r = super::try_jdk_from_properties_files(&os, &array);
-        println!("{}", &os.get_log());
-        clean_fake_files(&array);
-        assert_eq!(None, r);
-    }
-
-    #[test]
-    fn try_jdk_from_properties_files_invalid_jdk() {
-        let array: [Option<std::path::PathBuf>; 4] = [
-            Some(std::path::PathBuf::from(tu::create_tmp_propfile_with_custom_jre_content("non/existing/jre1"))),
-            Some(std::path::PathBuf::from(tu::create_tmp_propfile_with_custom_jre_content("non/existing/jre2"))),
-            Some(std::path::PathBuf::from(tu::create_tmp_propfile_with_custom_jre_content("non/existing/jre3"))),
-            Some(std::path::PathBuf::from(tu::create_tmp_propfile_with_custom_jre_content("non/existing/jre4"))),
-        ];
-        let os = TestLogger { vec: RefCell::new(Vec::new()) };
-        let r = super::try_jdk_from_properties_files(&os, &array);
-        println!("{}", &os.get_log());
-        clean_fake_files(&array);
-        assert_eq!(None, r);
-        assert_eq!(true, os.get_log().contains("is not valid"));
-        assert_eq!(true, os.get_log().contains("non/existing/jre1"));
-        assert_eq!(true, os.get_log().contains("non/existing/jre2"));
-        assert_eq!(true, os.get_log().contains("non/existing/jre3"));
-        assert_eq!(true, os.get_log().contains("non/existing/jre4"));
-    }
-
-    #[test]
-    fn try_jdk_from_properties_files_none_and_valid() {
-        let master_dir = tu::fake_jre(true);
-        let array: [Option<std::path::PathBuf>; 4] = [
-            Some(std::path::PathBuf::from(tu::create_tmp_file())),
-            Some(std::path::PathBuf::from(tu::create_tmp_propfile_with_custom_jre_content(&master_dir.display().to_string()))),
-            Some(std::path::PathBuf::from(tu::create_tmp_propfile_with_custom_jre_content("non/existing/jre3"))),
-            Some(std::path::PathBuf::from(tu::create_tmp_propfile_with_custom_jre_content("non/existing/jre4"))),
-        ];
-        let os = TestLogger { vec: RefCell::new(Vec::new()) };
-        let r = super::try_jdk_from_properties_files(&os, &array);
-        println!("{}", &os.get_log());
-        clean_fake_files(&array);
-        assert_ne!(None, r);
-        assert_ne!(true, os.get_log().contains("is not valid"));
-        assert_ne!(true, os.get_log().contains("non/existing/jre3"));
-        assert_ne!(true, os.get_log().contains("non/existing/jre4"));
-        assert_eq!(master_dir.display().to_string(), r.expect("r should be full"));
-    }
-
-    #[test]
-    fn try_jdk_from_properties_files_none_and_more_valid() {
-        let master_dir1 = tu::fake_jre(true);
-        let master_dir2 = tu::fake_jre(true);
-        let array: [Option<std::path::PathBuf>; 4] = [
-            Some(std::path::PathBuf::from(tu::create_tmp_file())),
-            Some(std::path::PathBuf::from(tu::create_tmp_propfile_with_custom_jre_content(&master_dir1.display().to_string()))),
-            Some(std::path::PathBuf::from(tu::create_tmp_file())),
-            Some(std::path::PathBuf::from(tu::create_tmp_propfile_with_custom_jre_content(&master_dir2.display().to_string()))),
-        ];
-        let os = TestLogger { vec: RefCell::new(Vec::new()) };
-        let r = super::try_jdk_from_properties_files(&os, &array);
-        println!("{}", &os.get_log());
-        clean_fake_files(&array);
-        assert_ne!(None, r);
-        assert_ne!(true, os.get_log().contains("is not valid"));
-        assert_eq!(master_dir1.display().to_string(), r.expect("also this r should be full"));
-    }
-}
-
-
--- a/rust-launcher/src/main.rs	Wed Nov 28 12:35:38 2018 +0100
+++ b/rust-launcher/src/main.rs	Fri Nov 30 19:04:42 2018 +0100
@@ -1,7 +1,8 @@
 mod hardcoded_paths;
-mod jvm_from_properties;
+mod property_from_file;
 mod os_access;
-mod jvm_from_properties_resolver;
+mod dirs_paths_helper;
+mod property_from_files_resolver;
 mod utils;
 mod property;
 
@@ -26,11 +27,9 @@
     let os = os_access::Linux::new(is_debug_on());
     let java_dir: std::path::PathBuf;
     let mut info1 = String::new();
-    write!(&mut info1, "{}", "itw-rust-debug: trying jdk over properties (").expect("unwrap failed");
-    write!(&mut info1, "{}", jvm_from_properties::PROPERTY_NAME).expect("unwrap failed");
-    write!(&mut info1, "{}", ")").expect("unwrap failed");
+    write!(&mut info1, "itw-rust-debug: trying jdk over properties ({})", property_from_file::JRE_PROPERTY_NAME).expect("unwrap failed");
     os.log(&info1);
-    match jvm_from_properties_resolver::try_jdk_from_properties(&os) {
+    match property_from_files_resolver::try_jdk_from_properties(&os) {
         Some(path) => {
             java_dir = std::path::PathBuf::from(path);
             os.log("itw-rust-debug: found and using");
@@ -62,8 +61,7 @@
         }
     }
     let mut info2 = String::new();
-    write!(&mut info2, "{}", "selected jre: ").expect("unwrap failed");
-    write!(&mut info2, "{}", java_dir.display()).expect("unwrap failed");
+    write!(&mut info2, "selected jre: {}", java_dir.display()).expect("unwrap failed");
     os.info(&info2);
     let mut child = os.spawn_java_process(&java_dir, &(env::args().skip(1).collect()));
     let ecode = child.wait().expect("failed to wait on child");
--- a/rust-launcher/src/os_access.rs	Wed Nov 28 12:35:38 2018 +0100
+++ b/rust-launcher/src/os_access.rs	Fri Nov 30 19:04:42 2018 +0100
@@ -1,10 +1,19 @@
 use std;
+use dirs_paths_helper;
 
 pub trait Os {
     //logging "api" can change
     fn log(&self, s: &str);
     fn info(&self, s: &str);
     fn get_registry_jdk(&self) -> Option<std::path::PathBuf>;
+    // next to system and home cfg dir, there is also by-jre config dir, but that do not need to be handled os-specific way
+    //https://docs.oracle.com/javase/7/docs/technotes/guides/jweb/jcp/properties.html
+    fn get_system_config_javadir(&self) -> Option<std::path::PathBuf>;
+    fn get_user_config_dir(&self) -> Option<std::path::PathBuf>;
+    //is valid  only on linux, otherwise returns get_system_config_javadir
+    fn get_legacy_system_config_javadir(&self) -> Option<std::path::PathBuf>;
+    //is valid  only on linux, otherwise returns get_user_config_dir
+    fn get_legacy_user_config_dir(&self) -> Option<std::path::PathBuf>;
     fn spawn_java_process(&self, jre_dir: &std::path::PathBuf, args: &Vec<String>) -> std::process::Child;
 }
 
@@ -33,6 +42,36 @@
         None
     }
 
+    fn get_system_config_javadir(&self) -> Option<std::path::PathBuf> {
+        let path = std::path::PathBuf::from("/etc/.java/deployment");
+        Some(path)
+    }
+
+    fn get_user_config_dir(&self) -> Option<std::path::PathBuf> {
+        match dirs_paths_helper::get_xdg_config_dir() {
+            Some(mut p) => {
+                p.push(dirs_paths_helper::ICEDTEA_WEB);
+                Some(p)
+            }
+            None => None
+        }
+    }
+
+    fn get_legacy_system_config_javadir(&self) -> Option<std::path::PathBuf> {
+        let path = std::path::PathBuf::from("/etc/.java/.deploy");
+        Some(path)
+    }
+
+    fn get_legacy_user_config_dir(&self) -> Option<std::path::PathBuf> {
+        match dirs_paths_helper::get_home() {
+            Some(mut p) => {
+                p.push(".icedtea");
+                Some(p)
+            }
+            None => None
+        }
+    }
+    
     fn spawn_java_process(&self, jre_dir: &std::path::PathBuf, args: &Vec<String>) -> std::process::Child {
         let mut bin_java = jre_dir.clone();
         bin_java.push("bin");
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rust-launcher/src/property_from_file.rs	Fri Nov 30 19:04:42 2018 +0100
@@ -0,0 +1,199 @@
+use property;
+use hardcoded_paths;
+
+use std;
+use std::string::String;
+use std::fs::File;
+use std::fmt::Write;
+
+pub static JRE_PROPERTY_NAME: &'static str = "deployment.jre.dir";
+pub static VERBOSE_PROPERTY_NAME: &'static str = "deployment.log";
+
+
+pub trait Validator {
+    fn validate(&self, s: &str) -> bool;
+    fn get_fail_message(&self, key: &str, value: &str, file: &Option<std::path::PathBuf>) -> String;
+}
+
+pub struct JreValidator {}
+
+
+impl Validator for JreValidator {
+    fn validate(&self, s: &str) -> bool {
+        verify_jdk_string(&s)
+    }
+
+    fn get_fail_message(&self, key: &str, value: &str, file: &Option<std::path::PathBuf>) -> String {
+        let mut res = String::new();
+        write!(&mut res, "Your custom JRE {} read from {} under key {} is not valid.", value, file.clone().expect("jre path should be loaded").display(), key).expect("unwrap failed");
+        write!(&mut res, " Trying other config files, then using default ({}, {}, registry or JAVA_HOME) in attempt to start. Please fix this.", hardcoded_paths::get_java(), hardcoded_paths::get_jre()).expect("unwrap failed");
+        return res;
+    }
+}
+
+fn is_file(path: &std::path::PathBuf) -> bool {
+    path.metadata().map(|md| md.is_file()).unwrap_or(false)
+}
+
+
+pub fn get_property_from_file(file: Option<std::path::PathBuf>, key: &str) -> Option<String> {
+    match file {
+        None => None,
+        Some(path) => {
+            get_property_from_file_direct(path, key)
+        }
+    }
+}
+
+fn get_property_from_file_direct(path: std::path::PathBuf, key: &str) -> Option<String> {
+    if !path.exists() {
+        None
+    } else if !is_file(&path) {
+        return None;
+    } else {
+        let fileresult = File::open(path);
+        match fileresult {
+            Err(_fe) => None,
+            Ok(file) => {
+                let result = check_file_for_property(file, key);
+                result
+            }
+        }
+    }
+}
+
+fn check_file_for_property(file: File, key: &str) -> Option<String> {
+    let p = property::Property::load(file, key);
+    match p {
+        None => { None }
+        Some(property) => {
+            Some(property.value)
+        }
+    }
+}
+
+
+fn verify_jdk_string(spath: &str) -> bool {
+    let mut file = std::path::PathBuf::from(spath);
+    file.push("bin");
+    file.push("java");
+    if !file.exists() {
+        false
+    } else if !is_file(&file) {
+        false
+    } else {
+        true
+    }
+}
+
+/*tests*/
+#[cfg(test)]
+mod tests {
+    use std;
+    use std::fs::File;
+    use utils::tests_utils as tu;
+
+    fn get_jre_from_file(file: Option<std::path::PathBuf>) -> Option<String> {
+        super::get_property_from_file(file, super::JRE_PROPERTY_NAME)
+    }
+
+    #[test]
+    fn is_not_file_() {
+        let r = super::is_file(&std::path::PathBuf::from("/definitely/not/existing/file"));
+        assert_eq!(false, r);
+    }
+
+    #[test]
+    fn is_file_() {
+        let dir = tu::create_tmp_file();
+        let r = super::is_file(&dir);
+        tu::debuggable_remove_file(&dir);
+        assert_eq!(true, r);
+    }
+
+    #[test]
+    fn check_file_for_property_jredir_not_found() {
+        let path = tu::create_tmp_file();
+        let f = File::open(&path);
+        let prop = super::check_file_for_property(f.expect("file was not opened"), super::JRE_PROPERTY_NAME);
+        tu::debuggable_remove_file(&path);
+        assert_eq!(None, prop);
+    }
+
+    #[test]
+    fn check_file_for_property_jredir() {
+        let path = tu::create_tmp_propfile_with_content();
+        let f = File::open(&path);
+        let prop = super::check_file_for_property(f.expect("file was not opened"), super::JRE_PROPERTY_NAME);
+        tu::debuggable_remove_file(&path);
+        assert_eq!("/some/jre", prop.expect("property was supposed to be loaded"));
+    }
+
+
+    #[test]
+    fn check_file_for_property_not_found() {
+        let path = tu::create_tmp_propfile_with_content();
+        let f = File::open(&path);
+        let k = "not_existing_key";
+        let prop = super::check_file_for_property(f.expect("file was not opened"), k);
+        tu::debuggable_remove_file(&path);
+        assert_eq!(None, prop);
+    }
+
+    #[test]
+    fn check_file_for_property_item_exists() {
+        let path = tu::create_tmp_propfile_with_content();
+        let f = File::open(&path);
+        let k = "key2";
+        let prop = super::check_file_for_property(f.expect("file was not opened"), k);
+        tu::debuggable_remove_file(&path);
+        assert_eq!("val2", prop.expect("property was supposed to be loaded"));
+    }
+
+    #[test]
+    fn get_jre_from_file_exists() {
+        let path = tu::create_tmp_propfile_with_content();
+        let prop = get_jre_from_file(Some(path.clone()));
+        tu::debuggable_remove_file(&path);
+        assert_eq!("/some/jre", prop.expect("property was supposed to be loaded"));
+    }
+
+    #[test]
+    fn get_jre_from_file_not_found() {
+        let path = tu::create_tmp_file();
+        let prop = get_jre_from_file(Some(path.clone()));
+        tu::debuggable_remove_file(&path);
+        assert_eq!(None, prop);
+    }
+
+
+    #[test]
+    fn get_jre_from_file_notexists() {
+        let path = tu::create_tmp_file();
+        tu::debuggable_remove_file(&path);
+        let prop = get_jre_from_file(Some(path));
+        assert_eq!(None, prop);
+    }
+
+    #[test]
+    fn get_jre_from_file_none() {
+        let prop = get_jre_from_file(None);
+        assert_eq!(None, prop);
+    }
+
+    #[test]
+    fn verify_jdk_string_verify_jdk_path_jdk_ok() {
+        let master_dir = tu::fake_jre(true);
+        let vs = super::verify_jdk_string(&master_dir.display().to_string());
+        tu::debuggable_remove_dir(&master_dir);
+        assert_eq!(true, vs);
+    }
+
+    #[test]
+    fn verify_jdk_string_verify_jdk_path_jdk_bad() {
+        let master_dir = tu::fake_jre(false);
+        let vs = super::verify_jdk_string(&master_dir.display().to_string());
+        tu::debuggable_remove_dir(&master_dir);
+        assert_eq!(false, vs);
+    }
+}
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/rust-launcher/src/property_from_files_resolver.rs	Fri Nov 30 19:04:42 2018 +0100
@@ -0,0 +1,229 @@
+use property_from_file;
+use os_access;
+use dirs_paths_helper;
+
+use std;
+use std::string::String;
+use std::fmt::Write;
+
+pub fn try_jdk_from_properties(logger: &os_access::Os) -> Option<String> {
+    //obviously search in jre dir is missing, when we search for jre
+    let array: [Option<std::path::PathBuf>; 4] = [
+        dirs_paths_helper::get_itw_config_file(logger),
+        dirs_paths_helper::get_itw_legacy_config_file(logger),
+        dirs_paths_helper::get_itw_legacy_global_config_file(logger),
+        dirs_paths_helper::get_itw_global_config_file(logger)
+    ];
+    try_key_from_properties_files(logger, &array, property_from_file::JRE_PROPERTY_NAME, &property_from_file::JreValidator {})
+}
+
+fn try_key_from_properties_files(logger: &os_access::Os, array: &[Option<std::path::PathBuf>], key: &str, validator: &property_from_file::Validator) -> Option<String> {
+    for file in array {
+        let mut info1 = String::new();
+        write!(&mut info1, "itw-rust-debug: checking {} in: {}", key, file.clone().unwrap_or(std::path::PathBuf::from("None")).display()).expect("unwrap failed");
+        logger.log(&info1);
+        match property_from_file::get_property_from_file(file.clone(), &key) {
+            Some(value) => {
+                let mut info2 = String::new();
+                write!(&mut info2, "itw-rust-debug: located {} in file {}", value, file.clone().expect("file should be already verified").display()).expect("unwrap failed");
+                logger.log(&info2);
+                if validator.validate(&value) {
+                    return Some(value);
+                } else {
+                    //the only output out of verbose mode
+                    let res = validator.get_fail_message(&key, &value, file);
+                    logger.info(&res);
+                }
+            }
+            None => {
+                logger.log("itw-rust-debug: property not located or file inaccessible");
+            }
+        }
+    }
+    None
+}
+
+/*tests*/
+/*To print the diagnostic output use `cargo test -- --nocapture
+`*/
+#[cfg(test)]
+mod tests {
+    use std;
+    use os_access;
+    use std::cell::RefCell;
+    use utils::tests_utils as tu;
+    use property_from_file;
+    //if you wont to investigate files used for testing
+    // use cargo test -- --nocapture to see  files which needs delete
+    static DELETE_TEST_FILES: bool = true;
+
+    pub struct TestLogger {
+        vec: RefCell<Vec<String>>,
+    }
+
+    impl TestLogger {
+        fn get_log(&self) -> String {
+            let joined = self.vec.borrow_mut().join("; ");
+            joined
+        }
+    }
+
+    impl os_access::Os for TestLogger {
+        fn log(&self, s: &str) {
+            let ss = String::from(s);
+            self.vec.borrow_mut().push(ss);
+        }
+
+        fn info(&self, s: &str) {
+            let ss = String::from(s);
+            self.vec.borrow_mut().push(ss);
+        }
+
+        fn get_registry_jdk(&self) -> Option<std::path::PathBuf> {
+            None
+        }
+
+        fn spawn_java_process(&self, jre_dir: &std::path::PathBuf, args: &Vec<String>) -> std::process::Child {
+            panic!("not implemented");
+        }
+
+        fn get_system_config_javadir(&self) -> Option<std::path::PathBuf> {
+            panic!("not implemented");
+        }
+
+        fn get_user_config_dir(&self) -> Option<std::path::PathBuf> {
+            panic!("not implemented");
+        }
+
+        fn get_legacy_system_config_javadir(&self) -> Option<std::path::PathBuf> {
+            panic!("not implemented");
+        }
+
+        fn get_legacy_user_config_dir(&self) -> Option<std::path::PathBuf> {
+            panic!("not implemented");
+        }
+    }
+
+    fn try_jdk_from_properties_files(logger: &os_access::Os, array: &[Option<std::path::PathBuf>]) -> Option<String> {
+        super::try_key_from_properties_files(logger, &array, property_from_file::JRE_PROPERTY_NAME, &property_from_file::JreValidator {})
+    }
+
+    #[test]
+    fn try_jdk_from_properties_files_4nothing() {
+        let array: [Option<std::path::PathBuf>; 4] = [
+            None,
+            None,
+            None,
+            None
+        ];
+        let os = TestLogger { vec: RefCell::new(Vec::new()) };
+        let r = try_jdk_from_properties_files(&os, &array);
+        println!("{}", &os.get_log());
+        assert_eq!(None, r);
+    }
+
+    #[test]
+    fn try_jdk_from_properties_files_4nonexisting() {
+        let array: [Option<std::path::PathBuf>; 4] = [
+            Some(std::path::PathBuf::from("Nonexisting file 1")),
+            Some(std::path::PathBuf::from("Nonexisting file 2")),
+            Some(std::path::PathBuf::from("Nonexisting file 3")),
+            Some(std::path::PathBuf::from("Nonexisting file 4")),
+        ];
+        let os = TestLogger { vec: RefCell::new(Vec::new()) };
+        let r = try_jdk_from_properties_files(&os, &array);
+        println!("{}", &os.get_log());
+        assert_eq!(None, r);
+    }
+
+    fn clean_fake_files(array: &[Option<std::path::PathBuf>]) {
+        for jdk in array {
+            match jdk.clone() {
+                Some(path) => {
+                    if DELETE_TEST_FILES {
+                        tu::debuggable_remove_file(&path);
+                    } else {
+                        println!("file {} intentionally not deleted!", path.display());
+                    }
+                }
+                None => {}
+            }
+        }
+    }
+
+    #[test]
+    fn try_jdk_from_properties_files_4empty() {
+        let array: [Option<std::path::PathBuf>; 4] = [
+            Some(std::path::PathBuf::from(tu::create_tmp_file())),
+            Some(std::path::PathBuf::from(tu::create_tmp_file())),
+            Some(std::path::PathBuf::from(tu::create_tmp_file())),
+            Some(std::path::PathBuf::from(tu::create_tmp_file())),
+        ];
+        let os = TestLogger { vec: RefCell::new(Vec::new()) };
+        let r = try_jdk_from_properties_files(&os, &array);
+        println!("{}", &os.get_log());
+        clean_fake_files(&array);
+        assert_eq!(None, r);
+    }
+
+    #[test]
+    fn try_jdk_from_properties_files_invalid_jdk() {
+        let array: [Option<std::path::PathBuf>; 4] = [
+            Some(std::path::PathBuf::from(tu::create_tmp_propfile_with_custom_jre_content("non/existing/jre1"))),
+            Some(std::path::PathBuf::from(tu::create_tmp_propfile_with_custom_jre_content("non/existing/jre2"))),
+            Some(std::path::PathBuf::from(tu::create_tmp_propfile_with_custom_jre_content("non/existing/jre3"))),
+            Some(std::path::PathBuf::from(tu::create_tmp_propfile_with_custom_jre_content("non/existing/jre4"))),
+        ];
+        let os = TestLogger { vec: RefCell::new(Vec::new()) };
+        let r = try_jdk_from_properties_files(&os, &array);
+        println!("{}", &os.get_log());
+        clean_fake_files(&array);
+        assert_eq!(None, r);
+        assert_eq!(true, os.get_log().contains("is not valid"));
+        assert_eq!(true, os.get_log().contains("non/existing/jre1"));
+        assert_eq!(true, os.get_log().contains("non/existing/jre2"));
+        assert_eq!(true, os.get_log().contains("non/existing/jre3"));
+        assert_eq!(true, os.get_log().contains("non/existing/jre4"));
+    }
+
+    #[test]
+    fn try_jdk_from_properties_files_none_and_valid() {
+        let master_dir = tu::fake_jre(true);
+        let array: [Option<std::path::PathBuf>; 4] = [
+            Some(std::path::PathBuf::from(tu::create_tmp_file())),
+            Some(std::path::PathBuf::from(tu::create_tmp_propfile_with_custom_jre_content(&master_dir.display().to_string()))),
+            Some(std::path::PathBuf::from(tu::create_tmp_propfile_with_custom_jre_content("non/existing/jre3"))),
+            Some(std::path::PathBuf::from(tu::create_tmp_propfile_with_custom_jre_content("non/existing/jre4"))),
+        ];
+        let os = TestLogger { vec: RefCell::new(Vec::new()) };
+        let r = try_jdk_from_properties_files(&os, &array);
+        println!("{}", &os.get_log());
+        clean_fake_files(&array);
+        assert_ne!(None, r);
+        assert_ne!(true, os.get_log().contains("is not valid"));
+        assert_ne!(true, os.get_log().contains("non/existing/jre3"));
+        assert_ne!(true, os.get_log().contains("non/existing/jre4"));
+        assert_eq!(master_dir.display().to_string(), r.expect("r should be full"));
+    }
+
+    #[test]
+    fn try_jdk_from_properties_files_none_and_more_valid() {
+        let master_dir1 = tu::fake_jre(true);
+        let master_dir2 = tu::fake_jre(true);
+        let array: [Option<std::path::PathBuf>; 4] = [
+            Some(std::path::PathBuf::from(tu::create_tmp_file())),
+            Some(std::path::PathBuf::from(tu::create_tmp_propfile_with_custom_jre_content(&master_dir1.display().to_string()))),
+            Some(std::path::PathBuf::from(tu::create_tmp_file())),
+            Some(std::path::PathBuf::from(tu::create_tmp_propfile_with_custom_jre_content(&master_dir2.display().to_string()))),
+        ];
+        let os = TestLogger { vec: RefCell::new(Vec::new()) };
+        let r = try_jdk_from_properties_files(&os, &array);
+        println!("{}", &os.get_log());
+        clean_fake_files(&array);
+        assert_ne!(None, r);
+        assert_ne!(true, os.get_log().contains("is not valid"));
+        assert_eq!(master_dir1.display().to_string(), r.expect("also this r should be full"));
+    }
+}
+
+
--- a/rust-launcher/src/utils.rs	Wed Nov 28 12:35:38 2018 +0100
+++ b/rust-launcher/src/utils.rs	Fri Nov 30 19:04:42 2018 +0100
@@ -7,7 +7,7 @@
     use std::fmt::Write as fmt_write;
     use std::io::Write;
     use std::sync::atomic::{AtomicUsize, Ordering, ATOMIC_USIZE_INIT};
-    use jvm_from_properties;
+    use property_from_file;
 
     // rand is in separate crate, so using atomic increment instead
     static TMP_COUNTER: AtomicUsize = ATOMIC_USIZE_INIT;
@@ -98,7 +98,7 @@
         let mut res = String::new();
         write!(&mut res, "{}", "key1=val1\n").expect("unwrap failed");
         write!(&mut res, "{}", "key2=val2\n").expect("unwrap failed");
-        write!(&mut res, "{}", jvm_from_properties::PROPERTY_NAME).expect("unwrap failed");
+        write!(&mut res, "{}", property_from_file::JRE_PROPERTY_NAME).expect("unwrap failed");
         write!(&mut res, "{}", "=").expect("unwrap failed");
         write!(&mut res, "{}", jre_path).expect("unwrap failed");
         write!(&mut res, "{}", "\n").expect("unwrap failed");