Migrate apigateway and helpserver 25/117425/3
authorRavi Pendurty <ravi.pendurty@highstreet-technologies.com>
Wed, 3 Feb 2021 13:18:39 +0000 (14:18 +0100)
committerDan Timoney <dtimoney@att.com>
Fri, 5 Feb 2021 22:55:53 +0000 (22:55 +0000)
Migrate apigateway and helpserver to Aluminium

Issue-ID: CCSDK-3129
Signed-off-by: Ravi Pendurty <ravi.pendurty@highstreet-technologies.com>
Change-Id: I6a669b7e0e5d805cab4a9e59e2b21a95fb6506f8
Signed-off-by: Ravi Pendurty <ravi.pendurty@highstreet-technologies.com>
14 files changed:
sdnr/wt/apigateway/feature/pom.xml
sdnr/wt/apigateway/installer/pom.xml
sdnr/wt/apigateway/pom.xml
sdnr/wt/apigateway/provider/pom.xml
sdnr/wt/apigateway/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/apigateway/MyProperties.java
sdnr/wt/apigateway/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/apigateway/TilesServlet.java [new file with mode: 0644]
sdnr/wt/apigateway/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/apigateway/TopologyServlet.java [new file with mode: 0644]
sdnr/wt/apigateway/provider/src/main/resources/org/opendaylight/blueprint/blueprint.xml
sdnr/wt/apigateway/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/apigateway/test/helper/HelpServletBase.java
sdnr/wt/helpserver/feature/pom.xml
sdnr/wt/helpserver/installer/pom.xml
sdnr/wt/helpserver/pom.xml
sdnr/wt/helpserver/provider/pom.xml
sdnr/wt/helpserver/provider/src/test/java/org/onap/ccsdk/features/sdnr/wt/helpserver/test/TestMyServlet.java

index 000ed6b..9ed61b8 100644 (file)
@@ -29,7 +29,7 @@
     <parent>
         <groupId>org.onap.ccsdk.parent</groupId>
         <artifactId>single-feature-parent</artifactId>
-        <version>2.1.0</version>
+        <version>2.1.1-SNAPSHOT</version>
         <relativePath/>
     </parent>
 
 
     <name>ccsdk-features :: ${project.artifactId}</name>
 
-    <dependencyManagement>
-        <dependencies>
-            <dependency>
-                <groupId>org.opendaylight.controller</groupId>
-                <artifactId>mdsal-artifacts</artifactId>
-                <version>${odl.controller.mdsal.version}</version>
-                <type>pom</type>
-                <scope>import</scope>
-            </dependency>
-        </dependencies>
-    </dependencyManagement>
     <dependencies>
         <dependency>
             <groupId>${project.groupId}</groupId>
index f50e652..93aeedf 100755 (executable)
@@ -26,7 +26,7 @@
     <parent>
         <groupId>org.onap.ccsdk.parent</groupId>
         <artifactId>odlparent-lite</artifactId>
-        <version>2.1.0</version>
+        <version>2.1.1-SNAPSHOT</version>
         <relativePath/>
     </parent>
 
@@ -62,6 +62,7 @@
             <artifactId>${application.name}-provider</artifactId>
             <version>${project.version}</version>
         </dependency>
+
     </dependencies>
 
     <build>
index cbcf704..6074f47 100755 (executable)
@@ -29,7 +29,7 @@
     <parent>
         <groupId>org.onap.ccsdk.parent</groupId>
         <artifactId>odlparent-lite</artifactId>
-        <version>2.1.0</version>
+        <version>2.1.1-SNAPSHOT</version>
         <relativePath/>
     </parent>
 
index c1df995..f6e52a8 100644 (file)
@@ -29,7 +29,7 @@
     <parent>
         <groupId>org.onap.ccsdk.parent</groupId>
         <artifactId>binding-parent</artifactId>
-        <version>2.1.0</version>
+        <version>2.1.1-SNAPSHOT</version>
         <relativePath/>
     </parent>
 
     <name>ccsdk-features :: ${project.artifactId}</name>
 
     <properties>
-        <checkstyle.skip>true</checkstyle.skip>
+        <maven.javadoc.skip>true</maven.javadoc.skip>
     </properties>
 
     <dependencies>
         <dependency>
             <groupId>javax.servlet</groupId>
-            <artifactId>servlet-api</artifactId>
+            <artifactId>javax.servlet-api</artifactId>
         </dependency>
         <dependency>
             <groupId>org.osgi</groupId>
             <artifactId>mockito-core</artifactId>
             <scope>test</scope>
         </dependency>
+        <dependency>
+            <groupId>${project.groupId}</groupId>
+            <artifactId>sdnr-wt-common</artifactId>
+            <version>${project.version}</version>
+        </dependency>
     </dependencies>
 
     <build>
index d644c63..c518cff 100644 (file)
@@ -28,6 +28,8 @@ import java.io.InputStream;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.Properties;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
 import org.json.JSONArray;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
@@ -41,12 +43,20 @@ public class MyProperties {
     private static final String DEFAULT_TRUSTINSECURE = "0";
     private static final String DEFAULT_ESDATABASE = "http://sdnrdb:9200";
     private static final String DEFAULT_AAI = "off";
-
+    private static final String DEFAULT_URL_OFF = "off";
+    private static final String DEFAULT_TILES = "${TILEURL}";
+    private static final String DEFAULT_TOPOLOGY = "${TOPOURL}";
     private static MyProperties mObj;
+    private static final String ENVVARIABLE = "${";
+    private static final String REGEXENVVARIABLE = "(\\$\\{[A-Z0-9_-]+\\})";
+    private static final Pattern ENV_PATTERN = Pattern.compile(REGEXENVVARIABLE);
+
 
     private String aaiBase;
     private Map<String, String> aaiHeaders;
     private String esBase;
+    private String tilesBase;
+    private String topologyBase;
 
     private boolean trustInsecure;
 
@@ -60,6 +70,14 @@ public class MyProperties {
         return this.esBase == null ? true : this.esBase.equals("off");
     }
 
+    public boolean isTilesOff() {
+        return this.tilesBase == null ? true : this.tilesBase.equals("off");
+    }
+
+    public boolean isTopologyOff() {
+        return this.topologyBase == null ? true : this.topologyBase.equals("off");
+    }
+
     public String getAAIBaseUrl() {
         return this.aaiBase;
     }
@@ -68,6 +86,14 @@ public class MyProperties {
         return this.esBase;
     }
 
+    public String getTilesBaseUrl() {
+        return this.tilesBase;
+    }
+
+    public String getTopologyBaseUrl() {
+        return this.topologyBase;
+    }
+
     public Map<String, String> getAAIHeaders() {
         return this.aaiHeaders;
     }
@@ -98,7 +124,7 @@ public class MyProperties {
     }
 
     private MyProperties(File file) throws IOException, NumberFormatException {
-        this.aaiBase = "off";
+        this.aaiBase = DEFAULT_AAI;
         this.trustInsecure = false;
         if (!file.exists()) {
             this.writeDefaults(file);
@@ -112,13 +138,47 @@ public class MyProperties {
         defaultProps.load(in);
         in.close();
 
-        this.aaiBase = defaultProps.getProperty("aai", DEFAULT_AAI);
-        this.aaiHeaders = _parseHeadersMap(defaultProps.getProperty("aaiHeaders", DEFAULT_AAI_HEADERS));
-        this.esBase = defaultProps.getProperty("database", DEFAULT_ESDATABASE);
-        this.trustInsecure = Integer.parseInt(defaultProps.getProperty("insecure", DEFAULT_TRUSTINSECURE)) == 1;
-        this.corsEnabled = Integer.parseInt(defaultProps.getProperty("cors", DEFAULT_CORSENABLED)) == 1;
+        this.aaiBase = getProperty(defaultProps,"aai", DEFAULT_AAI);
+        this.aaiHeaders = _parseHeadersMap(getProperty(defaultProps,"aaiHeaders", DEFAULT_AAI_HEADERS));
+        this.esBase = getProperty(defaultProps,"database", DEFAULT_ESDATABASE);
+        this.tilesBase = getProperty(defaultProps,"tiles", DEFAULT_TILES, DEFAULT_URL_OFF);
+        this.topologyBase = getProperty(defaultProps,"topology", DEFAULT_TOPOLOGY, DEFAULT_URL_OFF);
+        this.trustInsecure = Integer.parseInt(getProperty(defaultProps,"insecure", DEFAULT_TRUSTINSECURE)) == 1;
+        this.corsEnabled = Integer.parseInt(getProperty(defaultProps,"cors", DEFAULT_CORSENABLED)) == 1;
+    }
+    private static String getProperty(Properties props,final String key, final String defValue) {
+        return getProperty(props, key, defValue, null);
+    }
+    private static String getProperty(Properties props,final String key, final String defValue, final String valueIfEmpty) {
+
+        LOG.debug("try to get property for {} with def {}", key, defValue);
+        String value = props.getProperty(key,defValue);
+        //try to read env var
+        if (value != null && value.contains(ENVVARIABLE)) {
+
+            LOG.debug("try to find env var(s) for {}", value);
+            final Matcher matcher = ENV_PATTERN.matcher(value);
+            String tmp = new String(value);
+            while (matcher.find() && matcher.groupCount() > 0) {
+                final String mkey = matcher.group(1);
+                if (mkey != null) {
+                    try {
+                        LOG.debug("match found for v={} and env key={}", tmp, mkey);
+                        //String env=System.getenv(mkey.substring(2,mkey.length()-1));
+                        String env = System.getenv(mkey.substring(2, mkey.length() - 1));
+                        tmp = tmp.replace(mkey, env == null ? "" : env);
+                    } catch (SecurityException e) {
+                        LOG.warn("unable to read env {}: {}", value, e);
+                    }
+                }
+            }
+            value = tmp;
+        }
+        if((value==null || value == "") && valueIfEmpty!=null) {
+            value = valueIfEmpty;
+        }
+        return value;
     }
-
     private static Map<String, String> _parseHeadersMap(String s) {
         Map<String, String> r = new HashMap<>();
         try {
@@ -145,6 +205,8 @@ public class MyProperties {
         sb.append("aai=" + DEFAULT_AAI + LR);
         sb.append("aaiHeaders=" + DEFAULT_AAI_HEADERS + LR);
         sb.append("database=" + DEFAULT_ESDATABASE + LR);
+        sb.append("tiles=" + DEFAULT_TILES + LR);
+        sb.append("topology=" + DEFAULT_TOPOLOGY + LR);
         sb.append("insecure=" + DEFAULT_TRUSTINSECURE + LR);
         sb.append("cors=" + DEFAULT_CORSENABLED);
         try {
@@ -166,4 +228,5 @@ public class MyProperties {
         return "MyProperties [aaiBase=" + aaiBase + ", aaiHeaders=" + aaiHeaders + ", esBase=" + esBase
                 + ", trustInsecure=" + trustInsecure + ", corsEnabled=" + corsEnabled + "]";
     }
+
 }
diff --git a/sdnr/wt/apigateway/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/apigateway/TilesServlet.java b/sdnr/wt/apigateway/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/apigateway/TilesServlet.java
new file mode 100644 (file)
index 0000000..a29717a
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * ============LICENSE_START=======================================================
+ * ONAP : CCSDK.apps.sdnr.wt.apigateway
+ * ================================================================================
+ * Copyright (C) 2019 highstreet technologies GmbH Intellectual Property.
+ * All rights reserved.
+ * ================================================================================
+ * Licensed 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.
+ * ============LICENSE_END=========================================================
+ */
+package org.onap.ccsdk.features.sdnr.wt.apigateway;
+
+import java.io.IOException;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+public class TilesServlet extends BaseServlet {
+
+    private static final long serialVersionUID = 5946205120796162644L;
+    private static final String OFFLINE_RESPONSE_MESSAGE = "Tiles interface is offline";
+    private static boolean trustAll = false;
+
+    public TilesServlet() {
+        super();
+    }
+
+    @Override
+    protected void doOptions(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+        resp.setStatus(200);
+    }
+
+    @Override
+    protected String getOfflineResponse() {
+        return OFFLINE_RESPONSE_MESSAGE;
+    }
+
+    @Override
+    protected boolean isOff() {
+        return MyProperties.getInstance().isTilesOff();
+    }
+
+    @Override
+    protected String getRemoteUrl(String uri) {
+
+        if (uri.startsWith("/")) {
+            uri = uri.substring(1);
+        }
+        if (uri.startsWith("tiles")) {
+            uri = uri.substring("tiles".length());
+        }
+        if (uri.startsWith("/")) {
+            uri = uri.substring(1);
+        }
+        String base = MyProperties.getInstance().getTilesBaseUrl();
+        if (!base.endsWith("/")) {
+            base += "/";
+        }
+
+        return base + uri;
+    }
+
+    @Override
+    protected boolean doTrustAll() {
+        return trustAll;
+    }
+
+    @Override
+    protected void trustAll(boolean trust) {
+        trustAll = trust;
+    }
+}
diff --git a/sdnr/wt/apigateway/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/apigateway/TopologyServlet.java b/sdnr/wt/apigateway/provider/src/main/java/org/onap/ccsdk/features/sdnr/wt/apigateway/TopologyServlet.java
new file mode 100644 (file)
index 0000000..1a81876
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ * ============LICENSE_START=======================================================
+ * ONAP : CCSDK.apps.sdnr.wt.apigateway
+ * ================================================================================
+ * Copyright (C) 2019 highstreet technologies GmbH Intellectual Property.
+ * All rights reserved.
+ * ================================================================================
+ * Licensed 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.
+ * ============LICENSE_END=========================================================
+ */
+package org.onap.ccsdk.features.sdnr.wt.apigateway;
+
+import java.io.IOException;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+
+public class TopologyServlet extends BaseServlet {
+
+    private static final long serialVersionUID = 5946205120796162644L;
+    private static final String OFFLINE_RESPONSE_MESSAGE = "Topology interface is offline";
+    private static boolean trustAll = false;
+
+    public TopologyServlet() {
+        super();
+    }
+
+    @Override
+    protected void doOptions(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
+        resp.setStatus(200);
+    }
+
+    @Override
+    protected String getOfflineResponse() {
+        return OFFLINE_RESPONSE_MESSAGE;
+    }
+
+    @Override
+    protected boolean isOff() {
+        return MyProperties.getInstance().isTopologyOff();
+    }
+
+    @Override
+    protected String getRemoteUrl(String uri) {
+
+        if (uri.startsWith("/")) {
+            uri = uri.substring(1);
+        }
+        if (uri.startsWith("topology")) {
+            uri = uri.substring("topology".length());
+        }
+        if (uri.startsWith("/")) {
+            uri = uri.substring(1);
+        }
+        String base = MyProperties.getInstance().getTopologyBaseUrl();
+        if (!base.endsWith("/")) {
+            base += "/";
+        }
+
+        return base + uri;
+    }
+
+    @Override
+    protected boolean doTrustAll() {
+        return trustAll;
+    }
+
+    @Override
+    protected void trustAll(boolean trust) {
+        trustAll = trust;
+    }
+}
index 256a9cf..cd325e4 100644 (file)
         </service-properties>
     </service>
 
+    <bean id="tilesServlet"
+          class="org.onap.ccsdk.features.sdnr.wt.apigateway.TilesServlet">
+    </bean>
+
+    <service interface="javax.servlet.http.HttpServlet" ref="tilesServlet">
+        <service-properties>
+            <entry key="alias" value="/tiles"/>
+        </service-properties>
+    </service>
+
+    <bean id="topologyServlet"
+          class="org.onap.ccsdk.features.sdnr.wt.apigateway.TopologyServlet">
+    </bean>
+
+    <service interface="javax.servlet.http.HttpServlet" ref="topologyServlet">
+        <service-properties>
+            <entry key="alias" value="/topology"/>
+        </service-properties>
+    </service>
+
 </blueprint>
index b12281e..4048012 100644 (file)
@@ -26,28 +26,23 @@ import static org.junit.Assert.fail;
 import static org.mockito.Mockito.mock;
 import static org.mockito.Mockito.verify;
 import static org.mockito.Mockito.when;
-
-import java.io.ByteArrayInputStream;
+import com.sun.net.httpserver.HttpExchange;
+import com.sun.net.httpserver.HttpHandler;
+import com.sun.net.httpserver.HttpServer;
 import java.io.IOException;
 import java.io.OutputStream;
-import java.io.StringWriter;
 import java.net.InetSocketAddress;
 import java.util.Enumeration;
 import java.util.Map;
 import java.util.Vector;
 import java.util.concurrent.ExecutorService;
 import java.util.concurrent.Executors;
-
-import javax.servlet.ServletInputStream;
-import javax.servlet.ServletOutputStream;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
-
 import org.junit.After;
 import org.junit.Before;
-import com.sun.net.httpserver.HttpExchange;
-import com.sun.net.httpserver.HttpHandler;
-import com.sun.net.httpserver.HttpServer;
+import org.onap.ccsdk.features.sdnr.wt.common.test.ServletInputStreamFromByteArrayInputStream;
+import org.onap.ccsdk.features.sdnr.wt.common.test.ServletOutputStreamToStringWriter;
 
 @SuppressWarnings("restriction")
 public class HelpServletBase {
@@ -89,21 +84,8 @@ public class HelpServletBase {
         HttpServletRequest mockRequest = mock(HttpServletRequest.class);
         HttpServletResponse mockResponse = mock(HttpServletResponse.class);
 
-        StringWriter out = new StringWriter();
-        ServletOutputStream printOut = new ServletOutputStream() {
-
-            @Override
-            public void write(int arg0) throws IOException {
-                out.write(arg0);
-            }
-        };
-        ByteArrayInputStream bis = new ByteArrayInputStream(data.getBytes());
-        ServletInputStream inputStream = new ServletInputStream() {
-            @Override
-            public int read() throws IOException {
-                return bis.read();
-            }
-        };
+        ServletOutputStreamToStringWriter printOut = new ServletOutputStreamToStringWriter();
+        ServletInputStreamFromByteArrayInputStream inputStream = new ServletInputStreamFromByteArrayInputStream(data.getBytes());
         Vector<String> headers = new Vector<String>();
         headers.addElement("Accept");
         headers.add("User-Agent");
@@ -134,9 +116,9 @@ public class HelpServletBase {
 
         verify(mockResponse).setStatus(200);
         if (exact)
-            assertEquals(expectedResponse, out.toString());
+            assertEquals(expectedResponse, printOut.getStringWriter().toString());
         else
-            assertTrue("response not for method " + method + "correct", out.toString().contains(expectedResponse));
+            assertTrue("response not for method " + method + "correct", printOut.getStringWriter().toString().contains(expectedResponse));
         // currently unable to check extra headers
         if (headersToCheck != null) {
 
index b5e7daf..08f0c63 100644 (file)
@@ -29,7 +29,7 @@
     <parent>
         <groupId>org.onap.ccsdk.parent</groupId>
         <artifactId>single-feature-parent</artifactId>
-        <version>2.1.0</version>
+        <version>2.1.1-SNAPSHOT</version>
         <relativePath/>
     </parent>
 
     <name>ccsdk-features :: ${project.artifactId}</name>
 
     <dependencies>
+
         <dependency>
             <groupId>${project.groupId}</groupId>
             <artifactId>sdnr-wt-helpserver-provider</artifactId>
             <version>${project.version}</version>
         </dependency>
+
     </dependencies>
 </project>
index 802079c..654d740 100755 (executable)
@@ -29,7 +29,7 @@
     <parent>
         <groupId>org.onap.ccsdk.parent</groupId>
         <artifactId>odlparent-lite</artifactId>
-        <version>2.1.0</version>
+        <version>2.1.1-SNAPSHOT</version>
         <relativePath/>
     </parent>
 
index 3c5d471..0fa2c3f 100755 (executable)
@@ -29,7 +29,7 @@
     <parent>
         <groupId>org.onap.ccsdk.parent</groupId>
         <artifactId>odlparent-lite</artifactId>
-        <version>2.1.0</version>
+        <version>2.1.1-SNAPSHOT</version>
         <relativePath/>
     </parent>
 
index 5db0853..6cf2d03 100644 (file)
@@ -29,7 +29,7 @@
     <parent>
         <groupId>org.onap.ccsdk.parent</groupId>
         <artifactId>binding-parent</artifactId>
-        <version>2.1.0</version>
+        <version>2.1.1-SNAPSHOT</version>
         <relativePath/>
     </parent>
 
 
     <properties>
         <maven.javadoc.skip>true</maven.javadoc.skip>
-        <checkstyle.skip>true</checkstyle.skip>
     </properties>
 
     <dependencies>
+        <dependency>
+            <groupId>org.onap.ccsdk.features.sdnr.wt</groupId>
+            <artifactId>sdnr-wt-common</artifactId>
+            <version>${project.version}</version>
+        </dependency>
         <dependency>
             <groupId>javax.servlet</groupId>
-            <artifactId>servlet-api</artifactId>
+            <artifactId>javax.servlet-api</artifactId>
         </dependency>
         <dependency>
             <groupId>org.slf4j</groupId>
index cd40e12..c650023 100644 (file)
@@ -25,17 +25,16 @@ import static org.junit.Assert.assertEquals;
 import static org.junit.Assert.fail;
 import java.io.File;
 import java.io.IOException;
-import java.io.StringWriter;
 import java.nio.file.Files;
 import java.nio.file.OpenOption;
 import javax.servlet.ServletException;
-import javax.servlet.ServletOutputStream;
 import javax.servlet.http.HttpServletRequest;
 import javax.servlet.http.HttpServletResponse;
 import org.junit.After;
 import org.junit.Before;
 import org.junit.Test;
 import org.mockito.Mockito;
+import org.onap.ccsdk.features.sdnr.wt.common.test.ServletOutputStreamToStringWriter;
 import org.onap.ccsdk.features.sdnr.wt.helpserver.HelpServlet;
 import org.onap.ccsdk.features.sdnr.wt.helpserver.data.ExtactBundleResource;
 import org.onap.ccsdk.features.sdnr.wt.helpserver.data.HelpInfrastructureObject;
@@ -87,14 +86,7 @@ public class TestMyServlet extends Mockito {
         when(request.getRequestURI()).thenReturn("help/");
         when(request.getQueryString()).thenReturn("?meta");
 
-        StringWriter stringWriter = new StringWriter();
-        ServletOutputStream out = new ServletOutputStream() {
-
-            @Override
-            public void write(int arg0) throws IOException {
-                stringWriter.write(arg0);
-            }
-        };
+        ServletOutputStreamToStringWriter out = new ServletOutputStreamToStringWriter();
         when(response.getOutputStream()).thenReturn(out);
 
         HelpServlet helpServlet = null;
@@ -114,7 +106,7 @@ public class TestMyServlet extends Mockito {
             helpServlet.close();
         }
 
-        String result = stringWriter.toString().trim();
+        String result = out.getStringWriter().toString().trim();
         System.out.println("Result: '" + result + "'");
         assertEquals(CONTENT, result);
     }
@@ -134,14 +126,7 @@ public class TestMyServlet extends Mockito {
         HttpServletResponse response = mock(HttpServletResponse.class);
 
         when(request.getRequestURI()).thenReturn("help/" + fn);
-        StringWriter sw = new StringWriter();
-        ServletOutputStream out = new ServletOutputStream() {
-
-            @Override
-            public void write(int arg0) throws IOException {
-                sw.write(arg0);
-            }
-        };
+        ServletOutputStreamToStringWriter out = new ServletOutputStreamToStringWriter();
         try {
             when(response.getOutputStream()).thenReturn(out);
             helpServlet.doGet(request, response);
@@ -157,6 +142,6 @@ public class TestMyServlet extends Mockito {
         } catch (Exception e) {
         }
 
-        assertEquals("compare content for " + fn, CONTENT, sw.toString().trim());
+        assertEquals("compare content for " + fn, CONTENT, out.getStringWriter().toString().trim());
     }
 }