You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@cxf.apache.org by se...@apache.org on 2017/10/26 15:45:54 UTC
[cxf] branch 3.1.x-fixes updated: Adding a Spring View-aware
MessageBodyWriter, patch from Adrian Gonzalez applied, This closes #328
This is an automated email from the ASF dual-hosted git repository.
sergeyb pushed a commit to branch 3.1.x-fixes
in repository https://gitbox.apache.org/repos/asf/cxf.git
The following commit(s) were added to refs/heads/3.1.x-fixes by this push:
new ab960da Adding a Spring View-aware MessageBodyWriter, patch from Adrian Gonzalez applied, This closes #328
ab960da is described below
commit ab960dafe6a6432109b8a2aa92f73bd6ad6bc85f
Author: Sergey Beryozkin <sb...@gmail.com>
AuthorDate: Thu Oct 26 16:41:41 2017 +0100
Adding a Spring View-aware MessageBodyWriter, patch from Adrian Gonzalez applied, This closes #328
---
rt/frontend/jaxrs/pom.xml | 6 +
.../apache/cxf/jaxrs/spring/Messages.properties | 21 ++
.../jaxrs/spring/SpringViewResolverProvider.java | 395 ++++++++++++++++++++
.../spring/SpringViewResolverProviderTest.java | 414 +++++++++++++++++++++
4 files changed, 836 insertions(+)
diff --git a/rt/frontend/jaxrs/pom.xml b/rt/frontend/jaxrs/pom.xml
index 1b4045d..61d243a 100644
--- a/rt/frontend/jaxrs/pom.xml
+++ b/rt/frontend/jaxrs/pom.xml
@@ -92,6 +92,12 @@
<optional>true</optional>
</dependency>
<dependency>
+ <groupId>org.springframework</groupId>
+ <artifactId>spring-webmvc</artifactId>
+ <scope>provided</scope>
+ <optional>true</optional>
+ </dependency>
+ <dependency>
<groupId>javax.ws.rs</groupId>
<artifactId>javax.ws.rs-api</artifactId>
</dependency>
diff --git a/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/spring/Messages.properties b/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/spring/Messages.properties
new file mode 100644
index 0000000..7dd2773
--- /dev/null
+++ b/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/spring/Messages.properties
@@ -0,0 +1,21 @@
+#
+#
+# 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.
+#
+#
+RESPONSE_REDIRECTED_TO=Setting an instance of \"{0}\" as HttpServletRequest attribute \"{1}\" and redirecting the response to \"{2}\".
diff --git a/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/spring/SpringViewResolverProvider.java b/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/spring/SpringViewResolverProvider.java
new file mode 100644
index 0000000..8fa38cd
--- /dev/null
+++ b/rt/frontend/jaxrs/src/main/java/org/apache/cxf/jaxrs/spring/SpringViewResolverProvider.java
@@ -0,0 +1,395 @@
+/**
+ * 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.cxf.jaxrs.spring;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.lang.annotation.Annotation;
+import java.lang.reflect.Type;
+import java.util.Collections;
+import java.util.Locale;
+import java.util.Map;
+import java.util.ResourceBundle;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+import javax.servlet.RequestDispatcher;
+import javax.ws.rs.Produces;
+import javax.ws.rs.core.Context;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedMap;
+import javax.ws.rs.ext.MessageBodyWriter;
+import javax.ws.rs.ext.Provider;
+
+import org.apache.cxf.common.i18n.BundleUtils;
+import org.apache.cxf.common.logging.LogUtils;
+import org.apache.cxf.common.util.StringUtils;
+import org.apache.cxf.jaxrs.ext.MessageContext;
+import org.apache.cxf.jaxrs.provider.AbstractConfigurableProvider;
+import org.apache.cxf.jaxrs.utils.ExceptionUtils;
+import org.apache.cxf.message.Message;
+import org.apache.cxf.phase.PhaseInterceptorChain;
+import org.apache.cxf.transport.http.AbstractHTTPDestination;
+import org.springframework.web.servlet.LocaleResolver;
+import org.springframework.web.servlet.View;
+import org.springframework.web.servlet.ViewResolver;
+
+/**
+ * CXF view provider that delegates view rendering to Spring MVC Views.
+ *
+ * Sample usage in a spring application:
+ * <pre>
+ @Bean
+ public SpringViewResolverProvider springViewProvider(ViewResolver viewResolver) {
+ SpringViewResolverProvider viewProvider = new SpringViewResolverProvider(viewResolver,
+ new AcceptHeaderLocaleResolver());
+ viewProvider.setUseClassNames(true);
+ viewProvider.setBeanName("model");
+ viewProvider.setResourcePaths(Collections.singletonMap("/remove", "registeredClients"));
+ return viewProvider;
+ }
+ * </pre>
+ */
+@Produces("text/html")
+@Provider
+public class SpringViewResolverProvider extends AbstractConfigurableProvider implements MessageBodyWriter<Object> {
+
+ private static final ResourceBundle BUNDLE = BundleUtils.getBundle(SpringViewResolverProvider.class);
+
+ private static final Logger LOG = LogUtils.getL7dLogger(SpringViewResolverProvider.class);
+
+ private static final String MESSAGE_RESOURCE_PATH_PROPERTY = "redirect.resource.path";
+
+ private static final String DEFAULT_RESOURCE_EXTENSION = "";
+
+ private static final String DEFAULT_LOCATION_PREFIX = "";
+
+ private final ViewResolver viewResolver;
+
+ private String resourcePath;
+
+ private Map<String, String> resourcePaths = Collections.emptyMap();
+
+ private Map<String, String> classResources = Collections.emptyMap();
+
+ private Map<? extends Enum<?>, String> enumResources = Collections.emptyMap();
+
+ private boolean useClassNames;
+
+ private Map<String, String> beanNames = Collections.emptyMap();
+
+ private String beanName;
+
+ private boolean logRedirects;
+
+ private boolean strictPathCheck;
+
+ private String locationPrefix;
+
+ private String resourceExtension;
+
+ private MessageContext mc;
+
+ private LocaleResolver localeResolver;
+
+ private String errorView = "/error";
+
+ public SpringViewResolverProvider(ViewResolver viewResolver, LocaleResolver localeResolver) {
+ if (viewResolver == null) {
+ throw new IllegalArgumentException("Argument viewResolver is required");
+ }
+ if (localeResolver == null) {
+ throw new IllegalArgumentException("Argument localeResolver is required");
+ }
+ this.viewResolver = viewResolver;
+ this.localeResolver = localeResolver;
+ }
+
+ @Context
+ public void setMessageContext(MessageContext context) {
+ this.mc = context;
+ }
+
+ public void setStrictPathCheck(boolean use) {
+ strictPathCheck = use;
+ }
+
+ public void setUseClassNames(boolean use) {
+ useClassNames = use;
+ }
+
+ public long getSize(Object t, Class<?> type, Type genericType, Annotation[] annotations, MediaType mt) {
+ return -1;
+ }
+
+ private String getViewName(Class<?> type) {
+ String viewName = doGetClassResourceName(type);
+ if (viewName == null) {
+ for (Class<?> in : type.getInterfaces()) {
+ viewName = doGetClassResourceName(in);
+ if (viewName != null) {
+ break;
+ }
+ }
+ }
+ return viewName;
+ }
+
+ private Locale getLocale() {
+ return localeResolver.resolveLocale(mc.getHttpServletRequest());
+ }
+
+ private String doGetClassResourceName(Class<?> type) {
+ String simpleName = StringUtils.uncapitalize(type.getSimpleName());
+ String thePrefix = locationPrefix == null ? DEFAULT_LOCATION_PREFIX : locationPrefix;
+ String theExtension = resourceExtension == null ? DEFAULT_RESOURCE_EXTENSION : resourceExtension;
+ String viewName = thePrefix + simpleName + theExtension;
+ View view = resolveView(viewName);
+ return view != null ? viewName : null;
+ }
+
+ public boolean isWriteable(Class<?> type, Type genericType, Annotation[] annotations, MediaType mt) {
+
+ if (useClassNames && getViewName(type) != null) {
+ return true;
+ }
+ if (resourcePath != null || classResourceSupported(type)) {
+ return true;
+ }
+ if (!resourcePaths.isEmpty()) {
+ String path = getRequestPath();
+ for (String requestPath : resourcePaths.keySet()) {
+ boolean result = strictPathCheck ? path.endsWith(requestPath) : path.contains(requestPath);
+ if (result) {
+ return true;
+ }
+ }
+ }
+ return mc != null && mc.get(MESSAGE_RESOURCE_PATH_PROPERTY) != null;
+ }
+
+ private boolean classResourceSupported(Class<?> type) {
+ String typeName = type.getName();
+ if (type.isEnum()) {
+ for (Object o : enumResources.keySet()) {
+ if (o.getClass().getName().equals(typeName)) {
+ return true;
+ }
+ }
+ for (String name : classResources.keySet()) {
+ if (name.startsWith(typeName)) {
+ return true;
+ }
+ }
+ return false;
+ }
+ return classResources.containsKey(typeName);
+ }
+
+ public void writeTo(Object o, Class<?> clazz, Type genericType, Annotation[] annotations, MediaType type,
+ MultivaluedMap<String, Object> headers, OutputStream os) throws IOException {
+
+ View view = getView(clazz, o);
+ String attributeName = getBeanName(o);
+ Map<String, Object> model = Collections.singletonMap(attributeName, o);
+
+ try {
+ mc.put(AbstractHTTPDestination.REQUEST_REDIRECTED, Boolean.TRUE);
+ logRedirection(view, attributeName, o);
+ view.render(model, mc.getHttpServletRequest(), mc.getHttpServletResponse());
+ } catch (Throwable ex) {
+ handleViewRenderingException(view, ex);
+ }
+ }
+
+ /**
+ * By default we'll try to forward to Spring error handler.
+ *
+ * If no such handler has been set, or if there is an error during error handling,
+ * we throw an error and let CXF handle the internal error.
+ *
+ * @param view view that produced the rendering error
+ * @param exception rendering error
+ */
+ private void handleViewRenderingException(View view, Throwable exception) {
+ LOG.log(Level.WARNING, String.format("Error forwarding to '%s': %s", view, exception.getMessage()), exception);
+ if (errorView != null) {
+ mc.getHttpServletRequest().setAttribute(RequestDispatcher.ERROR_EXCEPTION, exception);
+ mc.getHttpServletRequest().setAttribute(RequestDispatcher.ERROR_STATUS_CODE, 500);
+ mc.getHttpServletRequest().setAttribute(RequestDispatcher.ERROR_MESSAGE, exception.getMessage());
+ try {
+ mc.getServletContext().getRequestDispatcher(errorView).forward(mc.getHttpServletRequest(),
+ mc.getHttpServletResponse());
+ } catch (Exception e) {
+ LOG.log(Level.SEVERE, String.format("Error forwarding to error page '%s': %s",
+ errorView, e.toString()),
+ e);
+ handleInternalViewRenderingException(exception);
+ }
+ } else {
+ handleInternalViewRenderingException(exception);
+ }
+ }
+
+ private void handleInternalViewRenderingException(Throwable exception) {
+ mc.put(AbstractHTTPDestination.REQUEST_REDIRECTED, Boolean.FALSE);
+ throw ExceptionUtils.toInternalServerErrorException(exception, null);
+ }
+
+ private void logRedirection(View view, String attributeName, Object o) {
+ Level level = logRedirects ? Level.INFO : Level.FINE;
+ if (LOG.isLoggable(level)) {
+ String message = new org.apache.cxf.common.i18n.Message("RESPONSE_REDIRECTED_TO",
+ BUNDLE, o.getClass().getName(),
+ attributeName, view).toString();
+ LOG.log(level, message);
+ }
+ }
+
+ View getView(Class<?> cls, Object o) {
+ String currentResourcePath = getPathFromMessageContext();
+ if (currentResourcePath != null) {
+ return resolveView(currentResourcePath);
+ }
+
+ if (!resourcePaths.isEmpty()) {
+
+ String path = getRequestPath();
+ for (Map.Entry<String, String> entry : resourcePaths.entrySet()) {
+ if (path.endsWith(entry.getKey())) {
+ return resolveView(entry.getValue());
+ }
+ }
+ }
+ if (!enumResources.isEmpty() || !classResources.isEmpty()) {
+ String name = cls.getName();
+ if (cls.isEnum()) {
+ String enumResource = enumResources.get(o);
+ if (enumResource != null) {
+ return resolveView(enumResource);
+ }
+ name += "." + o.toString();
+ }
+
+ String clsResourcePath = classResources.get(name);
+ if (clsResourcePath != null) {
+ return resolveView(clsResourcePath);
+ }
+ }
+
+ if (useClassNames) {
+ return resolveView(getViewName(cls));
+ }
+
+ return resolveView(resourcePath);
+ }
+
+ private View resolveView(String viewName) {
+ try {
+ return viewResolver.resolveViewName(viewName, getLocale());
+ } catch (Exception ex) {
+ LOG.warning(ExceptionUtils.getStackTrace(ex));
+ throw ExceptionUtils.toInternalServerErrorException(ex, null);
+ }
+ }
+
+ private String getPathFromMessageContext() {
+ if (mc != null) {
+ Object resourcePathProp = mc.get(MESSAGE_RESOURCE_PATH_PROPERTY);
+ if (resourcePathProp != null) {
+ StringBuilder sb = new StringBuilder();
+ if (locationPrefix != null) {
+ sb.append(locationPrefix);
+ }
+ sb.append(resourcePathProp.toString());
+ if (resourceExtension != null) {
+ sb.append(resourceExtension);
+ }
+ return sb.toString();
+ }
+ }
+ return null;
+ }
+
+ private String getRequestPath() {
+ Message inMessage = PhaseInterceptorChain.getCurrentMessage().getExchange().getInMessage();
+ return (String) inMessage.get(Message.REQUEST_URI);
+ }
+
+ public void setResourcePath(String resourcePath) {
+ this.resourcePath = resourcePath;
+ }
+
+ public void setBeanNames(Map<String, String> beanNames) {
+ this.beanNames = beanNames;
+ }
+
+ public void setBeanName(String beanName) {
+ this.beanName = beanName;
+ }
+
+ public void setLogRedirects(String value) {
+ this.logRedirects = Boolean.valueOf(value);
+ }
+
+ protected String getBeanName(Object bean) {
+ if (beanName != null) {
+ return beanName;
+ }
+ String name = beanNames.get(bean.getClass().getName());
+ if (name != null) {
+ return name;
+ }
+ Class<?> resourceClass = bean.getClass();
+ if (useClassNames && doGetClassResourceName(resourceClass) == null) {
+ for (Class<?> cls : bean.getClass().getInterfaces()) {
+ if (doGetClassResourceName(cls) != null) {
+ resourceClass = cls;
+ break;
+ }
+ }
+ }
+
+ return resourceClass.getSimpleName().toLowerCase();
+ }
+
+ public void setResourcePaths(Map<String, String> resourcePaths) {
+ this.resourcePaths = resourcePaths;
+ }
+
+ public void setClassResources(Map<String, String> resources) {
+ this.classResources = resources;
+ }
+
+ public void setEnumResources(Map<? extends Enum<?>, String> enumResources) {
+ this.enumResources = enumResources;
+ }
+
+ public void setLocationPrefix(String locationPrefix) {
+ this.locationPrefix = locationPrefix;
+ }
+
+ public void setResourceExtension(String resourceExtension) {
+ this.resourceExtension = resourceExtension;
+ }
+
+ public void setErrorView(String errorView) {
+ this.errorView = errorView;
+ }
+}
\ No newline at end of file
diff --git a/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/spring/SpringViewResolverProviderTest.java b/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/spring/SpringViewResolverProviderTest.java
new file mode 100644
index 0000000..1c830ba
--- /dev/null
+++ b/rt/frontend/jaxrs/src/test/java/org/apache/cxf/jaxrs/spring/SpringViewResolverProviderTest.java
@@ -0,0 +1,414 @@
+/**
+ * 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.cxf.jaxrs.spring;
+
+import java.io.Closeable;
+import java.lang.annotation.Annotation;
+import java.util.Collection;
+import java.util.Collections;
+import java.util.List;
+import java.util.Locale;
+import java.util.Map;
+import java.util.concurrent.Executor;
+
+import javax.servlet.RequestDispatcher;
+import javax.servlet.ServletContext;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import javax.ws.rs.InternalServerErrorException;
+import javax.ws.rs.core.MediaType;
+import javax.ws.rs.core.MultivaluedHashMap;
+
+import org.apache.cxf.Bus;
+import org.apache.cxf.binding.Binding;
+import org.apache.cxf.endpoint.Endpoint;
+import org.apache.cxf.feature.Feature;
+import org.apache.cxf.interceptor.AbstractAttributedInterceptorProvider;
+import org.apache.cxf.interceptor.Interceptor;
+import org.apache.cxf.jaxrs.ext.MessageContextImpl;
+import org.apache.cxf.jaxrs.provider.ServerProviderFactory;
+import org.apache.cxf.message.ExchangeImpl;
+import org.apache.cxf.message.Message;
+import org.apache.cxf.message.MessageImpl;
+import org.apache.cxf.service.Service;
+import org.apache.cxf.service.model.BindingInfo;
+import org.apache.cxf.service.model.EndpointInfo;
+import org.apache.cxf.transport.MessageObserver;
+import org.apache.cxf.transport.http.AbstractHTTPDestination;
+import org.easymock.EasyMockRule;
+import org.easymock.EasyMockSupport;
+import org.easymock.Mock;
+import org.junit.Before;
+import org.junit.Rule;
+import org.junit.Test;
+import org.springframework.web.servlet.LocaleResolver;
+import org.springframework.web.servlet.View;
+import org.springframework.web.servlet.ViewResolver;
+import org.springframework.web.servlet.i18n.AcceptHeaderLocaleResolver;
+import org.springframework.web.servlet.view.BeanNameViewResolver;
+
+import static org.easymock.EasyMock.anyObject;
+import static org.easymock.EasyMock.expect;
+import static org.easymock.EasyMock.expectLastCall;
+import static org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+public class SpringViewResolverProviderTest extends EasyMockSupport {
+
+ @Rule
+ public EasyMockRule rule = new EasyMockRule(this);
+
+ @Mock
+ private ViewResolver viewResolverMock;
+
+ @Mock
+ private LocaleResolver localeResolverMock;
+
+ @Mock
+ private View viewMock;
+
+ @Mock
+ private HttpServletRequest requestMock;
+
+ @Mock
+ private HttpServletResponse responseMock;
+
+ @Mock
+ private ServletContext servletContextMock;
+
+ @Mock
+ private RequestDispatcher requestDispatcherMock;
+
+ private SpringViewResolverProvider viewResolver;
+
+ private Locale locale = Locale.US;
+
+ @Before
+ public void setUp() {
+ this.viewResolver = new SpringViewResolverProvider(viewResolverMock, localeResolverMock);
+ ExchangeImpl exchange = new ExchangeImpl();
+ Endpoint endpoint = new MockEndpoint();
+ endpoint.put(ServerProviderFactory.class.getName(), ServerProviderFactory.getInstance());
+ exchange.put(Endpoint.class, endpoint);
+ exchange.put(ServerProviderFactory.class.getName(), ServerProviderFactory.getInstance());
+ MessageImpl message = new MessageImpl();
+ message.setExchange(exchange);
+ message.put(AbstractHTTPDestination.HTTP_REQUEST, requestMock);
+ message.put(AbstractHTTPDestination.HTTP_RESPONSE, responseMock);
+ message.put(AbstractHTTPDestination.HTTP_CONTEXT, servletContextMock);
+ viewResolver.setMessageContext(new MessageContextImpl(message));
+ }
+
+ @Test
+ public void testIsWriteableEnum() throws Exception {
+ String viewName = "/test";
+ View view = expectGetView(viewName);
+ viewResolver.setClassResources(Collections.singletonMap(TestEnum.class.getName() + "."
+ + TestEnum.ONE, viewName));
+ replayAll();
+ assertTrue(viewResolver.isWriteable(TestEnum.ONE.getClass(), null, null, null));
+ assertEquals(view, viewResolver.getView(TestEnum.ONE.getClass(), TestEnum.ONE));
+ }
+
+ @Test
+ public void testIsWriteableEnum2() {
+ String viewName = "/test";
+ View view = expectGetView(viewName);
+ viewResolver.setEnumResources(Collections.singletonMap(TestEnum.ONE, viewName));
+ replayAll();
+ assertTrue(viewResolver.isWriteable(TestEnum.ONE.getClass(), null, null, null));
+ assertEquals(view, viewResolver.getView(TestEnum.ONE.getClass(), TestEnum.ONE));
+ }
+
+ @SuppressWarnings("unchecked")
+ @Test
+ public void testWriteTo() throws Exception {
+ String viewName = "/test";
+ expectWriteTo(viewName);
+ viewMock.render(anyObject(Map.class), anyObject(HttpServletRequest.class),
+ anyObject(HttpServletResponse.class));
+ expectLastCall();
+ replayAll();
+ viewResolver.writeTo(TestEnum.ONE, TestEnum.ONE.getClass(), null, new Annotation[] {},
+ MediaType.TEXT_HTML_TYPE,
+ new MultivaluedHashMap<String, Object>(), null);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Test
+ public void testWriteToWithRenderingError() throws Exception {
+ String viewName = "/test";
+ Exception exception = new RuntimeException("my exception");
+ expectWriteTo(viewName);
+ viewMock.render(anyObject(Map.class), anyObject(HttpServletRequest.class),
+ anyObject(HttpServletResponse.class));
+ expectLastCall().andThrow(exception);
+ requestMock.setAttribute(RequestDispatcher.ERROR_EXCEPTION, exception);
+ requestMock.setAttribute(RequestDispatcher.ERROR_STATUS_CODE, 500);
+ requestMock.setAttribute(RequestDispatcher.ERROR_MESSAGE, exception.getMessage());
+ expect(servletContextMock.getRequestDispatcher("/error")).andReturn(requestDispatcherMock);
+ requestDispatcherMock.forward(anyObject(HttpServletRequest.class), anyObject(HttpServletResponse.class));
+ expectLastCall();
+ replayAll();
+ viewResolver.writeTo(TestEnum.ONE, TestEnum.ONE.getClass(), null, new Annotation[] {},
+ MediaType.TEXT_HTML_TYPE,
+ new MultivaluedHashMap<String, Object>(), null);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Test(expected = InternalServerErrorException.class)
+ public void testWriteToWithInternalRenderingError() throws Exception {
+ String viewName = "/test";
+ Exception exception = new RuntimeException("my exception");
+ expectWriteTo(viewName);
+ viewMock.render(anyObject(Map.class), anyObject(HttpServletRequest.class),
+ anyObject(HttpServletResponse.class));
+ expectLastCall().andThrow(exception);
+ requestMock.setAttribute(RequestDispatcher.ERROR_EXCEPTION, exception);
+ requestMock.setAttribute(RequestDispatcher.ERROR_STATUS_CODE, 500);
+ requestMock.setAttribute(RequestDispatcher.ERROR_MESSAGE, exception.getMessage());
+ expect(servletContextMock.getRequestDispatcher("/error")).andReturn(requestDispatcherMock);
+ requestDispatcherMock.forward(anyObject(HttpServletRequest.class), anyObject(HttpServletResponse.class));
+ expectLastCall().andThrow(new RuntimeException("internal"));
+ replayAll();
+ viewResolver.writeTo(TestEnum.ONE, TestEnum.ONE.getClass(), null, new Annotation[] {},
+ MediaType.TEXT_HTML_TYPE,
+ new MultivaluedHashMap<String, Object>(), null);
+ }
+
+ @SuppressWarnings("unchecked")
+ @Test(expected = InternalServerErrorException.class)
+ public void testWriteToWithNullErrorView() throws Exception {
+ viewResolver.setErrorView(null);
+ String viewName = "/test";
+ Exception exception = new RuntimeException("my exception");
+ expectWriteTo(viewName);
+ viewMock.render(anyObject(Map.class), anyObject(HttpServletRequest.class),
+ anyObject(HttpServletResponse.class));
+ expectLastCall().andThrow(exception);
+ replayAll();
+ viewResolver.writeTo(TestEnum.ONE, TestEnum.ONE.getClass(), null, new Annotation[] {},
+ MediaType.TEXT_HTML_TYPE,
+ new MultivaluedHashMap<String, Object>(), null);
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testConstructorWithViewResolverNull() {
+ new SpringViewResolverProvider(null, new AcceptHeaderLocaleResolver());
+ }
+
+ @Test(expected = IllegalArgumentException.class)
+ public void testConstructorWithLocaleResolverNull() {
+ new SpringViewResolverProvider(new BeanNameViewResolver(), null);
+ }
+
+ private View expectGetView(String viewName) {
+ expect(localeResolverMock.resolveLocale(anyObject(HttpServletRequest.class))).andReturn(locale);
+ try {
+ expect(viewResolverMock.resolveViewName(viewName, locale)).andReturn(viewMock);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ return viewMock;
+ }
+
+ private void expectWriteTo(String viewName) {
+ expectGetView(viewName);
+ viewResolver.setEnumResources(Collections.singletonMap(TestEnum.ONE, viewName));
+ expect(localeResolverMock.resolveLocale(anyObject(HttpServletRequest.class))).andReturn(locale);
+ try {
+ expect(viewResolverMock.resolveViewName(viewName, locale)).andReturn(viewMock);
+ } catch (Exception e) {
+ throw new RuntimeException(e);
+ }
+ }
+
+ private enum TestEnum {
+ ONE,
+ TWO
+ }
+
+ @SuppressWarnings("unused")
+ private static final class TestView implements View {
+
+ private String viewName;
+
+ TestView(String viewName) {
+ this.viewName = viewName;
+ }
+
+ @Override
+ public String getContentType() {
+ return null;
+ }
+
+ @Override
+ public void render(Map<String, ?> model, HttpServletRequest request, HttpServletResponse response)
+ throws Exception {
+ }
+
+ public String getViewName() {
+ return viewName;
+ }
+ }
+
+ private static final class MockEndpoint extends AbstractAttributedInterceptorProvider implements Endpoint {
+
+ private static final long serialVersionUID = 1L;
+
+ private EndpointInfo epi = new EndpointInfo();
+
+ MockEndpoint() {
+ epi.setBinding(new BindingInfo(null, null));
+ }
+
+ public List<Feature> getActiveFeatures() {
+ return null;
+ }
+
+ public Binding getBinding() {
+ return null;
+ }
+
+ public EndpointInfo getEndpointInfo() {
+ return this.epi;
+ }
+
+ public Executor getExecutor() {
+ return null;
+ }
+
+ public void setExecutor(Executor executor) {
+ }
+
+ public MessageObserver getInFaultObserver() {
+ return null;
+ }
+
+ public void setInFaultObserver(MessageObserver observer) {
+ }
+
+ public MessageObserver getOutFaultObserver() {
+ return null;
+ }
+
+ public void setOutFaultObserver(MessageObserver observer) {
+ }
+
+ public Service getService() {
+ return null;
+ }
+
+ public void addCleanupHook(Closeable c) {
+ }
+
+ public List<Closeable> getCleanupHooks() {
+ return null;
+ }
+ }
+
+ @SuppressWarnings("unused")
+ private static class MockBus implements Bus {
+
+ @Override
+ public <T> T getExtension(Class<T> extensionType) {
+ return null;
+ }
+
+ @Override
+ public <T> void setExtension(T extension, Class<T> extensionType) {
+
+ }
+
+ @Override
+ public boolean hasExtensionByName(String name) {
+ return false;
+ }
+
+ @Override
+ public String getId() {
+ return null;
+ }
+
+ @Override
+ public void setId(String i) {
+
+ }
+
+ @Override
+ public void shutdown(boolean wait) {
+
+ }
+
+ @Override
+ public void setProperty(String s, Object o) {
+
+ }
+
+ @Override
+ public Object getProperty(String s) {
+ return null;
+ }
+
+ @Override
+ public Map<String, Object> getProperties() {
+ return null;
+ }
+
+ @Override
+ public void setProperties(Map<String, Object> properties) {
+
+ }
+
+ @Override
+ public Collection<Feature> getFeatures() {
+ return null;
+ }
+
+ @Override
+ public void setFeatures(Collection<? extends Feature> features) {
+
+ }
+
+ @Override
+ public BusState getState() {
+ return null;
+ }
+
+ @Override
+ public List<Interceptor<? extends Message>> getInInterceptors() {
+ return null;
+ }
+
+ @Override
+ public List<Interceptor<? extends Message>> getOutInterceptors() {
+ return null;
+ }
+
+ @Override
+ public List<Interceptor<? extends Message>> getInFaultInterceptors() {
+ return null;
+ }
+
+ @Override
+ public List<Interceptor<? extends Message>> getOutFaultInterceptors() {
+ return null;
+ }
+ }
+}
\ No newline at end of file
--
To stop receiving notification emails like this one, please contact
['"commits@cxf.apache.org" <co...@cxf.apache.org>'].