/*
Change environment variables on Windows
Uses envvar.txt for the variables to set
NOTE: Many developers think they need to change the classpath to
make their Java app work on customers' machines. Fortunately,
most JVMs that are freely distributable let you change the
classpath on the command line. You can easily configure your
customer's Java environment with JExpress by changing the
setting on the JVM panel in JExpress Developer.
If you still feel that you need to change the environment
variable CLASSPATH, then you can use this class. Add the
appropriate changes to envvar.txt.
If this class does not perform as expected, please turn on debugging
(i.e., set debugging=true) and use the diagnostic log (env.log).
Also, the variables [$AppDir]/ and [$JvmDir]/ are only implemented for
the CLASSPATH variable -- feel free to modify the code if you want to
use them for other environment variables, too
1. Include your envvar.txt file in the JExpressInstaller subdirectory
2. envvar.txt is a plain text file that you create; its format is:
action name=value
where
action is replace or append
(replace means that if this name already exists, then overwrite it
with value; if the name doesn't already exist, then set it with value)
(append means if name already exists, then append value to the
existing value; if name doesn't already exist, then set it with value)
name is the environment variable to set, and
value is the value to set the environment variable
For example, if you want to append the installation directory to the CLASSPATH,
the line would look like this (without leading spaces):
append CLASSPATH=[$AppDir]/
3. There must be a single blank space separating the action and the name
4. There must be an equal sign separating the variable name from the value
5. Any line that starts with ; is ignored
6. There must be *no* blank lines in the file
7. If you want to reset the environment variable, then the line should look like this:
replace name=
8. If you want to add to the classpath, then use the following command:
replace CLASSPATH=value
where value contains the appropriate information; you can include directories
that are relative to the installation or the Java home directories
when setting CLASSPATH;
use [$AppDir]/ to reference the installation directory
use [$JavaHomeDir]/ to reference the Java home directory
for example, if you want to add a jar file called myapp.jar that is in the
installation directory, then you would use the following line:
replace CLASSPATH=[$AppDir]/myapp.jar
9. The [$AppDir]/ and [$JavaHomeDir]/ only work with the CLASSPATH environment variable.
Of course, you're welcome to change this class so it works with other environment
variables, too.
10. You are welcome to adapt this class to meet your needs as long as you
only use it with the JExpress Professional product.
11. If the class doesn't work as you expected, then you should turn debugging on (i.e.,
change the initial setting of debugging to true) and create a plain text file called
env.log in the same directory where you run the installer.
Copyright (C) 1998-2006 DeNova
*/
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.File;
import java.awt.BorderLayout;
import javax.swing.JLabel;
import com.denova.io.Log;
import com.denova.runtime.WindowsRegistry;
import com.denova.runtime.WindowsUtils;
import com.denova.ui.Fonts;
import com.denova.ui.WizardPanel;
import com.denova.util.PropertyList;
import com.denova.JExpress.Installer.CustomInstaller;
import com.denova.JExpress.Installer.InstallPropertyNames;
public class ChangeEnv extends WizardPanel
implements InstallPropertyNames {
public ChangeEnv (PropertyList properties) {
// initialize WizardPanel superclass
super (properties);
// let them know what's happening
setLayout ( new BorderLayout () );
JLabel notice = new JLabel("Changing environment variables", JLabel.CENTER);
notice.setFont(Fonts.Bold);
add(notice);
}
/**
* Enter the panel.
*
* Do not call this method; only the wizard should call it.
*/
public void enter()
{
// this panel simply changes the environment varialbes
// it looks at the text file envvar.txt for the variables to set
applicationDirectory = getPropertyList (). getProperty ( ApplicationDirectory, "" );
try {
// if we're on Windows, add the environment variable to autoexec.bat
if ( isWindows() ) {
setEnvOnWindows ();
}
}
catch ( Exception e ) {
// if there's no file, then there's nothing to do
debug ( "exception while setting environment variables" );
log ( e );
}
// we don't want any user interaction
// so move them to the next panel automatically
showNextPanel ();
}
// set the environment variables under Windows
public void setEnvOnWindows ()
throws Exception {
// get the envvar file from the JAR
File envVarFile = new File ( envVarFilename );
CustomInstaller. getResourceAsFile ( envVarFile. getPath () );
log ( "extracted " + envVarFile. getPath () );
// open envvar.txt
FileReader fr = new FileReader ( envVarFile );
BufferedReader envVarReader = new BufferedReader ( fr );
log ( "opened envvar.txt for buffered read" );
String line = envVarReader. readLine ();
while ( line != null ) {
// if this isn't a comment line
if ( line. charAt (0) != ';' ) {
log ( "non-comment envvar line is " + line );
// determine where the components of the line end
int endActionIndex = line. indexOf ( " " );
int endVarIndex = line. indexOf ( "=" );
// if the line contained the substrings, then add the variable
if ( endActionIndex != -1 &&
endVarIndex != -1 ) {
String value;
String action = line. substring ( 0, endActionIndex );
String variable = line. substring ( endActionIndex + 1, endVarIndex );
log ( "action is " + action + " variable is " + variable );
if ( line. length() > endVarIndex + 1 ) {
value = line. substring ( endVarIndex + 1 );
log ( "value is " + value );
}
else {
value = "";
log ( "value is blank" );
}
// clear any errors
WindowsUtils. clearError ();
if ( isWindowsNT() ) {
log ( "running on WinNT" );
setWindowsNtEnvVar ( action. trim (),
variable. trim (),
value. trim () );
}
else {
log ( "error after isWindowsNT() call " + WindowsUtils. getLastError() );
log ( "running on Win95/98" );
setWindows95EnvVar ( action. trim (),
variable. trim (),
value. trim () );
}
}
}
else {
log ( "comment envvar line is " + line );
}
Thread. yield ();
// get the next line
line = envVarReader. readLine ();
}
envVarReader. close();
fr. close ();
envVarFile. delete ();
log ( "closed reader and deleted file" );
}
// set a variable in Windows NT environment
public void setWindowsNtEnvVar ( String action,
String variable,
String value )
throws Exception {
boolean ok = false;
String keyName;
// we need to handle classpath specially
value = setClasspathValue ( variable, value );
log ( "after setClasspathValue value is " + value );
if ( action. equalsIgnoreCase ( AppendAction ) ) {
String oldValue;
if ( changeNtSystemWide ) {
// see if the system wide variable exists
keyName = NtSystem + "\\" + NtEnvironment;
log ( "query " + keyName );
oldValue = WindowsRegistry. getData ( keyName, variable );
if ( oldValue != null &&
oldValue. length () > 0 ) {
if ( oldValue. endsWith ( File. pathSeparator ) ) {
value = oldValue + value;
}
else {
value = oldValue + File. pathSeparator + value;
}
log ( " old value for " + variable + " is " + oldValue );
}
else {
log ( " no old value for " + variable );
}
}
// also see if the user's environment variable exists
keyName = NtCurrentUser + "\\" + NtEnvironment;
log ( "query " + keyName );
oldValue = WindowsRegistry. getData ( keyName, variable );
if ( oldValue != null &&
oldValue. length () > 0 ) {
value = oldValue + File. pathSeparator + value;
log ( " old value for " + variable + " is " + oldValue );
}
else {
log ( " no old value for " + variable );
}
}
if ( changeNtSystemWide ) {
// try a system wide change
keyName = NtSystem + "\\" + NtEnvironment;
log ( "replace action for " + keyName );
ok = WindowsRegistry. replaceData ( keyName, variable, value );
log ( "after replaceData ok is " + String. valueOf ( ok ) );
}
// change the user's environment, too
keyName = NtCurrentUser + "\\" + NtEnvironment;
log ( "replace value for " + keyName + "\\" + variable + " to " + value );
ok = WindowsRegistry. replaceData ( keyName, variable, value );
log ( "after replaceData ok = " + String. valueOf ( ok ) );
}
// set a variable in Windows 95/98 environment
public void setWindows95EnvVar ( String action,
String variable,
String value )
throws Exception {
boolean matchFound = false;
File inFile = new File ( WinFilename );
if ( inFile. exists () ) {
matchFound = changeWindows95EnvVar ( action, variable, value );
}
// if the variable didn't exist, then add it to top of the file
if ( ! matchFound ) {
addWindows95EnvVar ( action, variable, value );
}
// make a backup and then copy the file to it's permanent location
com.denova.io.FileSystem. copyFile ( WinFilename, BackupWinFilename );
com.denova.io.FileSystem. copyFile ( TempWinFilename, WinFilename );
// delete our temporary file
File outFile = new File ( TempWinFilename );
outFile. delete ();
}
// if the variable exists, change it
public boolean changeWindows95EnvVar ( String action,
String variable,
String value )
throws Exception {
final String SetLine = "set";
boolean matchFound = false;
File inFile = new File ( WinFilename );
FileReader inputFile = new FileReader ( inFile );
BufferedReader inputReader = new BufferedReader ( inputFile );
File outFile = new File ( TempWinFilename );
FileWriter outputFile = new FileWriter ( outFile );
BufferedWriter outputWriter = new BufferedWriter ( outputFile );
// look for the variable, save all lines in a temporary file
String line = inputReader. readLine ();
while ( line != null ) {
if ( ! matchFound ) {
// if this line sets an environment variable
if ( line. length() > SetLine. length () ) {
String startLine = line. substring ( 0, SetLine. length () );
if ( startLine. equalsIgnoreCase ( SetLine ) ) {
int endIndex = line. indexOf ( "=" );
if ( endIndex != -1 ) {
startLine = line. substring ( SetLine. length () + 1,
endIndex );
// and it's the variable we want to set
if ( startLine. equalsIgnoreCase ( variable ) ) {
matchFound = true;
set95EnvVar ( line,
outputWriter,
action,
variable,
value );
}
}
}
}
if ( ! matchFound ) {
saveLine ( line, outputWriter );
}
}
else {
saveLine ( line, outputWriter );
}
// get the next line
line = inputReader. readLine ();
} // while
inputReader. close ();
inputFile. close ();
outputWriter. close ();
outputFile. close ();
return matchFound;
}
// add a new variable to Windows' environment
public void addWindows95EnvVar ( String action,
String variable,
String value )
throws Exception {
File outFile = new File ( TempWinFilename );
FileWriter outputFile = new FileWriter ( outFile );
BufferedWriter outputWriter = new BufferedWriter ( outputFile );
set95EnvVar ( "",
outputWriter,
action,
variable,
value );
File inFile = new File ( WinFilename );
if ( inFile. exists () ) {
FileReader inputFile = new FileReader ( inFile );
BufferedReader inputReader = new BufferedReader ( inputFile );
String line = inputReader. readLine ();
while ( line != null ) {
// save the line to the new temporary file
saveLine ( line, outputWriter );
// get the next line
line = inputReader. readLine ();
} // while
inputReader. close ();
inputFile. close ();
}
outputWriter. close ();
outputFile. close ();
}
// set the actual variable
public void set95EnvVar ( String line,
BufferedWriter outputWriter,
String action,
String variable,
String value )
{
String newLine;
// we need to handle classpath specially
value = setClasspathValue ( variable, value );
// if action equals replace or there isn't a line
// then use the new setting
if ( action. equalsIgnoreCase ( "replace" ) ||
line. length() <= 0 ) {
newLine = "set " + variable + "=" + value;
try {
saveLine ( newLine, outputWriter );
}
catch ( Exception e ) {
// !!!!! you may want to handle this situation
}
}
else if ( action. equalsIgnoreCase ( "append" ) ) {
if ( isWindows() ) {
newLine = line + File. pathSeparator + value;
}
else {
newLine = line + ":" + value;
}
try {
saveLine ( newLine, outputWriter );
}
catch ( Exception e ) {
// !!!!! you may want to handle this situation
}
}
}
// handle classpath environment variable
public String setClasspathValue ( String variable,
String value )
{
// we need to handle classpath specially
if ( variable. equalsIgnoreCase ( "classpath" ) ) {
final String AppDirVar = "[$AppDir]/";
final String JavaHomeDirVar = "[$JavaHomeDir]/";
String appDir = getPropertyList (). getProperty ( ApplicationDirectory, "" );
String javaHomeDir = System. getProperty ( "java.home" );
log ( "classpath variable is " + variable );
// change all references to [$AppDir] to the actual directory
value = changeDirname ( value, AppDirVar, appDir );
log ( "value after AppDirVar changeDirname is " + value );
// change all references to [$JavaHomeDir] to the actual directory
value = changeDirname ( value, JavaHomeDirVar, javaHomeDir );
log ( "value after JavaHomeDirVar changeDirname is " + value );
// use the correct version of the directory separator
value = value. replace ( '/', File. separatorChar );
log ( "value after File.separatorChar changeDirname is " + value );
// if there are any spaces in the directory names
if ( value. indexOf ( " " ) != -1 ) {
// add quotes so Windows doesn't get confused
value = "\"" + value + "\"";
log ( "value after adding quotes is " + value );
}
}
else {
log ( "non-classpath variable is " + variable );
}
return value;
}
// change the directory variable
public String changeDirname ( String value,
String varDirname,
String fullDirname )
{
String newValue;
String tempValue;
int startIndex, endIndex;
// default to the starting value
newValue = value;
// in value, change all references to varDirname to the fullDirname
startIndex = newValue. indexOf ( varDirname );
if ( startIndex == -1 ) {
log ( varDirname + " is not found in " + newValue );
}
while ( startIndex != -1 ) {
endIndex = startIndex + varDirname. length ();
// save the beginning of the value
if ( startIndex > 0 ) {
tempValue = newValue. substring ( 0, startIndex );
}
else {
tempValue = "";
}
log ( "found " + varDirname + " in " + newValue );
// add the actual application directory
tempValue += fullDirname;
tempValue += "/";
// add the rest of the original value
tempValue += newValue. substring ( endIndex, newValue. length() );
// remember our handy work
newValue = tempValue;
log ( "value after " + varDirname + " replaced is " + newValue );
// see if there are any other AppDir variables we need to change
startIndex = newValue. indexOf ( varDirname );
}
return newValue;
}
// save the line
public void saveLine ( String line,
BufferedWriter outputWriter )
throws Exception {
outputWriter. write ( line );
// add the appropriate line ending for the OS
if ( isWindows() ) {
outputWriter. write ( "\r\n" );
}
else {
outputWriter. write ( '\n' );
}
}
// don't let the user bypass this command before we're done
public boolean isNextButtonEnabled () {
return false;
}
// don't let the user back up before we're done
public boolean isPreviousButtonEnabled () {
return false;
}
void debug ( String s ) {
if ( debugging ) {
log (s);
}
}
static private void log ( String s ) {
startLog ();
envLog. write ( s );
}
static private void log ( Exception e ) {
startLog ();
envLog. write ( e );
}
static private void startLog () {
if ( envLog == null ) {
envLog = new Log ( "env" );
}
}
static private void stopLogging () {
if ( envLog != null ) {
envLog. stopLogging ();
}
}
static Log envLog;
static final boolean debugging = true;
static final boolean changeNtSystemWide = false;
static String applicationDirectory;
// the name of the file with the environment variables
static final String envVarFilename = "envvar.txt";
static final String WinFilename = "c:\\autoexec.bat";
static final String BackupWinFilename = "c:\\autoexec.bak";
static final String TempWinFilename = "autoexec.new";
static final String ReplaceAction = "replace";
static final String AppendAction = "append";
static final String NtSystem = "HKEY_LOCAL_MACHINE\\SYSTEM\\CurrentControlSet\\Control";
static final String NtEnvironment = "Environment";
static final String NtCurrentUser = "HKEY_CURRENT_USER";
} // ChangeEnv