FREEMARKER-55: Adding more functions.
Project: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/commit/234f96ec Tree: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/tree/234f96ec Diff: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/diff/234f96ec Branch: refs/heads/3 Commit: 234f96ec2c2868c72f797bda42a8d0c854e63b87 Parents: d0bd43c Author: Woonsan Ko <[email protected]> Authored: Fri Sep 8 12:21:53 2017 -0400 Committer: Woonsan Ko <[email protected]> Committed: Fri Sep 8 12:21:53 2017 -0400 ---------------------------------------------------------------------- .../AbstractSpringTemplateCallableModel.java | 11 +- .../spring/model/BindErrorsDirective.java | 5 +- .../freemarker/spring/model/EvalFunction.java | 153 +++++++++++++++++++ .../spring/model/MessageFunction.java | 14 +- .../freemarker/spring/model/MvcUrlFunction.java | 74 +++++++++ .../model/SpringTemplateCallableHashModel.java | 7 +- .../spring/model/TransformFunction.java | 101 ++++++++++++ .../freemarker/spring/model/UrlFunction.java | 86 +++++++++++ 8 files changed, 437 insertions(+), 14 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/234f96ec/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/AbstractSpringTemplateCallableModel.java ---------------------------------------------------------------------- diff --git a/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/AbstractSpringTemplateCallableModel.java b/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/AbstractSpringTemplateCallableModel.java index de95df5..0d5d6ed 100644 --- a/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/AbstractSpringTemplateCallableModel.java +++ b/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/AbstractSpringTemplateCallableModel.java @@ -73,14 +73,21 @@ public abstract class AbstractSpringTemplateCallableModel implements TemplateCal RequestContext requestContext, String path, boolean ignoreNestedPath) throws TemplateException { final String resolvedPath = (ignoreNestedPath) ? path : resolveNestedPath(env, objectWrapperAndUnwrapper, path); BindStatus status = requestContext.getBindStatus(resolvedPath, false); + return wrapObject(objectWrapperAndUnwrapper, status); + } + + protected final Object unwrapObject(ObjectWrapperAndUnwrapper objectWrapperAndUnwrapper, TemplateModel model) throws TemplateException { + return (model != null) ? objectWrapperAndUnwrapper.unwrap(model) : null; + } - if (status != null) { + protected final TemplateModel wrapObject(ObjectWrapperAndUnwrapper objectWrapperAndUnwrapper, Object object) throws TemplateException { + if (object != null) { if (!(objectWrapperAndUnwrapper instanceof DefaultObjectWrapper)) { CallableUtils.newGenericExecuteException("objectWrapperAndUnwrapper is not a DefaultObjectWrapper.", this, isFunction()); } - return ((DefaultObjectWrapper) objectWrapperAndUnwrapper).wrap(status); + return ((DefaultObjectWrapper) objectWrapperAndUnwrapper).wrap(object); } return null; http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/234f96ec/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/BindErrorsDirective.java ---------------------------------------------------------------------- diff --git a/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/BindErrorsDirective.java b/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/BindErrorsDirective.java index c98db67..e35b6ee 100644 --- a/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/BindErrorsDirective.java +++ b/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/BindErrorsDirective.java @@ -30,7 +30,6 @@ import org.apache.freemarker.core.Environment; import org.apache.freemarker.core.TemplateException; import org.apache.freemarker.core.model.ArgumentArrayLayout; import org.apache.freemarker.core.model.ObjectWrapperAndUnwrapper; -import org.apache.freemarker.core.model.ObjectWrappingException; import org.apache.freemarker.core.model.TemplateModel; import org.apache.freemarker.core.model.impl.DefaultObjectWrapper; import org.apache.freemarker.core.util.CallableUtils; @@ -104,7 +103,7 @@ public class BindErrorsDirective extends AbstractSpringTemplateDirectiveModel { } private final TemplateModel getBindErrorsTemplateModel(Environment env, ObjectWrapperAndUnwrapper objectWrapperAndUnwrapper, - RequestContext requestContext, String name) throws ObjectWrappingException { + RequestContext requestContext, String name) throws TemplateException { final Errors errors = requestContext.getErrors(name, false); if (errors != null && errors.hasErrors()) { @@ -113,7 +112,7 @@ public class BindErrorsDirective extends AbstractSpringTemplateDirectiveModel { this, isFunction()); } - return ((DefaultObjectWrapper) objectWrapperAndUnwrapper).wrap(errors); + return wrapObject(objectWrapperAndUnwrapper, errors); } return null; http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/234f96ec/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/EvalFunction.java ---------------------------------------------------------------------- diff --git a/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/EvalFunction.java b/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/EvalFunction.java new file mode 100644 index 0000000..a380f19 --- /dev/null +++ b/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/EvalFunction.java @@ -0,0 +1,153 @@ +/* + * 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.spring.model; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.freemarker.core.CallPlace; +import org.apache.freemarker.core.Environment; +import org.apache.freemarker.core.TemplateException; +import org.apache.freemarker.core.model.ArgumentArrayLayout; +import org.apache.freemarker.core.model.ObjectWrapperAndUnwrapper; +import org.apache.freemarker.core.model.TemplateModel; +import org.apache.freemarker.core.util.CallableUtils; +import org.springframework.context.expression.BeanFactoryResolver; +import org.springframework.context.expression.EnvironmentAccessor; +import org.springframework.context.expression.MapAccessor; +import org.springframework.core.convert.ConversionService; +import org.springframework.expression.AccessException; +import org.springframework.expression.EvaluationContext; +import org.springframework.expression.Expression; +import org.springframework.expression.ExpressionParser; +import org.springframework.expression.PropertyAccessor; +import org.springframework.expression.TypedValue; +import org.springframework.expression.spel.standard.SpelExpressionParser; +import org.springframework.expression.spel.support.StandardEvaluationContext; +import org.springframework.expression.spel.support.StandardTypeConverter; +import org.springframework.web.servlet.support.RequestContext; + +/** + * A <code>TemplateFunctionModel</code> providing functionality equivalent to the Spring Framework's + * <code><spring:eval /></code> JSP Tag Library. + * <P> + * Some valid example(s): + * </P> + * <PRE> + * </PRE> + * <P> + * <EM>Note:</EM> Unlike Spring Framework's <code><spring:message /></code> JSP Tag Library, this function + * does not support <code>htmlEscape</code> parameter. It always returns the message not to escape HTML's + * because it is much easier to control escaping in FreeMarker Template expressions. + * </P> + */ +public class EvalFunction extends AbstractSpringTemplateFunctionModel { + + public static final String NAME = "eval"; + + private static final int EXPRESSION_PARAM_IDX = 0; + + private static final ArgumentArrayLayout ARGS_LAYOUT = ArgumentArrayLayout.create(1, false, null, false); + + private final ExpressionParser expressionParser = new SpelExpressionParser(); + + public EvalFunction(HttpServletRequest request, HttpServletResponse response) { + super(request, response); + } + + @Override + public TemplateModel executeInternal(TemplateModel[] args, CallPlace callPlace, Environment env, + ObjectWrapperAndUnwrapper objectWrapperAndUnwrapper, RequestContext requestContext) + throws TemplateException { + final String expressionString = CallableUtils.getStringArgument(args, EXPRESSION_PARAM_IDX, this); + final Expression expression = expressionParser.parseExpression(expressionString); + + // TODO: cache evaluationContext somewhere in request level.... + EvaluationContext evaluationContext = createEvaluationContext(env, requestContext); + + final Object result = expression.getValue(evaluationContext); + return wrapObject(objectWrapperAndUnwrapper, result); + } + + @Override + public ArgumentArrayLayout getFunctionArgumentArrayLayout() { + return ARGS_LAYOUT; + } + + private EvaluationContext createEvaluationContext(final Environment env, final RequestContext requestContext) { + StandardEvaluationContext context = new StandardEvaluationContext(); + + context.addPropertyAccessor(new EnvironmentVariablesPropertyAccessor(env)); + context.addPropertyAccessor(new MapAccessor()); + context.addPropertyAccessor(new EnvironmentAccessor()); + context.setBeanResolver(new BeanFactoryResolver(requestContext.getWebApplicationContext())); + + ConversionService conversionService = getConversionService(); + + if (conversionService != null) { + context.setTypeConverter(new StandardTypeConverter(conversionService)); + } + + return context; + } + + private ConversionService getConversionService() { + return (ConversionService) getRequest().getAttribute(ConversionService.class.getName()); + } + + private static class EnvironmentVariablesPropertyAccessor implements PropertyAccessor { + + private final Environment env; + + public EnvironmentVariablesPropertyAccessor(final Environment env) { + this.env = env; + } + + @Override + public Class<?>[] getSpecificTargetClasses() { + // TODO Auto-generated method stub + return null; + } + + @Override + public boolean canRead(EvaluationContext context, Object target, String name) throws AccessException { + // TODO Auto-generated method stub + return false; + } + + @Override + public TypedValue read(EvaluationContext context, Object target, String name) throws AccessException { + // TODO Auto-generated method stub + return null; + } + + @Override + public boolean canWrite(EvaluationContext context, Object target, String name) throws AccessException { + // TODO Auto-generated method stub + return false; + } + + @Override + public void write(EvaluationContext context, Object target, String name, Object newValue) + throws AccessException { + // TODO Auto-generated method stub + } + } +} http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/234f96ec/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/MessageFunction.java ---------------------------------------------------------------------- diff --git a/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/MessageFunction.java b/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/MessageFunction.java index 46547a6..94a1e0f 100644 --- a/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/MessageFunction.java +++ b/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/MessageFunction.java @@ -33,7 +33,6 @@ import org.apache.freemarker.core.model.ObjectWrapperAndUnwrapper; import org.apache.freemarker.core.model.TemplateCollectionModel; import org.apache.freemarker.core.model.TemplateModel; import org.apache.freemarker.core.model.TemplateModelIterator; -import org.apache.freemarker.core.model.impl.SimpleString; import org.apache.freemarker.core.util.CallableUtils; import org.apache.freemarker.core.util.StringToIndexMap; import org.apache.freemarker.core.util._StringUtils; @@ -111,10 +110,10 @@ public class MessageFunction extends AbstractSpringTemplateFunctionModel { final TemplateModel messageResolvableModel = CallableUtils.getOptionalArgument(args, MESSAGE_RESOLVABLE_PARAM_IDX, TemplateModel.class, this); + final MessageSourceResolvable messageResolvable = (MessageSourceResolvable) unwrapObject( + objectWrapperAndUnwrapper, messageResolvableModel); - if (messageResolvableModel != null) { - MessageSourceResolvable messageResolvable = (MessageSourceResolvable) objectWrapperAndUnwrapper - .unwrap(messageResolvableModel); + if (messageResolvable != null) { message = messageSource.getMessage(messageResolvable, requestContext.getLocale()); } else { final String code = _StringUtils @@ -127,10 +126,9 @@ public class MessageFunction extends AbstractSpringTemplateFunctionModel { if (!messageArgsModel.isEmptyCollection()) { msgArgumentList = new ArrayList<>(); TemplateModel msgArgModel; - int i = 0; - for (TemplateModelIterator tit = messageArgsModel.iterator(); tit.hasNext(); i++) { + for (TemplateModelIterator tit = messageArgsModel.iterator(); tit.hasNext(); ) { msgArgModel = tit.next(); - msgArgumentList.add(objectWrapperAndUnwrapper.unwrap(msgArgModel)); + msgArgumentList.add(unwrapObject(objectWrapperAndUnwrapper, msgArgModel)); } } @@ -143,7 +141,7 @@ public class MessageFunction extends AbstractSpringTemplateFunctionModel { } } - return (message != null) ? new SimpleString(message) : null; + return wrapObject(objectWrapperAndUnwrapper, message); } @Override http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/234f96ec/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/MvcUrlFunction.java ---------------------------------------------------------------------- diff --git a/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/MvcUrlFunction.java b/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/MvcUrlFunction.java new file mode 100644 index 0000000..047d5c2 --- /dev/null +++ b/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/MvcUrlFunction.java @@ -0,0 +1,74 @@ +/* + * 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.spring.model; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.freemarker.core.CallPlace; +import org.apache.freemarker.core.Environment; +import org.apache.freemarker.core.TemplateException; +import org.apache.freemarker.core.model.ArgumentArrayLayout; +import org.apache.freemarker.core.model.ObjectWrapperAndUnwrapper; +import org.apache.freemarker.core.model.TemplateModel; +import org.apache.freemarker.core.util.StringToIndexMap; +import org.springframework.web.servlet.support.RequestContext; + +/** + * A <code>TemplateFunctionModel</code> providing functionality equivalent to the Spring Framework's + * <code>spring:mvcUrl</code> JSP Tag Library Function. + * <P> + * Some valid example(s): + * </P> + * <PRE> + * </PRE> + */ +public class MvcUrlFunction extends AbstractSpringTemplateFunctionModel { + + public static final String NAME = "mvcUrl"; + + private static final int MAPPING_NAME_PARAM_IDX = 0; + + private static final ArgumentArrayLayout ARGS_LAYOUT = + ArgumentArrayLayout.create( + 1, + false, + null, + false + ); + + public MvcUrlFunction(HttpServletRequest request, HttpServletResponse response) { + super(request, response); + } + + @Override + public TemplateModel executeInternal(TemplateModel[] args, CallPlace callPlace, Environment env, + ObjectWrapperAndUnwrapper objectWrapperAndUnwrapper, RequestContext requestContext) + throws TemplateException { + // TODO + return null; + } + + @Override + public ArgumentArrayLayout getFunctionArgumentArrayLayout() { + return ARGS_LAYOUT; + } + +} http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/234f96ec/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/SpringTemplateCallableHashModel.java ---------------------------------------------------------------------- diff --git a/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/SpringTemplateCallableHashModel.java b/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/SpringTemplateCallableHashModel.java index dd2f71c..e090cd9 100644 --- a/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/SpringTemplateCallableHashModel.java +++ b/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/SpringTemplateCallableHashModel.java @@ -47,11 +47,16 @@ public final class SpringTemplateCallableHashModel implements TemplateHashModel, private String nestedPath; public SpringTemplateCallableHashModel(final HttpServletRequest request, final HttpServletResponse response) { - callablesMap.put(BindDirective.NAME, new BindDirective(request, response)); callablesMap.put(MessageFunction.NAME, new MessageFunction(request, response)); callablesMap.put(ThemeFunction.NAME, new ThemeFunction(request, response)); callablesMap.put(BindErrorsDirective.NAME, new BindErrorsDirective(request, response)); callablesMap.put(NestedPathDirective.NAME, new NestedPathDirective(request, response)); + callablesMap.put(BindDirective.NAME, new BindDirective(request, response)); + + callablesMap.put(TransformFunction.NAME, new TransformFunction(request, response)); + callablesMap.put(UrlFunction.NAME, new UrlFunction(request, response)); + callablesMap.put(EvalFunction.NAME, new EvalFunction(request, response)); + callablesMap.put(MvcUrlFunction.NAME, new MvcUrlFunction(request, response)); } public TemplateModel get(String key) throws TemplateException { http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/234f96ec/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/TransformFunction.java ---------------------------------------------------------------------- diff --git a/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/TransformFunction.java b/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/TransformFunction.java new file mode 100644 index 0000000..ee3cc1c --- /dev/null +++ b/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/TransformFunction.java @@ -0,0 +1,101 @@ +/* + * 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.spring.model; + +import java.beans.PropertyEditor; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.freemarker.core.CallPlace; +import org.apache.freemarker.core.Environment; +import org.apache.freemarker.core.TemplateException; +import org.apache.freemarker.core.model.ArgumentArrayLayout; +import org.apache.freemarker.core.model.ObjectWrapperAndUnwrapper; +import org.apache.freemarker.core.model.TemplateModel; +import org.apache.freemarker.core.util.CallableUtils; +import org.springframework.web.servlet.support.RequestContext; + +/** + * A <code>TemplateFunctionModel</code> providing functionality equivalent to the Spring Framework's + * <code><spring:transform /></code> JSP Tag Library. + * <P> + * Some valid example(s): + * </P> + * <PRE> + * </PRE> + * <P> + * Some valid example(s): + * </P> + * <PRE> + * <@spring.bind "user"; status> + * ${spring.transform(status, user.birthDate)} + * </@spring.bind> + * </PRE> + * <P> + * <EM>Note:</EM> Unlike Spring Framework's <code><spring:bind /></code> JSP Tag Library, this directive + * does not support <code>htmlEscape</code> parameter. It always has <code>BindStatus</code> not to escape HTML's + * because it is much easier to control escaping in FreeMarker Template expressions. + * </P> + */ +public class TransformFunction extends AbstractSpringTemplateFunctionModel { + + public static final String NAME = "transform"; + + private static final int PROPERTY_EDITOR_PARAM_IDX = 0; + private static final int VALUE_PARAM_IDX = 1; + + private static final ArgumentArrayLayout ARGS_LAYOUT = ArgumentArrayLayout.create(2, false, null, false); + + public TransformFunction(HttpServletRequest request, HttpServletResponse response) { + super(request, response); + } + + @Override + public TemplateModel executeInternal(TemplateModel[] args, CallPlace callPlace, Environment env, + ObjectWrapperAndUnwrapper objectWrapperAndUnwrapper, RequestContext requestContext) + throws TemplateException { + final TemplateModel editorModel = CallableUtils.getOptionalArgument(args, PROPERTY_EDITOR_PARAM_IDX, + TemplateModel.class, this); + final PropertyEditor editor = (PropertyEditor) unwrapObject(objectWrapperAndUnwrapper, editorModel); + + final TemplateModel valueModel = CallableUtils.getOptionalArgument(args, VALUE_PARAM_IDX, TemplateModel.class, this); + final Object value = unwrapObject(objectWrapperAndUnwrapper, valueModel); + + String valueAsString = null; + + if (value != null) { + if (editor != null) { + editor.setValue(value); + valueAsString = editor.getAsText(); + } else { + valueAsString = value.toString(); + } + } + + return wrapObject(objectWrapperAndUnwrapper, valueAsString); + } + + @Override + public ArgumentArrayLayout getFunctionArgumentArrayLayout() { + return ARGS_LAYOUT; + } + +} http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/234f96ec/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/UrlFunction.java ---------------------------------------------------------------------- diff --git a/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/UrlFunction.java b/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/UrlFunction.java new file mode 100644 index 0000000..402e74d --- /dev/null +++ b/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/UrlFunction.java @@ -0,0 +1,86 @@ +/* + * 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.spring.model; + +import javax.servlet.http.HttpServletRequest; +import javax.servlet.http.HttpServletResponse; + +import org.apache.freemarker.core.CallPlace; +import org.apache.freemarker.core.Environment; +import org.apache.freemarker.core.TemplateException; +import org.apache.freemarker.core.model.ArgumentArrayLayout; +import org.apache.freemarker.core.model.ObjectWrapperAndUnwrapper; +import org.apache.freemarker.core.model.TemplateModel; +import org.apache.freemarker.core.util.StringToIndexMap; +import org.springframework.web.servlet.support.RequestContext; + +/** + * A <code>TemplateFunctionModel</code> providing functionality equivalent to the Spring Framework's + * <code><spring:url /></code> JSP Tag Library. + * <P> + * Some valid example(s): + * </P> + * <PRE> + * </PRE> + * <P> + * <EM>Note:</EM> Unlike Spring Framework's <code><spring:message /></code> JSP Tag Library, this function + * does not support <code>htmlEscape</code> parameter. It always returns the message not to escape HTML's + * because it is much easier to control escaping in FreeMarker Template expressions. + * </P> + */ +public class UrlFunction extends AbstractSpringTemplateFunctionModel { + + public static final String NAME = "url"; + + private static final int VALUE_PARAM_IDX = 0; + private static final int CONTEXT_PARAM_IDX = 1; + + private static final String CONTEXT_PARAM_NAME = "context"; + + + // TODO: How to deal with parameters (spring:param tags)?? + + + private static final ArgumentArrayLayout ARGS_LAYOUT = + ArgumentArrayLayout.create( + 1, + false, + StringToIndexMap.of(CONTEXT_PARAM_NAME, CONTEXT_PARAM_IDX), + false + ); + + public UrlFunction(HttpServletRequest request, HttpServletResponse response) { + super(request, response); + } + + @Override + public TemplateModel executeInternal(TemplateModel[] args, CallPlace callPlace, Environment env, + ObjectWrapperAndUnwrapper objectWrapperAndUnwrapper, RequestContext requestContext) + throws TemplateException { + // TODO + return null; + } + + @Override + public ArgumentArrayLayout getFunctionArgumentArrayLayout() { + return ARGS_LAYOUT; + } + +}
