| /* |
| * 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.util.Arrays; |
| |
| import freemarker.template.Configuration; |
| import freemarker.template.TemplateBooleanModel; |
| import freemarker.template.TemplateException; |
| import freemarker.template.TemplateModel; |
| import freemarker.template.TemplateNumberModel; |
| import freemarker.template.TemplateScalarModel; |
| import freemarker.template._TemplateAPI; |
| import freemarker.template.utility.StringUtil; |
| |
| /** |
| * An instruction that sets a property of the template rendering |
| * environment. |
| */ |
| final class PropertySetting extends TemplateElement { |
| |
| private final String key; |
| private final Expression value; |
| |
| static final String[] SETTING_NAMES = new String[] { |
| // Must be sorted alphabetically! |
| Configurable.BOOLEAN_FORMAT_KEY_CAMEL_CASE, |
| Configurable.BOOLEAN_FORMAT_KEY_SNAKE_CASE, |
| Configurable.CLASSIC_COMPATIBLE_KEY_CAMEL_CASE, |
| Configurable.CLASSIC_COMPATIBLE_KEY_SNAKE_CASE, |
| Configurable.DATE_FORMAT_KEY_CAMEL_CASE, |
| Configurable.DATE_FORMAT_KEY_SNAKE_CASE, |
| Configurable.DATETIME_FORMAT_KEY_CAMEL_CASE, |
| Configurable.DATETIME_FORMAT_KEY_SNAKE_CASE, |
| Configurable.LOCALE_KEY, |
| Configurable.NUMBER_FORMAT_KEY_CAMEL_CASE, |
| Configurable.NUMBER_FORMAT_KEY_SNAKE_CASE, |
| Configurable.OUTPUT_ENCODING_KEY_CAMEL_CASE, |
| Configurable.OUTPUT_ENCODING_KEY_SNAKE_CASE, |
| Configurable.SQL_DATE_AND_TIME_TIME_ZONE_KEY_CAMEL_CASE, |
| Configurable.SQL_DATE_AND_TIME_TIME_ZONE_KEY, |
| Configurable.TIME_FORMAT_KEY_CAMEL_CASE, |
| Configurable.TIME_ZONE_KEY_CAMEL_CASE, |
| Configurable.TIME_FORMAT_KEY_SNAKE_CASE, |
| Configurable.TIME_ZONE_KEY_SNAKE_CASE, |
| Configurable.URL_ESCAPING_CHARSET_KEY_CAMEL_CASE, |
| Configurable.URL_ESCAPING_CHARSET_KEY_SNAKE_CASE |
| }; |
| |
| PropertySetting(Token keyTk, FMParserTokenManager tokenManager, Expression value, Configuration cfg) |
| throws ParseException { |
| String key = keyTk.image; |
| if (Arrays.binarySearch(SETTING_NAMES, key) < 0) { |
| StringBuilder sb = new StringBuilder(); |
| if (_TemplateAPI.getConfigurationSettingNames(cfg, true).contains(key) |
| || _TemplateAPI.getConfigurationSettingNames(cfg, false).contains(key)) { |
| sb.append("The setting name is recognized, but changing this setting from inside a template isn't " |
| + "supported."); |
| } else { |
| sb.append("Unknown setting name: "); |
| sb.append(StringUtil.jQuote(key)).append("."); |
| sb.append(" The allowed setting names are: "); |
| |
| int shownNamingConvention; |
| { |
| int namingConvention = tokenManager.namingConvention; |
| shownNamingConvention = namingConvention != Configuration.AUTO_DETECT_NAMING_CONVENTION |
| ? namingConvention : Configuration.LEGACY_NAMING_CONVENTION /* [2.4] CAMEL_CASE */; |
| } |
| |
| boolean first = true; |
| for (int i = 0; i < SETTING_NAMES.length; i++) { |
| String correctName = SETTING_NAMES[i]; |
| int correctNameNamingConvetion = _CoreStringUtils.getIdentifierNamingConvention(correctName); |
| if (shownNamingConvention == Configuration.CAMEL_CASE_NAMING_CONVENTION |
| ? correctNameNamingConvetion != Configuration.LEGACY_NAMING_CONVENTION |
| : correctNameNamingConvetion != Configuration.CAMEL_CASE_NAMING_CONVENTION) { |
| if (first) { |
| first = false; |
| } else { |
| sb.append(", "); |
| } |
| |
| sb.append(SETTING_NAMES[i]); |
| } |
| } |
| } |
| throw new ParseException(sb.toString(), null, keyTk); |
| } |
| |
| this.key = key; |
| this.value = value; |
| } |
| |
| @Override |
| TemplateElement[] accept(Environment env) throws TemplateException { |
| TemplateModel mval = value.eval(env); |
| String strval; |
| if (mval instanceof TemplateScalarModel) { |
| strval = ((TemplateScalarModel) mval).getAsString(); |
| } else if (mval instanceof TemplateBooleanModel) { |
| strval = ((TemplateBooleanModel) mval).getAsBoolean() ? "true" : "false"; |
| } else if (mval instanceof TemplateNumberModel) { |
| strval = ((TemplateNumberModel) mval).getAsNumber().toString(); |
| } else { |
| strval = value.evalAndCoerceToStringOrUnsupportedMarkup(env); |
| } |
| env.setSetting(key, strval); |
| return null; |
| } |
| |
| @Override |
| protected String dump(boolean canonical) { |
| StringBuilder sb = new StringBuilder(); |
| if (canonical) sb.append('<'); |
| sb.append(getNodeTypeSymbol()); |
| sb.append(' '); |
| sb.append(_CoreStringUtils.toFTLTopLevelTragetIdentifier(key)); |
| sb.append('='); |
| sb.append(value.getCanonicalForm()); |
| if (canonical) sb.append("/>"); |
| return sb.toString(); |
| } |
| |
| @Override |
| String getNodeTypeSymbol() { |
| return "#setting"; |
| } |
| |
| @Override |
| int getParameterCount() { |
| return 2; |
| } |
| |
| @Override |
| Object getParameterValue(int idx) { |
| switch (idx) { |
| case 0: return key; |
| case 1: return value; |
| default: throw new IndexOutOfBoundsException(); |
| } |
| } |
| |
| @Override |
| ParameterRole getParameterRole(int idx) { |
| switch (idx) { |
| case 0: return ParameterRole.ITEM_KEY; |
| case 1: return ParameterRole.ITEM_VALUE; |
| default: throw new IndexOutOfBoundsException(); |
| } |
| } |
| |
| @Override |
| boolean isNestedBlockRepeater() { |
| return false; |
| } |
| |
| } |