Im currently working on a java program and I need to read/write to the registry. i've looked at several API's to do this and I found ini4j (ini4j Project Page). I also need to edit ini files so I like this solution because it does both. I'm curious if anybody has tried ini4j in this type of scenario?
I found a better solution for reading/writing to the registry without the need for ini4j or passing arguments to the command line. I use JNA quite a lot in my program so I figured that it would be easier to use native library calls instead of including an additional library to do this for me. Here is an example from my project were I search through the registry looking for a specific key. The specific key is also dependent on whether or not the OS is x64 or x86.
public static String GetUninstallerPath() {
try {
//if (logger.IsInfoEnabled) logger.Info("GetUninstallerPath - begin");
String uninstallerPath = null;
try {
String vncDisplayName = "UltraVNC";
String subkey32 = "Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall";
String subkey64 = "Software\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall";
boolean is64Bit = Platform.is64Bit();
String[] key;
if (is64Bit) {
key = Advapi32Util.registryGetKeys(WinReg.HKEY_LOCAL_MACHINE,
subkey64);
} else {
key = Advapi32Util.registryGetKeys(WinReg.HKEY_LOCAL_MACHINE,
subkey32);
}
if (key != null) {
for (String nextSubkeyName : key) {
TreeMap<String, Object> subKey = Advapi32Util.registryGetValues(
WinReg.HKEY_LOCAL_MACHINE,
subkey64 + "\\" + nextSubkeyName);
Object value = subKey.get("DisplayName");
Object path = null;
if (value != null) {
if (value.toString().startsWith(vncDisplayName)) {
path = subKey.get("UninstallString");
if (path != null) {
uninstallerPath = path.toString().trim();
}
}
}
}
}
}
catch (Exception ex) {
System.err.println(ex.getMessage());
}
return uninstallerPath;
}
}
I use objects to initially store the key values because I kept getting NullPointerExceptions. Feel free to provide another solution.
Unfortunately your test for 64 bits using Platform.is64Bit() doesn't do what you think it does...
It tells you if your JVM is 32 bits or 64 bits, not if your Windows is 32 bits or 64 bits...
The only reason why your code seems to work as intended is because the Windows registry redirector takes care of the "magic" involved (accessing the right registry key) for you...
When your code runs on a 32 bits JVM on a 64 bits Windows Platform.is64Bit() returns false and you are using subkey32 (ie "Software\Microsoft\Windows\CurrentVersion\Uninstall").
I unfortunately did the same mistake as you and released a program with the same erroneous test after readings threads such as yours which is why I am now posting this even though this thread is several years old.
Related
I want my program to be able to detect whether OBS-Studio is currently running, and if it is, perform certain functionality in my program. The problem is I can't seem to find a solution that will work on both platforms. I've found things that use taskList, wmic.exe and others on windows, and I've found things using top, ps aux and others on linux, however these are very platform specific, and not easily ported. Is there a universal use case, and if so, what might it be?
I'm aware of ProcessHandle in Java9+, however my program runs Java8, with no current hope of upgrading, so that's not possible.
I Cannot think of a solution that will work on both platforms,
maybe use something like below to determine the operating system in Java then from there, use a conditional statement to execute the portion of the code appropriate for your host machine.
os = System.getProperty("os.name");
I hope this helps
I ended up creating a method that would return a Map<Integer, String> for all processes by running os-specific commands:
public Map<Integer, String> getProcesses() {
final Map<Integer, String> processes = Maps.newHashMap();
final boolean windows = System.getProperty("os.name").contains("Windows");
try {
final Process process = Runtime.getRuntime().exec(windows ? "tasklist /fo csv /nh" : "ps -e");
try (final BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
reader.lines().skip(1).forEach(x -> { // the first line is usually just a line to explain the format
if (windows) {
// "name","id","type","priority","memory?"
final String[] split = x.replace("\"", "").split(",");
processes.put(Integer.valueOf(split[1]), split[0]);
}
else {
// id tty time command
final String[] split = Arrays.stream(x.trim().split(" ")).map(String::trim)
.filter(s -> !s.isEmpty()).toArray(String[]::new); // yikes
processes.put(Integer.valueOf(split[0]), split[split.length - 1]);
}
});
}
}
catch (IOException e) {
e.printStackTrace();
}
return processes;
}
This hasn't been tested on Windows, but it should work. It also hasn't been tested on literally anything else other than Linux, but I hope this serves as a helpful method for others to work off of.
I am new to registrykeyexists(root,key) method of Advapi32util which checks whether registry key "key"(key that is passed to registrykeyexists) is present in windows registry under the root.
Root that i am passing is "HKEY_LOCAL_MACHINE".
Key is something that looks like "SOFTWARE\ABC\ABC DB"
And I see that this key is present in window's registry. ( by running "regedit" via cmd)
Below is the code snippet which does this work.
public static String getRegistryData(WinReg.HKEY root, String key, String value) {
System.out.println("Registry key exists status:" + Advapi32Util.registryKeyExists(root, key));
if (Advapi32Util.registryKeyExists(root, key)) {
String retVal = Advapi32Util.registryGetStringValue(root, key, value);
return retVal;
} else {
return null;
}
}
So,here when I debug, Advapi32Util.registryKeyExists(root, key) returns false.
Can anyone help me on this?? I would be grateful !!
Thanks In Advance.
I know it is some months old, but I had the same question as you.. And I hope this answer can help more people.
This can be a bit confusing, but the namings for these items work like this:
The Keys would be like the Path, and the Values would be each value inside a Key. After understanding it, it should be easier to do the coding. The method Advapi32Util.registryKeyExists looks for Keys (in other words, paths), so it won't help you.
If you want to verify if the value Counter exists in the key HKEY_LOCAL_MACHINE\SOFTWARE\Microsoft\Windows NT\CurrentVersion\Perflib\009 for example, you should use this method:
boolean keyExists = Advapi32Util.registryValueExists(WinReg.HKEY_LOCAL_MACHINE, "SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion\\Perflib\\009", "Counter");
In your case, your method would be:
public static String getRegistryData(WinReg.HKEY root, String key, String value) {
System.out.println("Registry key exists status:" + Advapi32Util.registryValueExists(root, key, value));
if (Advapi32Util.registryValueExists(root, key, value)) {
String retVal = Advapi32Util.registryGetStringValue(root, key, value);
return retVal;
} else {
return null;
}
}
You can take a look in their GitHub project if you are curious in how they implemented it: Advapi32Util - JNA GitHub Project
Late answer, but I guess it applies to what you witnessed there.
Since version 5, JNA added a parameter into their registry navigation methods that allow to switch from 32 to 64 registry "realms"
Look at that excellent answer from #CamW
https://stackoverflow.com/a/57051855/2143734
I have requirement of updating hashmap. In Spark job I have JavaPairRDD and in this wrapper is having 9 different hashmap. Each hashmap is having key near about 40-50 cr keys. While merging two maps (ReduceByKey in spark) I am getting Java heap memory OutOfMemory exception. Below is the code snippet.
private HashMap<String, Long> getMergedMapNew(HashMap<String, Long> oldMap,
HashMap<String, Long> newMap) {
for (Entry<String, Long> entry : newMap.entrySet()) {
try {
String imei = entry.getKey();
Long oldTimeStamp = oldMap.get(imei);
Long newTimeStamp = entry.getValue();
if (oldTimeStamp != null && newTimeStamp != null) {
if (oldTimeStamp < newTimeStamp) {
oldMap.put(imei, newTimeStamp);
} else {
oldMap.put(imei, oldTimeStamp);
}
} else if (oldTimeStamp == null) {
oldMap.put(imei, newTimeStamp);
} else if (newTimeStamp == null) {
oldMap.put(imei, oldTimeStamp);
}
} catch (Exception e) {
logger.error("{}", Utils.getStackTrace(e));
}
}
return oldMap;
}
This method works on small dataset but failed with large dataset. Same method is being used for all 9 different hashmap. I searched for increasing heap memory but no idea how to increase this in spark as it works on cluster. My cluster size is also large (nr. 300 nodes). Please help me to find out some solutions.
Thanks.
Firstly I'd focus on 3 parameters: spark.driver.memory=45g spark.executor.memory=6g spark.dirver.maxResultSize=8g Don't take the config for granted, this is something that works on my set up without OOM errors. Check how much available memory you have in UI. You want to give executors as much memory as you can. btw. spark.driver.memory enables more heap space.
As far as i can see, this code is executed on the spark driver. I would recommend to convert those two Hashmaps to DataFrames with 2 columns imei and timestamp. Then join both using an outer join on imei and select the appropriate timestamps using when.
This code will be executed on the workers, be parallized and consequentially you wont run into the memory problems. If you plan on really doing this on the driver then follow the instructions given by Jarek and increase spark.driver.memory.
The Java tutorials recommend using the Preferences API over Properties files.
Properties files and ResourceBundles are the recommended way to handle Internalization requirements in applications.
I am considering using both for a desktop application that will display preferences in a locale specific way.
Can anyone point out problems with this approach?
Maybe I should just use Properties files period?
I am considering using both for a desktop application that will display preferences in a locale specific way.
OK, so what you want is translated configuration file in form of:
some_translated_key=some_value
Well, unless you want to support MUI at some point it should not be a big deal. However, if you do, so that different users on the same computer could use different languages, or user might be able to switch language, you would have troubles in matching key to a property. You would have to scan all translations while reading the key, and you would surely end up with multiple entries for the same key. How to resolve that? Well, that's a good question.
From my experience, configuration files should be language-independent (neutral culture) and should never be edited by hand (that is translating keys doesn't really matter).
I thought there could be a problem with character encoding, but following code snippet works without an issue (files are UTF-8 encoded):
public class Main {
private static final String FILE_NAME = "i18ned.properties";
private File propertiesFile;
private Properties properties;
public Main() {
properties = new Properties();
propertiesFile = new File(FILE_NAME);
if (propertiesFile.exists()) {
try {
properties.load(new BufferedReader(new FileReader(
propertiesFile)));
} catch (FileNotFoundException e) {
// not likely, but should be logged either way
} catch (IOException e) {
// logger should be used instead
e.printStackTrace();
}
}
}
public void saveProperties() {
try {
properties
.store(new BufferedWriter(new FileWriter(propertiesFile)), "");
} catch (IOException e) {
// oops, use logger instead
e.printStackTrace();
}
}
public static void main(String[] args) {
Main main = new Main();
main.storeSome();
main.readSome();
}
private void readSome() {
String highAsciiKey = "żółć";
String value = properties.getProperty(highAsciiKey);
System.out.println(value);
}
private void storeSome() {
String highAsciiKey = "żółć";
String highAsciiValue = "łąkę";
properties.setProperty(highAsciiKey, highAsciiValue);
saveProperties();
}
}
Using resource bundle for localizing applications is the standard way in java. The problems of this way are:
there is no compile time check of number and type of parameters required by resource.
It is hard to hold files clean, e.g. there is no mechanism the helps to remove unused strings
It is hard to make all texts translated to all supported languages.
etc....
The probably better internationalization mechanism is suggested by Google in their GWT. They generate class with method per string.
For example if you have text Hello, {0} they will generate method
String hello(String name);
So, you cannot pass neither 0 nor 2 arguments to this method. Only one.
This partially solves the second problem also. It is easier to see if method is not used in whole project. It does not solve the 3rd problem anyway.
how to list files and directories in current directory without using java.io.*?
This is actually possible without having to write any JNI or make any Runtime calls.
import java.net.URL;
import sun.net.www.content.text.PlainTextInputStream;
public class NoIO {
public static void main(String args[]) {
NoIO n = new NoIO();
n.doT();
}
public void doT() {
try {
//Create a URL from the user.dir (run directory)
//Prefix with the protocol file:/
//Users java.net
URL u = new URL("file:/"+System.getProperty("user.dir"));
//Get the contents of the URL (this basically prints out the directory
//list. Uses sun.net.www.content.text
PlainTextInputStream in = (PlainTextInputStream)u.getContent();
//Iterate over the InputStream and print it out.
int c;
while ((c = in.read()) != -1) {
System.out.print((char) c);
}
} catch(Exception e) {
e.printStackTrace();
}
}
}
It's amazing what a little thought and boredom will do (and an inability to jump to hasty conclusions (where there's a will, there's a way)).
You could probably also do it using the ClassLoader, by overriding it, at some point Java has to iterate over all the files in the classpath, by hooking at that point you can print out all the files that it tries to load without using any kind of java.io.*.
After some investigation I don't think this is possible very easily, certainly not for a homework assignment unless it's some kind of RE'ing assignment or Forensics assignment.
You can use Runtime.getRuntime().exec():
String[] cmdarray;
if (System.getProperty("os.name").startsWith("Windows")) {
cmdarray = new String[] { "cmd.exe", "/c", "dir /b" };
} else { // for UNIX-like systems
cmdarray = new String[] { "ls" };
}
Runtime.getRuntime().exec(cmdarray);
Thanks to #Geo for the Windows commands.
You could use JNA to make native calls to the underlying OS.
As an exercise in hard work it might be a worth while.
Another option is writing OS specific code in C and accessing it via JNI. But once again. Why do you want this?