11 Resource Management - Reference Documentation
Authors: Andres Almiray
Version: 1.2.0
Table of Contents
11 Resource Management
This chapter describes resource management and injection features available to all applications.11.1 Locating Classpath Resources
Resources can be loaded form the classpath using the standard mechanism provided by the Java runtime, that is, ask aClassLoader instance to load a resource URL or obtain an InputStream that points to the resource.But the code can get quite verbose, take for example the following view code that locates a text file and displays it on a text componentscrollPane {
textArea(columns: 40, rows: 20,
text: this.class.classLoader.getResource('someTextFile.txt').text)
}GriffonApplication and GriffonArtifact have a set of methods that simply working with resources. Those methods are provided by ResourceHandler:
URL getResourceAsURL(String resourceName)InputStream getResourceAsStream(String resourceName)List<URL> getResources(String resourceName)
scrollPane {
textArea(columns: 40, rows: 20,
text: app.getResourceAsURL('someTextFile.txt').text)
}11.2 Resolving Configured Resources
Parameterized resources may be resolved by an application by leveraging the behavior exposed bygriffon.core.resources.ResourceResolver which every single griffon.core.GriffonApplication implements. This interface exposes the following methods:
- Object resolveResource(String key)
- Object resolveResource(String key, Locale locale)
- Object resolveResource(String key, Object[] args)
- Object resolveResource(String key, Object[] args, Locale locale)
- Object resolveResource(String key, List args)
- Object resolveResource(String key, List args, Locale locale)
- Object resolveResource(String key, Map args)
- Object resolveResource(String key, Map args, Locale locale)
NoSuchResourceException if a resource could not be resolved given the key sent as argument. The following methods take and additional defaultValue parameter that may be used if no configured resource is found. If this optional parameter were to be null then the key is used as the literal value of the resource; in other words, these methods never throw NoSuchResourceException nor return null unless the passed in key is null.
- Object resolveResource(String key, Object defaultValue)
- Object resolveResource(String key, Object defaultValue, Locale locale)
- Object resolveResource(String key, Object[] args, Object defaultValue)
- Object resolveResource(String key, Object[] args, Object defaultValue, Locale locale)
- Object resolveResource(String key, List args, Object defaultValue)
- Object resolveResource(String key, List args, Object defaultValue, Locale locale)
- Object resolveResource(String key, Map args, Object defaultValue)
- Object resolveResource(String key, Map args, Object defaultValue, Locale locale)
app.resolveResource('menu.icon')List as arguments are meant to be used from Groovy code whereas those that take an Object[] are meant for Java code; this leads to better idiomatic code as the following examples revealapp.resolveResource('groovy.icon.resource', ['small'])
app.resolveResource("java.icon.resource", new Object[]{"large"});List versions in Java, like thisimport static java.util.Arrays.asList; … app.resolveResource("hybrid.icon.resource", asList("medium"));
Resource Formats
There are three types of resource formats supported by default. Additional formats may be supported if the right plugins are installed. Resources may be configured using either properties files or Groovy scripts, please refer to the configuration section.Standard FormatThe first set of resource formats are those supported by the JDK'sMessageFormat facilities. These formats work with all versions of the resolveResource() method that take a List or an Object[] as arguments. Examples follow. First the resource definitions stored in a properties filemenu.icon = /img/icons/menu-{0}.pnggriffon-app/resources/img/icons whose filenames are menu-small.png, menu-medium.png and menu-large.png a component may resolve any of them withObject largeIcon = app.resolveResource('menu.icon', ['large'])MessageFormat) and can only be resolved by Griffon. This format uses symbols instead of numbers as placeholders for arguments. Thus the previous messages can be rewritten as followsmenu.icon = /img/icons/menu-{:size}.pngObject largeIcon = app.resolveResource('menu.icon', [size: 'large'])java.awt.Rectangle resourcesimport java.awt.Rectangledirect.instance = new Rectangle(10i, 20i, 30i, 40i) computed.instance = { x, y, w, h -> new Rectangle(x, y, w, h) }
resolveResource is marked as Object but you'll get a String from the first two formats. You'll have to make use of property editors in order to transform the value into the correct type. Injected resources are automatically transformed to the expected type.Here's how it can be doneimport javax.swing.Icon import java.beans.PropertyEditor import java.beans.PropertyEditorManager … Object iconValue = app.resolveResource('menu.icon', ['large']) PropertyEditor propertyEditor = PropertyEditorManager.findEditor(Icon) propertyEditor.setAsText(String.valueOf(iconValue)) Icon icon = propertyEditor.getValue()
11.3 Configuration
Resources may be configured in either properties files or Groovy scripts. Properties files have precedence over Groovy scripts should there be two files that match the same basename. The default configured basename is "resources", thus the application will search for the following resources in the classpath
- resources.groovy
- resources.properties
Config.groovy
resources.basenames = ['resources', 'icons']Both properties files and Groovy scripts are subject to the same locale aware loading mechanism described in Runtime Configuration, that is, the following resources will be searched for and loaded for a Locate set to de_CH_Basel
- resources.groovy
- resources.properties
- resources_de.groovy
- resources_de.properties
- resources_de_CH.groovy
- resources_de_CH.properties
- resources_de_CH_Basel.groovy
- resources_de_CH_Basel.properties
griffon-app/i18n as these files are automatically processed with native2ascii when packaging is executed. The default resources.properties file is placed in this directory upon creating an application with create-app.
11.4 Automatically Injected Resources
Resources may be automatically injected to any instance created using the application's facilities (by callingnewInstance() on the application instance or any Griffon artifact instance). Injection points must be annotated with @griffon.core.resources.InjectedResource which can only be set on properties (Groovy) or fields (Java and Groovy). @InjectedResource is a perfect companion to models as the following example showsresources.properties
sample.SampleModel.griffonLogo = /griffon-logo-48x48.png
logo = /griffon-logo-{0}x{0}.pngpackage sampleimport griffon.core.resources.InjectedResource import javax.swing.Iconclass SampleModel { @InjectedResource Icon griffonLogo @InjectedResource(key='logo', args=['16']) Icon smallGriffonLogo @InjectedResource(key='logo', args=['64']) Icon largeGriffonLogo }
@InjectedResource assumes a naming convention in order to determine the resource key to use. These are the rules applied by the default ResourcesInjector:
- If a value is specified for the
keyargument then use it as is - otherwise construct a key based in the field name prefixed with the full qualified class name of the field's owner
11.5 Injecting Resource Resolution Behavior
Any component may gain the ability to resolve messages through the application's ResourceResolver. You only need annotate the class withgriffon.transform.ResourceResolverAware and it will automatically gain all methods exposed by ResourceResolver.This feature is just a shortcut to avoid reaching for the application instance from objects that do not hold a reference to it.
11.6 Property Editors
Resource injection makes use of the PropertyEditor mechanism provided by thejava.beans package. The default ResourcesInjector queries PropertyEditorManager whenever a resource value must be transformed to a target type.PropertyEditorManager provides methods for registering custom PropertyEditors, it also follows a class name convention to load PropertyEditors should a custom one is not programmatically registered. Griffon applications will automatically load and register PropertyEditors from the following classpath resource: /META-INF/services/java.beans.PropertyEditor. Each line follows the format
target.type = full.qualified.classnameThe following table enumerates the default PropertyEditors loaded by Griffon at startup. Plugins such as swing and javafx may register additional editors.| Type | Editor Class |
|---|---|
| java.lang.String | griffon.core.resources.editors.StringPropertyEditor |
| java.io.File | griffon.core.resources.editors.FilePropertyEditor |
| java.net.URL | griffon.core.resources.editors.URLPropertyEditor |
| java.net.URI | griffon.core.resources.editors.URIPropertyEditor |
/META-INF/services/java.beans.PropertyEditor inside griffon-rt-1.2.0.jar) for these editors is thusjava.lang.String = griffon.core.resources.editors.StringPropertyEditor
java.io.File = griffon.core.resources.editors.FilePropertyEditor
java.net.URL = griffon.core.resources.editors.URLPropertyEditor
java.net.URI = griffon.core.resources.editors.URIPropertyEditor