http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/ecb4e230/src/main/java/freemarker/core/Range.java ---------------------------------------------------------------------- diff --git a/src/main/java/freemarker/core/Range.java b/src/main/java/freemarker/core/Range.java deleted file mode 100644 index 2fde57c..0000000 --- a/src/main/java/freemarker/core/Range.java +++ /dev/null @@ -1,122 +0,0 @@ -/* - * 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 freemarker.template.TemplateException; -import freemarker.template.TemplateModel; -import freemarker.template._TemplateAPI; - -/** - * A class that represents a Range between two integers. - */ -final class Range extends Expression { - - static final int END_INCLUSIVE = 0; - static final int END_EXCLUSIVE = 1; - static final int END_UNBOUND = 2; - static final int END_SIZE_LIMITED = 3; - - final Expression lho; - final Expression rho; - final int endType; - - Range(Expression lho, Expression rho, int endType) { - this.lho = lho; - this.rho = rho; - this.endType = endType; - } - - int getEndType() { - return endType; - } - - @Override - TemplateModel _eval(Environment env) throws TemplateException { - final int begin = lho.evalToNumber(env).intValue(); - if (endType != END_UNBOUND) { - final int lhoValue = rho.evalToNumber(env).intValue(); - return new BoundedRangeModel( - begin, endType != END_SIZE_LIMITED ? lhoValue : begin + lhoValue, - endType == END_INCLUSIVE, endType == END_SIZE_LIMITED); - } else { - return _TemplateAPI.getTemplateLanguageVersionAsInt(this) >= _TemplateAPI.VERSION_INT_2_3_21 - ? (RangeModel) new ListableRightUnboundedRangeModel(begin) - : (RangeModel) new NonListableRightUnboundedRangeModel(begin); - } - } - - // Surely this way we can tell that it won't be a boolean without evaluating the range, but why was this important? - @Override - boolean evalToBoolean(Environment env) throws TemplateException { - throw new NonBooleanException(this, new BoundedRangeModel(0, 0, false, false), env); - } - - @Override - public String getCanonicalForm() { - String rhs = rho != null ? rho.getCanonicalForm() : ""; - return lho.getCanonicalForm() + getNodeTypeSymbol() + rhs; - } - - @Override - String getNodeTypeSymbol() { - switch (endType) { - case END_EXCLUSIVE: return "..<"; - case END_INCLUSIVE: return ".."; - case END_UNBOUND: return ".."; - case END_SIZE_LIMITED: return "..*"; - default: throw new BugException(endType); - } - } - - @Override - boolean isLiteral() { - boolean rightIsLiteral = rho == null || rho.isLiteral(); - return constantValue != null || (lho.isLiteral() && rightIsLiteral); - } - - @Override - protected Expression deepCloneWithIdentifierReplaced_inner( - String replacedIdentifier, Expression replacement, ReplacemenetState replacementState) { - return new Range( - lho.deepCloneWithIdentifierReplaced(replacedIdentifier, replacement, replacementState), - rho.deepCloneWithIdentifierReplaced(replacedIdentifier, replacement, replacementState), - endType); - } - - @Override - int getParameterCount() { - return 2; - } - - @Override - Object getParameterValue(int idx) { - switch (idx) { - case 0: return lho; - case 1: return rho; - default: throw new IndexOutOfBoundsException(); - } - } - - @Override - ParameterRole getParameterRole(int idx) { - return ParameterRole.forBinaryOperatorOperand(idx); - } - -}
http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/ecb4e230/src/main/java/freemarker/core/RangeModel.java ---------------------------------------------------------------------- diff --git a/src/main/java/freemarker/core/RangeModel.java b/src/main/java/freemarker/core/RangeModel.java deleted file mode 100644 index d0ef959..0000000 --- a/src/main/java/freemarker/core/RangeModel.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * 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 freemarker.template.SimpleNumber; -import freemarker.template.TemplateModel; -import freemarker.template.TemplateModelException; -import freemarker.template.TemplateSequenceModel; - -abstract class RangeModel implements TemplateSequenceModel, java.io.Serializable { - - private final int begin; - - public RangeModel(int begin) { - this.begin = begin; - } - - final int getBegining() { - return begin; - } - - final public TemplateModel get(int index) throws TemplateModelException { - if (index < 0 || index >= size()) { - throw new _TemplateModelException("Range item index ", Integer.valueOf(index), " is out of bounds."); - } - long value = begin + getStep() * (long) index; - return value <= Integer.MAX_VALUE ? new SimpleNumber((int) value) : new SimpleNumber(value); - } - - /** - * @return {@code 1} or {@code -1}; other return values need not be properly handled until FTL supports other steps. - */ - abstract int getStep(); - - abstract boolean isRightUnbounded(); - - abstract boolean isRightAdaptive(); - - abstract boolean isAffactedByStringSlicingBug(); - -} http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/ecb4e230/src/main/java/freemarker/core/RecoveryBlock.java ---------------------------------------------------------------------- diff --git a/src/main/java/freemarker/core/RecoveryBlock.java b/src/main/java/freemarker/core/RecoveryBlock.java deleted file mode 100644 index 67ff1fb..0000000 --- a/src/main/java/freemarker/core/RecoveryBlock.java +++ /dev/null @@ -1,74 +0,0 @@ -/* - * 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.template.TemplateException; - -final class RecoveryBlock extends TemplateElement { - - RecoveryBlock(TemplateElements children) { - setChildren(children); - } - - @Override - TemplateElement[] accept(Environment env) throws TemplateException, IOException { - return getChildBuffer(); - } - - @Override - protected String dump(boolean canonical) { - if (canonical) { - StringBuilder buf = new StringBuilder(); - buf.append('<').append(getNodeTypeSymbol()).append('>'); - buf.append(getChildrenCanonicalForm()); - return buf.toString(); - } else { - return getNodeTypeSymbol(); - } - } - - @Override - String getNodeTypeSymbol() { - return "#recover"; - } - - @Override - int getParameterCount() { - return 0; - } - - @Override - Object getParameterValue(int idx) { - throw new IndexOutOfBoundsException(); - } - - @Override - ParameterRole getParameterRole(int idx) { - throw new IndexOutOfBoundsException(); - } - - @Override - boolean isNestedBlockRepeater() { - return false; - } - -} http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/ecb4e230/src/main/java/freemarker/core/RecurseNode.java ---------------------------------------------------------------------- diff --git a/src/main/java/freemarker/core/RecurseNode.java b/src/main/java/freemarker/core/RecurseNode.java deleted file mode 100644 index 1c15da8..0000000 --- a/src/main/java/freemarker/core/RecurseNode.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * 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.template.SimpleSequence; -import freemarker.template.TemplateException; -import freemarker.template.TemplateHashModel; -import freemarker.template.TemplateModel; -import freemarker.template.TemplateNodeModel; -import freemarker.template.TemplateScalarModel; -import freemarker.template.TemplateSequenceModel; - - -/** - * An instruction to visit the children of a node. - */ -final class RecurseNode extends TemplateElement { - - Expression targetNode, namespaces; - - RecurseNode(Expression targetNode, Expression namespaces) { - this.targetNode = targetNode; - this.namespaces = namespaces; - } - - @Override - TemplateElement[] accept(Environment env) throws IOException, TemplateException { - TemplateModel node = targetNode == null ? null : targetNode.eval(env); - if (node != null && !(node instanceof TemplateNodeModel)) { - throw new NonNodeException(targetNode, node, "node", env); - } - - TemplateModel nss = namespaces == null ? null : namespaces.eval(env); - if (namespaces instanceof StringLiteral) { - nss = env.importLib(((TemplateScalarModel) nss).getAsString(), null); - } else if (namespaces instanceof ListLiteral) { - nss = ((ListLiteral) namespaces).evaluateStringsToNamespaces(env); - } - if (nss != null) { - if (nss instanceof TemplateHashModel) { - SimpleSequence ss = new SimpleSequence(1); - ss.add(nss); - nss = ss; - } else if (!(nss instanceof TemplateSequenceModel)) { - if (namespaces != null) { - throw new NonSequenceException(namespaces, nss, env); - } else { - // Should not occur - throw new _MiscTemplateException(env, "Expecting a sequence of namespaces after \"using\""); - } - } - } - - env.recurse((TemplateNodeModel) node, (TemplateSequenceModel) nss); - return null; - } - - @Override - protected String dump(boolean canonical) { - StringBuilder sb = new StringBuilder(); - if (canonical) sb.append('<'); - sb.append(getNodeTypeSymbol()); - if (targetNode != null) { - sb.append(' '); - sb.append(targetNode.getCanonicalForm()); - } - if (namespaces != null) { - sb.append(" using "); - sb.append(namespaces.getCanonicalForm()); - } - if (canonical) sb.append("/>"); - return sb.toString(); - } - - @Override - String getNodeTypeSymbol() { - return "#recurse"; - } - - @Override - int getParameterCount() { - return 2; - } - - @Override - Object getParameterValue(int idx) { - switch (idx) { - case 0: return targetNode; - case 1: return namespaces; - default: throw new IndexOutOfBoundsException(); - } - } - - @Override - ParameterRole getParameterRole(int idx) { - switch (idx) { - case 0: return ParameterRole.NODE; - case 1: return ParameterRole.NAMESPACE; - default: throw new IndexOutOfBoundsException(); - } - } - - @Override - boolean isNestedBlockRepeater() { - return false; - } - - @Override - boolean isShownInStackTrace() { - return true; - } - -} http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/ecb4e230/src/main/java/freemarker/core/RegexpHelper.java ---------------------------------------------------------------------- diff --git a/src/main/java/freemarker/core/RegexpHelper.java b/src/main/java/freemarker/core/RegexpHelper.java deleted file mode 100644 index 30d4dcf..0000000 --- a/src/main/java/freemarker/core/RegexpHelper.java +++ /dev/null @@ -1,209 +0,0 @@ -/* - * 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.regex.Pattern; -import java.util.regex.PatternSyntaxException; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import freemarker.cache.MruCacheStorage; -import freemarker.template.TemplateModelException; -import freemarker.template.utility.StringUtil; - -/** - * Helper for language features (like built-ins) that use regular expressions. - */ -final class RegexpHelper { - - private static final Logger LOG = LoggerFactory.getLogger("freemarker.runtime"); - - private static volatile boolean flagWarningsEnabled = LOG.isWarnEnabled(); - private static final int MAX_FLAG_WARNINGS_LOGGED = 25; - private static final Object flagWarningsCntSync = new Object(); - private static int flagWarningsCnt; - - private static final MruCacheStorage patternCache = new MruCacheStorage(50, 150); - - static private long intFlagToLong(int flag) { - return flag & 0x0000FFFFL; - } - - // Standard regular expression flags converted to long: - static final long RE_FLAG_CASE_INSENSITIVE = intFlagToLong(Pattern.CASE_INSENSITIVE); - - static final long RE_FLAG_MULTILINE = intFlagToLong(Pattern.MULTILINE); - - static final long RE_FLAG_COMMENTS = intFlagToLong(Pattern.COMMENTS); - - static final long RE_FLAG_DOTALL = intFlagToLong(Pattern.DOTALL); - - // FreeMarker-specific regular expression flags (using the higher 32 bits): - static final long RE_FLAG_REGEXP = 0x100000000L; - - static final long RE_FLAG_FIRST_ONLY = 0x200000000L; - - // Can't be instantiated - private RegexpHelper() { } - - static Pattern getPattern(String patternString, int flags) - throws TemplateModelException { - PatternCacheKey patternKey = new PatternCacheKey(patternString, flags); - - Pattern result; - - synchronized (patternCache) { - result = (Pattern) patternCache.get(patternKey); - } - if (result != null) { - return result; - } - - try { - result = Pattern.compile(patternString, flags); - } catch (PatternSyntaxException e) { - throw new _TemplateModelException(e, - "Malformed regular expression: ", new _DelayedGetMessage(e)); - } - synchronized (patternCache) { - patternCache.put(patternKey, result); - } - return result; - }; - - private static class PatternCacheKey { - private final String patternString; - private final int flags; - private final int hashCode; - - public PatternCacheKey(String patternString, int flags) { - this.patternString = patternString; - this.flags = flags; - hashCode = patternString.hashCode() + 31 * flags; - } - - @Override - public boolean equals(Object that) { - if (that instanceof PatternCacheKey) { - PatternCacheKey thatPCK = (PatternCacheKey) that; - return thatPCK.flags == flags - && thatPCK.patternString.equals(patternString); - } else { - return false; - } - } - - @Override - public int hashCode() { - return hashCode; - } - - } - - static long parseFlagString(String flagString) { - long flags = 0; - for (int i = 0; i < flagString.length(); i++) { - char c = flagString.charAt(i); - switch (c) { - case 'i': - flags |= RE_FLAG_CASE_INSENSITIVE; - break; - case 'm': - flags |= RE_FLAG_MULTILINE; - break; - case 'c': - flags |= RE_FLAG_COMMENTS; - break; - case 's': - flags |= RE_FLAG_DOTALL; - break; - case 'r': - flags |= RE_FLAG_REGEXP; - break; - case 'f': - flags |= RE_FLAG_FIRST_ONLY; - break; - default: - if (flagWarningsEnabled) { - // [FM3] Should be an error - RegexpHelper.logFlagWarning( - "Unrecognized regular expression flag: " - + StringUtil.jQuote(String.valueOf(c)) + "."); - } - } // switch - } - return flags; - } - - /** - * Logs flag warning for a limited number of times. This is used to prevent - * log flooding. - */ - static void logFlagWarning(String message) { - if (!flagWarningsEnabled) return; - - int cnt; - synchronized (flagWarningsCntSync) { - cnt = flagWarningsCnt; - if (cnt < MAX_FLAG_WARNINGS_LOGGED) { - flagWarningsCnt++; - } else { - flagWarningsEnabled = false; - return; - } - } - message += " This will be an error in some later FreeMarker version!"; - if (cnt + 1 == MAX_FLAG_WARNINGS_LOGGED) { - message += " [Will not log more regular expression flag problems until restart!]"; - } - LOG.warn(message); - } - - static void checkNonRegexpFlags(String biName, long flags) throws _TemplateModelException { - checkOnlyHasNonRegexpFlags(biName, flags, false); - } - - static void checkOnlyHasNonRegexpFlags(String biName, long flags, boolean strict) - throws _TemplateModelException { - if (!strict && !flagWarningsEnabled) return; - - String flag; - if ((flags & RE_FLAG_MULTILINE) != 0) { - flag = "m"; - } else if ((flags & RE_FLAG_DOTALL) != 0) { - flag = "s"; - } else if ((flags & RE_FLAG_COMMENTS) != 0) { - flag = "c"; - } else { - return; - } - - final Object[] msg = { "?", biName ," doesn't support the \"", flag, "\" flag " - + "without the \"r\" flag." }; - if (strict) { - throw new _TemplateModelException(msg); - } else { - // Suppress error for backward compatibility - logFlagWarning(new _ErrorDescriptionBuilder(msg).toString()); - } - } - -} http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/ecb4e230/src/main/java/freemarker/core/ReturnInstruction.java ---------------------------------------------------------------------- diff --git a/src/main/java/freemarker/core/ReturnInstruction.java b/src/main/java/freemarker/core/ReturnInstruction.java deleted file mode 100644 index 51feab7..0000000 --- a/src/main/java/freemarker/core/ReturnInstruction.java +++ /dev/null @@ -1,93 +0,0 @@ -/* - * 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 freemarker.template.TemplateException; - -/** - * Represents a <return> instruction to jump out of a macro. - */ -public final class ReturnInstruction extends TemplateElement { - - private Expression exp; - - ReturnInstruction(Expression exp) { - this.exp = exp; - } - - @Override - TemplateElement[] accept(Environment env) throws TemplateException { - if (exp != null) { - env.setLastReturnValue(exp.eval(env)); - } - if (nextSibling() == null && getParentElement() instanceof Macro) { - // Avoid unnecessary exception throwing - return null; - } - throw Return.INSTANCE; - } - - @Override - protected String dump(boolean canonical) { - StringBuilder sb = new StringBuilder(); - if (canonical) sb.append('<'); - sb.append(getNodeTypeSymbol()); - if (exp != null) { - sb.append(' '); - sb.append(exp.getCanonicalForm()); - } - if (canonical) sb.append("/>"); - return sb.toString(); - } - - @Override - String getNodeTypeSymbol() { - return "#return"; - } - - public static class Return extends RuntimeException { - static final Return INSTANCE = new Return(); - private Return() { - } - } - - @Override - int getParameterCount() { - return 1; - } - - @Override - Object getParameterValue(int idx) { - if (idx != 0) throw new IndexOutOfBoundsException(); - return exp; - } - - @Override - ParameterRole getParameterRole(int idx) { - if (idx != 0) throw new IndexOutOfBoundsException(); - return ParameterRole.VALUE; - } - - @Override - boolean isNestedBlockRepeater() { - return false; - } - -} http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/ecb4e230/src/main/java/freemarker/core/RightUnboundedRangeModel.java ---------------------------------------------------------------------- diff --git a/src/main/java/freemarker/core/RightUnboundedRangeModel.java b/src/main/java/freemarker/core/RightUnboundedRangeModel.java deleted file mode 100644 index bc95894..0000000 --- a/src/main/java/freemarker/core/RightUnboundedRangeModel.java +++ /dev/null @@ -1,48 +0,0 @@ -/* - * 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; - -abstract class RightUnboundedRangeModel extends RangeModel { - - RightUnboundedRangeModel(int begin) { - super(begin); - } - - @Override - final int getStep() { - return 1; - } - - @Override - final boolean isRightUnbounded() { - return true; - } - - @Override - final boolean isRightAdaptive() { - return true; - } - - @Override - final boolean isAffactedByStringSlicingBug() { - return false; - } - -} http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/ecb4e230/src/main/java/freemarker/core/Sep.java ---------------------------------------------------------------------- diff --git a/src/main/java/freemarker/core/Sep.java b/src/main/java/freemarker/core/Sep.java deleted file mode 100644 index 848bcd8..0000000 --- a/src/main/java/freemarker/core/Sep.java +++ /dev/null @@ -1,90 +0,0 @@ -/* - * 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.IteratorBlock.IterationContext; -import freemarker.template.TemplateException; - -/** - * A #sep element. - */ -class Sep extends TemplateElement { - - public Sep(TemplateElements children) { - setChildren(children); - } - - @Override - TemplateElement[] accept(Environment env) throws TemplateException, IOException { - final IterationContext iterCtx = IteratorBlock.findEnclosingIterationContext(env, null); - if (iterCtx == null) { - // The parser should prevent this situation - throw new _MiscTemplateException(env, - getNodeTypeSymbol(), " without iteration in context"); - } - - if (iterCtx.hasNext()) { - return getChildBuffer(); - } - return null; - } - - @Override - boolean isNestedBlockRepeater() { - return false; - } - - @Override - protected String dump(boolean canonical) { - StringBuilder sb = new StringBuilder(); - if (canonical) sb.append('<'); - sb.append(getNodeTypeSymbol()); - if (canonical) { - sb.append('>'); - sb.append(getChildrenCanonicalForm()); - sb.append("</"); - sb.append(getNodeTypeSymbol()); - sb.append('>'); - } - return sb.toString(); - } - - @Override - String getNodeTypeSymbol() { - return "#sep"; - } - - @Override - int getParameterCount() { - return 0; - } - - @Override - Object getParameterValue(int idx) { - throw new IndexOutOfBoundsException(); - } - - @Override - ParameterRole getParameterRole(int idx) { - throw new IndexOutOfBoundsException(); - } - -} http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/ecb4e230/src/main/java/freemarker/core/SpecialBuiltIn.java ---------------------------------------------------------------------- diff --git a/src/main/java/freemarker/core/SpecialBuiltIn.java b/src/main/java/freemarker/core/SpecialBuiltIn.java deleted file mode 100644 index b7451ef..0000000 --- a/src/main/java/freemarker/core/SpecialBuiltIn.java +++ /dev/null @@ -1,27 +0,0 @@ -/* - * 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; - - -/** - * Marker class for built-ins that has special treatment during parsing. - */ -abstract class SpecialBuiltIn extends BuiltIn { - -} http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/ecb4e230/src/main/java/freemarker/core/StopException.java ---------------------------------------------------------------------- diff --git a/src/main/java/freemarker/core/StopException.java b/src/main/java/freemarker/core/StopException.java deleted file mode 100644 index 5e3002d..0000000 --- a/src/main/java/freemarker/core/StopException.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * 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.PrintStream; -import java.io.PrintWriter; - -import freemarker.template.TemplateException; - -/** - * This exception is thrown when a <tt>#stop</tt> directive is encountered. - */ -public class StopException extends TemplateException { - - StopException(Environment env) { - super(env); - } - - StopException(Environment env, String s) { - super(s, env); - } - - @Override - public void printStackTrace(PrintWriter pw) { - synchronized (pw) { - String msg = this.getMessage(); - pw.print("Encountered stop instruction"); - if (msg != null && !msg.equals("")) { - pw.println("\nCause given: " + msg); - } else pw.println(); - super.printStackTrace(pw); - } - } - - @Override - public void printStackTrace(PrintStream ps) { - synchronized (ps) { - String msg = this.getMessage(); - ps.print("Encountered stop instruction"); - if (msg != null && !msg.equals("")) { - ps.println("\nCause given: " + msg); - } else ps.println(); - super.printStackTrace(ps); - } - } - -} - - http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/ecb4e230/src/main/java/freemarker/core/StopInstruction.java ---------------------------------------------------------------------- diff --git a/src/main/java/freemarker/core/StopInstruction.java b/src/main/java/freemarker/core/StopInstruction.java deleted file mode 100644 index 590d9f1..0000000 --- a/src/main/java/freemarker/core/StopInstruction.java +++ /dev/null @@ -1,83 +0,0 @@ -/* - * 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 freemarker.template.TemplateException; - -/** - * Represents a <stop> instruction to abort template processing. - */ -final class StopInstruction extends TemplateElement { - - private Expression exp; - - StopInstruction(Expression exp) { - this.exp = exp; - } - - @Override - TemplateElement[] accept(Environment env) throws TemplateException { - if (exp == null) { - throw new StopException(env); - } - throw new StopException(env, exp.evalAndCoerceToPlainText(env)); - } - - @Override - protected String dump(boolean canonical) { - StringBuilder sb = new StringBuilder(); - if (canonical) sb.append('<'); - sb.append(getNodeTypeSymbol()); - if (exp != null) { - sb.append(' '); - sb.append(exp.getCanonicalForm()); - } - if (canonical) sb.append("/>"); - return sb.toString(); - } - - @Override - String getNodeTypeSymbol() { - return "#stop"; - } - - @Override - int getParameterCount() { - return 1; - } - - @Override - Object getParameterValue(int idx) { - if (idx != 0) throw new IndexOutOfBoundsException(); - return exp; - } - - @Override - ParameterRole getParameterRole(int idx) { - if (idx != 0) throw new IndexOutOfBoundsException(); - return ParameterRole.MESSAGE; - } - - @Override - boolean isNestedBlockRepeater() { - return false; - } - -} http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/ecb4e230/src/main/java/freemarker/core/StringArraySequence.java ---------------------------------------------------------------------- diff --git a/src/main/java/freemarker/core/StringArraySequence.java b/src/main/java/freemarker/core/StringArraySequence.java deleted file mode 100644 index 5551a18..0000000 --- a/src/main/java/freemarker/core/StringArraySequence.java +++ /dev/null @@ -1,58 +0,0 @@ -/* - * 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 freemarker.template.SimpleScalar; -import freemarker.template.TemplateModel; -import freemarker.template.TemplateScalarModel; -import freemarker.template.TemplateSequenceModel; - -/** - * Sequence variable implementation that wraps a String[] with relatively low - * resource utilization. Warning: it does not copy the wrapped array, so do - * not modify that after the model was made! - */ -public class StringArraySequence implements TemplateSequenceModel { - private String[] stringArray; - private TemplateScalarModel[] array; - - /** - * Warning: Does not copy the argument array! - */ - public StringArraySequence(String[] stringArray) { - this.stringArray = stringArray; - } - - public TemplateModel get(int index) { - if (array == null) { - array = new TemplateScalarModel[stringArray.length]; - } - TemplateScalarModel result = array[index]; - if (result == null) { - result = new SimpleScalar(stringArray[index]); - array[index] = result; - } - return result; - } - - public int size() { - return stringArray.length; - } -} http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/ecb4e230/src/main/java/freemarker/core/StringLiteral.java ---------------------------------------------------------------------- diff --git a/src/main/java/freemarker/core/StringLiteral.java b/src/main/java/freemarker/core/StringLiteral.java deleted file mode 100644 index a81f726..0000000 --- a/src/main/java/freemarker/core/StringLiteral.java +++ /dev/null @@ -1,207 +0,0 @@ -/* - * 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.StringReader; -import java.util.List; - -import freemarker.template.SimpleScalar; -import freemarker.template.Template; -import freemarker.template.TemplateException; -import freemarker.template.TemplateModel; -import freemarker.template.TemplateScalarModel; -import freemarker.template.utility.StringUtil; - -final class StringLiteral extends Expression implements TemplateScalarModel { - - private final String value; - - /** {@link List} of {@link String}-s and {@link Interpolation}-s. */ - private List<Object> dynamicValue; - - StringLiteral(String value) { - this.value = value; - } - - /** - * @param parentTkMan - * The token source of the template that contains this string literal. As of this writing, we only need - * this to share the {@code namingConvetion} with that. - */ - void parseValue(FMParserTokenManager parentTkMan, OutputFormat outputFormat) throws ParseException { - // The way this works is incorrect (the literal should be parsed without un-escaping), - // but we can't fix this backward compatibly. - if (value.length() > 3 && (value.indexOf("${") >= 0 || value.indexOf("#{") >= 0)) { - - Template parentTemplate = getTemplate(); - ParserConfiguration pcfg = parentTemplate.getParserConfiguration(); - - try { - SimpleCharStream simpleCharacterStream = new SimpleCharStream( - new StringReader(value), - beginLine, beginColumn + 1, - value.length()); - simpleCharacterStream.setTabSize(pcfg.getTabSize()); - - FMParserTokenManager tkMan = new FMParserTokenManager( - simpleCharacterStream); - - FMParser parser = new FMParser(parentTemplate, false, tkMan, pcfg, - TemplateSpecifiedEncodingHandler.DEFAULT); - // We continue from the parent parser's current state: - parser.setupStringLiteralMode(parentTkMan, outputFormat); - try { - dynamicValue = parser.StaticTextAndInterpolations(); - } finally { - // The parent parser continues from this parser's current state: - parser.tearDownStringLiteralMode(parentTkMan); - } - } catch (ParseException e) { - e.setTemplateName(parentTemplate.getSourceName()); - throw e; - } - this.constantValue = null; - } - } - - @Override - TemplateModel _eval(Environment env) throws TemplateException { - if (dynamicValue == null) { - return new SimpleScalar(value); - } else { - // This should behave like concatenating the values with `+`. Thus, an interpolated expression that - // returns markup promotes the result of the whole expression to markup. - - // Exactly one of these is non-null, depending on if the result will be plain text or markup, which can - // change during evaluation, depending on the result of the interpolations: - StringBuilder plainTextResult = null; - TemplateMarkupOutputModel<?> markupResult = null; - - for (Object part : dynamicValue) { - Object calcedPart = - part instanceof String ? part - : ((Interpolation) part).calculateInterpolatedStringOrMarkup(env); - if (markupResult != null) { - TemplateMarkupOutputModel<?> partMO = calcedPart instanceof String - ? markupResult.getOutputFormat().fromPlainTextByEscaping((String) calcedPart) - : (TemplateMarkupOutputModel<?>) calcedPart; - markupResult = EvalUtil.concatMarkupOutputs(this, markupResult, partMO); - } else { // We are using `plainTextOutput` (or nothing yet) - if (calcedPart instanceof String) { - String partStr = (String) calcedPart; - if (plainTextResult == null) { - plainTextResult = new StringBuilder(partStr); - } else { - plainTextResult.append(partStr); - } - } else { // `calcedPart` is TemplateMarkupOutputModel - TemplateMarkupOutputModel<?> moPart = (TemplateMarkupOutputModel<?>) calcedPart; - if (plainTextResult != null) { - TemplateMarkupOutputModel<?> leftHandMO = moPart.getOutputFormat() - .fromPlainTextByEscaping(plainTextResult.toString()); - markupResult = EvalUtil.concatMarkupOutputs(this, leftHandMO, moPart); - plainTextResult = null; - } else { - markupResult = moPart; - } - } - } - } // for each part - return markupResult != null ? markupResult - : plainTextResult != null ? new SimpleScalar(plainTextResult.toString()) - : SimpleScalar.EMPTY_STRING; - } - } - - @Override - public String getAsString() { - return value; - } - - /** - * Tells if this is something like <tt>"${foo}"</tt>, which is usually a user mistake. - */ - boolean isSingleInterpolationLiteral() { - return dynamicValue != null && dynamicValue.size() == 1 - && dynamicValue.get(0) instanceof Interpolation; - } - - @Override - public String getCanonicalForm() { - if (dynamicValue == null) { - return StringUtil.ftlQuote(value); - } else { - StringBuilder sb = new StringBuilder(); - sb.append('"'); - for (Object child : dynamicValue) { - if (child instanceof Interpolation) { - sb.append(((Interpolation) child).getCanonicalFormInStringLiteral()); - } else { - sb.append(StringUtil.FTLStringLiteralEnc((String) child, '"')); - } - } - sb.append('"'); - return sb.toString(); - } - } - - @Override - String getNodeTypeSymbol() { - return dynamicValue == null ? getCanonicalForm() : "dynamic \"...\""; - } - - @Override - boolean isLiteral() { - return dynamicValue == null; - } - - @Override - protected Expression deepCloneWithIdentifierReplaced_inner( - String replacedIdentifier, Expression replacement, ReplacemenetState replacementState) { - StringLiteral cloned = new StringLiteral(value); - // FIXME: replacedIdentifier should be searched inside interpolatedOutput too: - cloned.dynamicValue = this.dynamicValue; - return cloned; - } - - @Override - int getParameterCount() { - return dynamicValue == null ? 0 : dynamicValue.size(); - } - - @Override - Object getParameterValue(int idx) { - checkIndex(idx); - return dynamicValue.get(idx); - } - - private void checkIndex(int idx) { - if (dynamicValue == null || idx >= dynamicValue.size()) { - throw new IndexOutOfBoundsException(); - } - } - - @Override - ParameterRole getParameterRole(int idx) { - checkIndex(idx); - return ParameterRole.VALUE_PART; - } - -} http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/ecb4e230/src/main/java/freemarker/core/SwitchBlock.java ---------------------------------------------------------------------- diff --git a/src/main/java/freemarker/core/SwitchBlock.java b/src/main/java/freemarker/core/SwitchBlock.java deleted file mode 100644 index 2cef5ce..0000000 --- a/src/main/java/freemarker/core/SwitchBlock.java +++ /dev/null @@ -1,132 +0,0 @@ -/* - * 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.template.TemplateException; - -/** - * An instruction representing a switch-case structure. - */ -final class SwitchBlock extends TemplateElement { - - private Case defaultCase; - private final Expression searched; - - /** - * @param searched the expression to be tested. - */ - SwitchBlock(Expression searched) { - this.searched = searched; - setChildBufferCapacity(4); - } - - /** - * @param cas a Case element. - */ - void addCase(Case cas) { - if (cas.condition == null) { - defaultCase = cas; - } - addChild(cas); - } - - @Override - TemplateElement[] accept(Environment env) - throws TemplateException, IOException { - boolean processedCase = false; - int ln = getChildCount(); - try { - for (int i = 0; i < ln; i++) { - Case cas = (Case) getChild(i); - boolean processCase = false; - - // Fall through if a previous case tested true. - if (processedCase) { - processCase = true; - } else if (cas.condition != null) { - // Otherwise, if this case isn't the default, test it. - processCase = EvalUtil.compare( - searched, - EvalUtil.CMP_OP_EQUALS, "case==", cas.condition, cas.condition, env); - } - if (processCase) { - env.visit(cas); - processedCase = true; - } - } - - // If we didn't process any nestedElements, and we have a default, - // process it. - if (!processedCase && defaultCase != null) { - env.visit(defaultCase); - } - } catch (BreakInstruction.Break br) {} - return null; - } - - @Override - protected String dump(boolean canonical) { - StringBuilder buf = new StringBuilder(); - if (canonical) buf.append('<'); - buf.append(getNodeTypeSymbol()); - buf.append(' '); - buf.append(searched.getCanonicalForm()); - if (canonical) { - buf.append('>'); - int ln = getChildCount(); - for (int i = 0; i < ln; i++) { - Case cas = (Case) getChild(i); - buf.append(cas.getCanonicalForm()); - } - buf.append("</").append(getNodeTypeSymbol()).append('>'); - } - return buf.toString(); - } - - @Override - String getNodeTypeSymbol() { - return "#switch"; - } - - @Override - int getParameterCount() { - return 1; - } - - @Override - Object getParameterValue(int idx) { - if (idx != 0) throw new IndexOutOfBoundsException(); - return searched; - } - - @Override - ParameterRole getParameterRole(int idx) { - if (idx != 0) throw new IndexOutOfBoundsException(); - return ParameterRole.VALUE; - } - - @Override - boolean isNestedBlockRepeater() { - return false; - } - -} http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/ecb4e230/src/main/java/freemarker/core/TemplateClassResolver.java ---------------------------------------------------------------------- diff --git a/src/main/java/freemarker/core/TemplateClassResolver.java b/src/main/java/freemarker/core/TemplateClassResolver.java deleted file mode 100644 index afe4707..0000000 --- a/src/main/java/freemarker/core/TemplateClassResolver.java +++ /dev/null @@ -1,84 +0,0 @@ -/* - * 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 freemarker.template.Template; -import freemarker.template.TemplateException; -import freemarker.template.utility.ClassUtil; - -/** - * Used by built-ins and other template language features that get a class - * based on a string. This can be handy both for implementing security - * restrictions and for working around local class-loader issues. - * - * The implementation should be thread-safe, unless an - * instance is always only used in a single {@link Environment} object. - * - * @see Configurable#setNewBuiltinClassResolver(TemplateClassResolver) - * - * @since 2.3.17 - */ -public interface TemplateClassResolver { - - /** - * Simply calls {@link ClassUtil#forName(String)}. - */ - TemplateClassResolver UNRESTRICTED_RESOLVER = new TemplateClassResolver() { - - @Override - public Class resolve(String className, Environment env, Template template) - throws TemplateException { - try { - return ClassUtil.forName(className); - } catch (ClassNotFoundException e) { - throw new _MiscTemplateException(e, env); - } - } - - }; - - /** - * Doesn't allow resolving any classes. - */ - TemplateClassResolver ALLOWS_NOTHING_RESOLVER = new TemplateClassResolver() { - - @Override - public Class resolve(String className, Environment env, Template template) - throws TemplateException { - throw MessageUtil.newInstantiatingClassNotAllowedException(className, env); - } - - }; - - /** - * Gets a {@link Class} based on the class name. - * - * @param className the full-qualified class name - * @param env the environment in which the template executes - * @param template the template where the operation that require the - * class resolution resides in. This is <code>null</code> if the - * call doesn't come from a template. - * - * @throws TemplateException if the class can't be found or shouldn't be - * accessed from a template for security reasons. - */ - Class resolve(String className, Environment env, Template template) throws TemplateException; - -} http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/ecb4e230/src/main/java/freemarker/core/TemplateCombinedMarkupOutputModel.java ---------------------------------------------------------------------- diff --git a/src/main/java/freemarker/core/TemplateCombinedMarkupOutputModel.java b/src/main/java/freemarker/core/TemplateCombinedMarkupOutputModel.java deleted file mode 100644 index 0bb72a2..0000000 --- a/src/main/java/freemarker/core/TemplateCombinedMarkupOutputModel.java +++ /dev/null @@ -1,50 +0,0 @@ -/* - * 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; - -/** - * Stores combined markup to be printed; used with {@link CombinedMarkupOutputFormat}. - * - * @since 2.3.24 - */ -public final class TemplateCombinedMarkupOutputModel - extends CommonTemplateMarkupOutputModel<TemplateCombinedMarkupOutputModel> { - - private final CombinedMarkupOutputFormat outputFormat; - - /** - * See {@link CommonTemplateMarkupOutputModel#CommonTemplateMarkupOutputModel(String, String)}. - * - * @param outputFormat - * The {@link CombinedMarkupOutputFormat} format this value is bound to. Because - * {@link CombinedMarkupOutputFormat} has no singleton, we have to pass it in, unlike with most other - * {@link CommonTemplateMarkupOutputModel}-s. - */ - TemplateCombinedMarkupOutputModel(String plainTextContent, String markupContent, - CombinedMarkupOutputFormat outputFormat) { - super(plainTextContent, markupContent); - this.outputFormat = outputFormat; - } - - @Override - public CombinedMarkupOutputFormat getOutputFormat() { - return outputFormat; - } - -} http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/ecb4e230/src/main/java/freemarker/core/TemplateConfiguration.java ---------------------------------------------------------------------- diff --git a/src/main/java/freemarker/core/TemplateConfiguration.java b/src/main/java/freemarker/core/TemplateConfiguration.java deleted file mode 100644 index 019f547..0000000 --- a/src/main/java/freemarker/core/TemplateConfiguration.java +++ /dev/null @@ -1,645 +0,0 @@ -/* - * 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.Reader; -import java.util.ArrayList; -import java.util.LinkedHashMap; -import java.util.List; -import java.util.Map; - -import freemarker.cache.TemplateCache; -import freemarker.template.Configuration; -import freemarker.template.Template; -import freemarker.template.Version; -import freemarker.template._TemplateAPI; -import freemarker.template.utility.NullArgumentException; - -/** - * Used for customizing the configuration settings for individual {@link Template}-s (or rather groups of templates), - * relatively to the common setting values coming from the {@link Configuration}. This was designed with the standard - * template loading mechanism of FreeMarker in mind ({@link Configuration#getTemplate(String)} - * and {@link TemplateCache}), though can also be reused for custom template loading and caching solutions. - * - * <p> - * Note on the {@code locale} setting: When used with the standard template loading/caching mechanism ( - * {@link Configuration#getTemplate(String)} and its overloads), localized lookup happens before the {@code locale} - * specified here could have effect. The {@code locale} will be only set in the template that the localized lookup has - * already found. - * - * <p> - * Note on the encoding setting {@code encoding}: See {@link #setEncoding(String)}. - * - * <p> - * Note that the result value of the reader methods (getter and "is" methods) is usually not useful unless the value of - * that setting was already set on this object. Otherwise you will get the value from the parent {@link Configuration}, - * or an {@link IllegalStateException} before this object is associated to a {@link Configuration}. - * - * <p> - * If you are using this class for your own template loading and caching solution, rather than with the standard one, - * you should be aware of a few more details: - * - * <ul> - * <li>This class implements both {@link Configurable} and {@link ParserConfiguration}. This means that it can influence - * both the template parsing phase and the runtime settings. For both aspects (i.e., {@link ParserConfiguration} and - * {@link Configurable}) to take effect, you have first pass this object to the {@link Template} constructor - * (this is where the {@link ParserConfiguration} interface is used), and then you have to call {@link #apply(Template)} - * on the resulting {@link Template} object (this is where the {@link Configurable} aspect is used). - * - * <li>{@link #apply(Template)} only change the settings that weren't yet set on the {@link Template} (but are inherited - * from the {@link Configuration}). This is primarily because if the template configures itself via the {@code #ftl} - * header, those values should have precedence. A consequence of this is that if you want to configure the same - * {@link Template} with multiple {@link TemplateConfiguration}-s, you either should merge them to a single one before - * that (with {@link #merge(TemplateConfiguration)}), or you have to apply them in reverse order of their intended - * precedence. - * </ul> - * - * @see Template#Template(String, String, Reader, Configuration, ParserConfiguration, String) - * - * @since 2.3.24 - */ -public final class TemplateConfiguration extends Configurable implements ParserConfiguration { - - private boolean parentConfigurationSet; - private Integer tagSyntax; - private Integer namingConvention; - private Boolean whitespaceStripping; - private Integer autoEscapingPolicy; - private Boolean recognizeStandardFileExtensions; - private OutputFormat outputFormat; - private String encoding; - private Integer tabSize; - - /** - * Creates a new instance. The parent will be {@link Configuration#getDefaultConfiguration()} initially, but it will - * be changed to the real parent {@link Configuration} when this object is added to the {@link Configuration}. (It's - * not allowed to add the same instance to multiple {@link Configuration}-s). - */ - public TemplateConfiguration() { - super(Configuration.getDefaultConfiguration()); - } - - /** - * Same as {@link #setParentConfiguration(Configuration)}. - */ - @Override - void setParent(Configurable cfg) { - NullArgumentException.check("cfg", cfg); - if (!(cfg instanceof Configuration)) { - throw new IllegalArgumentException("The parent of a TemplateConfiguration can only be a Configuration"); - } - - if (parentConfigurationSet) { - if (getParent() != cfg) { - throw new IllegalStateException( - "This TemplateConfiguration is already associated with a different Configuration instance."); - } - return; - } - - if (((Configuration) cfg).getIncompatibleImprovements().intValue() < _TemplateAPI.VERSION_INT_2_3_22 - && hasAnyConfigurableSet()) { - throw new IllegalStateException( - "This TemplateConfiguration can't be associated to a Configuration that has " - + "incompatibleImprovements less than 2.3.22, because it changes non-parser settings."); - } - - super.setParent(cfg); - parentConfigurationSet = true; - } - - /** - * Associates this instance with a {@link Configuration}; usually you don't call this, as it's called internally - * when this instance is added to a {@link Configuration}. This method can be called only once (except with the same - * {@link Configuration} parameter again, as that changes nothing anyway). - * - * @throws IllegalArgumentException - * if the argument is {@code null} or not a {@link Configuration} - * @throws IllegalStateException - * if this object is already associated to a different {@link Configuration} object, - * or if the {@code Configuration} has {@code #getIncompatibleImprovements()} less than 2.3.22 and - * this object tries to change any non-parser settings - */ - public void setParentConfiguration(Configuration cfg) { - setParent(cfg); - } - - /** - * Returns the parent {@link Configuration}, or {@code null} if none was associated yet. - */ - public Configuration getParentConfiguration() { - return parentConfigurationSet ? (Configuration) getParent() : null; - } - - private Configuration getNonNullParentConfiguration() { - checkParentConfigurationSet(); - return (Configuration) getParent(); - } - - /** - * Set all settings in this {@link TemplateConfiguration} that were set in the parameter - * {@link TemplateConfiguration}, possibly overwriting the earlier value in this object. (A setting is said to be - * set in a {@link TemplateConfiguration} if it was explicitly set via a setter method, as opposed to be inherited.) - */ - public void merge(TemplateConfiguration tc) { - if (tc.isAPIBuiltinEnabledSet()) { - setAPIBuiltinEnabled(tc.isAPIBuiltinEnabled()); - } - if (tc.isArithmeticEngineSet()) { - setArithmeticEngine(tc.getArithmeticEngine()); - } - if (tc.isAutoEscapingPolicySet()) { - setAutoEscapingPolicy(tc.getAutoEscapingPolicy()); - } - if (tc.isAutoFlushSet()) { - setAutoFlush(tc.getAutoFlush()); - } - if (tc.isBooleanFormatSet()) { - setBooleanFormat(tc.getBooleanFormat()); - } - if (tc.isCustomDateFormatsSet()) { - setCustomDateFormats(mergeMaps(getCustomDateFormats(), tc.getCustomDateFormats(), false)); - } - if (tc.isCustomNumberFormatsSet()) { - setCustomNumberFormats(mergeMaps(getCustomNumberFormats(), tc.getCustomNumberFormats(), false)); - } - if (tc.isDateFormatSet()) { - setDateFormat(tc.getDateFormat()); - } - if (tc.isDateTimeFormatSet()) { - setDateTimeFormat(tc.getDateTimeFormat()); - } - if (tc.isEncodingSet()) { - setEncoding(tc.getEncoding()); - } - if (tc.isLocaleSet()) { - setLocale(tc.getLocale()); - } - if (tc.isLogTemplateExceptionsSet()) { - setLogTemplateExceptions(tc.getLogTemplateExceptions()); - } - if (tc.isNamingConventionSet()) { - setNamingConvention(tc.getNamingConvention()); - } - if (tc.isNewBuiltinClassResolverSet()) { - setNewBuiltinClassResolver(tc.getNewBuiltinClassResolver()); - } - if (tc.isNumberFormatSet()) { - setNumberFormat(tc.getNumberFormat()); - } - if (tc.isObjectWrapperSet()) { - setObjectWrapper(tc.getObjectWrapper()); - } - if (tc.isOutputEncodingSet()) { - setOutputEncoding(tc.getOutputEncoding()); - } - if (tc.isOutputFormatSet()) { - setOutputFormat(tc.getOutputFormat()); - } - if (tc.isRecognizeStandardFileExtensionsSet()) { - setRecognizeStandardFileExtensions(tc.getRecognizeStandardFileExtensions()); - } - if (tc.isShowErrorTipsSet()) { - setShowErrorTips(tc.getShowErrorTips()); - } - if (tc.isSQLDateAndTimeTimeZoneSet()) { - setSQLDateAndTimeTimeZone(tc.getSQLDateAndTimeTimeZone()); - } - if (tc.isTagSyntaxSet()) { - setTagSyntax(tc.getTagSyntax()); - } - if (tc.isTemplateExceptionHandlerSet()) { - setTemplateExceptionHandler(tc.getTemplateExceptionHandler()); - } - if (tc.isTimeFormatSet()) { - setTimeFormat(tc.getTimeFormat()); - } - if (tc.isTimeZoneSet()) { - setTimeZone(tc.getTimeZone()); - } - if (tc.isURLEscapingCharsetSet()) { - setURLEscapingCharset(tc.getURLEscapingCharset()); - } - if (tc.isWhitespaceStrippingSet()) { - setWhitespaceStripping(tc.getWhitespaceStripping()); - } - if (tc.isTabSizeSet()) { - setTabSize(tc.getTabSize()); - } - if (tc.isLazyImportsSet()) { - setLazyImports(tc.getLazyImports()); - } - if (tc.isLazyAutoImportsSet()) { - setLazyAutoImports(tc.getLazyAutoImports()); - } - if (tc.isAutoImportsSet()) { - setAutoImports(mergeMaps(getAutoImports(), tc.getAutoImports(), true)); - } - if (tc.isAutoIncludesSet()) { - setAutoIncludes(mergeLists(getAutoIncludes(), tc.getAutoIncludes())); - } - - tc.copyDirectCustomAttributes(this, true); - } - - /** - * Sets those settings of the {@link Template} which aren't yet set in the {@link Template} and are set in this - * {@link TemplateConfiguration}, leaves the other settings as is. A setting is said to be set in a - * {@link TemplateConfiguration} or {@link Template} if it was explicitly set via a setter method on that object, as - * opposed to be inherited from the {@link Configuration}. - * - * <p> - * Note that this method doesn't deal with settings that influence the parser, as those are already baked in at this - * point via the {@link ParserConfiguration}. - * - * <p> - * Note that the {@code encoding} setting of the {@link Template} counts as unset if it's {@code null}, - * even if {@code null} was set via {@link Template#setEncoding(String)}. - * - * @throws IllegalStateException - * If the parent configuration wasn't yet set. - */ - public void apply(Template template) { - Configuration cfg = getNonNullParentConfiguration(); - if (template.getConfiguration() != cfg) { - // This is actually not a problem right now, but for future BC we enforce this. - throw new IllegalArgumentException( - "The argument Template doesn't belong to the same Configuration as the TemplateConfiguration"); - } - - if (isAPIBuiltinEnabledSet() && !template.isAPIBuiltinEnabledSet()) { - template.setAPIBuiltinEnabled(isAPIBuiltinEnabled()); - } - if (isArithmeticEngineSet() && !template.isArithmeticEngineSet()) { - template.setArithmeticEngine(getArithmeticEngine()); - } - if (isAutoFlushSet() && !template.isAutoFlushSet()) { - template.setAutoFlush(getAutoFlush()); - } - if (isBooleanFormatSet() && !template.isBooleanFormatSet()) { - template.setBooleanFormat(getBooleanFormat()); - } - if (isCustomDateFormatsSet()) { - template.setCustomDateFormats( - mergeMaps(getCustomDateFormats(), template.getCustomDateFormatsWithoutFallback(), false)); - } - if (isCustomNumberFormatsSet()) { - template.setCustomNumberFormats( - mergeMaps(getCustomNumberFormats(), template.getCustomNumberFormatsWithoutFallback(), false)); - } - if (isDateFormatSet() && !template.isDateFormatSet()) { - template.setDateFormat(getDateFormat()); - } - if (isDateTimeFormatSet() && !template.isDateTimeFormatSet()) { - template.setDateTimeFormat(getDateTimeFormat()); - } - if (isEncodingSet() && template.getEncoding() == null) { - template.setEncoding(getEncoding()); - } - if (isLocaleSet() && !template.isLocaleSet()) { - template.setLocale(getLocale()); - } - if (isLogTemplateExceptionsSet() && !template.isLogTemplateExceptionsSet()) { - template.setLogTemplateExceptions(getLogTemplateExceptions()); - } - if (isNewBuiltinClassResolverSet() && !template.isNewBuiltinClassResolverSet()) { - template.setNewBuiltinClassResolver(getNewBuiltinClassResolver()); - } - if (isNumberFormatSet() && !template.isNumberFormatSet()) { - template.setNumberFormat(getNumberFormat()); - } - if (isObjectWrapperSet() && !template.isObjectWrapperSet()) { - template.setObjectWrapper(getObjectWrapper()); - } - if (isOutputEncodingSet() && !template.isOutputEncodingSet()) { - template.setOutputEncoding(getOutputEncoding()); - } - if (isShowErrorTipsSet() && !template.isShowErrorTipsSet()) { - template.setShowErrorTips(getShowErrorTips()); - } - if (isSQLDateAndTimeTimeZoneSet() && !template.isSQLDateAndTimeTimeZoneSet()) { - template.setSQLDateAndTimeTimeZone(getSQLDateAndTimeTimeZone()); - } - if (isTemplateExceptionHandlerSet() && !template.isTemplateExceptionHandlerSet()) { - template.setTemplateExceptionHandler(getTemplateExceptionHandler()); - } - if (isTimeFormatSet() && !template.isTimeFormatSet()) { - template.setTimeFormat(getTimeFormat()); - } - if (isTimeZoneSet() && !template.isTimeZoneSet()) { - template.setTimeZone(getTimeZone()); - } - if (isURLEscapingCharsetSet() && !template.isURLEscapingCharsetSet()) { - template.setURLEscapingCharset(getURLEscapingCharset()); - } - if (isLazyImportsSet() && !template.isLazyImportsSet()) { - template.setLazyImports(getLazyImports()); - } - if (isLazyAutoImportsSet() && !template.isLazyAutoImportsSet()) { - template.setLazyAutoImports(getLazyAutoImports()); - } - if (isAutoImportsSet()) { - // Regarding the order of the maps in the merge: - // - Existing template-level imports have precedence over those coming from the TC (just as with the others - // apply()-ed settings), thus for clashing import prefixes they must win. - // - Template-level imports count as more specific, and so come after the more generic ones from TC. - template.setAutoImports(mergeMaps(getAutoImports(), template.getAutoImportsWithoutFallback(), true)); - } - if (isAutoIncludesSet()) { - template.setAutoIncludes(mergeLists(getAutoIncludes(), template.getAutoIncludesWithoutFallback())); - } - - copyDirectCustomAttributes(template, false); - } - - /** - * See {@link Configuration#setTagSyntax(int)}. - */ - public void setTagSyntax(int tagSyntax) { - _TemplateAPI.valideTagSyntaxValue(tagSyntax); - this.tagSyntax = Integer.valueOf(tagSyntax); - } - - /** - * The getter pair of {@link #setTagSyntax(int)}. - */ - @Override - public int getTagSyntax() { - return tagSyntax != null ? tagSyntax.intValue() : getNonNullParentConfiguration().getTagSyntax(); - } - - /** - * Tells if this setting is set directly in this object or its value is coming from the {@link #getParent() parent}. - */ - public boolean isTagSyntaxSet() { - return tagSyntax != null; - } - - /** - * See {@link Configuration#setNamingConvention(int)}. - */ - public void setNamingConvention(int namingConvention) { - _TemplateAPI.validateNamingConventionValue(namingConvention); - this.namingConvention = Integer.valueOf(namingConvention); - } - - /** - * The getter pair of {@link #setNamingConvention(int)}. - */ - @Override - public int getNamingConvention() { - return namingConvention != null ? namingConvention.intValue() - : getNonNullParentConfiguration().getNamingConvention(); - } - - /** - * Tells if this setting is set directly in this object or its value is coming from the {@link #getParent() parent}. - */ - public boolean isNamingConventionSet() { - return namingConvention != null; - } - - /** - * See {@link Configuration#setWhitespaceStripping(boolean)}. - */ - public void setWhitespaceStripping(boolean whitespaceStripping) { - this.whitespaceStripping = Boolean.valueOf(whitespaceStripping); - } - - /** - * The getter pair of {@link #getWhitespaceStripping()}. - */ - @Override - public boolean getWhitespaceStripping() { - return whitespaceStripping != null ? whitespaceStripping.booleanValue() - : getNonNullParentConfiguration().getWhitespaceStripping(); - } - - /** - * Tells if this setting is set directly in this object or its value is coming from the {@link #getParent() parent}. - */ - public boolean isWhitespaceStrippingSet() { - return whitespaceStripping != null; - } - - /** - * Sets the output format of the template; see {@link Configuration#setAutoEscapingPolicy(int)} for more. - */ - public void setAutoEscapingPolicy(int autoEscapingPolicy) { - _TemplateAPI.validateAutoEscapingPolicyValue(autoEscapingPolicy); - this.autoEscapingPolicy = Integer.valueOf(autoEscapingPolicy); - } - - /** - * The getter pair of {@link #setAutoEscapingPolicy(int)}. - */ - @Override - public int getAutoEscapingPolicy() { - return autoEscapingPolicy != null ? autoEscapingPolicy.intValue() - : getNonNullParentConfiguration().getAutoEscapingPolicy(); - } - - /** - * Tells if this setting is set directly in this object or its value is coming from the {@link #getParent() parent}. - */ - public boolean isAutoEscapingPolicySet() { - return autoEscapingPolicy != null; - } - - /** - * Sets the output format of the template; see {@link Configuration#setOutputFormat(OutputFormat)} for more. - */ - public void setOutputFormat(OutputFormat outputFormat) { - NullArgumentException.check("outputFormat", outputFormat); - this.outputFormat = outputFormat; - } - - /** - * The getter pair of {@link #setOutputFormat(OutputFormat)}. - */ - @Override - public OutputFormat getOutputFormat() { - return outputFormat != null ? outputFormat : getNonNullParentConfiguration().getOutputFormat(); - } - - /** - * Tells if this setting is set directly in this object or its value is coming from the {@link #getParent() parent}. - */ - public boolean isOutputFormatSet() { - return outputFormat != null; - } - - /** - * See {@link Configuration#setRecognizeStandardFileExtensions(boolean)}. - */ - public void setRecognizeStandardFileExtensions(boolean recognizeStandardFileExtensions) { - this.recognizeStandardFileExtensions = Boolean.valueOf(recognizeStandardFileExtensions); - } - - /** - * Getter pair of {@link #setRecognizeStandardFileExtensions(boolean)}. - */ - @Override - public boolean getRecognizeStandardFileExtensions() { - return recognizeStandardFileExtensions != null ? recognizeStandardFileExtensions.booleanValue() - : getNonNullParentConfiguration().getRecognizeStandardFileExtensions(); - } - - /** - * Tells if this setting is set directly in this object or its value is coming from the {@link #getParent() parent}. - */ - public boolean isRecognizeStandardFileExtensionsSet() { - return recognizeStandardFileExtensions != null; - } - - @Override - public void setStrictBeanModels(boolean strict) { - throw new UnsupportedOperationException( - "Setting strictBeanModels on " + TemplateConfiguration.class.getSimpleName() + " level isn't supported."); - } - - public String getEncoding() { - return encoding != null ? encoding : getNonNullParentConfiguration().getDefaultEncoding(); - } - - /** - * When the standard template loading/caching mechanism is used, this forces the charset used for reading the - * template "file", overriding everything but the encoding coming from the {@code #ftl} header. This setting - * overrides the locale-specific encodings set via {@link Configuration#setEncoding(java.util.Locale, String)}. It - * also overrides the {@code encoding} parameter of {@link Configuration#getTemplate(String, String)} (and of its - * overloads) and the {@code encoding} parameter of the {@code #include} directive. This works like that because - * specifying the encoding where you are requesting the template is error prone and deprecated. - * - * <p> - * If you are developing your own template loading/caching mechanism instead of the standard one, note that the - * above behavior is not guaranteed by this class alone; you have to ensure it. Also, read the note on - * {@code encoding} in the documentation of {@link #apply(Template)}. - */ - public void setEncoding(String encoding) { - NullArgumentException.check("encoding", encoding); - this.encoding = encoding; - } - - public boolean isEncodingSet() { - return encoding != null; - } - - /** - * See {@link Configuration#setTabSize(int)}. - * - * @since 2.3.25 - */ - public void setTabSize(int tabSize) { - this.tabSize = Integer.valueOf(tabSize); - } - - /** - * Getter pair of {@link #setTabSize(int)}. - * - * @since 2.3.25 - */ - @Override - public int getTabSize() { - return tabSize != null ? tabSize.intValue() - : getNonNullParentConfiguration().getTabSize(); - } - - /** - * Tells if this setting is set directly in this object or its value is coming from the {@link #getParent() parent}. - * - * @since 2.3.25 - */ - public boolean isTabSizeSet() { - return tabSize != null; - } - - /** - * Returns {@link Configuration#getIncompatibleImprovements()} from the parent {@link Configuration}. This mostly - * just exist to satisfy the {@link ParserConfiguration} interface. - * - * @throws IllegalStateException - * If the parent configuration wasn't yet set. - */ - @Override - public Version getIncompatibleImprovements() { - return getNonNullParentConfiguration().getIncompatibleImprovements(); - } - - private void checkParentConfigurationSet() { - if (!parentConfigurationSet) { - throw new IllegalStateException("The TemplateConfiguration wasn't associated with a Configuration yet."); - } - } - - private boolean hasAnyConfigurableSet() { - return - isAPIBuiltinEnabledSet() - || isArithmeticEngineSet() - || isAutoFlushSet() - || isAutoImportsSet() - || isAutoIncludesSet() - || isBooleanFormatSet() - || isCustomDateFormatsSet() - || isCustomNumberFormatsSet() - || isDateFormatSet() - || isDateTimeFormatSet() - || isLazyImportsSet() - || isLazyAutoImportsSet() - || isLocaleSet() - || isLogTemplateExceptionsSet() - || isNewBuiltinClassResolverSet() - || isNumberFormatSet() - || isObjectWrapperSet() - || isOutputEncodingSet() - || isShowErrorTipsSet() - || isSQLDateAndTimeTimeZoneSet() - || isTemplateExceptionHandlerSet() - || isTimeFormatSet() - || isTimeZoneSet() - || isURLEscapingCharsetSet(); - } - - private Map mergeMaps(Map m1, Map m2, boolean overwriteUpdatesOrder) { - if (m1 == null) return m2; - if (m2 == null) return m1; - if (m1.isEmpty()) return m2 != null ? m2 : m1; - if (m2.isEmpty()) return m1 != null ? m1 : m2; - - LinkedHashMap mergedM = new LinkedHashMap((m1.size() + m2.size()) * 4 / 3 + 1, 0.75f); - mergedM.putAll(m1); - for (Object m2Key : m2.keySet()) { - mergedM.remove(m2Key); // So that duplicate keys are moved after m1 keys - } - mergedM.putAll(m2); - return mergedM; - } - - private List<String> mergeLists(List<String> list1, List<String> list2) { - if (list1 == null) return list2; - if (list2 == null) return list1; - if (list1.isEmpty()) return list2 != null ? list2 : list1; - if (list2.isEmpty()) return list1 != null ? list1 : list2; - - ArrayList<String> mergedList = new ArrayList<String>(list1.size() + list2.size()); - mergedList.addAll(list1); - mergedList.addAll(list2); - return mergedList; - } - -}
