| /* |
| * 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 org.apache.freemarker.core; |
| |
| import org.apache.freemarker.core.outputformat.OutputFormat; |
| import org.apache.freemarker.core.outputformat.impl.UndefinedOutputFormat; |
| import org.apache.freemarker.core.templateresolver.TemplateLoader; |
| import org.apache.freemarker.core.util._NullArgumentException; |
| import org.apache.freemarker.core.util._SortedArraySet; |
| import org.apache.freemarker.core.util._StringUtils; |
| import org.apache.freemarker.core.util._UnmodifiableCompositeSet; |
| |
| import java.io.InputStream; |
| import java.nio.charset.Charset; |
| import java.util.Set; |
| |
| public abstract class MutableParsingAndProcessingConfiguration< |
| SelfT extends MutableParsingAndProcessingConfiguration<SelfT>> |
| extends MutableProcessingConfiguration<SelfT> |
| implements ParsingAndProcessingConfiguration { |
| |
| public static final String OUTPUT_FORMAT_KEY = "outputFormat"; |
| public static final String SOURCE_ENCODING_KEY = "sourceEncoding"; |
| public static final String WHITESPACE_STRIPPING_KEY = "whitespaceStripping"; |
| public static final String AUTO_ESCAPING_POLICY_KEY = "autoEscapingPolicy"; |
| public static final String RECOGNIZE_STANDARD_FILE_EXTENSIONS_KEY = "recognizeStandardFileExtensions"; |
| public static final String TEMPLATE_LANGUAGE_KEY = "templateLanguage"; |
| public static final String TAB_SIZE_KEY = "tabSize"; |
| public static final String INCOMPATIBLE_IMPROVEMENTS_KEY = "incompatibleImprovements"; |
| |
| private static final _UnmodifiableCompositeSet<String> SETTING_NAMES = new _UnmodifiableCompositeSet<>( |
| MutableProcessingConfiguration.getSettingNames(), |
| new _SortedArraySet<>( |
| // Must be sorted alphabetically! |
| AUTO_ESCAPING_POLICY_KEY, |
| INCOMPATIBLE_IMPROVEMENTS_KEY, |
| OUTPUT_FORMAT_KEY, |
| RECOGNIZE_STANDARD_FILE_EXTENSIONS_KEY, |
| SOURCE_ENCODING_KEY, |
| TAB_SIZE_KEY, |
| TEMPLATE_LANGUAGE_KEY, |
| WHITESPACE_STRIPPING_KEY |
| )); |
| |
| private TemplateLanguage templateLanguage; |
| private Boolean whitespaceStripping; |
| private AutoEscapingPolicy autoEscapingPolicy; |
| private Boolean recognizeStandardFileExtensions; |
| private OutputFormat outputFormat; |
| private Charset sourceEncoding; |
| private Integer tabSize; |
| |
| protected MutableParsingAndProcessingConfiguration() { |
| super(); |
| } |
| |
| @Override |
| public void setSetting(String name, String value) throws ConfigurationException { |
| boolean nameUnhandled = false; |
| try { |
| if (SOURCE_ENCODING_KEY.equals(name)) { |
| if (JVM_DEFAULT_VALUE.equalsIgnoreCase(value)) { |
| setSourceEncoding(Charset.defaultCharset()); |
| } else { |
| setSourceEncoding(Charset.forName(value)); |
| } |
| } else if (OUTPUT_FORMAT_KEY.equals(name)) { |
| if (value.equalsIgnoreCase(DEFAULT_VALUE)) { |
| unsetOutputFormat(); |
| } else { |
| OutputFormat stdOF = Configuration.LazyStatics.STANDARD_OUTPUT_FORMATS.get(value); |
| setOutputFormat( |
| stdOF != null ? stdOF |
| : (OutputFormat) _ObjectBuilderSettingEvaluator.eval( |
| value, OutputFormat.class, true, _SettingEvaluationEnvironment.getCurrent())); |
| } |
| } else if (WHITESPACE_STRIPPING_KEY.equals(name)) { |
| setWhitespaceStripping(_StringUtils.getYesNo(value)); |
| } else if (AUTO_ESCAPING_POLICY_KEY.equals(name)) { |
| if ("enableIfDefault".equals(value)) { |
| setAutoEscapingPolicy(AutoEscapingPolicy.ENABLE_IF_DEFAULT); |
| } else if ("enableIfSupported".equals(value)) { |
| setAutoEscapingPolicy(AutoEscapingPolicy.ENABLE_IF_SUPPORTED); |
| } else if ("force".equals(value)) { |
| setAutoEscapingPolicy(AutoEscapingPolicy.FORCE); |
| } else if ("disable".equals(value)) { |
| setAutoEscapingPolicy(AutoEscapingPolicy.DISABLE); |
| } else { |
| throw new InvalidSettingValueException( name, value, |
| "enable_if_default".equals(value) ? "The correct value is: enableIfDefault" : |
| "enable_if_supported".equals(value) ? "The correct value is: enableIfSupported" : |
| "No such predefined auto escaping policy name"); |
| } |
| } else if (RECOGNIZE_STANDARD_FILE_EXTENSIONS_KEY.equals(name)) { |
| if (value.equalsIgnoreCase(DEFAULT_VALUE)) { |
| unsetRecognizeStandardFileExtensions(); |
| } else { |
| setRecognizeStandardFileExtensions(_StringUtils.getYesNo(value)); |
| } |
| } else if (TEMPLATE_LANGUAGE_KEY.equals(name)) { |
| TemplateLanguage templateLanguage = Configuration.LazyStatics.PREDEFINED_TEMPLATE_LANGUAGES_BY_EXTENSION |
| .get(value.toLowerCase()); |
| if (templateLanguage == null) { |
| if ("unparsed".equals(value)) { |
| templateLanguage = UnparsedTemplateLanguage.F3UU; |
| } else { |
| // TODO [FM3] Allow setting a custom template language by class name. |
| throw new InvalidSettingValueException(name, value, "Unsupported template language name"); |
| } |
| } |
| setTemplateLanguage(templateLanguage); |
| } else if (TAB_SIZE_KEY.equals(name)) { |
| setTabSize(Integer.parseInt(value)); |
| } else { |
| nameUnhandled = true; |
| } |
| } catch (InvalidSettingValueException e) { |
| throw e; |
| } catch (Exception e) { |
| throw new InvalidSettingValueException(name, value, e); |
| } |
| if (nameUnhandled) { |
| super.setSetting(name, value); |
| } |
| } |
| |
| @Override |
| protected Version getRemovalVersionForUnknownSetting(String name) { |
| if (name.equals("namingConvention") || name.equalsIgnoreCase("naming_convention")) { |
| return Configuration.VERSION_3_0_0; |
| } |
| return super.getRemovalVersionForUnknownSetting(name); |
| } |
| |
| public static Set<String> getSettingNames() { |
| return SETTING_NAMES; |
| } |
| |
| @Override |
| public TemplateLanguage getTemplateLanguage() { |
| return isTemplateLanguageSet() ? templateLanguage : getDefaultTemplateLanguage(); |
| } |
| |
| /** |
| * Returns the value the getter method returns when the setting is not set, possibly by inheriting the setting value |
| * from another {@link ParsingConfiguration}, or throws {@link CoreSettingValueNotSetException}. |
| */ |
| protected abstract TemplateLanguage getDefaultTemplateLanguage(); |
| |
| /** |
| * Setter pair of {@link #getTemplateLanguage()}. |
| */ |
| public void setTemplateLanguage(TemplateLanguage templateLanguage) { |
| _NullArgumentException.check("templateLanguage", templateLanguage); |
| this.templateLanguage = templateLanguage; |
| } |
| |
| /** |
| * Fluent API equivalent of {@link #setTemplateLanguage(TemplateLanguage)} |
| */ |
| public SelfT templateLanguage(TemplateLanguage templateLanguage) { |
| setTemplateLanguage(templateLanguage); |
| return self(); |
| } |
| |
| /** |
| * Resets the setting value as if it was never set (but it doesn't affect the value inherited from another |
| * {@link ParsingConfiguration}). |
| */ |
| public void unsetTemplateLanguage() { |
| this.templateLanguage = null; |
| } |
| |
| @Override |
| public boolean isTemplateLanguageSet() { |
| return templateLanguage != null; |
| } |
| |
| /** |
| * Setter pair of {@link ParsingConfiguration#getWhitespaceStripping()}. |
| */ |
| public void setWhitespaceStripping(boolean whitespaceStripping) { |
| this.whitespaceStripping = whitespaceStripping; |
| } |
| |
| /** |
| * Fluent API equivalent of {@link #setWhitespaceStripping(boolean)} |
| */ |
| public SelfT whitespaceStripping(boolean whitespaceStripping) { |
| setWhitespaceStripping(whitespaceStripping); |
| return self(); |
| } |
| |
| /** |
| * Resets the setting value as if it was never set (but it doesn't affect the value inherited from another |
| * {@link ParsingConfiguration}). |
| */ |
| public void unsetWhitespaceStripping() { |
| this.whitespaceStripping = null; |
| } |
| |
| /** |
| * The getter pair of {@link #getWhitespaceStripping()}. |
| */ |
| @Override |
| public boolean getWhitespaceStripping() { |
| return isWhitespaceStrippingSet() ? whitespaceStripping : getDefaultWhitespaceStripping(); |
| } |
| |
| /** |
| * Returns the value the getter method returns when the setting is not set, possibly by inheriting the setting value |
| * from another {@link ParsingConfiguration}, or throws {@link CoreSettingValueNotSetException}. |
| */ |
| protected abstract boolean getDefaultWhitespaceStripping(); |
| |
| /** |
| * Tells if this setting is set directly in this object or its value is inherited from the parent parsing configuration.. |
| */ |
| @Override |
| public boolean isWhitespaceStrippingSet() { |
| return whitespaceStripping != null; |
| } |
| |
| /** |
| * Setter pair of {@link #getAutoEscapingPolicy()}. |
| */ |
| public void setAutoEscapingPolicy(AutoEscapingPolicy autoEscapingPolicy) { |
| _NullArgumentException.check("autoEscapingPolicy", autoEscapingPolicy); |
| this.autoEscapingPolicy = autoEscapingPolicy; |
| } |
| |
| /** |
| * Fluent API equivalent of {@link #setAutoEscapingPolicy(AutoEscapingPolicy)} |
| */ |
| public SelfT autoEscapingPolicy(AutoEscapingPolicy autoEscapingPolicy) { |
| setAutoEscapingPolicy(autoEscapingPolicy); |
| return self(); |
| } |
| |
| /** |
| * Resets the setting value as if it was never set (but it doesn't affect the value inherited from another |
| * {@link ParsingConfiguration}). |
| */ |
| public void unsetAutoEscapingPolicy() { |
| this.autoEscapingPolicy = null; |
| } |
| |
| /** |
| * The getter pair of {@link #setAutoEscapingPolicy(AutoEscapingPolicy)}. |
| */ |
| @Override |
| public AutoEscapingPolicy getAutoEscapingPolicy() { |
| return isAutoEscapingPolicySet() ? autoEscapingPolicy : getDefaultAutoEscapingPolicy(); |
| } |
| |
| /** |
| * Returns the value the getter method returns when the setting is not set, possibly by inheriting the setting value |
| * from another {@link ParsingConfiguration}, or throws {@link CoreSettingValueNotSetException}. |
| */ |
| protected abstract AutoEscapingPolicy getDefaultAutoEscapingPolicy(); |
| |
| /** |
| * Tells if this setting is set directly in this object or its value is inherited from the parent parsing configuration.. |
| */ |
| @Override |
| public boolean isAutoEscapingPolicySet() { |
| return autoEscapingPolicy != null; |
| } |
| |
| /** |
| * Setter pair of {@link #getOutputFormat()}. |
| */ |
| public void setOutputFormat(OutputFormat outputFormat) { |
| if (outputFormat == null) { |
| throw new _NullArgumentException( |
| "outputFormat", |
| "You may meant: " + UndefinedOutputFormat.class.getSimpleName() + ".INSTANCE"); |
| } |
| this.outputFormat = outputFormat; |
| } |
| |
| /** |
| * Resets this setting to its initial state, as if it was never set. |
| */ |
| public void unsetOutputFormat() { |
| this.outputFormat = null; |
| } |
| |
| /** |
| * Fluent API equivalent of {@link #setOutputFormat(OutputFormat)} |
| */ |
| public SelfT outputFormat(OutputFormat outputFormat) { |
| setOutputFormat(outputFormat); |
| return self(); |
| } |
| |
| @Override |
| public OutputFormat getOutputFormat() { |
| return isOutputFormatSet() ? outputFormat : getDefaultOutputFormat(); |
| } |
| |
| /** |
| * Returns the value the getter method returns when the setting is not set, possibly by inheriting the setting value |
| * from another {@link ParsingConfiguration}, or throws {@link CoreSettingValueNotSetException}. |
| */ |
| protected abstract OutputFormat getDefaultOutputFormat(); |
| |
| /** |
| * Tells if this setting is set directly in this object or its value is inherited from the parent parsing configuration.. |
| */ |
| @Override |
| public boolean isOutputFormatSet() { |
| return outputFormat != null; |
| } |
| |
| /** |
| * Setter pair of {@link ParsingConfiguration#getRecognizeStandardFileExtensions()}. |
| */ |
| public void setRecognizeStandardFileExtensions(boolean recognizeStandardFileExtensions) { |
| this.recognizeStandardFileExtensions = recognizeStandardFileExtensions; |
| } |
| |
| /** |
| * Fluent API equivalent of {@link #setRecognizeStandardFileExtensions(boolean)} |
| */ |
| public SelfT recognizeStandardFileExtensions(boolean recognizeStandardFileExtensions) { |
| setRecognizeStandardFileExtensions(recognizeStandardFileExtensions); |
| return self(); |
| } |
| |
| /** |
| * Resets this setting to its initial state, as if it was never set. |
| */ |
| public void unsetRecognizeStandardFileExtensions() { |
| recognizeStandardFileExtensions = null; |
| } |
| |
| /** |
| * Getter pair of {@link #setRecognizeStandardFileExtensions(boolean)}. |
| */ |
| @Override |
| public boolean getRecognizeStandardFileExtensions() { |
| return isRecognizeStandardFileExtensionsSet() ? recognizeStandardFileExtensions |
| : getDefaultRecognizeStandardFileExtensions(); |
| } |
| |
| /** |
| * Returns the value the getter method returns when the setting is not set, possibly by inheriting the setting value |
| * from another {@link ParsingConfiguration}, or throws {@link CoreSettingValueNotSetException}. |
| */ |
| protected abstract boolean getDefaultRecognizeStandardFileExtensions(); |
| |
| /** |
| * Tells if this setting is set directly in this object or its value is inherited from the parent parsing configuration.. |
| */ |
| @Override |
| public boolean isRecognizeStandardFileExtensionsSet() { |
| return recognizeStandardFileExtensions != null; |
| } |
| |
| @Override |
| public Charset getSourceEncoding() { |
| return isSourceEncodingSet() ? sourceEncoding : getDefaultSourceEncoding(); |
| } |
| |
| /** |
| * Returns the value the getter method returns when the setting is not set, possibly by inheriting the setting value |
| * from another {@link ParsingConfiguration}, or throws {@link CoreSettingValueNotSetException}. |
| */ |
| protected abstract Charset getDefaultSourceEncoding(); |
| |
| /** |
| * The charset to be used when reading the template "file" that the {@link TemplateLoader} returns as binary |
| * ({@link InputStream}). If the {@code #ftl} header specifies an charset, that will override this. |
| */ |
| public void setSourceEncoding(Charset sourceEncoding) { |
| _NullArgumentException.check("sourceEncoding", sourceEncoding); |
| this.sourceEncoding = sourceEncoding; |
| } |
| |
| /** |
| * Fluent API equivalent of {@link #setSourceEncoding(Charset)} |
| */ |
| public SelfT sourceEncoding(Charset sourceEncoding) { |
| setSourceEncoding(sourceEncoding); |
| return self(); |
| } |
| |
| /** |
| * Resets the setting value as if it was never set (but it doesn't affect the value inherited from another |
| * {@link ParsingConfiguration}). |
| */ |
| public void unsetSourceEncoding() { |
| this.sourceEncoding = null; |
| } |
| |
| @Override |
| public boolean isSourceEncodingSet() { |
| return sourceEncoding != null; |
| } |
| |
| /** |
| * Setter pair of {@link #getTabSize()}. |
| */ |
| public void setTabSize(int tabSize) { |
| if (tabSize < 1) { |
| throw new IllegalArgumentException("\"tabSize\" must be at least 1, but was " + tabSize); |
| } |
| // To avoid integer overflows: |
| if (tabSize > 256) { |
| throw new IllegalArgumentException("\"tabSize\" can't be more than 256, but was " + tabSize); |
| } |
| this.tabSize = Integer.valueOf(tabSize); |
| } |
| |
| /** |
| * Fluent API equivalent of {@link #setTabSize(int)} |
| */ |
| public SelfT tabSize(int tabSize) { |
| setTabSize(tabSize); |
| return self(); |
| } |
| |
| /** |
| * Resets the setting value as if it was never set (but it doesn't affect the value inherited from another |
| * {@link ParsingConfiguration}). |
| */ |
| public void unsetTabSize() { |
| this.tabSize = null; |
| } |
| |
| @Override |
| public int getTabSize() { |
| return isTabSizeSet() ? tabSize.intValue() : getDefaultTabSize(); |
| } |
| |
| /** |
| * Returns the value the getter method returns when the setting is not set, possibly by inheriting the setting value |
| * from another {@link ParsingConfiguration}, or throws {@link CoreSettingValueNotSetException}. |
| */ |
| protected abstract int getDefaultTabSize(); |
| |
| /** |
| * Tells if this setting is set directly in this object or its value is inherited from the parent parsing configuration.. |
| */ |
| @Override |
| public boolean isTabSizeSet() { |
| return tabSize != null; |
| } |
| |
| } |