Simple Variable Language

##### Table of Contents

## 1 - Simple Variable Language

The `org.apache.juneau.svl` package defines an API for a language called "Simple Variable Language". In a nutshell, Simple Variable Language (or SVL) is text that contains variables of the form "$varName{varKey}".

Variables can be recursively nested within the varKey (e.g. "$FOO{$BAR{xxx},$BAZ{xxx}}"). Variables can also return values that themselves contain more variables.

The {@link org.apache.juneau.svl.VarResolver} class is used to resolve variables. The {@link org.apache.juneau.svl.VarResolver#DEFAULT} resolver will resolve "$S{systemProperty}" and "$E{envVariable}" variables.

// Use the default variable resolver to resolve a string that contains $S (system property) variables String myProperty = VarResolver.DEFAULT.resolve("The Java home directory is $S{java.home}");

The following shows how variables can be arbitrarily nested...

// Look up a property in the following order: // 1) MYPROPERTY environment variable. // 2) 'my.property' system property if environment variable not found. // 3) 'not found' string if system property not found. String myproperty = VarResolver.DEFAULT.resolve("$E{MYPROPERTY,$S{my.property,not found}}");

### 1.1 - Vars

Variables are defined through the {@link org.apache.juneau.svl.Var} API.

// Create a var resolver that extends the default resolver and appends our own "$URLEncode{...}" variable // First create our var. public class UrlEncodeVar extends SimpleVar { // Must have a no-arg constructor! public UrlEncodeVar() { super("URLEncode"); } // The method we must implement @Override public String resolve(VarResolverSession session, String varVal) { return URLEncoder.encode(varVal, "UTF-8"); } } // Next create a var resolver that extends the existing DEFAULT resolver // that supports resolving system properties. VarResolver r = VarResolver.DEFAULT.builder().vars(UrlEncodeVar.class).build(); // Retrieve a system property and URL-encode it if necessary. String myProperty = r.resolve("$URLEncode{$S{my.property}}");

The following shows the class hierarchy of the {@link org.apache.juneau.svl.Var} class and all current predefined implementations.

- {@link org.apache.juneau.svl.Var} - Superclass of all vars.
  - {@link org.apache.juneau.svl.SimpleVar} - Superclass of all vars that return strings.
    - {@link org.apache.juneau.svl.DefaultingVar} - Variables that define a default value if the resolve method returns null.
      - {@link org.apache.juneau.svl.MapVar} - Variables that pull values from maps.
        - {@link org.apache.juneau.svl.vars.SystemPropertiesVar} - Resolves system properties.
      - {@link org.apache.juneau.svl.vars.ArgsVar} - Resolves variables from an {@link org.apache.juneau.utils.Args} object.
      - `ConfigFileVar` - Resolves variables from a {@link org.apache.juneau.ini.ConfigFile} object.
      - {@link org.apache.juneau.svl.vars.EnvVariablesVar} - Resolves environment variables.
      - {@link org.apache.juneau.svl.vars.ManifestFileVar} - Resolves variables from a {@link org.apache.juneau.utils.ManifestFile} object.
      - {@link org.apache.juneau.rest.vars.ServletInitParamVar} - Resolves servlet initialization parameters.
    - {@link org.apache.juneau.svl.MultipartVar} - Variables that consist of 2 or more comma-delimited arguments.
      - {@link org.apache.juneau.rest.vars.LocalizationVar} - Resolves localized strings for an HTTP request.
    - {@link org.apache.juneau.rest.vars.RequestVar} - Resolves specialized HTTP request values.
    - {@link org.apache.juneau.rest.vars.UrlEncodeVar} - URL-encodes the value inside the variable.
  - {@link org.apache.juneau.svl.StreamedVar} - Superclass of all vars that stream their value to writers.
    - {@link org.apache.juneau.rest.vars.SerializedRequestAttrVar} - Resolves HTTP request attribute values passed through a {@link org.apache.juneau.serializer.Serializer}.

### 1.2 - VarResolvers and VarResolverSessions

The main class for performing variable resolution is {@link org.apache.juneau.svl.VarResolver}. Two methods are provided for resolving variables:

- {@link org.apache.juneau.svl.VarResolver#resolve(String)} - Resolves variables and returns the results as a simple string.
- {@link org.apache.juneau.svl.VarResolver#resolveTo(String,Writer)} - Resolves variables and sends results to a writer.

Var resolvers can have zero or more context objects associated with them. Some {@link org.apache.juneau.svl.Var Vars} rely on the existence of some other object, such as an {@link org.apache.juneau.utils.Args} object for {@link org.apache.juneau.svl.vars.ArgsVar} or a {@link org.apache.juneau.ini.ConfigFile} for a `ConfigFileVar`. These object dependencies are made by setting context objects on the var resolver.

Context objects are set through the {@link org.apache.juneau.svl.VarResolverBuilder #contextObject(String,Object)} method. They can be any class type.

Context objects are used by {@link org.apache.juneau.svl.Var Vars} by calling the {@link org.apache.juneau.svl.VarResolverSession#getSessionObject(Class, String)} method.

In addition to context objects, there are also session objects. Session objects are considered more ephemeral than context objects. While a context object is unlikely to ever change, a session object may change on every use of the var resolver. For example, the server API defines various `Var` objects that use the `RestRequest` object as a session object for the duration of a single HTTP request.

Session objects are used by calling the {@link org.apache.juneau.svl.VarResolver#createSession()} or {@link org.apache.juneau.svl.VarResolver#createSession(Map)} methods to create an instance of a {@link org.apache.juneau.svl.VarResolverSession} object that contains {@link org.apache.juneau.svl.VarResolverSession#resolve(String)} and {@link org.apache.juneau.svl.VarResolverSession#resolveTo(String,Writer)} methods that are identical to {@link org.apache.juneau.svl.VarResolver#resolve(String)} and {@link org.apache.juneau.svl.VarResolver#resolveTo(String, Writer)} except that the `Var` objects have access to the session objects through the {@link org.apache.juneau.svl.VarResolverSession#getSessionObject(Class, String)} method. Session objects are specified through either the {@link org.apache.juneau.svl.VarResolver#createSession(Map)} method or the {@link org.apache.juneau.svl.VarResolverSession#sessionObject(String, Object)} methods.

Like Context object, Session objects are used by {@link org.apache.juneau.svl.Var Vars} by calling the {@link org.apache.juneau.svl.VarResolverSession#getSessionObject(Class, String)} method.

Var resolvers can be cloned and extended by using the {@link org.apache.juneau.svl.VarResolver#builder()} method. Cloning a resolver will copy it's {@link org.apache.juneau.svl.Var} class names and context objects.

###### Example:

// Create a resolver that copies the default resolver and adds $C and $ARG vars. VarResolver myVarResolver = VarResolver.DEFAULT.builder().vars(ConfigFileVar.class, ArgsVar.class).build();

### 1.3 - Other Notes

- The escape character '\' can be used when necessary to escape the following characters: `$ , { }`
- WARNING: It is possible to cause {@link java.lang.StackOverflowError StackOverflowErrors} if your nested variables result in a recursive loop (e.g. the environment variable `'MYPROPERTY'` has the value `'$E{MYPROPERTY}'`). So don't do that!
- As a general rule, this class tries to be as efficient as possible by not creating new strings when not needed.
  For example, calling the resolve method on a string that doesn't contain variables (e.g. `resolver.resolve("foobar")`) will simply be a no-op and return the same string.