1/*
2 * Copyright (C) 2010 Google Inc.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package com.google.clearsilver.jsilver.interpreter;
18
19import com.google.clearsilver.jsilver.autoescape.EscapeMode;
20import com.google.clearsilver.jsilver.data.Data;
21import com.google.clearsilver.jsilver.exceptions.JSilverInterpreterException;
22import com.google.clearsilver.jsilver.resourceloader.ResourceLoader;
23import com.google.clearsilver.jsilver.syntax.node.PCommand;
24import com.google.clearsilver.jsilver.template.Macro;
25import com.google.clearsilver.jsilver.template.RenderingContext;
26import com.google.clearsilver.jsilver.template.Template;
27
28import java.io.IOException;
29
30/**
31 * User defined macro that will be executed by the interpreter.
32 *
33 * NOTE: This is not thread safe and cannot be shared between RenderingContexts. This is taken care
34 * of by the TemplateInterpreter.
35 */
36public class InterpretedMacro implements Macro {
37
38  private final PCommand command;
39  private final Template owningTemplate;
40  private final String macroName;
41  private final String[] argumentNames;
42  private final TemplateInterpreter templateInterpreter;
43  private final RenderingContext owningContext;
44
45  public InterpretedMacro(PCommand command, Template owningTemplate, String macroName,
46      String[] argumentNames, TemplateInterpreter templateInterpreter,
47      RenderingContext owningContext) {
48    this.command = command;
49    this.owningTemplate = owningTemplate;
50    this.macroName = macroName;
51    this.argumentNames = argumentNames;
52    this.templateInterpreter = templateInterpreter;
53    this.owningContext = owningContext;
54  }
55
56  @Override
57  public void render(RenderingContext context) throws IOException {
58    assert context == owningContext : "Cannot render macro defined in another context";
59    context.pushExecutionContext(this);
60    boolean doRuntimeAutoEscaping = !(context.isRuntimeAutoEscaping());
61    if (doRuntimeAutoEscaping) {
62      context.startRuntimeAutoEscaping();
63    }
64    command.apply(templateInterpreter);
65    if (doRuntimeAutoEscaping) {
66      context.stopRuntimeAutoEscaping();
67    }
68    context.popExecutionContext();
69  }
70
71  @Override
72  public void render(Data data, Appendable out, ResourceLoader resourceLoader) throws IOException {
73    render(createRenderingContext(data, out, resourceLoader));
74  }
75
76  @Override
77  public RenderingContext createRenderingContext(Data data, Appendable out,
78      ResourceLoader resourceLoader) {
79    return owningTemplate.createRenderingContext(data, out, resourceLoader);
80  }
81
82  @Override
83  public String getTemplateName() {
84    return owningTemplate.getTemplateName();
85  }
86
87  @Override
88  public EscapeMode getEscapeMode() {
89    return owningTemplate.getEscapeMode();
90  }
91
92  @Override
93  public String getDisplayName() {
94    return owningTemplate.getDisplayName() + ":" + macroName;
95  }
96
97  @Override
98  public String getMacroName() {
99    return macroName;
100  }
101
102  @Override
103  public String getArgumentName(int index) {
104    if (index >= argumentNames.length) {
105      // TODO: Make sure this behavior of failing if too many
106      // arguments are passed to a macro is consistent with JNI / interpreter.
107      throw new JSilverInterpreterException("Too many arguments supplied to macro " + macroName);
108    }
109    return argumentNames[index];
110  }
111
112  @Override
113  public int getArgumentCount() {
114    return argumentNames.length;
115  }
116}
117