freemarker.core

## Interface DirectiveCallPlace

    public interface DirectiveCallPlace

Gives information about the place where a directive is called from, also lets you attach a custom data object to that place. Each directive call in a template has its own `DirectiveCallPlace` object (even when they call the same directive with the same parameters). The life cycle of the `DirectiveCallPlace` object is bound to the `Template` object that contains the directive call. Hence, the `DirectiveCallPlace` object and the custom data you put into it is cached together with the `Template` (and templates are normally cached - see `Configuration.getTemplate(String)`). The custom data is normally initialized on demand, that is, when the directive call is first executed, via `getOrCreateCustomData(Object, ObjectFactory)`.

Currently this method doesn't give you access to the `Template` object, because it's probable that future versions of FreeMarker will be able to use the same parsed representation of a "file" for multiple `Template` objects. Then the call place will be bound to the parsed representation, not to the `Template` objects that are based on it.

Don't implement this interface yourself, as new methods can be added to it any time! It's only meant to be implemented by the FreeMarker core.

This interface is currently only used for custom directive calls (that is, a `<@...>` that calls a `TemplateDirectiveModel`, `TemplateTransformModel`, or a macro).

Since:
  2.3.22
See Also:
  `Environment.getCurrentDirectiveCallPlace()`

### Method Summary

All Methods Instance Methods Abstract Methods
`int` `getBeginColumn()` The 1-based column number of the first character of the directive call in the template source code, or -1 if it's not known.
`int` `getBeginLine()` The 1-based line number of the first character of the directive call in the template source code, or -1 if it's not known.
`int` `getEndColumn()` The 1-based column number of the last character of the directive call in the template source code, or -1 if it's not known.
`int` `getEndLine()` The 1-based line number of the last character of the directive call in the template source code, or -1 if it's not known.
`Object` `getOrCreateCustomData(Object providerIdentity, ObjectFactory objectFactory)` Returns the custom data, or if that's `null`, then it creates and stores it in an atomic operation then returns it.
`boolean` `isNestedOutputCacheable()` Tells if the nested content (the body) can be safely cached, as it only depends on the template content (not on variable values and such) and has no side-effects (other than writing to the output).

### Method Detail

#### getBeginColumn

    int getBeginColumn()

The 1-based column number of the first character of the directive call in the template source code, or -1 if it's not known.

#### getBeginLine

    int getBeginLine()

The 1-based line number of the first character of the directive call in the template source code, or -1 if it's not known.

#### getEndColumn

    int getEndColumn()

The 1-based column number of the last character of the directive call in the template source code, or -1 if it's not known. If the directive has an end-tag (`</@...>`), then it points to the last character of that.

#### getEndLine

    int getEndLine()

The 1-based line number of the last character of the directive call in the template source code, or -1 if it's not known. If the directive has an end-tag (`</@...>`), then it points to the last character of that.

#### getOrCreateCustomData

    Object getOrCreateCustomData(Object providerIdentity,
                                 ObjectFactory objectFactory)
                          throws CallPlaceCustomDataInitializationException

Returns the custom data, or if that's `null`, then it creates and stores it in an atomic operation then returns it. This method is thread-safe, however, it doesn't ensure thread safe (like synchronized) access to the custom data itself. See the top-level documentation of `DirectiveCallPlace` to understand the scope and life-cycle of the custom data. Be sure that the custom data only depends on things that get their final value during template parsing, not on runtime settings.

This method will block other calls while the `objectFactory` is executing, thus, the object will be usually created only once, even if multiple threads request the value when it's still `null`. It doesn't stand though when `providerIdentity` mismatches occur (see later). Furthermore, then it's also possible that multiple objects created by the same `ObjectFactory` will be in use on the same time, because of directive executions already running in parallel, and because of memory synchronization delays (hardware dependent) between the threads.

Parameters:
  `providerIdentity` - This is usually the class of the `TemplateDirectiveModel` that creates (and uses) the custom data, or if you are using your own class for the custom data object (as opposed to a class from some more generic API), then that class. This is needed as the same call place might calls different directives depending on runtime conditions, and so it must be ensured that these directives won't accidentally read each other's custom data, ending up with class cast exceptions or worse. In the current implementation, if there's a `providerIdentity` mismatch (means, the `providerIdentity` object used when the custom data was last set isn't the exactly same object as the one provided with the parameter now), the previous custom data will be just ignored as if it was `null`. So if multiple directives that use the custom data feature use the same call place, the caching of the custom data can be inefficient, as they will keep overwriting each other's custom data. (In a more generic implementation the `providerIdentity` would be a key in a `IdentityHashMap`, but then this feature would be slower, while `providerIdentity` mismatches aren't occurring in most applications.)
  `objectFactory` - Called when the custom data wasn't yet set, to create its initial value. If this parameter is `null` and the custom data wasn't set yet, then `null` will be returned. The returned value of `ObjectFactory.createObject()` can be any kind of object, but can't be `null`.
Returns:
  The current custom data object, or possibly `null` if there was no `ObjectFactory` provided.
Throws:
  `CallPlaceCustomDataInitializationException` - If the `ObjectFactory` had to be invoked but failed.

#### isNestedOutputCacheable

    boolean isNestedOutputCacheable()

Tells if the nested content (the body) can be safely cached, as it only depends on the template content (not on variable values and such) and has no side-effects (other than writing to the output). Examples of cases that give `false`: `<@foo>Name:` `${name}`, `<@foo>Name: <#if showIt>Joe</#if></@foo>`. Examples of cases that give `true`: `<@foo>Name: Joe</@foo>`, `<@foo />`. Note that we get `true` for no nested content, because that's equivalent with 0-length nested content in FTL.

This method returns a pessimistic result. For example, if it sees a custom directive call, it can't know what it does, so it will assume that it's not cacheable.