public class AssociationService {
private String m_ApplicationID;
private String m_ApplicationName;
private String m_Description;
private Class m_MainClass;
private Class m_ResourceClass;
private String m_ApplicationDir;
private Iterable m_Associations;
private boolean m_Install;
private boolean m_SystemInstall;
private String m_RootPassword = null;
private String m_SudoStr = null;
private String m_XDGModeStr = null;
private Shell m_Shell = new Shell();
private String quotedQuote(String str) {
return "\\\"" + str + "\\\"";
}
private String quote(String str) {
return "\"" + str + "\"";
}
private String getCodeBase() {
String cp = System.getProperty("java.class.path");
int i = cp.indexOf(File.pathSeparator);
return new File(cp.substring(0, i < 0 ? cp.length() : i)).getAbsolutePath();
}
private String getAppDir(String codeBase) {
int i = codeBase.lastIndexOf(File.separator);
return codeBase.substring(0, i < 0 ? codeBase.length() : i);
}
private String getGnomeDir() {
String gnomeDir = System.getenv("GNOMEDIR");
if (m_SystemInstall) {
if (gnomeDir != null)
gnomeDir += "/share";
else
gnomeDir = "/usr/share/gnome";
} else
gnomeDir = System.getProperty("user.home") + "/.gnome";
return gnomeDir;
}
private boolean sudo(String cmd, boolean fail) throws Exception {
m_Shell.sudoExecute(cmd, null, m_RootPassword);
if (fail && m_Shell.getExitCode() != 0)
throw new Exception("sudo failure, exit code " + m_Shell.getExitCode() + ", command line: " + m_Shell.getCommand());
return m_Shell.getExitCode() == 0;
}
/**
* Copies a resorce to a file.
* A non essential but nonetheless usefull, hence public, helper function that copies a named resource from the given class to
* the given file.
* @param clss
* @param resource
* @param toFile
* @throws IOException
*/
static public void copyResourceToFile(Class clss, String resource, File toFile) throws IOException {
InputStream input = clss.getResourceAsStream(resource);
if (input == null)
throw new IllegalArgumentException("Could not get resource " + resource + " from class " + clss.getName());
else {
OutputStream output = null;
IOException ioe = null;
try {
output = new FileOutputStream(toFile);
byte b[] = new byte[10 * 1024];
int n;
while ((n = input.read(b)) > 0)
output.write(b, 0, n);
} catch (IOException e) {
ioe = e;
} finally {
if (input != null)
try {
input.close();
} catch (IOException e) {
ioe = e;
}
if (output != null)
try {
output.close();
} catch (IOException e) {
ioe = e;
}
if (ioe != null)
throw ioe;
}
}
}
void installDotXML() throws Exception {
String home = System.getProperty("user.home");
File dotXMLFile = new File(m_ApplicationDir + File.separator + m_ApplicationID + ".xml");
PrintStream out = new PrintStream(new FileOutputStream(dotXMLFile));
out.println("");
out.println(" ");
for (Association type : m_Associations) {
if (type.getMimeType() == null)
continue;
out.println(" ");
out.println(" " + type.getDescription() + " ");
String frgmnt = type.getMagicPattern();
if (frgmnt != null) {
out.println(frgmnt);
}
out.println(" ");
out.println(" ");
}
out.println(" ");
out.close();
if (m_Install)
XDGUtils.execute(m_Shell, m_SudoStr, "xdg-mime " + "install " + "--mode " + m_XDGModeStr + "--novendor " + dotXMLFile.getAbsolutePath(), m_RootPassword);
else
XDGUtils.execute(m_Shell, m_SudoStr, "xdg-mime " + "uninstall " + "--mode " + m_XDGModeStr + dotXMLFile.getAbsolutePath(), m_RootPassword);
}
private String getLinuxLaunchCmd() {
String command;
String codeBase = getCodeBase();
if (codeBase.endsWith(".jar"))
command = "java -jar " + quote(codeBase);
else
command = "java -cp " + quote(System.getProperty("java.class.path")) + " " + m_MainClass.getCanonicalName();
return command + " %F";
}
private String getMimeTypesString() {
String mimeTypes = "";
for (Association type : m_Associations) {
if (type.getMimeType() == null)
continue;
if (mimeTypes.length()>0)
mimeTypes = mimeTypes+";"+type.getMimeType();
else
mimeTypes = type.getMimeType();
}
return mimeTypes;
}
private String installDotDesktop() throws Exception {
String command = getLinuxLaunchCmd();
String iconName = m_ApplicationID + "-app" + ".png";
File iconFile = new File(m_ApplicationDir + "/" + iconName);
copyResourceToFile(m_ResourceClass, iconName, iconFile);
File dotDesktopFile = new File(m_ApplicationDir + File.separator + m_ApplicationID + ".desktop");
PrintStream out = new PrintStream(new FileOutputStream(dotDesktopFile));
out.println("[Desktop Entry]");
out.println(" Version=1.0");
out.println(" Type=Application");
out.println(" Name=" + m_ApplicationName);
out.println(" Comment=" + m_Description);
out.println(" Exec=" + command);
out.println(" Icon=" + iconFile.getAbsolutePath());
out.println(" MimeType=" + getMimeTypesString());
out.close();
if (m_Install) {
XDGUtils.execute(m_Shell, m_SudoStr, "xdg-desktop-menu " + "install " + "--novendor " + dotDesktopFile.getAbsolutePath(), m_RootPassword);
XDGUtils.execute(m_Shell, m_SudoStr, "xdg-desktop-icon " + "install " + "--novendor " + dotDesktopFile.getAbsolutePath(), m_RootPassword);
}
else {
XDGUtils.execute(m_Shell, m_SudoStr, "xdg-desktop-menu " + "uninstall " + dotDesktopFile.getAbsolutePath(), m_RootPassword);
XDGUtils.execute(m_Shell, m_SudoStr, "xdg-desktop-icon " + "uninstall " + dotDesktopFile.getAbsolutePath(), m_RootPassword);
}
return command;
}
private void installMimeIcons() throws Exception {
for (Association type : m_Associations) {
if (type.getMimeType() != null) {
String iconSourceName = m_ApplicationID + "-doc-" + type.getExtension().substring(1) + ".png";
File mimeIconFile = new File(m_ApplicationDir + File.separator + iconSourceName);
copyResourceToFile(m_ResourceClass, iconSourceName, mimeIconFile);
String iconName = type.getMimeType().replace("/", "-");
ImageIcon icon = new ImageIcon(m_ResourceClass.getResource(iconSourceName));
String iconSize = Integer.toString(icon.getIconWidth()) + " ";
if (m_Install)
XDGUtils.execute(m_Shell, m_SudoStr, "xdg-icon-resource " + "install " + "--novendor --context mimetypes --size " + iconSize + mimeIconFile.getAbsolutePath() + " " + iconName, m_RootPassword);
else // following does not work unfortunately
XDGUtils.execute(m_Shell, m_SudoStr, "xdg-icon-resource " + "uninstall " + "--context mimetypes --size " + iconSize + mimeIconFile.getAbsolutePath() + " " + iconName, m_RootPassword);
}
}
}
private void installDotMimeFile(String gnomeDir) throws Exception {
File temp = getTempFile();
PrintStream out = new PrintStream(new FileOutputStream(temp));
for (Association type : m_Associations) {
out.println(type.getMimeType());
out.print("\t" + "ext:");
if (type.getExtension() != null)
out.print(" " + type.getExtension().substring(1));
}
out.println();
out.close();
File file = new File(gnomeDir + "/mime-info/" + m_ApplicationID + ".mime");
installTempFile(temp, file);
}
private File getTempFile() {
return new File(m_ApplicationDir + "/temporary-installation-file");
}
private void installTempFile(File tempFile, File installTo) throws Exception {
sudo("cp " + tempFile.getAbsolutePath() + " " + installTo.getAbsolutePath(), true);
sudo("rm " + tempFile.getAbsolutePath(), true);
}
private File installGnomeIcon(String gnomeDir) throws Exception {
String iconName = m_ApplicationID + "-app" + ".png";
File temp = getTempFile();
File iconFile = new File(gnomeDir + "/pixmaps/" + iconName);
copyResourceToFile(m_ResourceClass, iconName, temp);
installTempFile(temp, iconFile);
return iconFile;
}
private void installDotKeysFile(String gnomeDir) throws Exception {
File iconFile = installGnomeIcon(gnomeDir);
File temp = getTempFile();
PrintStream out = new PrintStream(new FileOutputStream(temp));
for (Association type : m_Associations) {
if (type.getMimeType() != null) {
out.println(type.getMimeType());
out.println("\t" + "description=" + m_Description);
out.println("\t" + "icon_filename=" + iconFile.getAbsolutePath());
out.println("\t" + "default_action_type=application");
out.println("\t" + "default_application_id=" + m_ApplicationID);
out.println("\t" + "short_list_application_user_additions=" + m_ApplicationID);
out.println();
}
}
out.close();
File file = new File(gnomeDir + "/mime-info/" + m_ApplicationID + ".keys");
installTempFile(temp, file);
}
private void installDotApplicationsFile(String gnomeDir) throws Exception {
String command = getLinuxLaunchCmd();
File tempFile = getTempFile();
PrintStream out = new PrintStream(new FileOutputStream(tempFile));
out.println(m_ApplicationID);
out.println("\t" + "command=" + command);
out.println("\t" + "name=" + m_ApplicationName);
out.println("\t" + "can_open_multiple_files=false");
out.println("\t" + "mime_types=" + getMimeTypesString());
out.println();
out.close();
File file = new File(gnomeDir + "/application-info/" + m_ApplicationID + ".applications");
installTempFile(tempFile, file);
}
private boolean checkGnome(String gnomeDir) {
File f;
f = new File(gnomeDir + "/application-registry");
if (!f.exists()) {
System.out.println("missing: " + f.getAbsolutePath());
return false;
}
f = new File(gnomeDir + "/application-info");
if (!f.exists()) {
System.out.println("missing: " + f.getAbsolutePath());
return false;
}
f = new File(gnomeDir + "/mime-info");
if (!f.exists()) {
System.out.println("missing: " + f.getAbsolutePath());
return false;
}
f = new File(gnomeDir + "/pixmaps");
if (!f.exists()) {
System.out.println("missing: " + f.getAbsolutePath());
return false;
}
return true;
}
void linuxInstall() throws Exception {
try {
System.out.println("linux install...");
m_XDGModeStr = m_SystemInstall ? "system " : "user ";
m_SudoStr = m_RootPassword != null ? "sudo -S " : "";
installDotDesktop();
installDotXML();
installMimeIcons();
String gnomeDir = getGnomeDir();
if (checkGnome(gnomeDir)) {
installDotMimeFile(gnomeDir);
installDotKeysFile(gnomeDir);
installDotApplicationsFile(gnomeDir);
} else
System.out.println("gnome (old style) installation not performed");
} finally {
// kill user time stamp, no matter what happens
if (m_RootPassword != null)
sudo("-K", true);
}
}
private void windowsInstall() throws Exception {
String codeBase = getCodeBase();
String appDir = m_ApplicationDir;
String appRegKey = m_ApplicationID;
for (Association type : m_Associations) {
String fileRegKey = appRegKey + "-doc-" + type.getExtension().substring(1);
String iconName = fileRegKey + ".ico";
String iconPath = appDir + File.separator + iconName;
if (m_Install) {
copyResourceToFile(m_ResourceClass, iconName, new File(iconPath));
m_Shell.execute("REG ADD HKCR\\" + type.getExtension() + " /f /v \"\" /t REG_SZ /d " + fileRegKey, null);
m_Shell.execute("REG ADD HKCR\\" + fileRegKey + " /f /v \"\" /t REG_SZ /d " + quote(type.getDescription()), null);
m_Shell.execute("REG ADD HKCR\\" + fileRegKey + "\\DefaultIcon /f /v \"\" /t REG_SZ /d " + quote(iconPath), null);
String cmd = "";
if (codeBase.endsWith(".exe"))
cmd = quotedQuote(codeBase);
else if (codeBase.endsWith(".jar"))
cmd = "java -jar " + quotedQuote(codeBase);
else
cmd = "java -cp " + quotedQuote(System.getProperty("java.class.path")) + " " + m_MainClass.getCanonicalName();
m_Shell.execute("REG ADD HKCR\\" + fileRegKey + "\\shell\\open\\command /f /v \"\" /t REG_SZ /d \"" + cmd + " " + quotedQuote("%1"), null);
}
else {
m_Shell.execute("REG DELETE HKCR\\" + fileRegKey , null);
m_Shell.execute("REG DELETE HKCR\\" + type.getExtension(), null);
}
}
}
private void assertNotNull(String argName, Object arg) {
if (arg == null)
throw new IllegalArgumentException("Argument '" + argName + "' must not be null.");
}
/**
* Registers/unregister the application and file associations with the platforms Desktop.
* Registers/unregisters the associations with the platforms Desktop Manager (Gnome/KDE/Finder/Explorer) so that
* both the application and the documents have the correct appearance (icon) and can be launched/opened
* by double clicking at the icon on the Desktop.
* the application lauched b
* @param install weather to install or uninstall
* @param systemInstall install into system or for the user (Linux only)
* @param password the root (admin) password for 'sudo'ing the regisration (Linux only)
* @param mainClass the mainClass of the application
* @param resourceClass the class that contains the resources (icons)
* @param applicationID the internal name for the application (used as key in regisration)
* @param applicationName the user name for the application
* @param description the user description of the application
* @param applicationDir the directory used to store registration related files, needs to be writable
* @param associations list of associations to register
* @throws Exception if something goes wrong
*/
public void register(//
boolean install,//
boolean systemInstall,//
String password,//
Class mainClass,//
Class resourceClass,//
String applicationID,//
String applicationName,//
String description, //
String applicationDir,//
Iterable associations//
) throws Exception {
assertNotNull("mainClass", mainClass);
assertNotNull("resourceClass", resourceClass);
assertNotNull("applicationID", applicationID);
assertNotNull("applicationName", applicationName);
assertNotNull("description", description);
assertNotNull("associations", associations);
assertNotNull("applicationDir", applicationDir);
if (!(new File(applicationDir)).exists())
throw new IllegalArgumentException("Argument applicationDir='" + applicationDir + "' which doens not exist.");
if (associations.iterator().hasNext() == false)
throw new IllegalArgumentException("Argument 'associations' cannot be empty.");
m_Install = install;
m_SystemInstall = systemInstall;
m_RootPassword = password;
m_MainClass = mainClass;
m_ResourceClass = resourceClass;
m_ApplicationID = applicationID;
m_ApplicationName = applicationName;
m_Description = description;
m_Associations = associations;
m_ApplicationDir = applicationDir;
String osname = System.getProperty("os.name").toLowerCase();
if (osname.indexOf("window") >= 0)
windowsInstall();
if (osname.indexOf("linux") >= 0)
linuxInstall();
}
}