/* * NetBeans.java * * Created on December 15, 2005, 8:48 PM * */ package launch; import java.beans.PropertyChangeListener; import java.beans.PropertyChangeSupport; import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.InputStreamReader; import java.util.ArrayList; import java.util.Collections; import java.util.List; /** * Provides simple access to a locally installed NetBeans IDE. * It's intended to enable one to open a local file, launching * NetBeans if needed. Typical use of this class is: *
* NetBeans nb = new NetBeans();
* nb.initialize();
* if (!nb.isInstalled()) {
* // point the user at the download page
* }
* else {
* File file = new File("C:\MyProject\src\pkg\MyFile.java");
* try {
* nb.openFile(file);
* }
* catch (NetBeans.Failure e) {
* // report the failure
* }
* }
*
*
* @author Hans Muller (Hans.Muller@Sun.COM)
*/
public class NetBeans {
private final PropertyChangeSupport pcs;
private boolean isInitialized = false;
private boolean installed = false;
private String displayName = null;
private File installLocation = null;
private ProcessBuilder openFileCommand = null;
public NetBeans() {
pcs = new PropertyChangeSupport(this);
}
public void addPropertyChangeListener(PropertyChangeListener listener) {
if (listener != null) {
pcs.addPropertyChangeListener(listener);
}
}
public void removePropertyChangeListener(PropertyChangeListener listener) {
if (listener != null) {
pcs.removePropertyChangeListener(listener);
}
}
public PropertyChangeListener[] getPropertyChangeListeners() {
return pcs.getPropertyChangeListeners();
}
private void firePCS(String propertyName, Object oldValue, Object newValue) {
if (!(oldValue != null && newValue != null && oldValue.equals(newValue))) {
pcs.firePropertyChange(propertyName, oldValue, newValue);
}
}
/**
* @return true if an installed copy of NetBeans exists.
* @see initialize
*/
public boolean isInstalled() {
return installed;
}
private void setInstalled(boolean installed) {
boolean oldValue = this.installed;
this.installed = installed;
firePCS("installed", oldValue, this.installed);
}
/**
* @return a String that identifies the (installed) version of NetBeans
* @see initialize
*/
public String getDisplayName() {
return displayName;
}
private void setDisplayName(String displayName) {
String oldValue = this.displayName;
this.displayName = displayName;
firePCS("displayName", oldValue, this.displayName);
}
/**
* @return the Directory where NetBeans is installed
* @see initialize
*/
public File getInstallLocation() {
return installLocation;
}
private void setInstallLocation(File installLocation) {
File oldValue = this.installLocation;
this.installLocation = installLocation;
firePCS("installLocation", oldValue, this.installLocation);
}
/**
* Returns a ProcessBuilder that launches NetBeans with the
* "-open" option. The NetBeans process will pull the name
* of the file to be loaded from an environment variable
* called "NBFILE". For example the Unix version of the
* command for launching NetBeans is:
*
* sh -c './netbeans -open $NBFILE'
*
*
* @return a ProcessBuilder that will launch NetBeans
* @see initialize
* @see openFile
*/
public ProcessBuilder getOpenFileCommand() {
return openFileCommand;
}
private void setOpenFileCommand(ProcessBuilder openFileCommand) {
ProcessBuilder oldValue = this.openFileCommand;
this.openFileCommand = openFileCommand;
firePCS("openFileCommand", oldValue, this.openFileCommand);
}
/**
* Launch a NetBeans subprocess that causes the IDE to load
* the specified file.
*
* @see initialize
* @see getOpenFileCommand
*/
public void openFile(File file) throws Failure {
ProcessBuilder pb = getOpenFileCommand();
pb.environment().put("NBFILE", file.toString());
pb.redirectErrorStream(true);
try {
Process p = pb.start();
BufferedReader stdout = new BufferedReader(new InputStreamReader(p.getInputStream()));
String line;
while ((line = stdout.readLine()) != null) {
// [TBD send output to the GUI]
System.out.println(line);
}
} catch (IOException e) {
throw new Failure(e);
}
}
public static class Failure extends Exception {
public Failure(Exception e) {
super(e);
}
}
/**
* Given a (possibly valid) install directory, initialize
* the installed, displayName, installLocation, and
* openFileCommand properties.
*/
public boolean initializeFrom(String dirName) {
String osName = System.getProperty("os.name", "");
File binDir = new File(dirName, "bin");
if (osName.contains("Windows")) {
if (new File(binDir, "netbeans.exe").exists()) {
setInstalled(true);
setDisplayName("NetBeans"); // could do better
setInstallLocation(new File(dirName));
initializeWindowsOpenFileCommand();
return true;
}
}
else {
if (new File(binDir, "netbeans").exists()) {
setInstalled(true);
setDisplayName("NetBeans"); // could do better
setInstallLocation(new File(dirName));
initializeUnixOpenFileCommand();
return true;
}
}
return false;
}
/**
* Initialize the installed, displayName, installLocation, and
* openFileCommand properties.
*
* Case analysis based on the value of the "os.name" system property.
* There's no definitive guide for possible values however some collections
* exist, e.g.: http://lopica.sourceforge.net/os.html and
* http://tolstoy.com/samizdat/sysprops-windows.html
*/
public boolean initialize() {
String osName = System.getProperty("os.name", "");
if (osName.contains("Windows")) {
return initializeWindows();
}
else if (osName.contains("Mac")) {
return initializeUnix();
}
else {
return initializeUnix();
}
}
private void initializeUnixOpenFileCommand() {
File dir = getInstallLocation();
ProcessBuilder ofc = new ProcessBuilder("sh", "-c","'./netbeans -open $NBFILE'");
ofc.directory(new File(dir, "bin"));
setOpenFileCommand(ofc);
}
/* Hack: assume user has "[install-location]/bin/netbeans in their
* unix PATH and the Bourne shell (sh) and the which command
* are available and do what's expected.
*/
private boolean initializeUnixTry() throws IOException {
ProcessBuilder pb = new ProcessBuilder("which", "netbeans");
pb.redirectErrorStream(true);
Process p = pb.start();
BufferedReader stdout = new BufferedReader(new InputStreamReader(p.getInputStream()));
String nbPathName = stdout.readLine();
p.destroy();
if ((nbPathName != null) && (nbPathName.endsWith("/netbeans"))) {
File nbPath = new File(nbPathName);
String nbLocationName = nbPath.getParent();
if (nbLocationName.contains("netbeans")) {
File nbLocation = new File(nbLocationName);
setInstalled(true);
setDisplayName(nbLocation.getName());
setInstallLocation(nbLocation);
initializeUnixOpenFileCommand();
return true;
}
}
return false;
}
private boolean initializeUnix() {
try {
return initializeWindowsTry();
} catch (IOException e) {}
return false;
}
/* Create the ProcessBuilder for a Windows NetBeans command.
*
* This is a bit tricky to do. If the full pathname is used
* instead of just "netbeans.exe", the command shell gets
* hopelessly confused about spaces in pathnames. Quoting the
* entire "C:\[...]\bin\netbeans.exe" command doesn't help.
* Inserting the quote after the drive indicator, like
* C:\"[...]\bin\netbeans.exe" does work but that's a
* pain. Setting the working directory to "C:\[...]\bin" avoids
* the problem and hopefully there's no reason to care what the
* working directory actually is on Windows.
*/
private void initializeWindowsOpenFileCommand() {
File dir = getInstallLocation();
ProcessBuilder ofc = new ProcessBuilder("cmd", "/c", "netbeans.exe", "-open", "\"%NBFILE%\"");
ofc.directory(new File(dir, "bin"));
setOpenFileCommand(ofc);
}
/* getRegValue("DisplayName REG_SZ NetBeans IDE 5.0 Beta 2") =>
* "NetBeans IDE 5.0 Beta 2".
*/
private String windowsRegValue(String line) {
int i = line.indexOf("REG_SZ");
if (i != -1) {
return line.substring(i + "REG_SZ".length()).trim();
} else {
return null;
}
}
/*
* Find the NetBeans directories on Windows by looking for
* the "Uninstall" registry entries left behind by the standard installer.
* We use this query to dump all of the uninstall entries,
* and then extract the ones whose DisplayName contains "NetBeans".
* Windows command is:
* reg query hklm\Software\Microsoft\Windows\CurrentVersion\Uninstall /s
*
* The NetBeans uninstall records look like this (there's a blank
* line between records):
*
* HKEY_LOCAL_MACHINE\Software\Microsoft\Windows\CurrentVersion\Uninstall\274c5407c4fa26908310cb5c1c[...]
* DisplayName REG_SZ NetBeans IDE 5.0 Beta 2
* DisplayIcon REG_SZ C:\Program Files\netbeans-5.0beta2\bin\netbeans.exe
* InstallLocation REG_SZ C:\Program Files\netbeans-5.0beta2
*
* The 6 characters that follow the 26 character ID, noted "[...]"
* above, are the NetBeans version number. For example:
* 410000 - version 4.1
* 5000b2 - version 5.0 beta2
*
*/
private boolean initializeWindowsTry() throws IOException {
/* Start a subprocess to execute the "reg query" command
*/
String regPath = "hklm\\Software\\Microsoft\\Windows\\CurrentVersion\\Uninstall";
ProcessBuilder pb = new ProcessBuilder("reg", "query", regPath, "/s");
pb.redirectErrorStream(true);
Process p = pb.start();
BufferedReader stdout = new BufferedReader(new InputStreamReader(p.getInputStream()));
/* Create a nbRegEntry for each NetBeans entry
*/
final String nbid = "274c5407c4fa26908310cb5c1c";
String line;
NBRegEntry nbRegEntry = null;
List