Skip to content

Commit 88fdfd4

Browse files
committed
SWS-331
1 parent 439be91 commit 88fdfd4

File tree

2 files changed

+269
-0
lines changed

2 files changed

+269
-0
lines changed
Lines changed: 134 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,134 @@
1+
/*
2+
* Copyright 2007 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.oxm.support;
18+
19+
import java.io.ByteArrayOutputStream;
20+
import java.util.Iterator;
21+
import java.util.Map;
22+
import javax.servlet.ServletException;
23+
import javax.servlet.ServletOutputStream;
24+
import javax.servlet.http.HttpServletRequest;
25+
import javax.servlet.http.HttpServletResponse;
26+
import javax.xml.transform.stream.StreamResult;
27+
28+
import org.springframework.beans.BeansException;
29+
import org.springframework.oxm.Marshaller;
30+
import org.springframework.util.Assert;
31+
import org.springframework.web.servlet.View;
32+
import org.springframework.web.servlet.view.AbstractUrlBasedView;
33+
34+
/**
35+
* Spring-MVC {@link View} that allows for response context to be rendered as the result of marshalling by a {@link
36+
* Marshaller}.
37+
* <p/>
38+
* The Object to be marshalled is supplied as a parameter in the model and then {@linkplain #locateToBeMarshalled(Map)
39+
* detected} during response rendering. Users can either specify a specific entry in the model via the {@link
40+
* #setModelKey(String) sourceKey} property or have Spring locate the Source object.
41+
*
42+
* @author Arjen Poutsma
43+
* @since 1.5.1
44+
*/
45+
public class MarshallingView extends AbstractUrlBasedView {
46+
47+
/** Default content type. Overridable as bean property. */
48+
public static final String DEFAULT_CONTENT_TYPE = "application/xml";
49+
50+
private Marshaller marshaller;
51+
52+
private String modelKey;
53+
54+
/**
55+
* Constructs a new <code>MarshallingView</code> with no {@link Marshaller} set. The marshaller must be set after
56+
* construction by invoking {@link #setMarshaller(Marshaller)}.
57+
*/
58+
public MarshallingView() {
59+
setContentType(DEFAULT_CONTENT_TYPE);
60+
}
61+
62+
/** Constructs a new <code>MarshallingView</code> with the given {@link Marshaller} set. */
63+
public MarshallingView(Marshaller marshaller) {
64+
Assert.notNull(marshaller, "'marshaller' must not be null");
65+
setContentType(DEFAULT_CONTENT_TYPE);
66+
this.marshaller = marshaller;
67+
}
68+
69+
/** Sets the {@link Marshaller} to be used by this view. */
70+
public void setMarshaller(Marshaller marshaller) {
71+
Assert.notNull(marshaller, "'marshaller' must not be null");
72+
this.marshaller = marshaller;
73+
}
74+
75+
/**
76+
* Set the name of the model key that represents the object to be marshalled. If not specified, the model map will
77+
* be searched for a supported value type.
78+
*
79+
* @see Marshaller#supports(Class)
80+
*/
81+
public void setModelKey(String modelKey) {
82+
this.modelKey = modelKey;
83+
}
84+
85+
protected void initApplicationContext() throws BeansException {
86+
Assert.notNull(marshaller, "Property 'marshaller' is required");
87+
}
88+
89+
protected void renderMergedOutputModel(Map model, HttpServletRequest request, HttpServletResponse response)
90+
throws Exception {
91+
Object toBeMarshalled = locateToBeMarshalled(model);
92+
if (toBeMarshalled == null) {
93+
throw new ServletException("Unable to locate object to be marshalled in model: " + model);
94+
}
95+
ByteArrayOutputStream bos = new ByteArrayOutputStream(2048);
96+
marshaller.marshal(toBeMarshalled, new StreamResult(bos));
97+
98+
response.setContentType(getContentType());
99+
response.setContentLength(bos.size());
100+
101+
ServletOutputStream out = response.getOutputStream();
102+
bos.writeTo(out);
103+
out.flush();
104+
}
105+
106+
/**
107+
* Locates the object to be marshalled. The default implementation first attempts to look under the configured
108+
* {@linkplain #setModelKey(String) model key}, if any, before attempting to locate an object of {@linkplain
109+
* Marshaller#supports(Class) supported type}.
110+
*
111+
* @param model the model Map
112+
* @return the Object to be marshalled (or <code>null</code> if none found)
113+
* @throws ServletException if the model object specified by the {@linkplain #setModelKey(String) model key} is not
114+
* supported by the marshaller
115+
* @see #setModelKey(String)
116+
*/
117+
protected Object locateToBeMarshalled(Map model) throws ServletException {
118+
if (this.modelKey != null) {
119+
Object o = model.get(this.modelKey);
120+
if (!this.marshaller.supports(o.getClass())) {
121+
throw new ServletException("Model object [" + o + "] retrieved via key [" + modelKey +
122+
"] is not supported by the Marshaller");
123+
}
124+
return o;
125+
}
126+
for (Iterator iterator = model.values().iterator(); iterator.hasNext();) {
127+
Object o = iterator.next();
128+
if (this.marshaller.supports(o.getClass())) {
129+
return o;
130+
}
131+
}
132+
return null;
133+
}
134+
}
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
/*
2+
* Copyright 2007 the original author or authors.
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package org.springframework.oxm.support;
18+
19+
import java.util.HashMap;
20+
import java.util.Map;
21+
import javax.servlet.ServletException;
22+
import javax.xml.transform.stream.StreamResult;
23+
24+
import junit.framework.Assert;
25+
import junit.framework.TestCase;
26+
import org.easymock.MockControl;
27+
28+
import org.springframework.mock.web.MockHttpServletRequest;
29+
import org.springframework.mock.web.MockHttpServletResponse;
30+
import org.springframework.oxm.Marshaller;
31+
32+
public class MarshallingViewTest extends TestCase {
33+
34+
private MarshallingView view;
35+
36+
private MockControl control;
37+
38+
private Marshaller marshallerMock;
39+
40+
protected void setUp() throws Exception {
41+
control = MockControl.createControl(Marshaller.class);
42+
marshallerMock = (Marshaller) control.getMock();
43+
view = new MarshallingView(marshallerMock);
44+
}
45+
46+
public void testGetContentType() {
47+
Assert.assertEquals("Invalid content type", "application/xml", view.getContentType());
48+
}
49+
50+
public void testRenderModelKey() throws Exception {
51+
Object toBeMarshalled = new Object();
52+
String modelKey = "key";
53+
view.setModelKey(modelKey);
54+
Map model = new HashMap();
55+
model.put(modelKey, toBeMarshalled);
56+
57+
MockHttpServletRequest request = new MockHttpServletRequest();
58+
MockHttpServletResponse response = new MockHttpServletResponse();
59+
60+
control.expectAndReturn(marshallerMock.supports(Object.class), true);
61+
marshallerMock.marshal(toBeMarshalled, new StreamResult(response.getOutputStream()));
62+
control.setMatcher(MockControl.ALWAYS_MATCHER);
63+
64+
control.replay();
65+
view.render(model, request, response);
66+
Assert.assertEquals("Invalid content type", "application/xml", response.getContentType());
67+
Assert.assertEquals("Invalid content length", 0, response.getContentLength());
68+
control.verify();
69+
}
70+
71+
public void testRenderModelKeyUnsupported() throws Exception {
72+
Object toBeMarshalled = new Object();
73+
String modelKey = "key";
74+
view.setModelKey(modelKey);
75+
Map model = new HashMap();
76+
model.put(modelKey, toBeMarshalled);
77+
78+
MockHttpServletRequest request = new MockHttpServletRequest();
79+
MockHttpServletResponse response = new MockHttpServletResponse();
80+
81+
control.expectAndReturn(marshallerMock.supports(Object.class), false);
82+
83+
control.replay();
84+
try {
85+
view.render(model, request, response);
86+
fail("ServletException expected");
87+
}
88+
catch (ServletException ex) {
89+
// expected
90+
}
91+
control.verify();
92+
}
93+
94+
public void testRenderNoModelKey() throws Exception {
95+
Object toBeMarshalled = new Object();
96+
String modelKey = "key";
97+
Map model = new HashMap();
98+
model.put(modelKey, toBeMarshalled);
99+
100+
MockHttpServletRequest request = new MockHttpServletRequest();
101+
MockHttpServletResponse response = new MockHttpServletResponse();
102+
103+
control.expectAndReturn(marshallerMock.supports(Object.class), true);
104+
marshallerMock.marshal(toBeMarshalled, new StreamResult(response.getOutputStream()));
105+
control.setMatcher(MockControl.ALWAYS_MATCHER);
106+
107+
control.replay();
108+
view.render(model, request, response);
109+
Assert.assertEquals("Invalid content type", "application/xml", response.getContentType());
110+
Assert.assertEquals("Invalid content length", 0, response.getContentLength());
111+
control.verify();
112+
}
113+
114+
public void testRenderUnsupportedModel() throws Exception {
115+
Object toBeMarshalled = new Object();
116+
String modelKey = "key";
117+
Map model = new HashMap();
118+
model.put(modelKey, toBeMarshalled);
119+
120+
MockHttpServletRequest request = new MockHttpServletRequest();
121+
MockHttpServletResponse response = new MockHttpServletResponse();
122+
123+
control.expectAndReturn(marshallerMock.supports(Object.class), false);
124+
125+
control.replay();
126+
try {
127+
view.render(model, request, response);
128+
fail("ServletException expected");
129+
}
130+
catch (ServletException ex) {
131+
// expected
132+
}
133+
control.verify();
134+
}
135+
}

0 commit comments

Comments
 (0)