SLING-6183 - add Sling Model Exporter feature
git-svn-id: https://svn.apache.org/repos/asf/sling/trunk@1767030 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/pom.xml b/pom.xml
index 39bb93f..89da726 100644
--- a/pom.xml
+++ b/pom.xml
@@ -115,7 +115,8 @@
org.apache.sling.models.it.noclasses,
org.apache.sling.models.it.models,
org.apache.sling.models.it.rtbound,
- org.apache.sling.models.it.rtboundpicker
+ org.apache.sling.models.it.rtboundpicker,
+ org.apache.sling.models.it.exporter
</Sling-Model-Packages>
<Sling-Test-Regexp>.*Test</Sling-Test-Regexp>
<Export-Package>org.apache.sling.models.it</Export-Package>
@@ -242,7 +243,11 @@
<sling.additional.bundle.2>geronimo-atinject_1.0_spec</sling.additional.bundle.2>
<sling.additional.bundle.10>org.apache.sling.models.api</sling.additional.bundle.10>
<sling.additional.bundle.11>org.apache.sling.models.impl</sling.additional.bundle.11>
- <sling.additional.bundle.12>${project.build.finalName}.jar</sling.additional.bundle.12>
+ <sling.additional.bundle.12>org.apache.sling.models.jacksonexporter</sling.additional.bundle.12>
+ <sling.additional.bundle.13>jackson-annotations</sling.additional.bundle.13>
+ <sling.additional.bundle.14>jackson-core</sling.additional.bundle.14>
+ <sling.additional.bundle.15>jackson-databind</sling.additional.bundle.15>
+ <sling.additional.bundle.16>${project.build.finalName}.jar</sling.additional.bundle.16>
</systemPropertyVariables>
</configuration>
</plugin>
@@ -281,6 +286,12 @@
</dependency>
<dependency>
<groupId>org.apache.sling</groupId>
+ <artifactId>org.apache.sling.engine</artifactId>
+ <version>2.2.0</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>org.apache.sling</groupId>
<artifactId>org.apache.sling.models.api</artifactId>
<version>1.3.0-SNAPSHOT</version>
<scope>provided</scope>
@@ -291,6 +302,31 @@
<version>1.3.0-SNAPSHOT</version>
<scope>provided</scope>
</dependency>
+ <dependency>
+ <groupId>org.apache.sling</groupId>
+ <artifactId>org.apache.sling.models.jacksonexporter</artifactId>
+ <version>0.0.99-SNAPSHOT</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.fasterxml.jackson.core</groupId>
+ <artifactId>jackson-databind</artifactId>
+ <version>2.3.2</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.fasterxml.jackson.core</groupId>
+ <artifactId>jackson-core</artifactId>
+ <version>2.3.2</version>
+ <scope>provided</scope>
+ </dependency>
+ <dependency>
+ <groupId>com.fasterxml.jackson.core</groupId>
+ <artifactId>jackson-annotations</artifactId>
+ <version>2.3.2</version>
+ <scope>provided</scope>
+ </dependency>
+
<!-- not part of launchpad 7 (see SLING-4710) -->
<dependency>
<groupId>org.apache.geronimo.specs</groupId>
diff --git a/src/main/java/org/apache/sling/models/it/exporter/BaseComponent.java b/src/main/java/org/apache/sling/models/it/exporter/BaseComponent.java
new file mode 100644
index 0000000..0f7d7d8
--- /dev/null
+++ b/src/main/java/org/apache/sling/models/it/exporter/BaseComponent.java
@@ -0,0 +1,52 @@
+/*
+ * 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.sling.models.it.exporter;
+
+import javax.inject.Inject;
+
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.models.annotations.Exporter;
+import org.apache.sling.models.annotations.Model;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+@Model(adaptables = { Resource.class }, resourceType = "sling/exp/base")
+@Exporter(name = "jackson", extensions = "json")
+public class BaseComponent {
+
+ private final Resource resource;
+
+ @Inject
+ private String sampleValue;
+
+ public BaseComponent(Resource resource) {
+ this.resource = resource;
+ }
+
+ public String getId() {
+ return this.resource.getPath();
+ }
+
+ public String getSampleValue() {
+ return sampleValue;
+ }
+
+ @JsonProperty(value="UPPER")
+ public String getSampleValueToUpperCase() {
+ return sampleValue.toUpperCase();
+ }
+}
diff --git a/src/main/java/org/apache/sling/models/it/exporter/ExporterTest.java b/src/main/java/org/apache/sling/models/it/exporter/ExporterTest.java
new file mode 100644
index 0000000..5d6778c
--- /dev/null
+++ b/src/main/java/org/apache/sling/models/it/exporter/ExporterTest.java
@@ -0,0 +1,190 @@
+/*
+ * 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.sling.models.it.exporter;
+
+import java.util.Calendar;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+import java.util.TimeZone;
+
+import org.apache.commons.lang.StringUtils;
+import org.apache.sling.api.SlingConstants;
+import org.apache.sling.api.resource.LoginException;
+import org.apache.sling.api.resource.PersistenceException;
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.api.resource.ResourceResolver;
+import org.apache.sling.api.resource.ResourceResolverFactory;
+import org.apache.sling.api.resource.ResourceUtil;
+import org.apache.sling.commons.json.JSONObject;
+import org.apache.sling.engine.SlingRequestProcessor;
+import org.apache.sling.junit.annotations.SlingAnnotationsTestRunner;
+import org.apache.sling.junit.annotations.TestReference;
+import org.apache.sling.models.factory.MissingExporterException;
+import org.apache.sling.models.factory.ModelFactory;
+import org.junit.Assert;
+import org.junit.Before;
+import org.junit.Test;
+import org.junit.runner.RunWith;
+
+@RunWith(SlingAnnotationsTestRunner.class)
+public class ExporterTest {
+
+ @TestReference
+ private ResourceResolverFactory rrFactory;
+
+ @TestReference
+ private ModelFactory modelFactory;
+
+ @TestReference
+ private SlingRequestProcessor slingRequestProcessor;
+
+ private final String baseComponentPath = "/content/exp/baseComponent";
+ private final String childComponentPath = "/content/exp/childComponent";
+ private final String extendedComponentPath = "/content/exp/extendedComponent";
+ private Calendar testDate;
+
+ @Before
+ public void setup() throws LoginException, PersistenceException {
+ ResourceResolver adminResolver = null;
+ try {
+ adminResolver = rrFactory.getAdministrativeResourceResolver(null);
+ Map<String, Object> properties = new HashMap<String, Object>();
+ properties.put("sampleValue", "baseTESTValue");
+ properties.put(SlingConstants.NAMESPACE_PREFIX + ":" + SlingConstants.PROPERTY_RESOURCE_TYPE,
+ "sling/exp/base");
+ ResourceUtil.getOrCreateResource(adminResolver, baseComponentPath, properties, null, false);
+ properties.clear();
+
+ properties.put("sampleValue", "childTESTValue");
+ properties.put(SlingConstants.NAMESPACE_PREFIX + ":" + SlingConstants.PROPERTY_RESOURCE_TYPE,
+ "sling/exp/child");
+ properties.put(SlingConstants.NAMESPACE_PREFIX + ":" + SlingConstants.PROPERTY_RESOURCE_SUPER_TYPE,
+ "sling/exp/base");
+ ResourceUtil.getOrCreateResource(adminResolver, childComponentPath, properties, null, false);
+ properties.clear();
+
+ properties.put("sampleValue", "extendedTESTValue");
+ properties.put(SlingConstants.NAMESPACE_PREFIX + ":" + SlingConstants.PROPERTY_RESOURCE_TYPE,
+ "sling/exp/extended");
+ testDate = Calendar.getInstance();
+ testDate.setTimeZone(TimeZone.getTimeZone("UTC"));
+ testDate.setTimeInMillis(0);
+ testDate.set(2015, 6, 29);
+ properties.put("date", testDate);
+ ResourceUtil.getOrCreateResource(adminResolver, extendedComponentPath, properties, null, false);
+ adminResolver.commit();
+ } finally {
+ if (adminResolver != null && adminResolver.isLive()) {
+ adminResolver.close();
+ }
+ }
+ }
+
+ @Test
+ public void testExportToJSON() throws Exception {
+ ResourceResolver resolver = null;
+ try {
+ resolver = rrFactory.getAdministrativeResourceResolver(null);
+ final Resource baseComponentResource = resolver.getResource(baseComponentPath);
+ Assert.assertNotNull(baseComponentResource);
+ String jsonData = modelFactory.exportModelForResource(baseComponentResource, "jackson", String.class,
+ Collections.<String, String> emptyMap());
+ Assert.assertTrue("JSON Data should contain the property value",
+ StringUtils.contains(jsonData, "baseTESTValue"));
+
+ final Resource extendedComponentResource = resolver.getResource(extendedComponentPath);
+ Assert.assertNotNull(extendedComponentResource);
+ jsonData = modelFactory.exportModelForResource(extendedComponentResource, "jackson", String.class,
+ Collections.<String, String> emptyMap());
+ Assert.assertTrue("JSON Data should contain the property value",
+ StringUtils.contains(jsonData, "extendedTESTValue"));
+ } finally {
+ if (resolver != null && resolver.isLive()) {
+ resolver.close();
+ }
+ }
+ }
+
+ @Test
+ public void testExportToMap() throws Exception {
+ ResourceResolver resolver = null;
+ try {
+ resolver = rrFactory.getAdministrativeResourceResolver(null);
+ final Resource baseComponentResource = resolver.getResource(baseComponentPath);
+ Assert.assertNotNull(baseComponentResource);
+ Map<String, Object> data = modelFactory.exportModelForResource(baseComponentResource, "jackson", Map.class,
+ Collections.<String, String> emptyMap());
+ Assert.assertEquals("Should have resource value", "baseTESTValue", data.get("sampleValue"));
+ Assert.assertEquals("Should have resource value", "BASETESTVALUE", data.get("UPPER"));
+ } finally {
+ if (resolver != null && resolver.isLive()) {
+ resolver.close();
+ }
+ }
+ }
+
+ @Test
+ public void testServlets() throws Exception {
+ ResourceResolver resolver = null;
+ try {
+ resolver = rrFactory.getAdministrativeResourceResolver(null);
+ FakeResponse response = new FakeResponse();
+ slingRequestProcessor.processRequest(new FakeRequest(baseComponentPath + ".model.json"), response, resolver);
+ JSONObject obj = new JSONObject(response.getStringWriter().toString());
+ Assert.assertEquals("application/json", response.getContentType());
+ Assert.assertEquals("BASETESTVALUE", obj.getString("UPPER"));
+ Assert.assertEquals(baseComponentPath, obj.getString("id"));
+
+ response = new FakeResponse();
+ slingRequestProcessor.processRequest(new FakeRequest(extendedComponentPath + ".model.json"), response, resolver);
+ obj = new JSONObject(response.getStringWriter().toString());
+ Assert.assertEquals(extendedComponentPath, obj.getString("id"));
+ Assert.assertEquals(testDate.getTimeInMillis(), obj.getLong("date"));
+ } finally {
+ if (resolver != null && resolver.isLive()) {
+ resolver.close();
+ }
+ }
+ }
+
+ @Test
+ public void testFailedExport() throws Exception {
+ boolean thrown = false;
+ try {
+ ResourceResolver resolver = null;
+ try {
+ resolver = rrFactory.getAdministrativeResourceResolver(null);
+ final Resource baseComponentResource = resolver.getResource(baseComponentPath);
+ Assert.assertNotNull(baseComponentResource);
+ String data = modelFactory.exportModelForResource(baseComponentResource, "jaxb", String.class,
+ Collections.<String, String>emptyMap());
+ Assert.fail("Should have thrown missing serializer error.");
+ } finally {
+ if (resolver != null && resolver.isLive()) {
+ resolver.close();
+ }
+ }
+ } catch (MissingExporterException e) {
+ thrown = true;
+ Assert.assertEquals("No exporter named jaxb supports java.lang.String.", e.getMessage());
+ }
+ Assert.assertTrue(thrown);
+
+ }
+
+}
diff --git a/src/main/java/org/apache/sling/models/it/exporter/ExtendedComponent.java b/src/main/java/org/apache/sling/models/it/exporter/ExtendedComponent.java
new file mode 100644
index 0000000..033a6f6
--- /dev/null
+++ b/src/main/java/org/apache/sling/models/it/exporter/ExtendedComponent.java
@@ -0,0 +1,49 @@
+/*
+ * 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.sling.models.it.exporter;
+
+import java.util.Calendar;
+import java.util.Date;
+import java.util.GregorianCalendar;
+
+import org.apache.sling.api.resource.Resource;
+import org.apache.sling.models.annotations.Exporter;
+import org.apache.sling.models.annotations.Model;
+
+import javax.inject.Inject;
+
+@Model(adaptables = { Resource.class }, resourceType = "sling/exp/extended")
+@Exporter(name = "jackson", extensions = "json")
+public class ExtendedComponent extends BaseComponent {
+
+ @Inject
+ private Date date;
+
+ public ExtendedComponent(Resource resource) {
+ super(resource);
+ }
+
+ public Calendar getDateByCalendar() {
+ Calendar cal = new GregorianCalendar();
+ cal.setTime(date);
+ return cal;
+ }
+
+ public Date getDate() {
+ return date;
+ }
+}
diff --git a/src/main/java/org/apache/sling/models/it/exporter/FakeRequest.java b/src/main/java/org/apache/sling/models/it/exporter/FakeRequest.java
new file mode 100644
index 0000000..a11da83
--- /dev/null
+++ b/src/main/java/org/apache/sling/models/it/exporter/FakeRequest.java
@@ -0,0 +1,309 @@
+/*
+ * 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.sling.models.it.exporter;
+
+import javax.servlet.RequestDispatcher;
+import javax.servlet.ServletInputStream;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpSession;
+import java.io.BufferedReader;
+import java.io.IOException;
+import java.io.UnsupportedEncodingException;
+import java.security.Principal;
+import java.util.Enumeration;
+import java.util.Locale;
+import java.util.Map;
+
+class FakeRequest implements HttpServletRequest {
+
+ private final String path;
+
+ FakeRequest(String path) {
+ this.path = path;
+ }
+
+ @Override
+ public String getAuthType() {
+ return null;
+ }
+
+ @Override
+ public Cookie[] getCookies() {
+ return new Cookie[0];
+ }
+
+ @Override
+ public long getDateHeader(String name) {
+ return 0;
+ }
+
+ @Override
+ public String getHeader(String name) {
+ return null;
+ }
+
+ @Override
+ public Enumeration getHeaders(String name) {
+ return null;
+ }
+
+ @Override
+ public Enumeration getHeaderNames() {
+ return null;
+ }
+
+ @Override
+ public int getIntHeader(String name) {
+ return 0;
+ }
+
+ @Override
+ public String getMethod() {
+ return "GET";
+ }
+
+ @Override
+ public String getPathInfo() {
+ return path;
+ }
+
+ @Override
+ public String getPathTranslated() {
+ return null;
+ }
+
+ @Override
+ public String getContextPath() {
+ return null;
+ }
+
+ @Override
+ public String getQueryString() {
+ return null;
+ }
+
+ @Override
+ public String getRemoteUser() {
+ return null;
+ }
+
+ @Override
+ public boolean isUserInRole(String role) {
+ return false;
+ }
+
+ @Override
+ public Principal getUserPrincipal() {
+ return null;
+ }
+
+ @Override
+ public String getRequestedSessionId() {
+ return null;
+ }
+
+ @Override
+ public String getRequestURI() {
+ return null;
+ }
+
+ @Override
+ public StringBuffer getRequestURL() {
+ return null;
+ }
+
+ @Override
+ public String getServletPath() {
+ return "";
+ }
+
+ @Override
+ public HttpSession getSession(boolean create) {
+ return null;
+ }
+
+ @Override
+ public HttpSession getSession() {
+ return null;
+ }
+
+ @Override
+ public boolean isRequestedSessionIdValid() {
+ return false;
+ }
+
+ @Override
+ public boolean isRequestedSessionIdFromCookie() {
+ return false;
+ }
+
+ @Override
+ public boolean isRequestedSessionIdFromURL() {
+ return false;
+ }
+
+ @Override
+ public boolean isRequestedSessionIdFromUrl() {
+ return false;
+ }
+
+ @Override
+ public Object getAttribute(String name) {
+ return null;
+ }
+
+ @Override
+ public Enumeration getAttributeNames() {
+ return null;
+ }
+
+ @Override
+ public String getCharacterEncoding() {
+ return null;
+ }
+
+ @Override
+ public void setCharacterEncoding(String env) throws UnsupportedEncodingException {
+
+ }
+
+ @Override
+ public int getContentLength() {
+ return 0;
+ }
+
+ @Override
+ public String getContentType() {
+ return null;
+ }
+
+ @Override
+ public ServletInputStream getInputStream() throws IOException {
+ return null;
+ }
+
+ @Override
+ public String getParameter(String name) {
+ return null;
+ }
+
+ @Override
+ public Enumeration getParameterNames() {
+ return null;
+ }
+
+ @Override
+ public String[] getParameterValues(String name) {
+ return new String[0];
+ }
+
+ @Override
+ public Map getParameterMap() {
+ return null;
+ }
+
+ @Override
+ public String getProtocol() {
+ return null;
+ }
+
+ @Override
+ public String getScheme() {
+ return null;
+ }
+
+ @Override
+ public String getServerName() {
+ return null;
+ }
+
+ @Override
+ public int getServerPort() {
+ return 0;
+ }
+
+ @Override
+ public BufferedReader getReader() throws IOException {
+ return null;
+ }
+
+ @Override
+ public String getRemoteAddr() {
+ return null;
+ }
+
+ @Override
+ public String getRemoteHost() {
+ return null;
+ }
+
+ @Override
+ public void setAttribute(String name, Object o) {
+
+ }
+
+ @Override
+ public void removeAttribute(String name) {
+
+ }
+
+ @Override
+ public Locale getLocale() {
+ return null;
+ }
+
+ @Override
+ public Enumeration getLocales() {
+ return null;
+ }
+
+ @Override
+ public boolean isSecure() {
+ return false;
+ }
+
+ @Override
+ public RequestDispatcher getRequestDispatcher(String path) {
+ return null;
+ }
+
+ @Override
+ public String getRealPath(String path) {
+ return null;
+ }
+
+ @Override
+ public int getRemotePort() {
+ return 0;
+ }
+
+ @Override
+ public String getLocalName() {
+ return null;
+ }
+
+ @Override
+ public String getLocalAddr() {
+ return null;
+ }
+
+ @Override
+ public int getLocalPort() {
+ return 0;
+ }
+}
diff --git a/src/main/java/org/apache/sling/models/it/exporter/FakeResponse.java b/src/main/java/org/apache/sling/models/it/exporter/FakeResponse.java
new file mode 100644
index 0000000..8747d3f
--- /dev/null
+++ b/src/main/java/org/apache/sling/models/it/exporter/FakeResponse.java
@@ -0,0 +1,194 @@
+/*
+ * 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.sling.models.it.exporter;
+
+import javax.servlet.ServletOutputStream;
+import javax.servlet.http.Cookie;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.StringWriter;
+import java.util.Locale;
+
+class FakeResponse implements HttpServletResponse {
+
+ private StringWriter stringWriter = new StringWriter();
+ private String contentType = null;
+
+ @Override
+ public void addCookie(Cookie cookie) {
+ }
+
+ @Override
+ public boolean containsHeader(String name) {
+ return false;
+ }
+
+ @Override
+ public String encodeURL(String url) {
+ return null;
+ }
+
+ @Override
+ public String encodeRedirectURL(String url) {
+ return null;
+ }
+
+ @Override
+ public String encodeUrl(String url) {
+ return null;
+ }
+
+ @Override
+ public String encodeRedirectUrl(String url) {
+ return null;
+ }
+
+ @Override
+ public void sendError(int sc, String msg) throws IOException {
+
+ }
+
+ @Override
+ public void sendError(int sc) throws IOException {
+
+ }
+
+ @Override
+ public void sendRedirect(String location) throws IOException {
+
+ }
+
+ @Override
+ public void setDateHeader(String name, long date) {
+
+ }
+
+ @Override
+ public void addDateHeader(String name, long date) {
+
+ }
+
+ @Override
+ public void setHeader(String name, String value) {
+
+ }
+
+ @Override
+ public void addHeader(String name, String value) {
+
+ }
+
+ @Override
+ public void setIntHeader(String name, int value) {
+
+ }
+
+ @Override
+ public void addIntHeader(String name, int value) {
+
+ }
+
+ @Override
+ public void setStatus(int sc) {
+
+ }
+
+ @Override
+ public void setStatus(int sc, String sm) {
+
+ }
+
+ @Override
+ public String getCharacterEncoding() {
+ return null;
+ }
+
+ @Override
+ public String getContentType() {
+ return contentType;
+ }
+
+ @Override
+ public ServletOutputStream getOutputStream() throws IOException {
+ return null;
+ }
+
+ @Override
+ public PrintWriter getWriter() throws IOException {
+ return new PrintWriter(stringWriter);
+ }
+
+ @Override
+ public void setCharacterEncoding(String charset) {
+
+ }
+
+ @Override
+ public void setContentLength(int len) {
+
+ }
+
+ @Override
+ public void setContentType(String type) {
+ this.contentType = type;
+ }
+
+ @Override
+ public void setBufferSize(int size) {
+
+ }
+
+ @Override
+ public int getBufferSize() {
+ return 0;
+ }
+
+ @Override
+ public void flushBuffer() throws IOException {
+
+ }
+
+ @Override
+ public void resetBuffer() {
+
+ }
+
+ @Override
+ public boolean isCommitted() {
+ return false;
+ }
+
+ @Override
+ public void reset() {
+
+ }
+
+ @Override
+ public void setLocale(Locale loc) {
+
+ }
+
+ @Override
+ public Locale getLocale() {
+ return null;
+ }
+
+ public StringWriter getStringWriter() {
+ return stringWriter;
+ }
+}