public interface DirectiveCallPlace
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)
.
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).
Environment.getCurrentDirectiveCallPlace()
Modifier and Type | Method and Description |
---|---|
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.
|
java.lang.Object |
getOrCreateCustomData(java.lang.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. |
Template |
getTemplate()
The template that contains this call;
null if the call is not from a template (but directly from
user Java code, for example). |
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).
|
Template getTemplate()
null
if the call is not from a template (but directly from
user Java code, for example).int getBeginColumn()
int getBeginLine()
int getEndColumn()
</@...>
), then it points to the last character of that.int getEndLine()
</@...>
), then it points to the last character of that.java.lang.Object getOrCreateCustomData(java.lang.Object providerIdentity, ObjectFactory objectFactory) throws CallPlaceCustomDataInitializationException
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.
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
.null
if there was no ObjectFactory
provided.CallPlaceCustomDataInitializationException
- If the ObjectFactory
had to be invoked but failed.boolean isNestedOutputCacheable()
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.