| /* |
| * Licensed to the Apache Software Foundation (ASF) under one |
| * or more contributor license agreements. See the NOTICE file |
| * distributed with this work for additional information |
| * regarding copyright ownership. The ASF licenses this file |
| * to you under the Apache License, Version 2.0 (the |
| * "License"); you may not use this file except in compliance |
| * with the License. You may obtain a copy of the License at |
| * |
| * http://www.apache.org/licenses/LICENSE-2.0 |
| * |
| * Unless required by applicable law or agreed to in writing, |
| * software distributed under the License is distributed on an |
| * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY |
| * KIND, either express or implied. See the License for the |
| * specific language governing permissions and limitations |
| * under the License. |
| */ |
| |
| package freemarker.core; |
| |
| import java.io.IOException; |
| |
| import freemarker.core.Environment.Namespace; |
| import freemarker.template.Template; |
| import freemarker.template.TemplateException; |
| |
| /** |
| * A macro or function (or other future callable entity) associated to a namespace and a template. |
| * |
| * <p> |
| * With an analogy, a {@link UnboundCallable} is like a non-static {@link java.lang.reflect.Method} in Java; it |
| * describes everything about the method, but it isn't bound to any object on which the method could be called. |
| * Continuing this analogy, a {@link BoundCallable} is like a {@link java.lang.reflect.Method} paired with the object |
| * whose method it is (the {@code this} object), and is thus callable in itself. In the case of FTL macros and FTL |
| * functions, instead of a single {@code this} object, we have two such objects: a namespace and a template. (One may |
| * wonder why the namespace is not enough, given that a namespace already specifies a template ( |
| * {@link Namespace#getTemplate()} ). It's because a namespace can contain macros from included templates, and so the |
| * template that the callable belongs to isn't always the same as {@link Namespace#getTemplate()}, which just gives the |
| * "root" template of the namespace. Furthermore, several namespaces my include exactly the same template, so we can't |
| * get away with a template instead of a namespace either. Also note that knowing which template we are in is needed for |
| * example to resolve relative references to other templates.) |
| * |
| * <p> |
| * Historical note: Prior to 2.4, the two concepts ({@link UnboundCallable} and {@link BoundCallable}) were these same, |
| * represented by {@link Macro}, which still exists due to backward compatibility constraints. This class extends |
| * {@link Macro} only for the sake of legacy applications which expect macro and function FTL variables to be |
| * {@link Macro}-s. Especially, this class should not extend {@link TemplateElement} (which it does, because |
| * {@link Macro} is a subclass of that), but it had to, for backward compatibility. It just delegates the {@link Macro} |
| * methods to the embedded {@link UnboundCallable}. |
| * |
| * @see UnboundCallable |
| * |
| * @since 2.4.0 |
| */ |
| final class BoundCallable extends Macro { |
| |
| private final UnboundCallable unboundCallable; |
| private final Template template; |
| private final Namespace namespace; |
| |
| BoundCallable(UnboundCallable callableDefinition, Template template, Namespace namespace) { |
| this.unboundCallable = callableDefinition; |
| this.template = template; |
| this.namespace = namespace; |
| } |
| |
| UnboundCallable getUnboundCallable() { |
| return unboundCallable; |
| } |
| |
| Template getTemplate() { |
| return template; |
| } |
| |
| Namespace getNamespace() { |
| return namespace; |
| } |
| |
| @Override |
| public String toString() { |
| return "BoundCallable(" |
| + "name=" + getName() |
| + ", isFunction=" + isFunction() |
| + ", template" + (template != null ? ".name=" + template.getName() : "=null") |
| + ", namespace=" + (namespace != null ? namespace.getTemplate().getName() : "null") |
| + ")"; |
| } |
| |
| /** For backward compatibility only; delegates to the {@link UnboundCallable}'s identical method. */ |
| @Override |
| public String getCatchAll() { |
| return unboundCallable.getCatchAll(); |
| } |
| |
| /** For backward compatibility only; delegates to the {@link UnboundCallable}'s identical method. */ |
| @Override |
| public String[] getArgumentNames() { |
| return unboundCallable.getArgumentNames(); |
| } |
| |
| /** For backward compatibility only; delegates to the {@link UnboundCallable}'s identical method. */ |
| @Override |
| public String getName() { |
| return unboundCallable.getName(); |
| } |
| |
| /** For backward compatibility only; delegates to the {@link UnboundCallable}'s identical method. */ |
| @Override |
| public boolean isFunction() { |
| return unboundCallable.isFunction(); |
| } |
| |
| /** For backward compatibility only; delegates to the {@link UnboundCallable}'s identical method. */ |
| @Override |
| TemplateElement[] accept(Environment env) throws TemplateException, IOException { |
| return unboundCallable.accept(env); |
| } |
| |
| /** For backward compatibility only; delegates to the {@link UnboundCallable}'s identical method. */ |
| @Override |
| protected String dump(boolean canonical) { |
| return unboundCallable.dump(canonical); |
| } |
| |
| /** For backward compatibility only; delegates to the {@link UnboundCallable}'s identical method. */ |
| @Override |
| String getNodeTypeSymbol() { |
| return unboundCallable.getNodeTypeSymbol(); |
| } |
| |
| /** For backward compatibility only; delegates to the {@link UnboundCallable}'s identical method. */ |
| @Override |
| int getParameterCount() { |
| return unboundCallable.getParameterCount(); |
| } |
| |
| /** For backward compatibility only; delegates to the {@link UnboundCallable}'s identical method. */ |
| @Override |
| Object getParameterValue(int idx) { |
| return unboundCallable.getParameterValue(idx); |
| } |
| |
| /** For backward compatibility only; delegates to the {@link UnboundCallable}'s identical method. */ |
| @Override |
| ParameterRole getParameterRole(int idx) { |
| return unboundCallable.getParameterRole(idx); |
| } |
| |
| @Override |
| boolean isNestedBlockRepeater() { |
| return unboundCallable.isNestedBlockRepeater(); |
| } |
| |
| } |