/******************************************************************************* * Copyright (c) 2006 Sybase, Inc. and others. * * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * Sybase, Inc. - initial API and implementation *******************************************************************************/ package org.eclipse.jst.jsf.common.ui.internal.utils; import java.awt.Component; import java.awt.Dimension; import java.awt.Point; import java.awt.Rectangle; import java.awt.Toolkit; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStream; import java.util.MissingResourceException; import java.util.Properties; import java.util.ResourceBundle; import java.util.StringTokenizer; import org.eclipse.jst.jsf.common.ui.JSFUICommonPlugin; /** * The main purpose of this class is to give better access methods for property * and resource bundle access. * * @author mengbo */ public final class PropertyUtils { private static final String ENCODED_CHAR_PERCENT = "%25"; //$NON-NLS-1$ private static final String ENCODED_CHAR_CARRIAGE_RETURN = "%0d"; //$NON-NLS-1$ private static final String ENCODED_CHAR_TAB = "%09"; //$NON-NLS-1$ private static final String ENCODED_CHAR_NEWLINE = "%0a"; //$NON-NLS-1$ private static final String ENCODED_CHAR_SPACE = "%20"; //$NON-NLS-1$ private static final String ENCODED_CHAR_COLON = "%3a"; //$NON-NLS-1$ private static final String ENCODED_CHAR_EQUALS = "%3d"; //$NON-NLS-1$ // WARNING: There can be NO static logging line here since the logger uses // this class to figure out the preferences // for the logging system. "Logging" an error here would be useless since // you might be setting up the logging system // via a call to PropertyUtils.getServerProperty() instead it uses // "System.err.println". // This is the name for the properties file. // The prop-name will be prepended to this string.... private static final String NAME_PROPERTIES = ".props"; //$NON-NLS-1$ private static final String STR_BOUNDS_END = ".bounds"; // assumes the //$NON-NLS-1$ // window name or // name list is // prepended // ////////////////////////////////////////////////////////////////////////// // Property get methods. // ////////////////////////////////////////////////////////////////////////// /** * @param props * @param key * @param theDefault * @return the property */ public static String getProperty(Properties props, String key, String theDefault) { try { String value = props.getProperty(key, theDefault); if ((value != null) && (value.length() == 0)) { value = null; } // check again for null, since some versions of the jdk ignore the // default // if an empty property exists. if (value == null) { value = theDefault; } return value; } catch (Exception ee) { return theDefault; } } /** * @param props * @param key * @return the value for key in props, may return null */ public static String getProperty(Properties props, String key) { try { String value = props.getProperty(key); if ((value != null) && (value.length() == 0)) { value = null; } return value; } catch (Exception ee) { return null; } } /** * @param props * @param key * @param defaultValue * @param minimumValue * @return the integer property value for key, or defaultValue * if none. Enforces minimumValue in all cases */ public static int getPropertyValue(Properties props, String key, int defaultValue, int minimumValue) { int theValue = getPropertyValue(props, key, defaultValue); if (theValue < minimumValue) { theValue = minimumValue; } return theValue; } /** * @param props * @param key * @param defaultValue * @return the integer value for key in props or defaultValue if none */ public static int getPropertyValue(Properties props, String key, int defaultValue) { String stringValue = getProperty(props, key); if (stringValue != null) { try { return Integer.parseInt(stringValue); } catch (NumberFormatException ee)// NOPMD { // the property value maybe an invalid value, the editor should // show these to user. } } return defaultValue; } /** * @param props * @param key * @param defaultValue * @return the long value for key props or defaultValue if none */ public static long getPropertyLongValue(Properties props, String key, long defaultValue) { String stringValue = getProperty(props, key); if (stringValue != null) { try { return Long.parseLong(stringValue); } catch (NumberFormatException ee)// NOPMD { // the property value maybe an invalid value, the editor should // show these to user. } } return defaultValue; } /** * @param props * @param key * @param bDefault * @return true if props has a value for key */ public static boolean isProperty(Properties props, String key, boolean bDefault) { return getProperty(props, key, "" + bDefault).equals("" + true); //$NON-NLS-1$ //$NON-NLS-2$ } /** * @param props * @param key * @return the string values in props for key tokenized from * a comma-separated string */ public static String[] getPropertyStrings(Properties props, String key) { String tokenString = getProperty(props, key); if (tokenString == null) { return new String[0]; } StringTokenizer tokenizer = new StringTokenizer(tokenString, ","); //$NON-NLS-1$ String[] pNames = new String[tokenizer.countTokens()]; for (int ii = 0; ii < pNames.length; ii++) { pNames[ii] = ((String) tokenizer.nextElement()).trim(); } return pNames; } // ////////////////////////////////////////////////////////////////////////// // Resource bundle get methods. // ////////////////////////////////////////////////////////////////////////// /** * @param bundle * @param key * @param theDefault * @return the string value from bundle for key or default if none */ public static String getResourceProperty(ResourceBundle bundle, String key, String theDefault) { try { String value = bundle.getString(key); if ((value == null) || (value.length() == 0)) { value = theDefault; } return value; } catch(NullPointerException npe) { return theDefault; } catch (MissingResourceException mre) { return theDefault; } catch (ClassCastException cce) { return theDefault; } } /** * @param bundle * @param key * @return the value for key in bundle or null if none */ public static String getResourceProperty(ResourceBundle bundle, String key) { try { String value = bundle.getString(key); if ((value != null) && (value.length() == 0)) { value = null; } return value; } catch(NullPointerException npe) { return null; } catch (MissingResourceException mre) { return null; } catch (ClassCastException cce) { return null; } } /** * @param bundle * @param key * @param defaultValue * @param minimumValue * @return the integer value for key in bundle or defaultValue if none * Enforces minimum value in all cases */ public static int getResourcePropertyValue(ResourceBundle bundle, String key, int defaultValue, int minimumValue) { int theValue = getResourcePropertyValue(bundle, key, defaultValue); if (theValue < minimumValue) { theValue = minimumValue; } return theValue; } /** * @param bundle * @param key * @param defaultValue * @return the integer value for key in bundle or defaultValue if none */ public static int getResourcePropertyValue(ResourceBundle bundle, String key, int defaultValue) { String stringValue = getResourceProperty(bundle, key); if (stringValue != null) { try { return Integer.parseInt(stringValue); } catch (NumberFormatException ee)// NOPMD { // the property value maybe an invalid value, the editor should // show these to user. } } return defaultValue; } /** * @param bundle * @param key * @param defaultValue * @return the long value for key in bundle or default value if none */ public static long getResourcePropertyLongValue(ResourceBundle bundle, String key, long defaultValue) { String stringValue = getResourceProperty(bundle, key); if (stringValue != null) { try { return Long.parseLong(stringValue); } catch (NumberFormatException ee)// NOPMD { // the property value maybe an invalid value, the editor should // show these to user. } } return defaultValue; } /** * @param bundle * @param key * @param bDefault * @return true if bundle has a value for key */ public static boolean isResourceProperty(ResourceBundle bundle, String key, boolean bDefault) { return getResourceProperty(bundle, key, "" + bDefault) //$NON-NLS-1$ .equals("" + true); //$NON-NLS-1$ } // /////////////////////////////////////////////////////////////////////// // Property misc routines // /////////////////////////////////////////////////////////////////////// /** * @param theName * @return the encoded name */ public static String encodeName(String theName) { int theSize = theName.length(); StringBuffer encoded = new StringBuffer(theSize); char ch; for (int ii = 0; ii < theSize; ii++) { ch = theName.charAt(ii); switch (ch) { // these are the set of illegal characters in a Property name case '=': // %3d encoded.append(ENCODED_CHAR_EQUALS); break; case ':': // %3a encoded.append(ENCODED_CHAR_COLON); break; case ' ': // %20 encoded.append(ENCODED_CHAR_SPACE); break; case '\n': // %0a encoded.append(ENCODED_CHAR_NEWLINE); break; case '\t': // %09 encoded.append(ENCODED_CHAR_TAB); break; case '\r': // %0d encoded.append(ENCODED_CHAR_CARRIAGE_RETURN); break; case '%': // %25 // added because its our encoding flag encoded.append(ENCODED_CHAR_PERCENT); break; default: encoded.append(ch); break; } } return encoded.toString(); } /** * @param theName * @return the decoded name */ public static String decodeName(String theName) { int theSize = theName.length(); int kk; StringBuffer decoded = new StringBuffer(theSize); char ch; for (int ii = 0; ii < theSize; ii++) { ch = theName.charAt(ii); if (ch == '%') { ch = theName.charAt(++ii); kk = Character.digit(ch, 16); kk *= 16; ch = theName.charAt(++ii); kk += Character.digit(ch, 16); decoded.append((char) kk); } else { decoded.append(ch); } } return decoded.toString(); } /** * @param propName * @return the properties * @throws IOException * @throws FileNotFoundException */ public static Properties openProperties(String propName) throws IOException, FileNotFoundException { return openProperties(propName, null, true); } /** * @param propName * @param propDefaults * @return the properties * @throws IOException * @throws FileNotFoundException */ public static Properties openProperties(String propName, Properties propDefaults) throws IOException, FileNotFoundException { return openProperties(propName, propDefaults, true); } /** * @param propName * @param propDefaults * @param bCreatePropertiesPathname * @return the properties * @throws IOException * @throws FileNotFoundException */ public static Properties openProperties(String propName, Properties propDefaults, boolean bCreatePropertiesPathname) throws IOException, FileNotFoundException { Properties theProperties = new Properties(propDefaults); try { String propertiesFilename = bCreatePropertiesPathname ? getPropertiesPathname(propName) : propName; InputStream theStream = new FileInputStream(propertiesFilename); theProperties.load(theStream); theStream.close(); } catch (FileNotFoundException ee) { if (propDefaults == null) { throw ee; } } catch (IOException ee) { if (propDefaults == null) { throw ee; } } return theProperties; } /** * Combines two properties objects, with the second one as the default * properties * * @param localProperties * @param defaultProperties * @return the combined properties * @throws IOException */ public static Properties combineProperties(Properties localProperties, Properties defaultProperties) throws IOException { Properties theNewProperties = new Properties(); ByteArrayOutputStream os = new ByteArrayOutputStream(); defaultProperties.store(os, ""); //$NON-NLS-1$ localProperties.store(os, ""); //$NON-NLS-1$ byte[] theData = os.toByteArray(); ByteArrayInputStream is = new ByteArrayInputStream(theData); theNewProperties.load(is); return theNewProperties; } /** * @param theFilename * @return the encoded file name */ public static String encodeFilename(String theFilename) { // make theFilename legal on the local system.... String theSeparator = System.getProperty("file.separator"); //$NON-NLS-1$ // replace all occurrances of the file separator with a ' ' for (int ii = 0; ii < theSeparator.length(); ii++) { char theChar = theSeparator.charAt(ii); theFilename = theFilename.replace(theChar, ' '); } return theFilename; } /** * @param baseName * @return the properties path */ public static String getPropertiesPathname(String baseName) { if (baseName.endsWith(NAME_PROPERTIES)) { return System.getProperty("user.dir") //$NON-NLS-1$ + System.getProperty("file.separator") //$NON-NLS-1$ + encodeFilename(baseName); } return System.getProperty("user.dir") //$NON-NLS-1$ + System.getProperty("file.separator") //$NON-NLS-1$ + encodeFilename(baseName) + NAME_PROPERTIES; } // ///////////////////////////////////////////////////////////////////////// // These are generic routines that are used to get/set/save window bounds private static final int INSET = 40; /** * Set the initial bounds (size & location) of a component. This will get * the location from the preferences file based on the values of the "names" * parameter. These values will be encoded to make a legal properties name, * joined togther with ".", and the value STR_BOUNDS_END will be appended. * The resulting name will be used to obtain the intial bounds value from * the properties file, which will be decoded and the specified component * will then be set to that value. * @param props * @param theComponent * @param names * @param defaultValue */ public static void setComponentBounds(Properties props, Component theComponent, String names[], String defaultValue) { setComponentBounds(props, theComponent, names, defaultValue, false); } /** * @param props * @param theComponent * @param names * @param defaultValue * @param bEnsureDesktopVisibility */ public static void setComponentBounds(Properties props, Component theComponent, String names[], String defaultValue, boolean bEnsureDesktopVisibility) { String tmpString = getComponentPropertyName(names, STR_BOUNDS_END); setComponentBounds(props, theComponent, tmpString, defaultValue, bEnsureDesktopVisibility); } /** * @param props * @param theComponent * @param thePropertyName * @param defaultValue */ public static void setComponentBounds(Properties props, Component theComponent, String thePropertyName, String defaultValue) { setComponentBounds(props, theComponent, thePropertyName, defaultValue, false); } /** * @param props * @param theComponent * @param thePropertyName * @param defaultValue * @param bEnsureDesktopVisibility */ public static void setComponentBounds(Properties props, Component theComponent, String thePropertyName, String defaultValue, boolean bEnsureDesktopVisibility) { String tmpString = props.getProperty(thePropertyName, defaultValue); Rectangle theValue = decodeBounds(tmpString); theComponent.setBounds(theValue); if (bEnsureDesktopVisibility) { // make sure that this component is visible on the desktop... // verify that this window is visible... Point theLoc = theComponent.getLocation(); // get width/height of desktop.... Dimension portSize = new Dimension(Toolkit.getDefaultToolkit() .getScreenSize()); if (theLoc.x > portSize.width) // move it to top theLoc.x = INSET; if (theLoc.y > portSize.height) // move it to left theLoc.y = INSET; theComponent.setLocation(theLoc); } } /** * @param props * @param theComponent * @param names */ public static void saveComponentBounds(Properties props, Component theComponent, String names[]) { String tmpString = getComponentPropertyName(names, STR_BOUNDS_END); saveComponentBounds(props, theComponent, tmpString); } /** * @param props * @param theComponent * @param thePropertyName */ public static void saveComponentBounds(Properties props, Component theComponent, String thePropertyName) { Rectangle theBounds = theComponent.getBounds(); String theValue = encodeBounds(theBounds); props.put(thePropertyName, theValue); } /** * @param names * @param subsystemName * @return the component property name or "" */ public static String getComponentPropertyName(String names[], String subsystemName) { String tmpString = ""; //$NON-NLS-1$ for (int ii = 0; ii < names.length; ii++) { tmpString = tmpString + (ii > 0 ? "." : "") //$NON-NLS-1$ //$NON-NLS-2$ + PropertyUtils.encodeName(names[ii]); } if (subsystemName.startsWith(".") == false) //$NON-NLS-1$ tmpString += "."; //$NON-NLS-1$ tmpString = tmpString + subsystemName; return tmpString; } /** * Decode the comma separated values stored in sBounds. This method is * normally called to decode the location/size of a component which has been * saved into a Properties object. See encodeBounds(); Order of items in the * string is (x, y, w, h) * @param sBounds * @return the rectangle */ public static Rectangle decodeBounds(String sBounds) { int index; int ii; int theValue[] = new int[4]; String tmpString; String restString = sBounds; for (ii = 0; ii < 4; ii++) { theValue[ii] = 0; } try { for (ii = 0; ii < 4; ii++) { index = restString.indexOf(","); //$NON-NLS-1$ if (index > 0) { tmpString = restString.substring(0, index); restString = restString.substring(index + 1); } else { tmpString = restString; // should only happen on the last // one.... restString = null; // will cause an exception if not last // one... } theValue[ii] = Integer.valueOf(tmpString).intValue(); } } catch (Exception ee)// NOPMD { // the property value maybe an invalid value, the editor should show // these to user. } return new Rectangle(theValue[0], theValue[1], theValue[2], theValue[3]); } /** * * Encode the bounds of a component into a comma separated list * that is * appropriate for storing in a Properties object. * See decodeBounds(); * @param rBounds * @return the encoded bounds */ public static String encodeBounds(Rectangle rBounds) { return "" + rBounds.x + "," + rBounds.y + "," + rBounds.width + "," //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ + rBounds.height; } /** * Methods for creating Properties objects from strings. * * Then "Encoded" versions are used on values that are stored into a * properties file (think of them as sub-properties). They do the encoding * necessary to turn a properties object into a string that has legal * "value" syntax (they actually do more than they need to, but its all * non-destructive). * @param thePropertyString * @return the properties from the string * @throws IOException */ public static Properties getPropertiesFromString(String thePropertyString) throws IOException { if (thePropertyString == null) return null; ByteArrayInputStream in = new ByteArrayInputStream(thePropertyString .getBytes()); Properties props = new Properties(); props.load(in); // throws IOException in = null; return props; } /** * @param theEncodedPropertyString * @return the properties * @throws IOException */ public static Properties getPropertiesFromEncodedString( String theEncodedPropertyString) throws IOException { if (theEncodedPropertyString == null) return null; return (getPropertiesFromString(decodeName(theEncodedPropertyString))); } /** * @param theEncodedPropertyString * @return the properties */ public static Properties encodedStringToProperties( String theEncodedPropertyString) { try { return getPropertiesFromEncodedString(theEncodedPropertyString); } catch (IOException ee) { return null; } } /** * @param props * @param comment * @return the string * @throws IOException */ public static String savePropertiesToString(Properties props, String comment) throws IOException { if (props == null) return null; ByteArrayOutputStream out = new ByteArrayOutputStream(); props.store(out, comment); String tmpString = out.toString(); out = null; return tmpString; } /** * @param props * @param comment * @return the encoded string * @throws IOException */ public static String savePropertiesToEncodedString(Properties props, String comment) throws IOException { if (props == null) return null; return encodeName(savePropertiesToString(props, comment)); } /** * @param props * @return the encoded string */ public static String propertiesToEncodedString(Properties props) { try { return savePropertiesToEncodedString(props, ""); //$NON-NLS-1$ } catch (IOException ee)// NOPMD { JSFUICommonPlugin.getLogger(PropertyUtils.class).error("saving properties", ee); //$NON-NLS-1$ } return null; } private PropertyUtils() { // no instantiation } }