Compatibility with user-provided user.home

I don’t know it for sure, but I believe there is a bug in Java that results in Java system property “user.home” to be lost in processes launched from a Java program using ProcessBuilder. All other system properties carry on successfully.

If the user.home property would carry on to new processes as expected user could run Vassal using for example, PortableApps JavaPortableLauncher, thus Vassal settings would be come portable and you could carry Vassal and your favorite games on an USB stick.

The scenario is as follows: you provide a custom home directory via -Duser.home=xxx parameter (this is what JavaPortableLauncher does) to java.exe and it will work in the launched application, but will be reset to default directory if that application will launch another java application via ProcessBuilder (.start();). I have also experience that providing the same -D parameter to ProcessBuilder will result in a failure to launch the app (don’t know why).

The workaround for this is to set an environment variable in the ProcessBuilder object that will point to the provided user.home, because you can only set environment variables and not system properties using that class.

Example code:

//reading user home, with priority to the environment variable if set String user_home = System.getenv("VASSAL_USER_HOME"); if (user_home == null) { user_home = p.getProperty("user.home"); } //launching a process and providing the home ProcessBuilder pb = new ProcessBuilder(...); pb.environment().put("VASSAL_USER_HOME", user_home); ... pb.start();

Thus spake “morvael”:

Could you write a test case for me demonstrating the problem?

If this really happens, then (1) it should be reported to Sun as a bug,
and (2) I know a simple work-around (I think).


J.


Messages mailing list
Messages@forums.vassalengine.org
forums.vassalengine.org/mailman/ … engine.org

Post generated using Mail2Forum (mail2forum.com)

I have posted a simple workaround but if I remember correctly your Mail2Forum software doesn’t send parts of posts that are in the “code” section, so here is a repeat for you:

//reading user home, with priority to the environment variable if set
String user_home = System.getenv(“VASSAL_USER_HOME”);
if (user_home == null) {
user_home = p.getProperty(“user.home”);
}
//launching a process and providing the home
ProcessBuilder pb = new ProcessBuilder(…);
pb.environment().put(“VASSAL_USER_HOME”, user_home);

pb.start();

I will try to prepare a test case and post it here, I have never posted about bugs at Sun’s site.

Thus spake “morvael”:

No, I saw the code you posted before—what I meant was that I have a
workaround in mind for the particular place in AbstractLaunchAction
from which we launch the Player and Editor.

I’m happy to report the bug to Sun myself, so long as I have a test case
which demonstrates the problem.


J.


Messages mailing list
Messages@forums.vassalengine.org
forums.vassalengine.org/mailman/ … engine.org

Post generated using Mail2Forum (mail2forum.com)

I’m already filing the bug report, it looks it isn’t that hard.

That would actually be two bug reports because there is also issue with -D not working if there is a space in user.home, double quotes work in command line but not for ProcessBuilder.

I will post the links to bugs here.

The bugs got numbers (internal review ID) #1694942 and #1694943 but are not yet publicly visible.

I have attached a file to this post with source code and compiled class and a bat file that will create the files that you may then compare.

I have tried the code to be simple so I did assume the platform is Windows.

From my description of the first bug actual results:

Thus spake “morvael”:

I’m not able to reproduce the bug myself:

Parent.java:

import java.io.InputStream;
import java.io.IOException;

public class Parent {

public static void main(String[] args) throws IOException {

final ProcessBuilder pb = new ProcessBuilder(
“java”, “-Duser.home=foobar”, “Child”
);

final Process p = pb.start();
final InputStream in = p.getInputStream();

final byte[] buf = new byte[1024];
int len;
while ((len = in.read(buf)) != -1) System.out.write(buf, 0, len);
}
}

Child.java:

public class Child {
public static void main(String[] args) {
System.out.println("user.home = " + System.getProperty(“user.home”));
}
}

[juckelma@plataan pb]$ java Parent
user.home = foobar

This is the expected result for the test.


J.


Messages mailing list
Messages@forums.vassalengine.org
forums.vassalengine.org/mailman/ … engine.org

Post generated using Mail2Forum (mail2forum.com)

You have did the part that works, but you have to consider a different scenario to get to the bug.

Provide -Duser.home to the first app that you launch from command line (that’s what JavaPortableLauncher does, it also provided custom java.home to it’s portable copy of JRE). You would then expect that if you use ProcessBuilder it will copy all system properties from your instance of java to the child, but it will only copy part of them - java.home will be copied while user.home will not.

The first workaround is what you just did, forcibly specify current user.home to child via -Duser.home used as argument to ProcessBuilder but that will work only if the path doesn’t contain space (double quotes won’t help you).

The second workaround is to use environment variables, which works.

But both ways are workarounds, in that ProcessBuilder documentation promises to carry over all system properties to child app but it does not.

Thus spake “morvael”:

I disagree. I don’t expect system properties to be automatically passed on
to JVMs started as child processes. ProcessBuilder can be used to start any
process, not just another JVM. While the environment variables for the
parent process are copied to the child process, system properties are not
environment variables. In order for a child process which happens to be a
JVM to get system properties from the parent process, they need to be
specified using the -D flag.

So, I think this part is not a bug.

I disagree again. If you change “foobar” to “foobar baz” in my test case,
it still works.

Can you point out where in the javadoc it says this? I don’t find that.


J.


Messages mailing list
Messages@forums.vassalengine.org
forums.vassalengine.org/mailman/ … engine.org

Post generated using Mail2Forum (mail2forum.com)

Have you run my test case?

Thus spake Joel Uckelman:

More specifically: I think this is not a bug in ProcessBuilder. It is
a bug in VASSAL that we don’t pass on user.dir to subprocesses. I’ll
fix that ASAP.

Are there any other system properties we need to pass on? Should we
pass them all on?


J.


Messages mailing list
Messages@forums.vassalengine.org
forums.vassalengine.org/mailman/ … engine.org

Post generated using Mail2Forum (mail2forum.com)

Ok, looks like you have to provide path with spaces inside in quotes while running from windows command line, but without quotes when specifying a parameter to process builder (?!). I also wonder why java.library.path is then modified between parent and child ProcessBuilder, while it should remain the same if PB is not touching system properties.

If you don’t consider not copying system properties a bug, then we are back to Vassal and that it should specify -Duser.home in it’s launchers so it would be compatible with PortableApps and work from USB stick (or any other cases where users might wish to provide different home path). That would be a Feature Request then.

Thus spake “morvael”:

Yes, ProcessBuilder isn’t a shell, so doesn’t require shell quoting.

I don’t see how it could be a bug. In order to copy system properties
reliably, ProcessBuilder would have to somehow know that what it’s
starting is another JVM. How could it know that? E.g., what if it’s
running a custom JVM called ‘foo’? There’s no way to detect this
reliably, which is why I suppose Sun left it up to the API user to
handle.

Thanks for finding the problem. It will be fixed for 3.1.14.


J.


Messages mailing list
Messages@forums.vassalengine.org
forums.vassalengine.org/mailman/ … engine.org

Post generated using Mail2Forum (mail2forum.com)

It’s all in native ProcessImpl.create method, one would have to look in java native sources to see why it alters some system properties but not others.

I believe user.home is sufficient, how many other system variables do you use, you have to check that and may wish to also copy them. However user.home is the crucial one because that’s where Vassal looks for it’s files about registered modules, user preferences and so on.

Thus spake “morvael”:

Try the 3.1.14-svn6380 build:

nomic.net/~uckelman/tmp/vassal/

Does this solve the problem?


J.


Messages mailing list
Messages@forums.vassalengine.org
forums.vassalengine.org/mailman/ … engine.org

Post generated using Mail2Forum (mail2forum.com)

The Module Manager is launched directly from JavaPortableLauncher by opening VEngine.jar (that’s the only way it’s possible), I wonder what are the params given to it.

Then I select the module to open and the newly launched java process is created with params that look ok, but no game shows and the java process just works in background (to be seen in Task Manager).

The command line from errorLog:
E:\dominik\portable\PortableApps\CommonFiles\Java\bin\java -Xms256M -Xmx512M -DVASSAL.id=1 -Duser.home=E:\dominik\portable\PortableApps\JavaPortableLauncher\Data\AppData -cp X:\Downloads\vl\lib\Vengine.jar VASSAL.launch.Player

The java used is correct one from PortableApps, user.home too. Maybe the class path is missing something?

Thus spake “morvael”:

The only thing you need on the classpath is Vengine.jar. If the classpath
were wrong, you’d be getting an exception right away.

Can you attach to the Player’s JVM with a debugger so you can see what
it’s doing?

J.


Messages mailing list
Messages@forums.vassalengine.org
forums.vassalengine.org/mailman/ … engine.org

Post generated using Mail2Forum (mail2forum.com)

What’s the easiest method to do it? I have Eclipse without Vassal project and Netbeans with Vassal project.

Thus spake “morvael”:

That’s a good question. I doubt that you’ll be able to do it with Eclipse
or Netbeans, because you said that it happens only when launching from
JavaPortableLauncher.

I think you could modify AbstractLaunchAction to start the Player or Editor
with ‘jdb’ instead of ‘java’, or pass it the ‘-agentlib’ argument with
the right flags so that you could attach with jdb once it’s running. (See
the man page for jdb for examples.) If you need help with that, let me know.


J.


Messages mailing list
Messages@forums.vassalengine.org
forums.vassalengine.org/mailman/ … engine.org

Post generated using Mail2Forum (mail2forum.com)

I think it would be possible to find out what are the parameters used by JPL to launch jars, maybe then those parameters could be provided in the IDE to launch debug?

As JPL is open source and the source is always included I have been able to find out what it does once the jar is selected:

System::Call 'Kernel32::SetEnvironmentVariableA(t, t) i("JAVAHOME", "$PortableAppsPath\CommonFiles\Java").r0' System::Call 'Kernel32::SetEnvironmentVariableA(t, t) i("CLASSPATH", ".").r0' CreateDirectory "$EXEDIR\Data" CreateDirectory "$EXEDIR\Data\AppData" System::Call 'Kernel32::SetEnvironmentVariableA(t, t) i("APPDATA", "$EXEDIR\Data\AppData").r0' SetOutPath $0 Exec `"$PortableAppsPath\CommonFiles\Java\bin\javaw.exe" -Duser.home="$EXEDIR\Data\AppData" -jar "$JarPath"`

I guess this “code” is easily readable. Three environment variables are set pointing to portable data directories and the launch is a standard launch with just -Duser.home provided.

This can be replicated in the IDE I think.