FELIX-3958 Wrap plain text response in pseudo JSON
Make sure JSON response is generated even though a printer
may only support plain text
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@1455133 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/inventory/src/main/java/org/apache/felix/inventory/impl/AbstractWebConsolePlugin.java b/inventory/src/main/java/org/apache/felix/inventory/impl/AbstractWebConsolePlugin.java
index 2cb6db5..4ade7f3 100644
--- a/inventory/src/main/java/org/apache/felix/inventory/impl/AbstractWebConsolePlugin.java
+++ b/inventory/src/main/java/org/apache/felix/inventory/impl/AbstractWebConsolePlugin.java
@@ -5,9 +5,9 @@
* 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.
@@ -21,6 +21,7 @@
import java.io.PrintWriter;
import java.io.Writer;
import java.util.Date;
+import java.util.StringTokenizer;
import java.util.zip.Deflater;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;
@@ -45,7 +46,7 @@
/**
* Constructor
- *
+ *
* @param inventoryPrinterManager The manager
*/
AbstractWebConsolePlugin(final InventoryPrinterManagerImpl inventoryPrinterManager)
@@ -82,7 +83,7 @@
* <p>
* This method sets the <code>Cache-Control</code>, <code>Expires</code>,
* and <code>Pragma</code> headers.
- *
+ *
* @param response The response for which to set the cache prevention
*/
private final void setNoCache(final HttpServletResponse response)
@@ -203,7 +204,16 @@
response.setCharacterEncoding("UTF-8"); //$NON-NLS-1$
final JSONConfigurationWriter jcw = new JSONConfigurationWriter(response.getWriter());
- printConfigurationInventory(jcw, PrinterMode.JSON, handler);
+ final PrinterMode mode;
+ if (handler.supports(PrinterMode.JSON)) {
+ mode = PrinterMode.JSON;
+ } else {
+ mode = PrinterMode.TEXT;
+ jcw.startJSONWrapper();
+ }
+ printConfigurationInventory(jcw, mode, handler);
+ jcw.endJSONWrapper();
+ jcw.flush();
}
else
{
@@ -308,9 +318,157 @@
private static class JSONConfigurationWriter extends ConfigurationWriter
{
+ private boolean wrapJSON;
+
+ private boolean startLine;
+
+ private boolean needComma;
+
JSONConfigurationWriter(final Writer delegatee)
{
super(delegatee);
+ this.wrapJSON = false;
+ }
+
+ public void startJSONWrapper()
+ {
+ println("{");
+ println(" \"value\": [");
+
+ this.wrapJSON = true;
+ this.startLine = true;
+ this.needComma = false;
+ }
+
+ public void endJSONWrapper()
+ {
+ if (this.wrapJSON)
+ {
+ // properly terminate the current line
+ this.println();
+
+ this.wrapJSON = false;
+ this.startLine = false;
+
+ super.println();
+ super.println(" ]");
+ super.println("}");
+ }
+ }
+
+ // IE has an issue with white-space:pre in our case so, we write
+ // <br/> instead of [CR]LF to get the line break. This also works
+ // in other browsers.
+ public void println()
+ {
+ if (wrapJSON)
+ {
+ if (!this.startLine)
+ {
+ super.write('"');
+ this.startLine = true;
+ this.needComma = true;
+ }
+ }
+ else
+ {
+ super.println();
+ }
+ }
+
+ // some VM implementation directly write in underlying stream, instead
+ // of
+ // delegation to the write() method. So we need to override this, to
+ // make
+ // sure, that everything is escaped correctly
+ public void print(final String str)
+ {
+ final char[] chars = str.toCharArray();
+ write(chars, 0, chars.length);
+ }
+
+ private final char[] oneChar = new char[1];
+
+ // always delegate to write(char[], int, int) otherwise in some VM
+ // it cause endless cycle and StackOverflowError
+ public void write(final int character)
+ {
+ synchronized (oneChar)
+ {
+ oneChar[0] = (char) character;
+ write(oneChar, 0, 1);
+ }
+ }
+
+ // write the characters unmodified unless filtering is enabled in
+ // which case the writeFiltered(String) method is called for filtering
+ public void write(char[] chars, int off, int len)
+ {
+ if (this.wrapJSON)
+ {
+ if (this.startLine)
+ {
+ this.startLine();
+ this.startLine = false;
+ }
+
+ String v = new String(chars, off, len);
+ StringTokenizer st = new StringTokenizer(v, "\r\n\"", true);
+ while (st.hasMoreTokens())
+ {
+ String t = st.nextToken();
+ if (t.length() == 1)
+ {
+ char c = t.charAt(0);
+ if (c == '\r')
+ {
+ // ignore
+ }
+ else if (c == '\n')
+ {
+ this.println();
+ this.startLine();
+ }
+ else if (c == '"')
+ {
+ super.write('\\');
+ super.write(c);
+ }
+ else
+ {
+ super.write(c);
+ }
+ }
+ else
+ {
+ super.write(t.toCharArray(), 0, t.length());
+ }
+ }
+ }
+ else
+ {
+ super.write(chars, off, len);
+ }
+ }
+
+ // write the string unmodified unless filtering is enabled in
+ // which case the writeFiltered(String) method is called for filtering
+ public void write(final String string, final int off, final int len)
+ {
+ write(string.toCharArray(), off, len);
+ }
+
+ private void startLine()
+ {
+ if (this.needComma)
+ {
+ super.write(',');
+ super.println();
+ this.needComma = false;
+ }
+
+ super.write(" \"".toCharArray(), 0, 5);
+ this.startLine = false;
}
}
@@ -394,8 +552,8 @@
/**
* Escapes HTML special chars like: <>&\r\n and space
- *
- *
+ *
+ *
* @param text the text to escape
* @return the escaped text
*/