Java Web Start deploy on Windows startup - java

I have a Java application that I'm about to begin to use Web Start to deploy. But a new demand has made me rethink this, as I'm now required to add a piece of functionality that allows the end user to select whether or not they'd like to run this program on startup (of Windows, not cross-platform). But I'd still like to shy away from making this run as a service. Is there any way that this can be accomplished using Web Start, or should I explore other options to deploy this? Thanks in advance.

It actually works to put a this in the jnlp-file:
<shortcut online="true">
<desktop/>
<menu submenu="Startup"/>
</shortcut>
But that still would only work with English windows versions. German is "Autostart", Spanish was "Iniciar" I think. So it causes basically the same headache as the way via the IntegrationService.

I have not tried it, but I wonder if you could use the new JNLP IntegrationService in combination with the javaws command line program. The idea being to programmatically create a shortcut in the Windows startup group (although that location is dependent on specific Windows version).

To get around the language problem for the Startup folder just use the registry. Here is some code that should work. This calls reg.exe to make registry changes.
public class StartupCreator {
public static void setupStartupOnWindows(String jnlpUrl, String applicationName) throws Exception {
String foundJavaWsPath = findJavaWsOnWindows();
String cmd = foundJavaWsPath + " -Xnosplash \"" + jnlpUrl + "\"";
setRegKey("HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\Run", applicationName, cmd);
}
public static String findJavaWsOnWindows() {
// The paths where it will look for java
String[] paths = {
// first use the JRE that was used to launch this app, it will probably not reach the below paths
System.getProperty("java.home") + File.separator + "bin" + File.separator + "javaws.exe",
// it must check for the 64 bit path first because inside a 32-bit process system32 is actually syswow64
// 64 bit machine with 32 bit JRE
System.getenv("SYSTEMROOT") + File.separator + "syswow64" + File.separator + "javaws.exe",
// 32 bit machine with 32 bit JRE or 64 bit machine with 64 bit JRE
System.getenv("SYSTEMROOT") + File.separator + "system32" + File.separator + "javaws.exe",};
return findJavaWsInPaths(paths);
}
public static String findJavaWsInPaths(String[] paths) throws RuntimeException {
String foundJavaWsPath = null;
for (String p : paths) {
File f = new File(p);
if (f.exists()) {
foundJavaWsPath = p;
break;
}
}
if (foundJavaWsPath == null) {
throw new RuntimeException("Could not find path for javaws executable");
}
return foundJavaWsPath;
}
public static String setRegKey(String location, String regKey, String regValue) throws Exception {
String regCommand = "add \"" + location + "\" /v \"" + regKey + "\" /f /d \"" + regValue + "\"";
return doReg(regCommand);
}
public static String doReg(String regCommand) throws Exception {
final String REG_UTIL = "reg";
final String regUtilCmd = REG_UTIL + " " + regCommand;
return runProcess(regUtilCmd);
}
public static String runProcess(final String regUtilCmd) throws Exception {
StringWriter sw = new StringWriter();
Process process = Runtime.getRuntime().exec(regUtilCmd);
InputStream is = process.getInputStream();
int c = 0;
while ((c = is.read()) != -1) {
sw.write(c);
}
String result = sw.toString();
try {
process.waitFor();
} catch (Throwable ex) {
System.out.println(ex.getMessage());
}
if (process.exitValue() == -1) {
throw new Exception("REG QUERY command returned with exit code -1");
}
return result;
}
}

Related

Reboot javafx App

I'm trying to make a function that reboot the javafx application, On windows 10 works perfectly but on Windows 7 it doesn't, I search for this solution and it was perfect, then I test it on Windows 10 and nothing, the app just turn off. Also I test it watching for an exception inside the log file and it doesn't throw any Exception.
Something specific must be made in order to work also on windows 7? maybe a different approach? Thanks.
this is the code:
//Restart app the current Java application, with parameter you can pass a Runnable to do before restart app, null if not
public static void restartApplication(Runnable runBeforeRestart) throws IOException {
try {
/**
* Sun property pointing the main class and its arguments.
* Might not be defined on non Hotspot VM implementations.
*/
final String SUN_JAVA_COMMAND = "sun.java.command";
// java binary
String java = System.getProperty("java.home") + "/bin/java";
// vm arguments
List<String> vmArguments = ManagementFactory.getRuntimeMXBean().getInputArguments();
StringBuffer vmArgsOneLine = new StringBuffer();
for (String arg : vmArguments) {
// if it's the agent argument : we ignore it otherwise the
// address of the old application and the new one will be in conflict
if (!arg.contains("-agentlib")) {
vmArgsOneLine.append(arg);
vmArgsOneLine.append(" ");
}
}
// init the command to execute, add the vm args
final StringBuffer cmd = new StringBuffer("\"" + java + "\" " + vmArgsOneLine);
// program main and program arguments
String[] mainCommand = System.getProperty(SUN_JAVA_COMMAND).split(" ");
// program main is a jar
if (mainCommand[0].endsWith(".jar")) {
// if it's a jar, add -jar mainJar
cmd.append("-jar " + new File(mainCommand[0]).getPath());
} else {
// else it's a .class, add the classpath and mainClass
cmd.append("-cp \"" + System.getProperty("java.class.path") + "\" " + mainCommand[0]);
}
// finally add program arguments
for (int i = 1; i < mainCommand.length; i++) {
cmd.append(" ");
cmd.append(mainCommand[i]);
}
// execute the command in a shutdown hook, to be sure that all the
// resources have been disposed before restarting the application
Runtime.getRuntime().addShutdownHook(new Thread() {
#Override
public void run() {
try {
Runtime.getRuntime().exec(cmd.toString());
} catch (IOException e) {
logToFile.log(e, "info", "The application fail to restart, applying the command");
}
}
});
// execute some custom code before restarting
if (runBeforeRestart!= null) {
runBeforeRestart.run();
}
// Wait for 2 seconds before restart
//TimeUnit.SECONDS.sleep(2);
// exit
System.exit(0);
} catch (Exception e) {
// something went wrong
logToFile.log(e, "info", "The application fail to restart generally");
}
}
Update: Searching for other approach I found out a solution, It's test it on both Windows OS and works
here it's the code:
//Restart app the current Java application, with parameter you can pass a Runnable to do before restart app, null if not
public static void restartApplication(Runnable runBeforeRestart, Integer TimeToWaitToExecuteTask) throws IOException {
try {
// execute some custom code before restarting
if (runBeforeRestart != null) {
// Wait for 2 seconds before restart if null
if (TimeToWaitToExecuteTask != null) {
TimeUnit.SECONDS.sleep(TimeToWaitToExecuteTask);
} else {
TimeUnit.SECONDS.sleep(2);
}
runBeforeRestart.run();
}
final String javaBin = System.getProperty("java.home") + File.separator + "bin" + File.separator + "java";
final File currentJar = new File(Main.class.getProtectionDomain().getCodeSource().getLocation().toURI());
/* is it a jar file? */
if (!currentJar.getName().endsWith(".jar"))
return;
/* Build command: java -jar application.jar */
final ArrayList<String> command = new ArrayList<String>();
command.add(javaBin);
command.add("-jar");
command.add(currentJar.getPath());
final ProcessBuilder builder = new ProcessBuilder(command);
builder.start();
System.exit(0);
} catch (Exception e) {
// something went wrong
logToFile.log(e, "info", "The application fail to restart generally");
}
}

Process is not terminating Properly in java (Runtime)

I am executing CSharp Program with java Process by creating the .exe file but the process of that file is not responding with 0 exitCode.Errors are Empty.In Visual Studio it runs fine but with java, it creates problem.No output and no Errors, I am stuck in this Please help. I am using Java 7.
I am using Csc (inbuild compiler in .Net framework for windows) It is giving me dll reference error.Command is following
csc /nologo /r:D:/simulatorConfig/ArrayConversion.dll /out:D:\\apache-tomcat-7.0.64\\temp\\tmp749792186557790590.exe D:\\apache-tomcat-7.0.64\\temp\\tmp749792186557790590.cs
stream = new BufferedReader(new InputStreamReader(proc.getErrorStream()));
above is Error which is empty String.
code is here Please look at it.
public File compile(File sourceFile, LANGUAGE lang) throws InterruptedException, IOException, CompilerException, ConfigurationException {
String absolutePath = sourceFile.getCanonicalPath();
// System.out.println("absolutePath : " + absolutePath);
String destFile;
if (OsUtils.isWindows()) {
destFile = absolutePath.replace(lang.getFileExtension(), EXECUTABLE_FILE_SUFFIX);
} else {
destFile = absolutePath.replace(lang.getFileExtension(), "");
}
String compileCommand = generateCommand(absolutePath, destFile, lang);
logger.error("compileCommand : " + compileCommand);
// Compiles and create exe file for execution
Process proc = Runtime.getRuntime().exec(compileCommand);
// Wait for process to complete
int returnValue = proc.waitFor();
if (returnValue != 0) {
String errorMsg = getCompilerMessage(sourceFile, proc, lang);
throw new CompilerException(errorMsg);
}
proc.destroy();
return new File(destFile);
}
private String getCompilerMessage(File sourceFile, Process proc, LANGUAGE lang) throws IOException {
StringBuilder message = new StringBuilder();
BufferedReader stream = null;
String line = null;
switch (lang) {
case C:
case CPP:
// GNU C/CPP compiler prints compiler errors in standard errors
// tream
stream = new BufferedReader(new InputStreamReader(proc.getErrorStream()));
break;
case CSHARP:
// CSharp compiler prints compiler errors in standard output stream
stream = new BufferedReader(new InputStreamReader(proc.getErrorStream()));
break;
}
while ((line = stream.readLine()) != null) {
logger.error(line);
line = line.substring(line.indexOf(sourceFile.getName()) + (int) sourceFile.getName().length());
if (message.toString().isEmpty()) {
message.append(lang == LANGUAGE.CSHARP ? "Line" : "").append(line);
} else {
message.append("<br/>Line").append(line);
}
// message.append(line).append(SystemUtils.LINE_SEPARATOR);
}
stream.close();
return message.toString();
}
private String generateCommand(String sourceFile, String destFile, LANGUAGE lang) throws ConfigurationException {
// System.out.println("sourceFile : " + sourceFile + " -- destFile : " +
// destFile);
Configuration config = new PropertiesConfiguration("system.properties");
String cmd = "";
switch (lang) {
case C:
case CPP:
sourceFile = sourceFile.replace("\\", "\\\\");
destFile = destFile.replace("\\", "\\\\");
cmd = "g++ " + sourceFile + " -o " + destFile + " " + config.getString("C_CPP_HEADERFILE").trim();
break;
case CSHARP:
sourceFile = sourceFile.replace("\\", "\\\\");
destFile = destFile.replace("\\", "\\\\");
logger.error("Config Path : "+config.getString("MONO_PATH"));
if (OsUtils.isWindows()) {
cmd = "csc /nologo /r:" + config.getString("CS_HEADERFILE_WIN") + " /out:" + destFile + " " + sourceFile;
} else {
cmd = "/opt/mono/bin/mcs /reference:" + config.getString("CS_HEADERFILE") + " /out:" + destFile + " "
+ sourceFile;
}
break;
}
logger.info("Command :" + cmd);
return cmd;
}
When launching a command using Runtime#exec, you MUST consume the error and std streams in every case (not only when the return code is != 0), or else the internal buffers could/will get full and the subprocess will wait indefinitely until somebody consumes them.
The common symptom of this problem is an process that never return, making the whole seems to be deadlocked.
There are several ways to correct this, one the easiest is described here: https://docs.oracle.com/javase/7/docs/api/java/lang/ProcessBuilder.html#redirect-input.
Additionally, there seems to be an issue here:
// CSharp compiler prints compiler errors in standard output stream
stream = new BufferedReader(new InputStreamReader(proc.getErrorStream()));
break;
In the comment, you tell the compiler does output errors on stdout, but you are consuming the error stream.
There was .dll linking error in when I tried to do the same in command prompt with Demo files.By keeping .dll file and .exe file in the same directory it solved my purpose program was running Flawlessly with proper exit code (0).
So kept other .dll file in this path D:\apache-tomcat-7.0.64\temp\. and is fine.
The thumb rule says .dll and .exe should be in the same directoryeory

How to get short-filenames in Windows using Java?

How to get the short-filename for a long-filename in Windows using Java?
I need to determine the short-filenames of files, stored on a Windows system, using Java(tm).
Self Answer
There are related questions with related answers. I post this solution, however, because it uses Java(tm) code without the need for external libraries. Additional solutions for different versions of Java and/or Microsoft(R) Windows(tm) are welcome.
Main Concept
Main concept lies in calling CMD from Java(tm) by means of the runtime class:
cmd /c for %I in ("[long file name]") do #echo %~fsI
Solution
Tested on Java SE 7 running on Windows 7 system
(Code has been reduced for brevity).
public static String getMSDOSName(String fileName)
throws IOException, InterruptedException {
String path = getAbsolutePath(fileName);
// changed "+ fileName.toUpperCase() +" to "path"
Process process =
Runtime.getRuntime().exec(
"cmd /c for %I in (\"" + path + "\") do #echo %~fsI");
process.waitFor();
byte[] data = new byte[65536];
int size = process.getInputStream().read(data);
if (size <= 0)
return null;
return new String(data, 0, size).replaceAll("\\r\\n", "");
}
public static String getAbsolutePath(String fileName)
throws IOException {
File file = new File(fileName);
String path = file.getAbsolutePath();
if (file.exists() == false)
file = new File(path);
path = file.getCanonicalPath();
if (file.isDirectory() && (path.endsWith(File.separator) == false))
path += File.separator;
return path;
}
I found a slight problem Osmund's solution. It doesn't work properly for this file name for some reason:
N:\directoryY\tmp\temp\asdfasdf sdf dsfasdf [dfadss]\[asdfas] asdfasd asd asdfasdf ~fdfsdfdfdsfdfdfdfdfd~ TTTm7-9 [RR 1234a5678 A.888 OKOK]a
I'm not really sure why exactly. But if you run the command a slightly different way (using ProcessBuilder), it works. Here is the new code (I am using BufferedReader to read the output, it is much cleaner).
public static String getMSDOSName(String path) throws IOException, InterruptedException {
Process process = new ProcessBuilder().command("cmd", "/c", "for %I in (\"" + path + "\") do #echo %~fsI").start();
process.waitFor();
try (BufferedReader br = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
return br.readLine();
}
}
This is the output of the original solution vs my solution. The original solution fails to shorten the last path element:
N:\DIRECT~1\tmp\temp\ASDFAS~1\[asdfas] asdfasd asd asdfasdf ~fdfsdfdfdsfdfdfdfdfd~ TTTm7-9 [RR 1234a5678 A.888 OKOK]a
N:\DIRECT~1\tmp\temp\ASDFAS~1\_ASDFA~1.888

Issues with running Runtime.getRuntime().exec

I'm using process = Runtime.getRuntime().exec(cmd,null,new File(path));
to execute some SQL in file (abz.sql)
Command is:
"sqlplus "+ context.getDatabaseUser() + "/"
+ context.getDatabasePassword() + "#"
+ context.getDatabaseHost() + ":"
+ context.getDatabasePort() + "/"
+ context.getSid() + " #"
+ "\""
+ script + "\"";
String path=context.getReleasePath()+ "/Server/DB Scripts";
It is executing that file but not getting exit. Hence I tried using:
Writer out = new OutputStreamWriter(process.getOutputStream());
out.append("commit;\r\n");
out.append("exit \r\n");
System.out.println("---------"+out);
out.close();
This it complete block that I m using:
if(context.getConnectionField()=="ORACLE")
{
String cmd=
"sqlplus "+ context.getDatabaseUser() + "/"
+ context.getDatabasePassword() + "#"
+ context.getDatabaseHost() + ":"
+ context.getDatabasePort() + "/"
+ context.getSid() + " #"
+ "\""
+ script +"\"";
String path=context.getReleasePath()+ "/Server/DB Scripts";
process = Runtime.getRuntime().exec(cmd,null,new File(path));
out = new OutputStreamWriter(process.getOutputStream());
out.append("commit;\r\n");
out.append("exit \r\n");
System.out.println("---------"+out);
out.close();
Integer result1 = null;
while (result1 == null) {
try {
result1 = process.waitFor();
}
catch (InterruptedException e) {}
}
if(process.exitValue() != 0)
return false;
return true;
}
The code shown fails to read the error stream of the Process. That might be blocking progress. ProcessBuilder was introduced in Java 1.5 and has a handy method to redirectErrorStream() - so that it is only necessary to consume a single stream.
For more general tips, read & implement all the recommendations of When Runtime.exec() won't.
I can see a few issues here. The version of 'exec' that you are using will tokenize the command string using StringTokenizer, so unusual characters in the password (like spaces) or the other parameters being substituted are accidents waiting to happen. I recommend switching to the version
Process exec(String[] cmdarray,
String[] envp,
File dir)
throws IOException
It is a bit more work to use but much more robust.
The second issue that there are all kinds of caveat about whether or not exec will run concurrently with the Java process (see http://download.oracle.com/javase/1.4.2/docs/api/java/lang/Process.html). So you need to say which operating system you're on. If it does not run concurrently then your strategy of writing to the output stream cannot work!
The last bit of the program is written rather obscurely. I suggest ...
for (;;) {
try {
process.waitFor();
return process.exitValue() == 0;
} catch ( InterruptedException _ ) {
System.out.println( "INTERRUPTED!" ); // Debug only.
}
}
This eliminates the superfluous variable result1, eliminates the superfluous boxing and highlights a possible cause of endless looping.
Hope this helps & good luck!

How to get the Desktop path in java

I think this will work only on an English language Windows installation:
System.getProperty("user.home") + "/Desktop";
How can I make this work for non English Windows?
I use a french version of Windows and with it the instruction:
System.getProperty("user.home") + "/Desktop";
works fine for me.
I think this is the same question... but I'm not sure!:
In java under Windows, how do I find a redirected Desktop folder?
Reading it I would expect that solution to return the user.home, but apparently not, and the link in the answer comments back that up. Haven't tried it myself.
I guess by using JFileChooser the solution will require a non-headless JVM, but you are probably running one of them.
This is for Windows only. Launch REG.EXE and capture its output :
import java.io.*;
public class WindowsUtils {
private static final String REGQUERY_UTIL = "reg query ";
private static final String REGSTR_TOKEN = "REG_SZ";
private static final String DESKTOP_FOLDER_CMD = REGQUERY_UTIL
+ "\"HKCU\\Software\\Microsoft\\Windows\\CurrentVersion\\"
+ "Explorer\\Shell Folders\" /v DESKTOP";
private WindowsUtils() {}
public static String getCurrentUserDesktopPath() {
try {
Process process = Runtime.getRuntime().exec(DESKTOP_FOLDER_CMD);
StreamReader reader = new StreamReader(process.getInputStream());
reader.start();
process.waitFor();
reader.join();
String result = reader.getResult();
int p = result.indexOf(REGSTR_TOKEN);
if (p == -1) return null;
return result.substring(p + REGSTR_TOKEN.length()).trim();
}
catch (Exception e) {
return null;
}
}
/**
* TEST
*/
public static void main(String[] args) {
System.out.println("Desktop directory : "
+ getCurrentUserDesktopPath());
}
static class StreamReader extends Thread {
private InputStream is;
private StringWriter sw;
StreamReader(InputStream is) {
this.is = is;
sw = new StringWriter();
}
public void run() {
try {
int c;
while ((c = is.read()) != -1)
sw.write(c);
}
catch (IOException e) { ; }
}
String getResult() {
return sw.toString();
}
}
}
or you can use JNA (complete example here)
Shell32.INSTANCE.SHGetFolderPath(null,
ShlObj.CSIDL_DESKTOPDIRECTORY, null, ShlObj.SHGFP_TYPE_CURRENT,
pszPath);
javax.swing.filechooser.FileSystemView.getFileSystemView().getHomeDirectory()
Seems not that easy...
But you could try to find an anwser browsing the code of some open-source projects, e.g. on Koders. I guess all the solutions boil down to checking the HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Explorer\Shell Folders\Desktop path in the Windows registry. And probably are Windows-specific.
If you need a more general solution I would try to find an open-source application you know is working properly on different platforms and puts some icons on the user's Desktop.
You're just missing "C:\\Users\\":
String userDefPath = "C:\\Users\\" + System.getProperty("user.name") + "\\Desktop";
public class Sample {
public static void main(String[] args) {
String desktopPath =System.getProperty("user.home") + "\\"+"Desktop";
String s = "\"" + desktopPath.replace("\\","\\\\") + "\\\\" +"satis" + "\"";
System.out.print(s);
File f = new File(s);
boolean mkdir = f.mkdir();
System.out.println(mkdir);
}
}
there are 2 things.
you are using the wrong slash. for windows it's \ not /.
i'm using RandomAccesFile and File to manage fles and folders, and it requires double slash ( \\ ) to separate the folders name.
Simplest solution is to find out machine name, since this name is only variable changing in path to Desktop folder. So if you can find this, you have found path to Desktop. Following code should do the trick - it did for me :)
String machine_name = InetAddress.getLocalHost().getHostName();
String path_to_desktop = "C:/Documents and Settings/"+machine_name+"/Desktop/";

Categories