| /******************************************************************************* |
| * 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 |
| } |
| } |