Using CallableUtils to throw exceptions; use positional param for code
Project: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/repo Commit: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/commit/a8e73ec7 Tree: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/tree/a8e73ec7 Diff: http://git-wip-us.apache.org/repos/asf/incubator-freemarker/diff/a8e73ec7 Branch: refs/heads/3 Commit: a8e73ec77a735b643be986e0c190205f3b7a2192 Parents: b0acedd Author: Woonsan Ko <[email protected]> Authored: Tue Sep 5 08:33:55 2017 -0400 Committer: Woonsan Ko <[email protected]> Committed: Tue Sep 5 08:33:55 2017 -0400 ---------------------------------------------------------------------- .../AbstractSpringTemplateCallableModel.java | 6 +- .../AbstractSpringTemplateDirectiveModel.java | 17 ++++- .../AbstractSpringTemplateFunctionModel.java | 14 +++- .../spring/model/MessageFunction.java | 77 +++++++++++--------- .../freemarker/spring/model/ThemeFunction.java | 38 ++++++++++ .../spring/web/view/FreeMarkerView.java | 2 + 6 files changed, 112 insertions(+), 42 deletions(-) ---------------------------------------------------------------------- http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/a8e73ec7/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 431c066..b82bed1 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 @@ -28,6 +28,7 @@ import org.apache.freemarker.core.model.ObjectWrappingException; import org.apache.freemarker.core.model.TemplateCallableModel; import org.apache.freemarker.core.model.TemplateModel; import org.apache.freemarker.core.model.impl.DefaultObjectWrapper; +import org.apache.freemarker.core.util.CallableUtils; import org.springframework.web.servlet.support.BindStatus; import org.springframework.web.servlet.support.RequestContext; @@ -81,7 +82,8 @@ public abstract class AbstractSpringTemplateCallableModel implements TemplateCal if (status != null) { if (!(objectWrapperAndUnwrapper instanceof DefaultObjectWrapper)) { - throw new IllegalArgumentException("objectWrapperAndUnwrapper is not a DefaultObjectWrapper."); + CallableUtils.newGenericExecuteException("objectWrapperAndUnwrapper is not a DefaultObjectWrapper.", + this, isFunction()); } return ((DefaultObjectWrapper) objectWrapperAndUnwrapper).wrap(status); @@ -90,6 +92,8 @@ public abstract class AbstractSpringTemplateCallableModel implements TemplateCal return null; } + protected abstract boolean isFunction(); + private String resolveNestedPath(final Environment env, ObjectWrapperAndUnwrapper objectWrapperAndUnwrapper, final String path) { // TODO: should read it from request or env?? http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/a8e73ec7/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/AbstractSpringTemplateDirectiveModel.java ---------------------------------------------------------------------- diff --git a/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/AbstractSpringTemplateDirectiveModel.java b/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/AbstractSpringTemplateDirectiveModel.java index c4ed76c..df6a2bc 100644 --- a/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/AbstractSpringTemplateDirectiveModel.java +++ b/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/AbstractSpringTemplateDirectiveModel.java @@ -32,13 +32,15 @@ import org.apache.freemarker.core.model.ObjectWrapper; import org.apache.freemarker.core.model.ObjectWrapperAndUnwrapper; import org.apache.freemarker.core.model.TemplateDirectiveModel; import org.apache.freemarker.core.model.TemplateModel; +import org.apache.freemarker.core.util.CallableUtils; import org.springframework.web.servlet.support.RequestContext; import org.springframework.web.servlet.view.AbstractTemplateView; /** * Abstract TemplateDirectiveModel for derived classes to support Spring MVC based templating environment. */ -public abstract class AbstractSpringTemplateDirectiveModel extends AbstractSpringTemplateCallableModel implements TemplateDirectiveModel { +public abstract class AbstractSpringTemplateDirectiveModel extends AbstractSpringTemplateCallableModel + implements TemplateDirectiveModel { public AbstractSpringTemplateDirectiveModel(HttpServletRequest request, HttpServletResponse response) { super(request, response); @@ -50,14 +52,16 @@ public abstract class AbstractSpringTemplateDirectiveModel extends AbstractSprin final ObjectWrapper objectWrapper = env.getObjectWrapper(); if (!(objectWrapper instanceof ObjectWrapperAndUnwrapper)) { - throw new TemplateException( - "The ObjectWrapper of environment wasn't instance of ObjectWrapperAndUnwrapper."); + CallableUtils.newGenericExecuteException( + "The ObjectWrapper of environment isn't an instance of ObjectWrapperAndUnwrapper.", this, + isFunction()); } TemplateModel rcModel = env.getVariable(AbstractTemplateView.SPRING_MACRO_REQUEST_CONTEXT_ATTRIBUTE); if (rcModel == null) { - throw new TemplateException(AbstractTemplateView.SPRING_MACRO_REQUEST_CONTEXT_ATTRIBUTE + " not found."); + CallableUtils.newGenericExecuteException( + AbstractTemplateView.SPRING_MACRO_REQUEST_CONTEXT_ATTRIBUTE + " not found.", this, isFunction()); } RequestContext requestContext = (RequestContext) ((ObjectWrapperAndUnwrapper) objectWrapper).unwrap(rcModel); @@ -65,6 +69,11 @@ public abstract class AbstractSpringTemplateDirectiveModel extends AbstractSprin executeInternal(args, callPlace, out, env, (ObjectWrapperAndUnwrapper) objectWrapper, requestContext); } + @Override + protected final boolean isFunction() { + return false; + } + protected abstract void executeInternal(TemplateModel[] args, CallPlace callPlace, Writer out, Environment env, ObjectWrapperAndUnwrapper objectWrapperAndUnwrapper, RequestContext requestContext) throws TemplateException, IOException; http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/a8e73ec7/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/AbstractSpringTemplateFunctionModel.java ---------------------------------------------------------------------- diff --git a/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/AbstractSpringTemplateFunctionModel.java b/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/AbstractSpringTemplateFunctionModel.java index c0fe502..7851ad8 100644 --- a/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/AbstractSpringTemplateFunctionModel.java +++ b/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/AbstractSpringTemplateFunctionModel.java @@ -29,6 +29,7 @@ import org.apache.freemarker.core.model.ObjectWrapper; import org.apache.freemarker.core.model.ObjectWrapperAndUnwrapper; import org.apache.freemarker.core.model.TemplateFunctionModel; import org.apache.freemarker.core.model.TemplateModel; +import org.apache.freemarker.core.util.CallableUtils; import org.springframework.web.servlet.support.RequestContext; import org.springframework.web.servlet.view.AbstractTemplateView; @@ -47,14 +48,16 @@ public abstract class AbstractSpringTemplateFunctionModel extends AbstractSpring final ObjectWrapper objectWrapper = env.getObjectWrapper(); if (!(objectWrapper instanceof ObjectWrapperAndUnwrapper)) { - throw new TemplateException( - "The ObjectWrapper of environment wasn't instance of ObjectWrapperAndUnwrapper."); + CallableUtils.newGenericExecuteException( + "The ObjectWrapper of environment isn't an instance of ObjectWrapperAndUnwrapper.", this, + isFunction()); } TemplateModel rcModel = env.getVariable(AbstractTemplateView.SPRING_MACRO_REQUEST_CONTEXT_ATTRIBUTE); if (rcModel == null) { - throw new TemplateException(AbstractTemplateView.SPRING_MACRO_REQUEST_CONTEXT_ATTRIBUTE + " not found."); + CallableUtils.newGenericExecuteException( + AbstractTemplateView.SPRING_MACRO_REQUEST_CONTEXT_ATTRIBUTE + " not found.", this, isFunction()); } RequestContext requestContext = (RequestContext) ((ObjectWrapperAndUnwrapper) objectWrapper).unwrap(rcModel); @@ -62,6 +65,11 @@ public abstract class AbstractSpringTemplateFunctionModel extends AbstractSpring return executeInternal(args, callPlace, env, (ObjectWrapperAndUnwrapper) objectWrapper, requestContext); } + @Override + protected final boolean isFunction() { + return true; + } + protected abstract TemplateModel executeInternal(TemplateModel[] args, CallPlace callPlace, Environment env, ObjectWrapperAndUnwrapper objectWrapperAndUnwrapper, RequestContext requestContext) throws TemplateException; http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/a8e73ec7/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 9579366..c6d1c69 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 @@ -36,24 +36,26 @@ 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; import org.springframework.context.MessageSource; import org.springframework.context.MessageSourceResolvable; import org.springframework.web.servlet.support.RequestContext; public class MessageFunction extends AbstractSpringTemplateFunctionModel { - private static final int MESSAGE_PARAM_IDX = 0; - private static final int MESSAGE_ARGS_PARAM_IDX = 1; + private static final int CODE_PARAM_IDX = 0; + private static final int MESSAGE_RESOLVABLE_PARAM_IDX = 1; + private static final int MESSAGE_ARGS_PARAM_IDX = 2; - private static final String MESSAGE_PARAM_NAME = "message"; + private static final String MESSAGE_RESOLVABLE_PARAM_NAME = "message"; private static final ArgumentArrayLayout ARGS_LAYOUT = ArgumentArrayLayout.create( - 0, + 1, true, - StringToIndexMap.of( - MESSAGE_PARAM_NAME, MESSAGE_PARAM_IDX), - false); + StringToIndexMap.of(MESSAGE_RESOLVABLE_PARAM_NAME, MESSAGE_RESOLVABLE_PARAM_IDX), + false + ); public MessageFunction(HttpServletRequest request, HttpServletResponse response) { super(request, response); @@ -63,42 +65,45 @@ public class MessageFunction extends AbstractSpringTemplateFunctionModel { public TemplateModel executeInternal(TemplateModel[] args, CallPlace callPlace, Environment env, ObjectWrapperAndUnwrapper objectWrapperAndUnwrapper, RequestContext requestContext) throws TemplateException { - final MessageSource messageSource = requestContext.getMessageSource(); + final MessageSource messageSource = getMessageSource(requestContext); if (messageSource == null) { - throw new TemplateException("MessageSource not found."); + CallableUtils.newGenericExecuteException("MessageSource not found.", this); } String message = null; - final TemplateCollectionModel messageArgsModel = (TemplateCollectionModel) args[MESSAGE_ARGS_PARAM_IDX]; - - if (!messageArgsModel.isEmptyCollection()) { - String code = null; - List<Object> msgArgumentList = new ArrayList<>(); - TemplateModel msgArgModel; - int i = 0; - for (TemplateModelIterator tit = messageArgsModel.iterator(); tit.hasNext(); i++) { - msgArgModel = tit.next(); - if (i == 0) { - code = objectWrapperAndUnwrapper.unwrap(msgArgModel).toString(); - } else { - msgArgumentList.add(objectWrapperAndUnwrapper.unwrap(msgArgModel)); - } - } + final TemplateModel messageResolvableModel = CallableUtils.getOptionalArgument(args, MESSAGE_RESOLVABLE_PARAM_IDX, + TemplateModel.class, this); - // TODO: Is it okay to set the default value to null to avoid NoSuchMessageException from Spring MessageSource? - message = messageSource.getMessage(code, (msgArgumentList.isEmpty()) ? null : msgArgumentList.toArray(), - null, requestContext.getLocale()); + if (messageResolvableModel != null) { + MessageSourceResolvable messageResolvable = (MessageSourceResolvable) objectWrapperAndUnwrapper + .unwrap(messageResolvableModel); + message = messageSource.getMessage(messageResolvable, requestContext.getLocale()); } else { - final TemplateModel messageModel = CallableUtils.getOptionalArgument(args, MESSAGE_PARAM_IDX, - TemplateModel.class, this); - if (messageModel != null) { - MessageSourceResolvable messageResolvable = (MessageSourceResolvable) objectWrapperAndUnwrapper - .unwrap(messageModel); - message = messageSource.getMessage(messageResolvable, requestContext.getLocale()); + final String code = _StringUtils + .emptyToNull(CallableUtils.getOptionalStringArgument(args, CODE_PARAM_IDX, this)); + + if (code != null) { + List<Object> msgArgumentList = null; + final TemplateCollectionModel messageArgsModel = (TemplateCollectionModel) args[MESSAGE_ARGS_PARAM_IDX]; + + if (!messageArgsModel.isEmptyCollection()) { + msgArgumentList = new ArrayList<>(); + TemplateModel msgArgModel; + int i = 0; + for (TemplateModelIterator tit = messageArgsModel.iterator(); tit.hasNext(); i++) { + msgArgModel = tit.next(); + msgArgumentList.add(objectWrapperAndUnwrapper.unwrap(msgArgModel)); + } + } + + // Note: Pass null as default value to avoid NoSuchMessageException from Spring MessageSource + // since we want to take advantage of FreeMarker's default value expressions. + message = messageSource.getMessage(code, (msgArgumentList == null) ? null : msgArgumentList.toArray(), + null, requestContext.getLocale()); } else { - throw new TemplateException("Neither message code nor message resolvable was set."); + CallableUtils.newNullOrOmittedArgumentException(CODE_PARAM_IDX, this); } } @@ -110,4 +115,8 @@ public class MessageFunction extends AbstractSpringTemplateFunctionModel { return ARGS_LAYOUT; } + protected MessageSource getMessageSource(final RequestContext requestContext) { + return requestContext.getMessageSource(); + } + } http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/a8e73ec7/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/ThemeFunction.java ---------------------------------------------------------------------- diff --git a/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/ThemeFunction.java b/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/ThemeFunction.java new file mode 100644 index 0000000..b3b0653 --- /dev/null +++ b/freemarker-spring/src/main/java/org/apache/freemarker/spring/model/ThemeFunction.java @@ -0,0 +1,38 @@ +/* + * 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.springframework.context.MessageSource; +import org.springframework.web.servlet.support.RequestContext; + +public class ThemeFunction extends MessageFunction { + + public ThemeFunction(HttpServletRequest request, HttpServletResponse response) { + super(request, response); + } + + protected MessageSource getMessageSource(final RequestContext requestContext) { + return requestContext.getTheme().getMessageSource(); + } + +} http://git-wip-us.apache.org/repos/asf/incubator-freemarker/blob/a8e73ec7/freemarker-spring/src/main/java/org/apache/freemarker/spring/web/view/FreeMarkerView.java ---------------------------------------------------------------------- diff --git a/freemarker-spring/src/main/java/org/apache/freemarker/spring/web/view/FreeMarkerView.java b/freemarker-spring/src/main/java/org/apache/freemarker/spring/web/view/FreeMarkerView.java index f34fd4b..a789f4e 100644 --- a/freemarker-spring/src/main/java/org/apache/freemarker/spring/web/view/FreeMarkerView.java +++ b/freemarker-spring/src/main/java/org/apache/freemarker/spring/web/view/FreeMarkerView.java @@ -40,6 +40,7 @@ import org.apache.freemarker.servlet.ServletContextHashModel; import org.apache.freemarker.servlet.jsp.TaglibFactory; import org.apache.freemarker.spring.model.BindDirective; import org.apache.freemarker.spring.model.MessageFunction; +import org.apache.freemarker.spring.model.ThemeFunction; /** * FreeMarker template based view implementation, with being able to provide a {@link ServletContextHashModel} @@ -180,6 +181,7 @@ public class FreeMarkerView extends AbstractFreeMarkerView { final SimpleHash springCallableHash = new SimpleHash(objectWrapper); springCallableHash.put("bind", new BindDirective(request, response)); springCallableHash.put("message", new MessageFunction(request, response)); + springCallableHash.put("theme", new ThemeFunction(request, response)); return springCallableHash; } }
