| /* |
| * 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.Writer; |
| import java.util.Collection; |
| import java.util.Collections; |
| import java.util.Set; |
| import java.util.TreeSet; |
| |
| import freemarker.template.Configuration; |
| import freemarker.template.Template; |
| import freemarker.template.TemplateDirectiveBody; |
| import freemarker.template.TemplateException; |
| import freemarker.template.TemplateModel; |
| import freemarker.template.TemplateModelException; |
| import freemarker.template._TemplateAPI; |
| import freemarker.template.utility.ClassUtil; |
| |
| |
| /** |
| * For internal use only; don't depend on this, there's no backward compatibility guarantee at all! |
| * This class is to work around the lack of module system in Java, i.e., so that other FreeMarker packages can |
| * access things inside this package that users shouldn't. |
| */ |
| public class _CoreAPI { |
| |
| public static final String ERROR_MESSAGE_HR = "----"; |
| |
| // Can't be instantiated |
| private _CoreAPI() { } |
| |
| private static void addName(Set<String> allNames, Set<String> lcNames, Set<String> ccNames, |
| String commonName) { |
| allNames.add(commonName); |
| lcNames.add(commonName); |
| ccNames.add(commonName); |
| } |
| |
| private static void addName(Set<String> allNames, Set<String> lcNames, Set<String> ccNames, |
| String lcName, String ccName) { |
| allNames.add(lcName); |
| allNames.add(ccName); |
| lcNames.add(lcName); |
| ccNames.add(ccName); |
| } |
| |
| public static final Set<String> ALL_BUILT_IN_DIRECTIVE_NAMES; |
| public static final Set<String> LEGACY_BUILT_IN_DIRECTIVE_NAMES; |
| public static final Set<String> CAMEL_CASE_BUILT_IN_DIRECTIVE_NAMES; |
| static { |
| Set<String> allNames = new TreeSet(); |
| Set<String> lcNames = new TreeSet(); |
| Set<String> ccNames = new TreeSet(); |
| |
| addName(allNames, lcNames, ccNames, "assign"); |
| addName(allNames, lcNames, ccNames, "attempt"); |
| addName(allNames, lcNames, ccNames, "autoesc", "autoEsc"); |
| addName(allNames, lcNames, ccNames, "break"); |
| addName(allNames, lcNames, ccNames, "call"); |
| addName(allNames, lcNames, ccNames, "case"); |
| addName(allNames, lcNames, ccNames, "comment"); |
| addName(allNames, lcNames, ccNames, "compress"); |
| addName(allNames, lcNames, ccNames, "default"); |
| addName(allNames, lcNames, ccNames, "else"); |
| addName(allNames, lcNames, ccNames, "elseif", "elseIf"); |
| addName(allNames, lcNames, ccNames, "escape"); |
| addName(allNames, lcNames, ccNames, "fallback"); |
| addName(allNames, lcNames, ccNames, "flush"); |
| addName(allNames, lcNames, ccNames, "foreach", "forEach"); |
| addName(allNames, lcNames, ccNames, "ftl"); |
| addName(allNames, lcNames, ccNames, "function"); |
| addName(allNames, lcNames, ccNames, "global"); |
| addName(allNames, lcNames, ccNames, "if"); |
| addName(allNames, lcNames, ccNames, "import"); |
| addName(allNames, lcNames, ccNames, "include"); |
| addName(allNames, lcNames, ccNames, "items"); |
| addName(allNames, lcNames, ccNames, "list"); |
| addName(allNames, lcNames, ccNames, "local"); |
| addName(allNames, lcNames, ccNames, "lt"); |
| addName(allNames, lcNames, ccNames, "macro"); |
| addName(allNames, lcNames, ccNames, "nested"); |
| addName(allNames, lcNames, ccNames, "noautoesc", "noAutoEsc"); |
| addName(allNames, lcNames, ccNames, "noescape", "noEscape"); |
| addName(allNames, lcNames, ccNames, "noparse", "noParse"); |
| addName(allNames, lcNames, ccNames, "nt"); |
| addName(allNames, lcNames, ccNames, "outputformat", "outputFormat"); |
| addName(allNames, lcNames, ccNames, "recover"); |
| addName(allNames, lcNames, ccNames, "recurse"); |
| addName(allNames, lcNames, ccNames, "return"); |
| addName(allNames, lcNames, ccNames, "rt"); |
| addName(allNames, lcNames, ccNames, "sep"); |
| addName(allNames, lcNames, ccNames, "setting"); |
| addName(allNames, lcNames, ccNames, "stop"); |
| addName(allNames, lcNames, ccNames, "switch"); |
| addName(allNames, lcNames, ccNames, "t"); |
| addName(allNames, lcNames, ccNames, "transform"); |
| addName(allNames, lcNames, ccNames, "visit"); |
| |
| ALL_BUILT_IN_DIRECTIVE_NAMES = Collections.unmodifiableSet(allNames); |
| LEGACY_BUILT_IN_DIRECTIVE_NAMES = Collections.unmodifiableSet(lcNames); |
| CAMEL_CASE_BUILT_IN_DIRECTIVE_NAMES = Collections.unmodifiableSet(ccNames); |
| } |
| |
| /** |
| * Returns the names of the currently supported "built-ins" ({@code expr?builtin_name}-like things). |
| * |
| * @param namingConvention |
| * One of {@link Configuration#AUTO_DETECT_NAMING_CONVENTION}, |
| * {@link Configuration#LEGACY_NAMING_CONVENTION}, and |
| * {@link Configuration#CAMEL_CASE_NAMING_CONVENTION}. If it's |
| * {@link Configuration#AUTO_DETECT_NAMING_CONVENTION} then the union of the names in all the naming |
| * conventions is returned. |
| */ |
| public static Set<String> getSupportedBuiltInNames(int namingConvention) { |
| Set<String> names; |
| if (namingConvention == Configuration.AUTO_DETECT_NAMING_CONVENTION) { |
| names = BuiltIn.BUILT_INS_BY_NAME.keySet(); |
| } else if (namingConvention == Configuration.LEGACY_NAMING_CONVENTION) { |
| names = BuiltIn.SNAKE_CASE_NAMES; |
| } else if (namingConvention == Configuration.CAMEL_CASE_NAMING_CONVENTION) { |
| names = BuiltIn.CAMEL_CASE_NAMES; |
| } else { |
| throw new IllegalArgumentException("Unsupported naming convention constant: " + namingConvention); |
| } |
| return Collections.unmodifiableSet(names); |
| } |
| |
| public static void appendInstructionStackItem(TemplateElement stackEl, StringBuilder sb) { |
| Environment.appendInstructionStackItem(stackEl, sb); |
| } |
| |
| public static TemplateElement[] getInstructionStackSnapshot(Environment env) { |
| return env.getInstructionStackSnapshot(); |
| } |
| |
| public static void outputInstructionStack( |
| TemplateElement[] instructionStackSnapshot, boolean terseMode, Writer pw) { |
| Environment.outputInstructionStack(instructionStackSnapshot, terseMode, pw); |
| } |
| |
| /** |
| * ATTENTION: This is used by https://github.com/kenshoo/freemarker-online. Don't break backward |
| * compatibility without updating that project too! |
| */ |
| static final public void addThreadInterruptedChecks(Template template) { |
| try { |
| new ThreadInterruptionSupportTemplatePostProcessor().postProcess(template); |
| } catch (TemplatePostProcessorException e) { |
| throw new RuntimeException("Template post-processing failed", e); |
| } |
| } |
| |
| static final public void checkHasNoNestedContent(TemplateDirectiveBody body) |
| throws NestedContentNotSupportedException { |
| NestedContentNotSupportedException.check(body); |
| } |
| |
| static final public void replaceText(TextBlock textBlock, String text) { |
| textBlock.replaceText(text); |
| } |
| |
| /** |
| * @throws IllegalArgumentException |
| * if the type of the some of the values isn't as expected |
| */ |
| public static void checkSettingValueItemsType(String somethingsSentenceStart, Class<?> expectedClass, |
| Collection<? extends Object> values) { |
| if (values == null) return; |
| for (Object value : values) { |
| if (!expectedClass.isInstance(value)) { |
| throw new IllegalArgumentException(somethingsSentenceStart + " must be instances of " |
| + ClassUtil.getShortClassName(expectedClass) + ", but one of them was a(n) " |
| + ClassUtil.getShortClassNameOfObject(value) + "."); |
| } |
| } |
| } |
| |
| /** |
| * The work around the problematic cases where we should throw a {@link TemplateException}, but we are inside |
| * a {@link TemplateModel} method and so we can only throw {@link TemplateModelException}-s. |
| */ |
| public static TemplateModelException ensureIsTemplateModelException(String modelOpMsg, TemplateException e) { |
| if (e instanceof TemplateModelException) { |
| return (TemplateModelException) e; |
| } else { |
| return new _TemplateModelException( |
| _TemplateAPI.getBlamedExpression(e), e.getCause(), e.getEnvironment(), modelOpMsg); |
| } |
| } |
| |
| public static TemplateElement getParentElement(TemplateElement te) { |
| return te.getParentElement(); |
| } |
| |
| public static TemplateElement getChildElement(TemplateElement te, int index) { |
| return te.getChild(index); |
| } |
| |
| } |