Start line:  
End line:  

Snippet Preview

Snippet HTML Code

Stack Overflow Questions
   
   /*
    * Copyright (C) 2006 Sun Microsystems, Inc. All rights reserved. Use is
    * subject to license terms.
    */ 
   
   package org.jdesktop.application;
   
  import java.awt.Color;
  import java.awt.Event;
  import java.awt.Font;
  import java.awt.Image;
  import java.awt.Insets;
  import java.awt.Point;
  import java.awt.Toolkit;
  import java.net.URL;
  import java.util.Arrays;
  import java.util.HashSet;
  import java.util.List;
  import java.util.Locale;
  import java.util.Map;
  import java.util.Set;
  import javax.swing.Icon;
  import javax.swing.JMenu;
A read-only encapsulation of one or more ResourceBundles that adds automatic string conversion, support for field and Swing component property injection, string resource variable substitution, and chaining.

ResourceMaps are typically obtained with the ApplicationContext getResourceMap method which lazily creates per Application, package, and class ResourceMaps that are linked together with the ResourceMap parent property.

An individual ResourceMap provides read-only access to all of the resources defined by the ResourceBundles named when the ResourceMap was created as well as all of its parent ResourceMaps. Resources are retrieved with the getObject method which requires both the name of the resource and its expected type. The latter is used to convert strings if neccessary. Converted values are cached. As a convenience, getObject wrapper methods for common GUI types, like getFont, and getColor, are provided.

The getObject method scans raw string resource values for ${resourceName} variable substitutions before performing string conversion. Variables named this way can refer to String resources defined anywhere in their ResourceMap or any parent ResourceMap. The special variable ${null} means that the value of the resource will be null.

ResourceMaps can be used to "inject" resource values into Swing component properties and into object fields. The injectComponents method uses Component names (java.awt.Component.setName(java.lang.String)) to match resources names with properties. The injectFields method sets fields that have been tagged with the @Resource annotation to the value of resources with the same name.

  
  public class ResourceMap {
      private static Logger logger = Logger.getLogger(ResourceMap.class.getName());
      private final static Object nullResource = new String("null resource");
      private final ClassLoader classLoader;
      private final ResourceMap parent;
      private final List<StringbundleNames;
      private final String resourcesDir;
     private Map<StringObjectbundlesMapP = null// see getBundlesMap()
     private Locale locale = Locale.getDefault();    // ...
     private Set<StringbundlesMapKeysP = null;     // set getBundlesMapKeys()
     private boolean bundlesLoaded = false;  // ResourceBundles are loaded lazily
 
    
Creates a ResourceMap that contains all of the resources defined in the named java.util.ResourceBundles as well as (recursively) the parent ResourceMap. The parent may be null. Typically just one ResourceBundle is specified however one might name additional ResourceBundles that contain platform or Swing look and feel specific resources. When multiple bundles are named, a resource defined in bundlen will overide the same resource defined in bundles0..n-1. In other words bundles named later in the argument list take precendence over the bundles named earlier.

ResourceBundles are loaded with the specified ClassLoader. If classLoader is null, an IllegalArgumentException is thrown.

At least one bundleName must be specified and all of the bundleNames must be non-empty strings, or an IllegalArgumentException is thrown. The bundles are listed in priority order, highest priority first. In other words, resources in the the first ResourceBundle named first, shadow resources with the same name later in the list.

All of the bundleNames must share a common package prefix. The package prefix implicitly specifies the resources directory (see getResourcesDir()). For example, the resources directory for bundle names "myapp.resources.foo" and "myapp.resources.bar", would be "myapp/resources/". If bundle names don't share a common package prefix, then an IllegalArgumentException is thrown.

Parameters:
parent parent ResourceMap or null
classLoader the ClassLoader to be used to load the ResourceBundle
bundleNames names of the ResourceBundle to be loaded
Throws:
java.lang.IllegalArgumentException if classLoader or any bundleName is null, if no bundleNames are specified, if any bundleName is an empty (zero length) String, or if all of the bundleNames don't have a common package prefix
See also:
java.util.ResourceBundle
getParent()
getClassLoader()
getResourcesDir()
getBundleNames()
 
     public ResourceMap(ResourceMap parentClassLoader classLoaderList<StringbundleNames) {
 	if (classLoader == null) {
 	    throw new IllegalArgumentException("null ClassLoader");
 	}
 	if ((bundleNames == null) || (bundleNames.size() == 0)) {
 	    throw new IllegalArgumentException("no bundle specified");
 	}
 	for (String bn : bundleNames) {
 	    if ((bn == null) || (bn.length() == 0)) {
 		throw new IllegalArgumentException("invalid bundleName: \"" + bn + "\"");
 	    }
 	}
 	String bpn = bundlePackageName(bundleNames.get(0));
 	for (String bn : bundleNames) {
 	    if (!bpn.equals(bundlePackageName(bn))) {
 		throw new IllegalArgumentException("bundles not colocated: \"" + bn + "\" != \"" + bpn + "\"");
 	    }
 	}
 	this. = parent;
 	this. = classLoader;
 	this. = Collections.unmodifiableList(new ArrayList<String>(bundleNames));
 	this. = bpn.replace(".""/") + "/";
     }
 
     private String bundlePackageName(String bundleName) {
 	int i = bundleName.lastIndexOf(".");
 	return (i == -1) ? "" : bundleName.substring(0, i);
     }

    
Just a convenience version of the constructor for the common case where there's only one bundle name. Defined as: this(parent, classLoader, Arrays.asList(bundleNames)).
 
     public ResourceMap(ResourceMap parentClassLoader classLoaderString... bundleNames) {
 	this(parentclassLoader, Arrays.asList(bundleNames));
     }

    
Returns the parent ResourceMap, or null. Logically, this ResourceMap contains all of the resources defined here and (recursively) in the parent.

Returns:
the parent ResourceMap or null
 
     public ResourceMap getParent() { 
 	return ;  
     }

    
Returns the names of the ResourceBundles that define the resources contained by this ResourceMap.

Returns:
the names of the ResourceBundles in this ResourceMap
 
     public List<StringgetBundleNames() { 
 	return ;
     }

    
Returns the ClassLoader used to load the ResourceBundles for this ResourceMap.

Returns:
the classLoader constructor argument
 
     public ClassLoader getClassLoader() {
 	return ;
     }

    
Returns the resources directory that contains all of the ResourceBundles in this ResourceMap. It can be used with the the classLoader property to load files from the resources directory. For example:
 String filename = myResourceMap.getResourcesDir() + "myIcon.png";
 URL url = myResourceMap.getClassLoader().getResource(filename);
 new ImageIcon(iconURL);
 

Returns:
the the resources directory for this ResourceMap
 
     public String getResourcesDir() {
 	return ;
     }
 
     /* Lazily flattens all of the ResourceBundles named in bundleNames
      * into a single Map - bundlesMapP.  The bundleNames list is in
      * priority order, the first entry shadows later entries.
      */
     private synchronized Map<StringObjectgetBundlesMap() {
         // If the default locale has changed, then reload
         Locale defaultLocale = Locale.getDefault();
         if ( != defaultLocale) {
              = false;
              = defaultLocale;
         }
 	if (!) {
 	    Map<StringObjectbundlesMap = new ConcurrentHashMap<StringObject>();
 	    for (int i = .size() - 1; i >= 0; i--) {
 		try {
                     String bundleName = .get(i);
 		    ResourceBundle bundle = ResourceBundle.getBundle(bundleName);
 		    Enumeration<Stringkeys = bundle.getKeys();
 		    while(keys.hasMoreElements()) {
 			String key = keys.nextElement();
 			bundlesMap.put(keybundle.getObject(key));
 		    }
 		}
 		catch (MissingResourceException ignore) { 
 		    /* bundleName is just a location to check, it's not
 		     * guaranteed to name a ResourceBundle
 		     */
 		}
 	    }
              = bundlesMap;
 	     = true;
 	}
 	return ;
     }
 
     private void checkNullKey(String key) {
 	if (key == null) {
 	    throw new IllegalArgumentException("null key");
 	}
     }
 
     private synchronized Set<StringgetBundlesMapKeys() {
 	if ( == null) {
 	    Set<StringallKeys = new HashSet<String>(getResourceKeySet());
 	    ResourceMap parent = getParent();
 	    if (parent != null) {
 		allKeys.addAll(parent.keySet());
 	    }
 	     = Collections.unmodifiableSet(allKeys);
 	}
 	return ;
     }

    
Return a unmodifiable java.util.Set that contains all of the keys in this ResourceMap and (recursively) its parent ResourceMaps.

Returns:
all of the keys in this ResourceMap and its parent
See also:
getParent()
 
     public Set<StringkeySet() {
 	return getBundlesMapKeys();
     }

    
Returns true if this resourceMap or its parent (recursively) contains the specified key.

Returns:
true if this resourceMap or its parent contains the specified key.
See also:
getParent()
keySet()
 
     public boolean containsKey(String key) {
 	if (containsResourceKey(key)) {
 	    return true;
 	}
 	else {
 	    ResourceMap parent = getParent();
 	    return (parent != null) ? parent.containsKey(key) : false;
 	}
     }

    
Unchecked exception thrown by ResourceMap.getObject(java.lang.String,java.lang.Class) when resource lookup fails, for example because string conversion fails. This is not a missing resource exception. If a resource isn't defined for a particular key, getObject does not throw an exception.

 
     public static class LookupException extends RuntimeException {
 	private final Class type;
 	private final String key;

Constructs an instance of this class with some useful information about the failure.

Parameters:
msg the detail message
type the type of the resource
key the name of the resource
 
 	public LookupException(String msgString keyClass type) {
             super(String.format("%s: resource %s, type %s"msgkeytype));
             this. = key;
 	    this. = type;
 	}

Returns the type of the resource for which lookup failed.

Returns:
the resource type
 
 	public Class getType() {
 	    return ;
 	}

Returns the type of the name of resource for which lookup failed.

Returns:
the resource name
 
 	public String getKey() {
 	    return ;
 	}
     }

    
By default this method is used by keySet to get the names of the resources defined in this ResourceMap. This method lazily loads the ResourceBundles named by the constructor.

The protected getResource, putResource, and containsResourceKey, getResourceKeySet abstract the internal representation of this ResourceMap's list of ResourceBundles. Most applications can ignore them.

 
     protected  Set<StringgetResourceKeySet() {
 	Map<StringObjectbundlesMap = getBundlesMap();
         if (bundlesMap == null) {
             return Collections.emptySet();
         }
         else {
             return bundlesMap.keySet();
         }
     }


    
By default this method is used by getObject to see if a resource is defined by this ResourceMap. This method lazily loads the ResourceBundles named by the constructor.

The protected getResource, putResource, and containsResourceKey, getResourceKeySet abstract the internal representation of this ResourceMap's list of ResourceBundles. Most applications can ignore them.

If key is null, an IllegalArgumentException is thrown.

Parameters:
key the name of the resource
Returns:
true if a resource named key is defined in this ResourceMap
See also:
getResource(java.lang.String)
putResource(java.lang.String,java.lang.Object)
getResourceKeySet()
 
     protected boolean containsResourceKey(String key) {
 	Map<StringObjectbundlesMap = getBundlesMap();
 	return (bundlesMap != null) && bundlesMap.containsKey(key);
     }

    
By default this method is used by getObject to look up resource values in the internal representation of the ResourceBundles named when this ResourceMap was constructed. If a resource named key is defined then its value is returned, otherwise null. The getResource method lazily loads the ResourceBundles named by the constructor.

The protected getResource, putResource, and containsResourceKey, getResourceKeySet abstract the internal representation of this ResourceMap's list of ResourceBundles. Most applications can ignore them.

If key is null, an IllegalArgumentException is thrown.

Parameters:
key the name of the resource
Returns:
the value of the resource named key (can be null)
See also:
putResource(java.lang.String,java.lang.Object)
containsResourceKey(java.lang.String)
getResourceKeySet()
 
     protected Object getResource(String key) {
 	Map<StringObjectbundlesMap = getBundlesMap();
 	Object value = (bundlesMap != null) ? bundlesMap.get(key) : null;
 	return (value == ) ? null : value;
     }

    
By default this method is used by getObject to cache values that have been retrieved, evaluated (as in ${key} expressions), and string converted. A subclass could override this method to defeat caching or to refine the caching strategy. The putResource method lazily loads ResourceBundles.

The protected getResource, putResource, and containsResourceKey, getResourceKeySet abstract the internal representation of this ResourceMap's list of ResourceBundles. Most applications can ignore them.

If key is null, an IllegalArgumentException is thrown.

Parameters:
key the name of the resource
value the value of the resource (can be null)
See also:
getResource(java.lang.String)
containsResourceKey(java.lang.String)
getResourceKeySet()
 
     protected void putResource(String keyObject value) {
 	Map<StringObjectbundlesMap = getBundlesMap();
 	if (bundlesMap != null) {
 	    bundlesMap.put(key, (value == null) ?  : value);
 	}
     }

    
Returns the value of the resource named key, or null if no resource with that name exists. A resource exists if it's defined in this ResourceMap or (recursively) in the ResourceMap's parent.

String resources may contain variables that name other resources. Each ${variable-key} variable is replaced with the value of a string resource named variable-key. For example, given the following resources:

 Application.title = My Application
 ErrorDialog.title = Error: ${application.title}
 WarningDialog.title = Warning: ${application.title}
 
The value of "WarningDialog.title" would be "Warning: My Application". To include "${" in a resource, insert a backslash before the "$". For example, the value of escString in the example below, would be "${hello}":
 escString = \\${hello}
 
Note that, in a properties file, the backslash character is used for line continuation, so we've had to escape that too. If the value of a resource is the special variable ${null}, then the resource will be removed from this ResourceMap.

The value returned by getObject will be of the specified type. If a string valued resource exists for key, and type is not String.class, the value will be converted using a ResourceConverter and the ResourceMap entry updated with the converted value.

If the named resource exists and an error occurs during lookup, then a ResourceMap.LookupException is thrown. This can happen if string conversion fails, or if resource parameters can't be evaluated, or if the existing resource is of the wrong type.

An IllegalArgumentException is thrown if key or type are null.

Parameters:
key resource name
type resource type
Throws:
ResourceMap.LookupException if an error occurs during lookup or string conversion
java.lang.IllegalArgumentException if key or type are null
See also:
getParent()
ResourceConverter.forType(java.lang.Class)
ResourceMap.LookupException
 
     public Object getObject(String keyClass type) {
 	if (type == null) {
 	    throw new IllegalArgumentException("null type");
 	}
         if (type.isPrimitive()) {
             if      (type == .)   { type = Boolean.class; }
             else if (type == .) { type = Character.class; }
             else if (type ==  .)     { type = Byte.class; }
             else if (type ==  .)    { type = Short.class; }
             else if (type ==  .)  { type = Integer.class; }
             else if (type ==  .)     { type = Long.class; }
             else if (type ==  .)    { type = Float.class; }
             else if (type ==  .)   { type = Double.class; }
         }
 	Object value = null;
 	ResourceMap resourceMapNode = this;
 	/* Find the ResourceMap bundlesMap that contains a non-null
 	 * value for the specified key, first check this ResourceMap,
 	 * then its parents.
 	 */
 	while (resourceMapNode != null) {
 	    if (resourceMapNode.containsResourceKey(key)) {
 		value = resourceMapNode.getResource(key);
 		break;
 	    }
 	    resourceMapNode = resourceMapNode.getParent();
 	}
 	/* If we've found a String expression then replace
 	 * any ${key} variables, and then reset the 
 	 * the original resourceMapNode entry.
 	 */
 	if ((value instanceof String) && ((String)value).contains("${")) {
 	    value = evaluateStringExpression((String)value);
 	    resourceMapNode.putResource(keyvalue);
 	}
 	
 	/* If the value we've found in resourceMapNode is 
 	 * the expected type, then we're done.  If the expected
          * type is primitive and the value is the corresponding
          * object type then we're done too.  Otherwise, 
 	 * if it's a String, then try and convert the String
 	 * and replace the original resourceMapNode entry, 
 	 * otherwise return null.
 	 */
 	if (value != null) {
 	    Class valueClass = value.getClass();
 	    if (!type.isAssignableFrom(valueClass)) {
 		if (value instanceof String) {
 		    ResourceConverter stringConverter = ResourceConverter.forType(type);
 		    if (stringConverter != null) {
 			String sValue = (String)value;
 			try {
 			    value = stringConverter.parseString(sValueresourceMapNode);
 			    resourceMapNode.putResource(keyvalue);
 			}
 			    String msg = "string conversion failed";
 			    LookupException lfe = new LookupException(msgkeytype);
 			    lfe.initCause(e);
 			    throw lfe;
 			}
 		    }
 		    else {
 			String msg = "no StringConverter for required type";
 			throw new LookupException(msgkeytype);
 		    }
 		}
 		else {
 		    String msg = "named resource has wrong type";
 		    throw new LookupException(msgkeytype);
 		}
 	    }
 	}
 	return value;
     }
 
     /* Given the following resources:
      * 
      * hello = Hello
      * world = World
      * place = ${world}
      * 
      * The value of evaluateStringExpression("${hello} ${place}")
      * would be "Hello World".  The value of ${null} is null.
      */
     private String evaluateStringExpression(String expr) {
 	if (expr.trim().equals("${null}")) {
 	    return null;
 	}
 	StringBuffer value = new StringBuffer();
 	int i0 = 0, i1 = 0;
 	while((i1 = expr.indexOf("${"i0)) != -1) {
 	    if ((i1 == 0) || ((i1 > 0) && (expr.charAt(i1-1) != '\\'))) {
 		int i2 = expr.indexOf("}"i1);
 		if ((i2 != -1) && (i2 > i1+2)) {
 		    String k = expr.substring(i1+2, i2);
 		    String v = getString(k);
 		    value.append(expr.substring(i0i1));
 		    if (v != null) {
 			value.append(v);
 		    }
 		    else {
 			String msg = String.format("no value for \"%s\" in \"%s\""kexpr);
 			throw new LookupException(msgkString.class);
 		    }
 		    i0 = i2 + 1;  // skip trailing "}"
 		}
 		else {
 		    String msg = String.format("no closing brace in \"%s\""expr);
 		    throw new LookupException(msg"<not found>"String.class);
 		}
 	    }
 	    else {  // we've found an escaped variable - "\${"
 		value.append(expr.substring(i0i1-1));
 		value.append("${");
 		i0 = i1 + 2; // skip past "${"
 	    }
 	}
 	value.append(expr.substring(i0));
 	return value.toString();
     }
    
    
If no arguments are specified, return the String value of the resource named key. This is equivalent to calling getObject(key, String.class) If arguments are provided, then the type of the resource named key is assumed to be format string, which is applied to the arguments if it's non null. For example, given the following resources
 hello = Hello %s
 
then the value of getString("hello", "World") would be "Hello World".

Returns:
the String value of the resource named key
Throws:
ResourceMap.LookupException if an error occurs during lookup or string conversion
java.lang.IllegalArgumentException if key is null
See also:
getObject(java.lang.String,java.lang.Class)
java.lang.String.format(java.lang.String,java.lang.Object[])
 
     public String getString(String keyObject... args) {
 	if (args.length == 0) {
 	    return (String)getObject(keyString.class);
 	}
 	else {
 	    String format = (String)getObject(keyString.class);
 	    return (format == null) ? null : String.format(formatargs);
 	}
     }

    
A convenience method that's shorthand for calling: getObject(key, Boolean.class).

Parameters:
key the name of the resource
Returns:
the Boolean value of the resource named key
Throws:
ResourceMap.LookupException if an error occurs during lookup or string conversion
java.lang.IllegalArgumentException if key is null
See also:
getObject(java.lang.String,java.lang.Class)
 
     public final Boolean getBoolean(String key) { 
 	return (Boolean)getObject(keyBoolean.class); 
     }

    
A convenience method that's shorthand for calling: getObject(key, Integer.class).

Parameters:
key the name of the resource
Returns:
the Integer value of the resource named key
Throws:
ResourceMap.LookupException if an error occurs during lookup or string conversion
java.lang.IllegalArgumentException if key is null
See also:
getObject(java.lang.String,java.lang.Class)
 
     public final Integer getInteger(String key) { 
 	return (Integer)getObject(keyInteger.class); 
     }

    
A convenience method that's shorthand for calling: getObject(key, Long.class).

Parameters:
key the name of the resource
Returns:
the Long value of the resource named key
Throws:
ResourceMap.LookupException if an error occurs during lookup or string conversion
java.lang.IllegalArgumentException if key is null
See also:
getObject(java.lang.String,java.lang.Class)
 
     public final Long getLong(String key) { 
 	return (Long)getObject(keyLong.class); 
     }

    
A convenience method that's shorthand for calling: getObject(key, Short.class).

Parameters:
key the name of the resource
Returns:
the Short value of the resource named key
Throws:
ResourceMap.LookupException if an error occurs during lookup or string conversion
java.lang.IllegalArgumentException if key is null
See also:
getObject(java.lang.String,java.lang.Class)
 
     public final Short getShort(String key) { 
 	return (Short)getObject(keyShort.class); 
     }
    
    
A convenience method that's shorthand for calling: getObject(key, Byte.class).

Parameters:
key the name of the resource
Returns:
the Byte value of the resource named key
Throws:
ResourceMap.LookupException if an error occurs during lookup or string conversion
java.lang.IllegalArgumentException if key is null
See also:
getObject(java.lang.String,java.lang.Class)
 
     public final Byte getByte(String key) { 
 	return (Byte)getObject(keyByte.class); 
     }

    
A convenience method that's shorthand for calling: getObject(key, Float.class).

Parameters:
key the name of the resource
Returns:
the Float value of the resource named key
Throws:
ResourceMap.LookupException if an error occurs during lookup or string conversion
java.lang.IllegalArgumentException if key is null
See also:
getObject(java.lang.String,java.lang.Class)
 
     public final Float getFloat(String key) { 
 	return (Float)getObject(keyFloat.class); 
     }

    
A convenience method that's shorthand for calling: getObject(key, Double.class).

Parameters:
key the name of the resource
Returns:
the Double value of the resource named key
Throws:
ResourceMap.LookupException if an error occurs during lookup or string conversion
java.lang.IllegalArgumentException if key is null
See also:
getObject(java.lang.String,java.lang.Class)
 
     public final Double getDouble(String key) { 
 	return (Double)getObject(keyDouble.class); 
     }

    
A convenience method that's shorthand for calling: getObject(key, Icon.class). This method relies on the ImageIcon ResourceConverter that's registered by this class. See getImageIcon(java.lang.String) for more information.

Parameters:
key the name of the resource
Returns:
the Icon value of the resource named key
Throws:
ResourceMap.LookupException if an error occurs during lookup or string conversion
java.lang.IllegalArgumentException if key is null
See also:
getObject(java.lang.String,java.lang.Class)
 
     public final Icon getIcon(String key) { 
 	return (Icon)getObject(keyIcon.class); 
     }

    
A convenience method that's shorthand for calling: getObject(key, ImageIcon.class). This method relies on the ImageIcon ResourceConverter that's registered by this class.

If the resource named key is a String, it should name an image file to be found in the resources subdirectory that also contains the ResourceBundle (typically a ".properties" file) that was used to create the corresponding ResourceMap.

For example, given the ResourceMap produced by Application.getClass(com.mypackage.MyClass.class), and a ResourceBundle called MyClass.properties in com.mypackage.resources:

 openIcon = myOpenIcon.png
 
then resourceMap.getIcon("openIcon") would load the image file called "myOpenIcon.png" from the resources subdirectory, effectively like this:
 String filename = myResourceMap.getResourcesDir() + "myOpenIcon.png";
 URL url = myResourceMap.getClassLoader().getResource(filename);
 new ImageIcon(iconURL);
 

Parameters:
key the name of the resource
Returns:
the ImageIcon value of the resource named key
Throws:
ResourceMap.LookupException if an error occurs during lookup or string conversion
java.lang.IllegalArgumentException if key is null
See also:
getObject(java.lang.String,java.lang.Class)
 
     public final ImageIcon getImageIcon(String key) { 
 	return (ImageIcon)getObject(keyImageIcon.class); 
     }

    
A convenience method that's shorthand for calling: getObject(key, Font.class). This method relies on the Font ResourceConverter that's registered by this class. Font resources may be defined with strings that are recognized by java.awt.Font.decode(java.lang.String), face-STYLE-size. For example:
 myFont = Arial-PLAIN-12
 

Parameters:
key the name of the resource
Returns:
the Font value of the resource named key
Throws:
ResourceMap.LookupException if an error occurs during lookup or string conversion
IllegalResourceConverteron if key is null
See also:
getObject(java.lang.String,java.lang.Class)
ResourceConverter.forType(java.lang.Class)
java.awt.Font.decode(java.lang.String)
 
     public final Font getFont(String key) { 
 	return (Font)getObject(keyFont.class); 
     }

    
A convenience method that's shorthand for calling: getObject(key, Color.class). This method relies on the Color ResourceConverter that's registered by this class. It defines an improved version of Color.decode() that supports colors with an alpha channel and comma separated RGB[A] values. Legal format for color resources are:
 myHexRGBColor = #RRGGBB 
 myHexAlphaRGBColor = #AARRGGBB
 myRGBColor = R, G, B
 myAlphaRGBColor = R, G, B, A
 
The first two examples, with the leading "#" encode the color with 3 or 4 hex values and the latter with integer values between 0 and 255. In both cases the value represented by "A" is the color's (optional) alpha channel.

Parameters:
key the name of the resource
Returns:
the Color value of the resource named key
Throws:
ResourceMap.LookupException if an error occurs during lookup or string conversion
java.lang.IllegalArgumentException ResourceConverter is null
See also:
getObject(java.lang.String,java.lang.Class)
ResourceConverter.forType(java.lang.Class)
 
     public final Color getColor(String key) { 
 	return (Color)getObject(keyColor.class); 
     }

    
A convenience method that's shorthand for calling: getObject(key, KeyStroke.class). This method relies on the KeyStroke ResourceConverter that's registered by this class and uses javax.swing.KeyStroke.getKeyStroke(char) to convert strings.

Parameters:
key the name of the resource
Returns:
the KeyStroke value of the resource named key
Throws:
ResourceMap.LookupException if an error occurs during lookup or string conversion
java.lang.IllegalArgumentException if key is null
See also:
getObject(java.lang.String,java.lang.Class)
javax.swing.KeyStroke.getKeyStroke(char)
 
     public final KeyStroke getKeyStroke(String key) {
 	return (KeyStroke)getObject(keyKeyStroke.class); 
     }

    
A convenience method that's shorthand for calling: getKeyStroke(key).getKeyCode(). If there's no resource named key then null is returned.

Parameters:
key the name of the resource
Returns:
the KeyCode value of the resource named key
Throws:
ResourceMap.LookupException if an error occurs during lookup or string conversion
java.lang.IllegalArgumentException if key is null
See also:
getObject(java.lang.String,java.lang.Class)
 
     public Integer getKeyCode(String key) {
 	KeyStroke ks = getKeyStroke(key);
 	return (ks != null) ? new Integer(ks.getKeyCode()) : null;
     }

    
 
     public static class PropertyInjectionException extends RuntimeException {
 	private final String key;
 	private final Component component;
 	private final String propertyName;

Constructs an instance of this class with some useful information about the failure.

Parameters:
msg the detail message
key the name of the resource
component the component whose property couldn't be set
propertyName the name of the component property
 
 	public PropertyInjectionException(String msgString keyComponent componentString propertyName) {
 	    super(String.format("%s: resource %s, property %s, component %s"msgkeypropertyNamecomponent));
             this. = key;
 	    this. = component;
 	    this. = propertyName;
 	}

Returns the the name of resource whose value was to be used to set the property

Returns:
the resource name
 
 	public String getKey() {
 	    return ;
 	}

Returns the component whose property could not be set

Returns:
the component
 
 	public Component getComponent() {
 	    return ;
 	}

Returns the the name of property that could not be set

Returns:
the property name
 
 	public String getPropertyName() {
 	    return ;
 	}
     }
 
     private void injectComponentProperty(Component componentPropertyDescriptor pdString key) {
 	Method setter = pd.getWriteMethod();
 	Class type = pd.getPropertyType();
 	if ((setter != null) && (type != null) && containsKey(key)) {
 	    Object value = getObject(keytype);
             String propertyName = pd.getName();
             try {
                 // Note: this could be generalized, we could delegate 
                 // to a component property injector.
                 if ("text".equals(propertyName) && (component instanceof AbstractButton)) {
                     MnemonicText.configure(component, (String)value);
                 }
                 else if ("text".equals(propertyName) && (component instanceof JLabel)) {
                     MnemonicText.configure(component, (String)value);
                 }
                 else {
                     setter.invoke(componentvalue);
                 }
             }
             catch (Exception e) {
                 String pdn = pd.getName();
                 String msg = "property setter failed";
                 RuntimeException re = new PropertyInjectionException(msgkeycomponentpdn);
                 re.initCause(e);
                 throw re;
            }
        }
        else if (type != null) {
            String pdn = pd.getName();
            String msg = "no value specified for resource";
            throw new PropertyInjectionException(msgkeycomponentpdn);
        }
	else if (setter == null) {
	    String pdn = pd.getName();
	    String msg = "can't set read-only property";
	    throw new PropertyInjectionException(msgkeycomponentpdn);
    }
    private void injectComponentProperties(Component component) {
	String componentName = component.getName();
	if (componentName != null) {
	    /* Optimization: punt early if componentName doesn't 
	     * appear in any componentName.propertyName resource keys
	     */
	    boolean matchingResourceFound = false;
	    for(String key : keySet()) {
                int i = key.lastIndexOf(".");
                if ((i != -1) && componentName.equals(key.substring(0, i))) {
		    matchingResourceFound = true;
		    break;
	    }
	    if (!matchingResourceFound) {
		return;
	    }
	    BeanInfo beanInfo = null;
	    try {
		beanInfo = Introspector.getBeanInfo(component.getClass());
 	    }
	    catch (IntrospectionException e) {
		String msg = "introspection failed";
		RuntimeException re = new PropertyInjectionException(msgnullcomponentnull);
		throw re;
	    }
	    PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();
	    if ((pds != null) && (pds.length > 0)) {
		for (String key : keySet()) {
                    int i = key.lastIndexOf(".");
                    String keyComponentName = (i == -1) ? null : key.substring(0, i);
		    if (componentName.equals(keyComponentName)) {
			if ((i+1) == key.length()) {  
			    /* key has no property name suffix, e.g. "myComponentName."
			     * This is probably a mistake.
			     */
			    String msg = "component resource lacks property name suffix";
			    .warning(msg);
			    break;
			String propertyName = key.substring(i+1);
			boolean matchingPropertyFound = false;
			for(PropertyDescriptor pd : pds) {
			    if (pd.getName().equals(propertyName)) {
				injectComponentProperty(componentpdkey); 
				matchingPropertyFound = true;
				break;
			    }
			if (!matchingPropertyFound) {
			    String msg = String.format(
			        "[resource %s] component named %s doesn't have a property named %s",
				keycomponentNamepropertyName);
			    .warning(msg);
		    }
	    }
    }

    
Set each property in target to the value of the resource named componentName.propertyName, where componentName is the value of the target component's name property, i.e. the value of target.getName(). The type of the resource must match the type of the corresponding property. Properties that aren't defined by a resource aren't set.

For example, given a button configured like this:

 myButton = new JButton();
 myButton.setName("myButton");
 
And a ResourceBundle properties file with the following resources:
 myButton.text = Hello World
 myButton.foreground = 0, 0, 0 
 myButton.preferredSize = 256, 256
 
Then injectComponent(myButton) would initialize myButton's text, foreground, and preferredSize properties to Hello World, new Color(0,0,0), and new Dimension(256,256) respectively.

This method calls getObject(java.lang.String,java.lang.Class) to look up resources and it uses java.beans.Introspector.getBeanInfo() to find the target component's properties.

If target is null an IllegalArgumentException is thrown. If a resource is found that matches the target component's name but the corresponding property can't be set, an (unchecked) ResourceMap.PropertyInjectionException is thrown.

Parameters:
target the Component to inject
Throws:
ResourceMap.LookupException if an error occurs during lookup or string conversion
ResourceMap.PropertyInjectionException if a property specified by a resource can't be set
java.lang.IllegalArgumentException if target is null
See also:
injectComponents(java.awt.Component)
getObject(java.lang.String,java.lang.Class)
ResourceConverter.forType(java.lang.Class)
    public void injectComponent(Component target) {
	if (target == null) {
	    throw new IllegalArgumentException("null target");
    }


    
Applies injectComponent(java.awt.Component) to each Component in the hierarchy with root root.

Parameters:
root the root of the component hierarchy
Throws:
ResourceMap.PropertyInjectionException if a property specified by a resource can't be set
java.lang.IllegalArgumentException if target is null
See also:
injectComponent(java.awt.Component)
    public void injectComponents(Component root) {
	if (root instanceof JMenu) {
	    /* Warning: we're bypassing the popupMenu here because
	     * JMenu#getPopupMenu creates it; doesn't seem right
	     * to do so at injection time.  Unfortunately, this
	     * means that attempts to inject the popup menu's 
	     * "label" property will fail.
	     */
	    JMenu menu = (JMenu)root;
	    for(Component child : menu.getMenuComponents()) {
	    }
	else if (root instanceof Container) {
	    Container container = (Container)root;
	    for(Component child : container.getComponents()) {
	    }
    }

    
Unchecked exception thrown by ResourceMap.injectFields(java.lang.Object) when an error occurs while attempting to set a field (a field that had been marked with @Resource).

    public static class InjectFieldException extends RuntimeException {
	private final Field field;
	private final Object target;
	private final String key;

Constructs an instance of this class with some useful information about the failure.

Parameters:
msg the detail message
field the Field we were attempting to set
target the object whose field we were attempting to set
key the name of the resource
	public InjectFieldException(String msgField fieldObject targetString key) {
	    super(String.format("%s: resource %s, field %s, target %s"msgkeyfieldtarget));
	    this. = field;
	    this. = target;
            this. = key;
	}

Return the Field whose value couldn't be set.

Returns:
the field whose value couldn't be set
	public Field getField() {
	    return ;
	}

Return the Object whose Field we were attempting to set

Returns:
the Object whose Field we were attempting to set
	public Object getTarget() {
	    return ;
	}

Returns the type of the name of resource for which lookup failed.

Returns:
the resource name
	public String getKey() {
	    return ;
    }
    private void injectField(Field fieldObject targetString key) {
	Class type = field.getType();
	if (type.isArray()) {
	    type = type.getComponentType();
	    Pattern p = Pattern.compile(key + "\\[([\\d]+)\\]");  // matches key[12]
	    List<StringarrayKeys = new ArrayList<String>();
	    for(String arrayElementKey : keySet()) {
		Matcher m = p.matcher(arrayElementKey);
		if (m.matches()) {
		    /* field's value is an array, arrayElementKey is a resource 
		     * name of the form "MyClass.myArray[12]" and m.group(1) 
		     * matches the array index.  Set the index element 
		     * of the field's array to the value of the resource.
		     */
		    Object value = getObject(arrayElementKeytype);  
		    if (!field.isAccessible()) {
			field.setAccessible(true);
		    }
		    try {
			int index = Integer.parseInt(m.group(1));
			Array.set(field.get(target), indexvalue);
		    } 
		    /* Array.set throws IllegalArgumentException, ArrayIndexOutOfBoundsException
		     * field.get throws IllegalAccessException(Checked), IllegalArgumentException
		     * Integer.parseInt throws NumberFormatException (Checked)
		     */
		    catch (Exception e) {
			String msg = "unable to set array element";
			InjectFieldException ife = new InjectFieldException(msgfieldtargetkey);
			ife.initCause(e);
			throw ife;
		    }
	    }
	else {  // field is not an array
	    Object value = getObject(keytype);
	    if (value != null) {
		if (!field.isAccessible()) {
		    field.setAccessible(true);
		try {
		    field.set(targetvalue);
		/* Field.set throws IllegalAccessException, IllegalArgumentException, 
		 * ExceptionInInitializerError
		 */
		catch (Exception e) {
		    String msg = "unable to set field's value";
		    InjectFieldException ife = new InjectFieldException(msgfieldtargetkey);
		    ife.initCause(e);
		    throw ife;
	    }
    }

    
Set each field with a @Resource annotation in the target object, to the value of a resource whose name is the simple name of the target class followed by "." followed by the name of the field. If the key @Resource parameter is specified, then a resource with that name is used instead. Array valued fields can also be initialized with resources whose names end with "[index]". For example:
 class MyClass {
   @Resource String sOne; 
   @Resource(key="sTwo") String s2; 
   @Resource int[] numbers = new int[2];
 }
 
Given the previous class and the following resource file:
 MyClass.sOne = One
 sTwo = Two
 MyClass.numbers[0] = 10
 MyClass.numbers[1] = 11
 
Then injectFields(new MyClass()) would initialize the MyClass sOne field to "One", the s2 field to "Two", and the two elements of the numbers array to 10 and 11.

If target is null an IllegalArgumentException is thrown. If an error occurs during resource lookup, then an unchecked LookupException is thrown. If a target field marked with @Resource can't be set, then an unchecked InjectFieldException is thrown.

Parameters:
target the object whose fields will be initialized
Throws:
ResourceMap.LookupException if an error occurs during lookup or string conversion
ResourceMap.InjectFieldException if a field can't be set
java.lang.IllegalArgumentException if target is null
See also:
getObject(java.lang.String,java.lang.Class)
    public void injectFields(Object target) {
	if (target == null) {
	    throw new IllegalArgumentException("null target");
	Class targetType = target.getClass();
	if (targetType.isArray()) {
	    throw new IllegalArgumentException("array target");
	String keyPrefix = targetType.getSimpleName() + ".";
	for (Field field : targetType.getDeclaredFields()) {
	    Resource resource = field.getAnnotation(Resource.class);
	    if (resource != null) {
		String rKey = resource.key();
		String key = (rKey.length() > 0) ? rKey : keyPrefix + field.getName();
		injectField(fieldtargetkey);
	    }
    }
    /* Register ResourceConverters that are defined in this class
     * and documented here.
     */
    static {
	ResourceConverter[] stringConverters = {
	    new ColorStringConverter(),
	    new IconStringConverter(),
	    new ImageStringConverter(),
	    new FontStringConverter(),
            new DimensionStringConverter(),
            new PointStringConverter(),
            new RectangleStringConverter(),
            new InsetsStringConverter(),
            new EmptyBorderStringConverter()
	};
	for (ResourceConverter sc : stringConverters) {
	    ResourceConverter.register(sc);
    }
    /* If path doesn't have a leading "/" then the resourcesDir
     * is prepended, otherwise the leading "/" is removed. 
     */
    private static String resourcePath(String pathResourceMap resourceMap) {
	String rPath = path;
	if (path == null) {
	    rPath = null;
	else if (path.startsWith("/")) {
	    rPath = (path.length() > 1) ? path.substring(1) : null;
	else {
	    rPath = resourceMap.getResourcesDir() + path;
	return rPath;
    }
    private static ImageIcon loadImageIcon(String sResourceMap resourceMap)
        throws ResourceConverterException 
    {
	String rPath = resourcePath(sresourceMap);
	if (rPath == null) {
	    String msg = String.format("invalid image/icon path \"%s\""s);
	    throw new ResourceConverterException(msgs);
	URL url = resourceMap.getClassLoader().getResource(rPath);
	if (url != null) {
	    return new ImageIcon(url);
	else {
	    String msg = String.format("couldn't find Icon resource \"%s\""s);
	    throw new ResourceConverterException(msgs);
    }
    private static class FontStringConverter extends ResourceConverter {
	    super(Font.class);
	/* Just delegates to Font.decode.
	 * Typical string is: face-STYLE-size, for example "Arial-PLAIN-12"
	 */
	    return Font.decode(s);
    }
    private static class ColorStringConverter extends ResourceConverter {
	    super(Color.class);
	private void error(String msgString sException ethrows ResourceConverterException  {
	    throw new ResourceConverterException(msgse);
	private void error(String msgString sthrows ResourceConverterException {
	    error(msgsnull);
	/* An improved version of Color.decode() that supports colors
	 * with an alpha channel and comma separated RGB[A] values.
	 * Legal format for color resources are:
	 * "#RRGGBB",  "#AARRGGBB", "R, G, B", "R, G, B, A"
	 * Thanks to Romain Guy for the code.
	 */
	    Color color = null;
	    if (s.startsWith("#")) {
		switch (s.length()) {
		    // RGB/hex color
		case 7:
		    color = Color.decode(s);
		    break;
		    // ARGB/hex color
		case 9:
		    int alpha = Integer.decode(s.substring(0, 3));
		    int rgb = Integer.decode("#" + s.substring(3));
		    color = new Color(alpha << 24 | rgbtrue);
		    break;
		default:
		    throw new ResourceConverterException("invalid #RRGGBB or #AARRGGBB color string"s);
	    } 
	    else {
		String[] parts = s.split(",");
		if (parts.length < 3 || parts.length > 4) {
		    throw new ResourceConverterException("invalid R, G, B[, A] color string"s);
		try {
		    // with alpha component
		    if (parts.length == 4) {
			int r = Integer.parseInt(parts[0].trim());
			int g = Integer.parseInt(parts[1].trim());
			int b = Integer.parseInt(parts[2].trim());
			int a = Integer.parseInt(parts[3].trim());
			color = new Color(rgba);
		    } else {
			int r = Integer.parseInt(parts[0].trim());
			int g = Integer.parseInt(parts[1].trim());
			int b = Integer.parseInt(parts[2].trim());
			color = new Color(rgb);
		    }
		    throw new ResourceConverterException("invalid R, G, B[, A] color string"se);
	    }
	    return color;
    }
    private static class IconStringConverter extends ResourceConverter {
	    super(Icon.class);
	public Object parseString(String sResourceMap resourceMapthrows ResourceConverterException {
	    return loadImageIcon(sresourceMap);
	public boolean supportsType(Class testType) {
	    return testType.equals(Icon.class) || testType.equals(ImageIcon.class);
    }
    private static class ImageStringConverter extends ResourceConverter {
	    super(Image.class);
	public Object parseString(String sResourceMap resourceMapthrows ResourceConverterException {
	    return loadImageIcon(sresourceMap).getImage();
    }
    private static class KeyStrokeStringConverter extends ResourceConverter {
	    super(KeyStroke.class);
	public Object parseString(String sResourceMap ignore) {
            if (s.contains("shortcut")) {
                int k = Toolkit.getDefaultToolkit().getMenuShortcutKeyMask();
                s = s.replaceAll("shortcut", (k == .) ? "meta" : "control");
            }
	    return KeyStroke.getKeyStroke(s);
    }
    /* String s is assumed to contain n number substrings separated by
     * commas.  Return a list of those integers or null if there are too
     * many, too few, or if a substring can't be parsed.  The format
     * of the numbers is specified by Double.valueOf().
     */
    private static List<DoubleparseDoubles(String sint nString errorMsgthrows ResourceConverterException {
        String[] doubleStrings = s.split(","n + 1);
        if (doubleStrings.length != n) {
            throw new ResourceConverterException(errorMsgs);
        }
        else {
            List<Doubledoubles = new ArrayList<Double>(n);
            for(String doubleString : doubleStrings) {
                try {
                    doubles.add(Double.valueOf(doubleString));
                }
                catch(NumberFormatException e) {
                    throw new ResourceConverterException(errorMsgse);
                }
            }
            return doubles;
        }
    }
    private static class DimensionStringConverter extends ResourceConverter {
	    super(Dimension.class);
            List<Doublexy = parseDoubles(s, 2, "invalid x,y Dimension string");
            Dimension d = new Dimension();
            d.setSize(xy.get(0), xy.get(1));
            return d;
    }
    private static class PointStringConverter extends ResourceConverter {
	    super(Point.class);
            List<Doublexy = parseDoubles(s, 2, "invalid x,y Point string");
            Point p = new Point();
            p.setLocation(xy.get(0), xy.get(1));
            return p;
    }
    private static class RectangleStringConverter extends ResourceConverter {
	    super(Rectangle.class);
            List<Doublexywh = parseDoubles(s, 4, "invalid x,y,width,height Rectangle string");
            Rectangle r = new Rectangle();
            r.setFrame(xywh.get(0), xywh.get(1), xywh.get(2), xywh.get(3));
            return r;
    }
    private static class InsetsStringConverter extends ResourceConverter {
	    super(Insets.class);
            List<Doubletlbr = parseDoubles(s, 4, "invalid top,left,bottom,right Insets string");
            return new Insets(tlbr.get(0).intValue(), tlbr.get(1).intValue(), tlbr.get(2).intValue(), tlbr.get(3).intValue());
    }
    private static class EmptyBorderStringConverter extends ResourceConverter {
	    super(EmptyBorder.class);
            List<Doubletlbr = parseDoubles(s, 4, "invalid top,left,bottom,right EmptyBorder string");
            return new EmptyBorder(tlbr.get(0).intValue(), tlbr.get(1).intValue(), tlbr.get(2).intValue(), tlbr.get(3).intValue());
    }