/* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at * trunk/opends/resource/legal-notices/OpenDS.LICENSE * or https://OpenDS.dev.java.net/OpenDS.LICENSE. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at * trunk/opends/resource/legal-notices/OpenDS.LICENSE. If applicable, * add the following below this CDDL HEADER, with the fields enclosed * by brackets "[]" replaced with your own identifying * information: * Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * * Portions Copyright 2006 Sun Microsystems, Inc. */ package org.opends.quicksetup.util; import java.awt.Component; import java.awt.Dimension; import java.awt.Toolkit; import java.awt.Window; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.FileWriter; import java.io.IOException; import java.io.InputStream; import java.io.PrintWriter; import java.io.RandomAccessFile; import java.net.ConnectException; import java.net.InetSocketAddress; import java.net.ServerSocket; import java.util.ArrayList; import java.util.Hashtable; import javax.naming.CommunicationException; import javax.naming.Context; import javax.naming.NamingException; import javax.naming.ldap.InitialLdapContext; import javax.naming.ldap.LdapName; import org.opends.quicksetup.i18n.ResourceProvider; import org.opends.quicksetup.installer.webstart.JnlpProperties; /** * This class provides some static convenience methods of different nature. * */ public class Utils { private static final int BUFFER_SIZE = 1024; private Utils() { } /** * Center the component location based on its preferred size. The code * considers the particular case of 2 screens and puts the component on the * center of the left screen * * @param comp the component to be centered. */ public static void centerOnScreen(Component comp) { Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize(); int width = (int) comp.getPreferredSize().getWidth(); int height = (int) comp.getPreferredSize().getHeight(); boolean multipleScreen = screenSize.width / screenSize.height >= 2; if (multipleScreen) { comp.setLocation((screenSize.width / 4) - (width / 2), (screenSize.height - height) / 2); } else { comp.setLocation((screenSize.width - width) / 2, (screenSize.height - height) / 2); } } /** * Center the component location of the ref component. * * @param comp the component to be centered. * @param ref the component to be used as reference. * */ public static void centerOnComponent(Window comp, Component ref) { comp.setLocationRelativeTo(ref); } /** * Returns true if the provided port is free and we can use it, * false otherwise. * @param port the port we are analyzing. * @return true if the provided port is free and we can use it, * false otherwise. */ public static boolean canUseAsPort(int port) { boolean canUseAsPort = false; ServerSocket serverSocket = null; try { InetSocketAddress socketAddress = new InetSocketAddress(port); serverSocket = new ServerSocket(); if (!isWindows()) { serverSocket.setReuseAddress(true); } serverSocket.bind(socketAddress); canUseAsPort = true; } catch (IOException ex) { canUseAsPort = false; } finally { try { if (serverSocket != null) { serverSocket.close(); } } catch (Exception ex) { } } return canUseAsPort; } /** * Returns true if the provided port is a priviledged port, * false otherwise. * @param port the port we are analyzing. * @return true if the provided port is a priviledged port, * false otherwise. */ public static boolean isPriviledgedPort(int port) { return (port <= 1024) && !isWindows(); } /** * Returns the absolute path for the given parentPath and relativePath. * @param parentPath the parent path. * @param relativePath the relative path. * @return the absolute path for the given parentPath and relativePath. */ public static String getPath(String parentPath, String relativePath) { File f = new File(new File(parentPath), relativePath); return f.toString(); } /** * Returns true if we are running under windows and * false otherwise. * @return true if we are running under windows and * false otherwise. */ public static boolean isWindows() { return containsOsProperty("windows"); } /** * Returns true if we are running under Mac OS and * false otherwise. * @return true if we are running under Mac OS and * false otherwise. */ public static boolean isMacOS() { return containsOsProperty("Mac OS"); } /** * Returns true if we are running under Unix and * false otherwise. * @return true if we are running under Unix and * false otherwise. */ public static boolean isUnix() { return !isWindows(); } /** * Returns true if the parent directory for the provided path * exists and false otherwise. * @param path the path that we are analyzing. * @return true if the parent directory for the provided path * exists and false otherwise. */ public static boolean parentDirectoryExists(String path) { boolean parentExists = false; File f = new File(path); if (f != null) { File parentFile = f.getParentFile(); if (parentFile != null) { parentExists = parentFile.isDirectory(); } } return parentExists; } /** * Returns true if the the provided path is a file and exists and * false otherwise. * @param path the path that we are analyzing. * @return true if the the provided path is a file and exists and * false otherwise. */ public static boolean fileExists(String path) { boolean isFile = false; File f = new File(path); if (f != null) { isFile = f.isFile(); } return isFile; } /** * Returns true if the the provided path is a directory, exists * and is not empty false otherwise. * @param path the path that we are analyzing. * @return true if the the provided path is a directory, exists * and is not empty false otherwise. */ public static boolean directoryExistsAndIsNotEmpty(String path) { boolean directoryExistsAndIsNotEmpty = false; boolean isDirectory = false; File f = new File(path); if (f != null) { isDirectory = f.isDirectory(); } if (isDirectory) { String[] ch = f.list(); directoryExistsAndIsNotEmpty = (ch != null) && (ch.length > 0); } return directoryExistsAndIsNotEmpty; } /** * Returns true if the the provided string is a DN and * false otherwise. * @param dn the String we are analyzing. * @return true if the the provided string is a DN and * false otherwise. */ public static boolean isDn(String dn) { boolean isDn = true; try { new LdapName(dn); } catch (Exception ex) { isDn = false; } return isDn; } /** * Returns true if the the provided string is a configuration DN * and false otherwise. * @param dn the String we are analyzing. * @return true if the the provided string is a configuration DN * and false otherwise. */ public static boolean isConfigurationDn(String dn) { boolean isConfigurationDn = false; String[] configDns = { "cn=config", "cn=schema" }; for (int i = 0; i < configDns.length && !isConfigurationDn; i++) { isConfigurationDn = areDnsEqual(dn, configDns[i]); } return isConfigurationDn; } /** * Returns true if the the provided strings represent the same * DN and false otherwise. * @param dn1 the first dn to compare. * @param dn2 the second dn to compare. * @return true if the the provided strings represent the same * DN and false otherwise. */ public static boolean areDnsEqual(String dn1, String dn2) { boolean areDnsEqual = false; try { LdapName name1 = new LdapName(dn1); LdapName name2 = new LdapName(dn2); areDnsEqual = name1.equals(name2); } catch (Exception ex) { } return areDnsEqual; } /** * Creates the parent path for the provided path. * @param path the path. * @return true if the parent path was created or already existed * and false otherwise. */ public static boolean createParentPath(String path) { boolean parentPathExists = true; if (!parentDirectoryExists(path)) { File f = new File(path); if (f != null) { File parentFile = f.getParentFile(); parentPathExists = parentFile.mkdirs(); } } return parentPathExists; } /** * Returns true if we can write on the provided path and * false otherwise. * @param path the path. * @return true if we can write on the provided path and * false otherwise. */ public static boolean canWrite(String path) { boolean canWrite; File file = new File(path); if (file.exists()) { canWrite = file.canWrite(); } else { File parentFile = file.getParentFile(); if (parentFile != null) { canWrite = parentFile.canWrite(); } else { canWrite = false; } } return canWrite; } /** * Creates the a directory in the provided path. * @param path the path. * @return true if the path was created or already existed (and * was a directory) and false otherwise. * @throws IOException if something goes wrong. */ public static boolean createDirectory(String path) throws IOException { boolean directoryCreated; File f = new File(path); if (!f.exists()) { directoryCreated = f.mkdirs(); } else { directoryCreated = f.isDirectory(); } return directoryCreated; } /** * Creates a file on the specified path with the contents of the provided * stream. * @param path the path where the file will be created. * @param is the InputStream with the contents of the file. * @throws IOException if something goes wrong. */ public static void createFile(String path, InputStream is) throws IOException { FileOutputStream out; BufferedOutputStream dest; byte[] data = new byte[BUFFER_SIZE]; int count; out = new FileOutputStream(path); dest = new BufferedOutputStream(out); while ((count = is.read(data, 0, BUFFER_SIZE)) != -1) { dest.write(data, 0, count); } dest.flush(); dest.close(); } /** * Creates a file on the specified path with the contents of the provided * String. * @param path the path where the file will be created. * @param content the String with the contents of the file. * @throws IOException if something goes wrong. */ public static void createFile(String path, String content) throws IOException { FileWriter file = new FileWriter(path); PrintWriter out = new PrintWriter(file); out.println(content); out.flush(); out.close(); } /** * Returns the default server location that will be proposed to the user * in the installation. * @return the default server location that will be proposed to the user * in the installation. */ public static String getDefaultServerLocation() { String userDir = System.getProperty("user.home"); String firstLocation = userDir + File.separator + org.opends.server.util.DynamicConstants.COMPACT_VERSION_STRING; String serverLocation = firstLocation; int i = 1; while (fileExists(serverLocation) || directoryExistsAndIsNotEmpty(serverLocation)) { serverLocation = firstLocation + "-" + i; i++; } return serverLocation; } /** * Returns true if there is more disk space in the provided path * than what is specified with the bytes parameter. * @param directoryPath the path. * @param bytes the disk space. * @return true if there is more disk space in the provided path * than what is specified with the bytes parameter. */ public static synchronized boolean hasEnoughSpace(String directoryPath, long bytes) { // TODO This does not work with quotas etc. but at least it seems that // we do not write all data on disk if it fails. boolean hasEnoughSpace = false; File file = null; RandomAccessFile raf = null; File directory = new File(directoryPath); boolean deleteDirectory = false; if (!directory.exists()) { deleteDirectory = directory.mkdir(); } try { file = File.createTempFile("temp" + System.nanoTime(), ".tmp", directory); raf = new RandomAccessFile(file, "rw"); raf.setLength(bytes); hasEnoughSpace = true; } catch (IOException ex) { } finally { if (raf != null) { try { raf.close(); } catch (IOException ex2) { } } if (file != null) { file.delete(); } } if (deleteDirectory) { directory.delete(); } return hasEnoughSpace; } /** * Returns a localized message for a given properties key an exception. * @param key the key of the message in the properties file. * @param i18n the ResourceProvider to be used. * @param args the arguments of the message in the properties file. * @param ex the exception for which we want to get a message. * * @return a localized message for a given properties key an exception. */ public static String getExceptionMsg(ResourceProvider i18n, String key, String[] args, Exception ex) { String msg; if (args != null) { msg = i18n.getMsg(key, args); } else { msg = i18n.getMsg(key); } String detail = ex.toString(); if (detail != null) { String[] arg = { detail }; msg = msg + " " + i18n.getMsg("exception-details", arg); } return msg; } /** * Commodity method to help identifying the OS we are running on. * @param s the String that represents an OS. * @return true if there is os java property exists and contains * the value specified in s, false otherwise. */ private static boolean containsOsProperty(String s) { boolean containsOsProperty = false; String osName = System.getProperty("os.name"); if (osName != null) { containsOsProperty = osName.toLowerCase().indexOf(s) != -1; } return containsOsProperty; } /** * Sets the permissions of the provided paths with the provided permission * String. * @param paths the paths to set permissions on. * @param permissions the UNIX-mode file system permission representation * (for example "644" or "755") * @return the return code of the chmod command. * @throws IOException if something goes wrong. * @throws InterruptedException if the Runtime.exec method is interrupted. */ public static int setPermissionsUnix(ArrayList paths, String permissions) throws IOException, InterruptedException { String[] args = new String[paths.size() + 2]; args[0] = "chmod"; args[1] = permissions; for (int i = 2; i < args.length; i++) { args[i] = paths.get(i - 2); } Process p = Runtime.getRuntime().exec(args); return p.waitFor(); } // Very limited for the moment: apply only permissions to the current user and // does not work in non-English environments... to work in non English we // should use xcalcs but it does not come in the windows default install... // :-( // This method is not called for the moment, but the code works, so that is // why // is kept. private static int changePermissionsWindows(String path, String unixPerm) throws IOException, InterruptedException { String windowsPerm; int i = Integer.parseInt(unixPerm.substring(0, 1)); if (Integer.lowestOneBit(i) == 1) { // Executable: give full permissions windowsPerm = "F"; } else if (Integer.highestOneBit(i) == 4) { // Writable windowsPerm = "W"; } else if (Integer.highestOneBit(i) == 2) { // Readable windowsPerm = "R"; } else { // No permissions windowsPerm = "N"; } String user = System.getProperty("user.name"); String[] args = { "cacls", path, "/P", user + ":" + windowsPerm }; Process p = Runtime.getRuntime().exec(args); // TODO: This only works in ENGLISH systems!!!!!! p.getOutputStream().write("Y\n".getBytes()); p.getOutputStream().flush(); return p.waitFor(); } /** * Indicates whether we are in a web start installation or not. * * @return true if we are in a web start installation and * false if not. */ public static boolean isWebStart() { return "true".equals(System.getProperty(JnlpProperties.IS_WEBSTART)); } /** * Returns true if this is an uninstallation and * false otherwise. * @return true if this is an uninstallation and * false otherwise. */ public static boolean isUninstall() { return "true".equals(System.getProperty("org.opends.quicksetup.uninstall")); } /** * Creates a clear LDAP connection and returns the corresponding LdapContext. * This methods uses the specified parameters to create a JNDI environment * hashtable and creates an InitialLdapContext instance. * * @param ldapURL * the target LDAP URL * @param dn * passed as Context.SECURITY_PRINCIPAL if not null * @param pwd * passed as Context.SECURITY_CREDENTIALS if not null * @param timeout * passed as com.sun.jndi.ldap.connect.timeout if > 0 * @param env * null or additional environment properties * * @throws NamingException * the exception thrown when instantiating InitialLdapContext * * @return the created InitialLdapContext. * @see javax.naming.Context * @see javax.naming.ldap.InitialLdapContext */ public static InitialLdapContext createLdapContext(String ldapURL, String dn, String pwd, int timeout, Hashtable env) throws NamingException { if (env != null) { // We clone 'env' so that we can modify it freely env = new Hashtable(env); } else { env = new Hashtable(); } env .put(Context.INITIAL_CONTEXT_FACTORY, "com.sun.jndi.ldap.LdapCtxFactory"); env.put(Context.PROVIDER_URL, ldapURL); if (timeout >= 1) { env.put("com.sun.jndi.ldap.connect.timeout", String.valueOf(timeout)); } if (dn != null) { env.put(Context.SECURITY_PRINCIPAL, dn); } if (pwd != null) { env.put(Context.SECURITY_CREDENTIALS, pwd); } /* Contains the DirContext and the Exception if any */ final Object[] pair = new Object[] { null, null }; final Hashtable fEnv = env; Thread t = new Thread(new Runnable() { public void run() { try { pair[0] = new InitialLdapContext(fEnv, null); } catch (NamingException ne) { pair[1] = ne; } catch (RuntimeException re) { pair[1] = re; } } }); return getInitialLdapContext(t, pair, timeout); } /** * This is just a commodity method used to try to get an InitialLdapContext. * @param t the Thread to be used to create the InitialLdapContext. * @param pair an Object[] array that contains the InitialLdapContext and the * Exception if any occurred. * @param timeout the timeout. If we do not get to create the connection * before the timeout a CommunicationException will be thrown. * @return the created InitialLdapContext * @throws NamingException if something goes wrong during the creation. */ private static InitialLdapContext getInitialLdapContext(Thread t, Object[] pair, int timeout) throws NamingException { try { if (timeout > 0) { t.start(); t.join(timeout); } else { t.run(); } } catch (InterruptedException x) { // This might happen for problems in sockets // so it does not necessarily imply a bug } boolean throwException = false; if ((timeout > 0) && t.isAlive()) { t.interrupt(); try { t.join(2000); } catch (InterruptedException x) { // This might happen for problems in sockets // so it does not necessarily imply a bug } throwException = true; } if ((pair[0] == null) && (pair[1] == null)) { throwException = true; } if (throwException) { NamingException xx; ConnectException x = new ConnectException("Connection timed out"); xx = new CommunicationException("Connection timed out"); xx.initCause(x); throw xx; } if (pair[1] != null) { if (pair[1] instanceof NamingException) { throw (NamingException) pair[1]; } else if (pair[1] instanceof RuntimeException) { throw (RuntimeException) pair[1]; } } return (InitialLdapContext) pair[0]; } }