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}.png
griffon-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}.png
Object 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}.png
package 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
key
argument 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.classname
The 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