You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@felix.apache.org by fm...@apache.org on 2013/05/27 14:34:47 UTC
svn commit: r1486594 - in
/felix/trunk/inventory/src/main/java/org/apache/felix/inventory/impl: ./
helper/
Author: fmeschbe
Date: Mon May 27 12:34:46 2013
New Revision: 1486594
URL: http://svn.apache.org/r1486594
Log:
FELIX-4075 Fix Configuration ZIP writing
- Consolidate ConfigurationWriter classes into a new
helpers package (out of the AbstractWebConsolePlugin)
- Create a dead-simple SimpleJson helper class to
generate the configuration ZIP index.json file
- Create an index.json file providing the timestamp
and the files provided by the plugins
- Use "<pre>" formatting for plain text and JSON
output in the HTML (Browser) context
Added:
felix/trunk/inventory/src/main/java/org/apache/felix/inventory/impl/helper/
felix/trunk/inventory/src/main/java/org/apache/felix/inventory/impl/helper/ConfigurationWriter.java
felix/trunk/inventory/src/main/java/org/apache/felix/inventory/impl/helper/HtmlConfigurationWriter.java
felix/trunk/inventory/src/main/java/org/apache/felix/inventory/impl/helper/JSONConfigurationWriter.java
felix/trunk/inventory/src/main/java/org/apache/felix/inventory/impl/helper/PlainTextConfigurationWriter.java
felix/trunk/inventory/src/main/java/org/apache/felix/inventory/impl/helper/SimpleJson.java
felix/trunk/inventory/src/main/java/org/apache/felix/inventory/impl/helper/ZipConfigurationWriter.java
Modified:
felix/trunk/inventory/src/main/java/org/apache/felix/inventory/impl/AbstractWebConsolePlugin.java
felix/trunk/inventory/src/main/java/org/apache/felix/inventory/impl/DefaultWebConsolePlugin.java
felix/trunk/inventory/src/main/java/org/apache/felix/inventory/impl/InventoryPrinterAdapter.java
felix/trunk/inventory/src/main/java/org/apache/felix/inventory/impl/InventoryPrinterManagerImpl.java
Modified: felix/trunk/inventory/src/main/java/org/apache/felix/inventory/impl/AbstractWebConsolePlugin.java
URL: http://svn.apache.org/viewvc/felix/trunk/inventory/src/main/java/org/apache/felix/inventory/impl/AbstractWebConsolePlugin.java?rev=1486594&r1=1486593&r2=1486594&view=diff
==============================================================================
--- felix/trunk/inventory/src/main/java/org/apache/felix/inventory/impl/AbstractWebConsolePlugin.java (original)
+++ felix/trunk/inventory/src/main/java/org/apache/felix/inventory/impl/AbstractWebConsolePlugin.java Mon May 27 12:34:46 2013
@@ -17,21 +17,20 @@
package org.apache.felix.inventory.impl;
import java.io.IOException;
-import java.io.OutputStreamWriter;
-import java.io.PrintWriter;
-import java.io.Writer;
+import java.text.DateFormat;
import java.util.Date;
-import java.util.StringTokenizer;
-import java.util.zip.Deflater;
-import java.util.zip.ZipEntry;
-import java.util.zip.ZipOutputStream;
+import java.util.Locale;
-import javax.servlet.ServletException;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.felix.inventory.Format;
+import org.apache.felix.inventory.impl.helper.ConfigurationWriter;
+import org.apache.felix.inventory.impl.helper.HtmlConfigurationWriter;
+import org.apache.felix.inventory.impl.helper.JSONConfigurationWriter;
+import org.apache.felix.inventory.impl.helper.PlainTextConfigurationWriter;
+import org.apache.felix.inventory.impl.helper.ZipConfigurationWriter;
/**
* The web console plugin for a inventory printer.
@@ -69,7 +68,7 @@ public abstract class AbstractWebConsole
}
else
{
- if (handler.supports(format))
+ if (format == null || handler.supports(format))
{
pw.printInventory(format, handler);
}
@@ -101,8 +100,7 @@ public abstract class AbstractWebConsole
return null; // all by default
}
- protected void doGet(final HttpServletRequest request, final HttpServletResponse response) throws ServletException,
- IOException
+ protected void doGet(final HttpServletRequest request, final HttpServletResponse response) throws IOException
{
this.setNoCache(response);
@@ -140,33 +138,9 @@ public abstract class AbstractWebConsole
}
response.setContentType(type);
- final ZipOutputStream zip = new ZipOutputStream(response.getOutputStream());
- zip.setLevel(Deflater.BEST_SPEED);
- zip.setMethod(ZipOutputStream.DEFLATED);
-
- final Date now = new Date();
- // create time stamp entry
- final ZipEntry entry = new ZipEntry("timestamp.txt"); //$NON-NLS-2$
- entry.setTime(now.getTime());
- zip.putNextEntry(entry);
- final StringBuffer sb = new StringBuffer();
- sb.append("Date: ");
- synchronized (InventoryPrinterAdapter.DISPLAY_DATE_FORMAT)
- {
- sb.append(InventoryPrinterAdapter.DISPLAY_DATE_FORMAT.format(now));
- }
- sb.append(" (");
- sb.append(String.valueOf(now.getTime()));
- sb.append(")\n");
-
- zip.write(sb.toString().getBytes("UTF-8"));
- zip.closeEntry();
-
- final ZipConfigurationWriter pw = new ZipConfigurationWriter(zip);
- printConfigurationInventory(pw, Format.TEXT, handler);
- printConfigurationInventory(pw, Format.JSON, handler);
-
- zip.finish();
+ final ZipConfigurationWriter pw = ZipConfigurationWriter.create(response.getOutputStream());
+ printConfigurationInventory(pw, null, handler);
+ pw.finish();
}
else if (request.getPathInfo().endsWith(".nfo"))
{
@@ -259,12 +233,8 @@ public abstract class AbstractWebConsole
pw.println("</script>");
pw.println("<br/><p class=\"statline\">");
- final Date currentTime = new Date();
- synchronized (InventoryPrinterAdapter.DISPLAY_DATE_FORMAT)
- {
- pw.print("Date: ");
- pw.println(InventoryPrinterAdapter.DISPLAY_DATE_FORMAT.format(currentTime));
- }
+ pw.print("Date: ");
+ pw.println(DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, Locale.US).format(new Date()));
pw.print("<button type=\"button\" class=\"downloadFullZip\" style=\"float: right; margin-right: 30px; margin-top: 5px;\">Download Full Zip</button>");
pw.print("<button type=\"button\" class=\"downloadFullTxt\" style=\"float: right; margin-right: 30px; margin-top: 5px;\">Download Full Text</button>");
@@ -281,398 +251,38 @@ public abstract class AbstractWebConsole
pw.println("<br/> </p>"); // status line
pw.print("<div>");
- if (handler.supports(Format.HTML))
- {
- handler.print(pw, Format.HTML, false);
- }
- else
- {
- pw.enableFilter(true);
- handler.print(pw, Format.TEXT, false);
- pw.enableFilter(false);
- }
- pw.print("</div>");
- }
- }
- /**
- * Base class for all configuration writers.
- */
- private abstract static class ConfigurationWriter extends PrintWriter
- {
-
- ConfigurationWriter(final Writer delegatee)
- {
- super(delegatee);
- }
-
- protected void title(final String title) throws IOException
- {
- // dummy implementation
- }
-
- protected void end() throws IOException
- {
- // dummy implementation
- }
-
- public void printInventory(final Format format, final InventoryPrinterHandler handler) throws IOException
- {
- this.title(handler.getTitle());
- handler.print(this, format, false);
- this.end();
- }
- }
-
- /**
- * The JSON configuration writer
- */
- 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
+ final boolean filter;
+ final Format format;
+ if (handler.supports(Format.HTML))
{
- super.write(chars, off, len);
+ filter = false;
+ format = Format.HTML;
}
- }
-
- // 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)
+ else if (handler.supports(Format.TEXT))
{
- super.write(',');
- super.println();
- this.needComma = false;
+ // prefer TEXT of JSON if available
+ filter = true;
+ format = Format.TEXT;
}
-
- super.write(" \"".toCharArray(), 0, 5);
- this.startLine = false;
- }
- }
-
- /**
- * The HTML configuration writer outputs the status as an HTML snippet.
- */
- private static class HtmlConfigurationWriter extends ConfigurationWriter
- {
-
- // whether or not to filter "<" signs in the output
- private boolean doFilter;
-
- HtmlConfigurationWriter(final Writer delegatee)
- {
- super(delegatee);
- }
-
- void enableFilter(final boolean doFilter)
- {
- this.doFilter = doFilter;
- }
-
- // 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 (doFilter)
+ else if (handler.supports(Format.JSON))
{
- this.write('\n'); // write <br/>
+ filter = true;
+ format = Format.JSON;
}
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 (doFilter)
- {
- chars = this.escapeHtml(new String(chars, off, len)).toCharArray();
- off = 0;
- len = chars.length;
- }
- 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);
- }
-
- /**
- * Escapes HTML special chars like: <>&\r\n and space
- *
- *
- * @param text the text to escape
- * @return the escaped text
- */
- private String escapeHtml(final String text)
- {
- final StringBuffer sb = new StringBuffer(text.length() * 4 / 3);
- char ch, oldch = '_';
- for (int i = 0; i < text.length(); i++)
- {
- switch (ch = text.charAt(i))
- {
- case '<':
- sb.append("<"); //$NON-NLS-1$
- break;
- case '>':
- sb.append(">"); //$NON-NLS-1$
- break;
- case '&':
- sb.append("&"); //$NON-NLS-1$
- break;
- case ' ':
- sb.append(" "); //$NON-NLS-1$
- break;
- case '\r':
- case '\n':
- if (oldch != '\r' && oldch != '\n') // don't add twice
- // <br>
- sb.append("<br/>\n"); //$NON-NLS-1$
- break;
- default:
- sb.append(ch);
- }
- oldch = ch;
+ // fallback to TEXT (if unknown format)
+ filter = true;
+ format = Format.TEXT;
}
- return sb.toString();
- }
- }
-
- /**
- * The plain text configuration writer outputs the status as plain text.
- */
- private static class PlainTextConfigurationWriter extends ConfigurationWriter
- {
-
- PlainTextConfigurationWriter(final Writer delegatee)
- {
- super(delegatee);
- }
-
- protected void title(final String title) throws IOException
- {
- print("*** ");
- print(title);
- println(":");
- }
+ pw.enableFilter(filter);
+ handler.print(pw, format, false);
+ pw.enableFilter(false);
- protected void end() throws IOException
- {
- println();
+ pw.print("</div>");
}
}
- /**
- * The ZIP configuration writer creates a zip with
- * - txt output of a inventory printers (if supported)
- * - json output of a inventory printers (if supported)
- * - attachments from a inventory printer (if supported)
- */
- private static class ZipConfigurationWriter extends ConfigurationWriter
- {
-
- private final ZipOutputStream zip;
-
- ZipConfigurationWriter(final ZipOutputStream zip)
- {
- super(new OutputStreamWriter(zip));
- this.zip = zip;
- }
-
- public void printInventory(final Format format, final InventoryPrinterHandler handler) throws IOException
- {
- if (format == Format.TEXT)
- {
- final ZipEntry entry = new ZipEntry(handler.getName().concat(".txt"));
- zip.putNextEntry(entry);
- handler.print(this, format, false);
- flush();
- zip.closeEntry();
-
- handler.addAttachments(this.zip, handler.getName().concat("/"));
- }
- else if (format == Format.JSON)
- {
- final String name = "json/".concat(handler.getName()).concat(".json");
-
- final ZipEntry entry = new ZipEntry(name);
- zip.putNextEntry(entry);
- handler.print(this, Format.JSON, true);
- flush();
-
- zip.closeEntry();
- if (!handler.supports(Format.TEXT))
- {
- handler.addAttachments(this.zip, handler.getName().concat("/"));
- }
- }
- }
- }
}
\ No newline at end of file
Modified: felix/trunk/inventory/src/main/java/org/apache/felix/inventory/impl/DefaultWebConsolePlugin.java
URL: http://svn.apache.org/viewvc/felix/trunk/inventory/src/main/java/org/apache/felix/inventory/impl/DefaultWebConsolePlugin.java?rev=1486594&r1=1486593&r2=1486594&view=diff
==============================================================================
--- felix/trunk/inventory/src/main/java/org/apache/felix/inventory/impl/DefaultWebConsolePlugin.java (original)
+++ felix/trunk/inventory/src/main/java/org/apache/felix/inventory/impl/DefaultWebConsolePlugin.java Mon May 27 12:34:46 2013
@@ -90,7 +90,7 @@ public class DefaultWebConsolePlugin ext
*/
public void print(final PrintWriter printWriter, final Format format, final boolean isZip)
{
- final InventoryPrinterHandler[] handlers = this.inventoryPrinterManager.getAllHandlers();
+ final InventoryPrinterHandler[] handlers = this.inventoryPrinterManager.getHandlers(null);
printWriter.print("Currently registered ");
printWriter.print(String.valueOf(handlers.length));
printWriter.println(" printer(s).");
Modified: felix/trunk/inventory/src/main/java/org/apache/felix/inventory/impl/InventoryPrinterAdapter.java
URL: http://svn.apache.org/viewvc/felix/trunk/inventory/src/main/java/org/apache/felix/inventory/impl/InventoryPrinterAdapter.java?rev=1486594&r1=1486593&r2=1486594&view=diff
==============================================================================
--- felix/trunk/inventory/src/main/java/org/apache/felix/inventory/impl/InventoryPrinterAdapter.java (original)
+++ felix/trunk/inventory/src/main/java/org/apache/felix/inventory/impl/InventoryPrinterAdapter.java Mon May 27 12:34:46 2013
@@ -18,9 +18,7 @@ package org.apache.felix.inventory.impl;
import java.io.IOException;
import java.io.PrintWriter;
-import java.text.DateFormat;
import java.util.Comparator;
-import java.util.Locale;
import java.util.zip.ZipOutputStream;
import org.apache.felix.inventory.InventoryPrinter;
@@ -38,12 +36,6 @@ public class InventoryPrinterAdapter imp
{
/**
- * Formatter pattern to render the current time of inventory generation.
- */
- static final DateFormat DISPLAY_DATE_FORMAT = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG,
- Locale.US);
-
- /**
* Comparator for adapters based on the service ranking.
*/
public static final Comparator RANKING_COMPARATOR = new Comparator()
Modified: felix/trunk/inventory/src/main/java/org/apache/felix/inventory/impl/InventoryPrinterManagerImpl.java
URL: http://svn.apache.org/viewvc/felix/trunk/inventory/src/main/java/org/apache/felix/inventory/impl/InventoryPrinterManagerImpl.java?rev=1486594&r1=1486593&r2=1486594&view=diff
==============================================================================
--- felix/trunk/inventory/src/main/java/org/apache/felix/inventory/impl/InventoryPrinterManagerImpl.java (original)
+++ felix/trunk/inventory/src/main/java/org/apache/felix/inventory/impl/InventoryPrinterManagerImpl.java Mon May 27 12:34:46 2013
@@ -262,21 +262,13 @@ public class InventoryPrinterManagerImpl
}
/**
- * Get all inventory printer handlers.
+ * Get all handlers supporting the format or all handlers if {@code format}
+ * is {@code null}.
*
- * @return A list of handlers - might be empty.
- */
- public InventoryPrinterHandler[] getAllHandlers()
- {
- synchronized (this.usedAdapters)
- {
- return (InventoryPrinterHandler[]) this.usedAdapters.toArray(new InventoryPrinterHandler[this.usedAdapters
- .size()]);
- }
- }
-
- /**
- * Get all handlers supporting the format.
+ * @param format The {@link Format} the returned handlers are expected to
+ * support. If this parameter is {@code null} all handlers are
+ * returned regardless of {@link Format} supported by the
+ * handlers.
*
* @return A list of handlers - might be empty.
*/
@@ -289,7 +281,7 @@ public class InventoryPrinterManagerImpl
while (i.hasNext())
{
final InventoryPrinterAdapter printer = (InventoryPrinterAdapter) i.next();
- if (printer.supports(format))
+ if (format == null || printer.supports(format))
{
result.add(printer);
}
Added: felix/trunk/inventory/src/main/java/org/apache/felix/inventory/impl/helper/ConfigurationWriter.java
URL: http://svn.apache.org/viewvc/felix/trunk/inventory/src/main/java/org/apache/felix/inventory/impl/helper/ConfigurationWriter.java?rev=1486594&view=auto
==============================================================================
--- felix/trunk/inventory/src/main/java/org/apache/felix/inventory/impl/helper/ConfigurationWriter.java (added)
+++ felix/trunk/inventory/src/main/java/org/apache/felix/inventory/impl/helper/ConfigurationWriter.java Mon May 27 12:34:46 2013
@@ -0,0 +1,55 @@
+/*
+ * 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.felix.inventory.impl.helper;
+
+import java.io.IOException;
+import java.io.PrintWriter;
+import java.io.Writer;
+
+import org.apache.felix.inventory.Format;
+import org.apache.felix.inventory.impl.InventoryPrinterHandler;
+
+/**
+ * Base class for all configuration writers.
+ */
+public abstract class ConfigurationWriter extends PrintWriter
+{
+
+ ConfigurationWriter(final Writer delegatee)
+ {
+ super(delegatee);
+ }
+
+ protected void title(final String title) throws IOException
+ {
+ // dummy implementation
+ }
+
+ protected void end() throws IOException
+ {
+ // dummy implementation
+ }
+
+ public void printInventory(final Format format, final InventoryPrinterHandler handler) throws IOException
+ {
+ this.title(handler.getTitle());
+ handler.print(this, format, false);
+ this.end();
+ }
+}
\ No newline at end of file
Added: felix/trunk/inventory/src/main/java/org/apache/felix/inventory/impl/helper/HtmlConfigurationWriter.java
URL: http://svn.apache.org/viewvc/felix/trunk/inventory/src/main/java/org/apache/felix/inventory/impl/helper/HtmlConfigurationWriter.java?rev=1486594&view=auto
==============================================================================
--- felix/trunk/inventory/src/main/java/org/apache/felix/inventory/impl/helper/HtmlConfigurationWriter.java (added)
+++ felix/trunk/inventory/src/main/java/org/apache/felix/inventory/impl/helper/HtmlConfigurationWriter.java Mon May 27 12:34:46 2013
@@ -0,0 +1,150 @@
+/*
+ * 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.felix.inventory.impl.helper;
+
+import java.io.Writer;
+
+
+/**
+ * The HTML configuration writer outputs the status as an HTML snippet.
+ */
+public class HtmlConfigurationWriter extends ConfigurationWriter
+{
+
+ // whether or not to filter "<" signs in the output
+ private boolean doFilter;
+
+ public HtmlConfigurationWriter(final Writer delegatee)
+ {
+ super(delegatee);
+ }
+
+ public void enableFilter(final boolean doFilter)
+ {
+ this.doFilter = doFilter;
+ if (doFilter) {
+ // start filtering
+ super.write("<pre>", 0, 5);
+ } else {
+ // end filtering
+ super.write("</pre>", 0, 6);
+ }
+ 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 (doFilter)
+ {
+ this.write('\n'); // write <br/>
+ }
+ 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 (doFilter)
+ {
+ chars = this.escapeHtml(new String(chars, off, len)).toCharArray();
+ off = 0;
+ len = chars.length;
+ }
+ 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);
+ }
+
+ /**
+ * Escapes HTML special chars like: <>&\r\n and space
+ *
+ *
+ * @param text the text to escape
+ * @return the escaped text
+ */
+ private String escapeHtml(final String text)
+ {
+ final StringBuffer sb = new StringBuffer(text.length() * 4 / 3);
+ char ch, oldch = '_';
+ for (int i = 0; i < text.length(); i++)
+ {
+ switch (ch = text.charAt(i))
+ {
+ case '<':
+ sb.append("<"); //$NON-NLS-1$
+ break;
+ case '>':
+ sb.append(">"); //$NON-NLS-1$
+ break;
+ case '&':
+ sb.append("&"); //$NON-NLS-1$
+ break;
+ case ' ':
+ sb.append(" "); //$NON-NLS-1$
+ break;
+ case '\r':
+ case '\n':
+ if (oldch != '\r' && oldch != '\n')
+ sb.append("\n"); //$NON-NLS-1$
+ break;
+ default:
+ sb.append(ch);
+ }
+ oldch = ch;
+ }
+
+ return sb.toString();
+ }
+}
\ No newline at end of file
Added: felix/trunk/inventory/src/main/java/org/apache/felix/inventory/impl/helper/JSONConfigurationWriter.java
URL: http://svn.apache.org/viewvc/felix/trunk/inventory/src/main/java/org/apache/felix/inventory/impl/helper/JSONConfigurationWriter.java?rev=1486594&view=auto
==============================================================================
--- felix/trunk/inventory/src/main/java/org/apache/felix/inventory/impl/helper/JSONConfigurationWriter.java (added)
+++ felix/trunk/inventory/src/main/java/org/apache/felix/inventory/impl/helper/JSONConfigurationWriter.java Mon May 27 12:34:46 2013
@@ -0,0 +1,185 @@
+/*
+ * 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.felix.inventory.impl.helper;
+
+import java.io.Writer;
+import java.util.StringTokenizer;
+
+
+/**
+ * The JSON configuration writer
+ */
+public class JSONConfigurationWriter extends ConfigurationWriter
+{
+
+ private boolean wrapJSON;
+
+ private boolean startLine;
+
+ private boolean needComma;
+
+ public JSONConfigurationWriter(final Writer delegatee)
+ {
+ super(delegatee);
+ this.wrapJSON = false;
+ }
+
+ public void startJSONWrapper()
+ {
+// println("{");
+// println(" \"value\": [");
+ println("[");
+
+ 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("}");
+ 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;
+ }
+}
\ No newline at end of file
Added: felix/trunk/inventory/src/main/java/org/apache/felix/inventory/impl/helper/PlainTextConfigurationWriter.java
URL: http://svn.apache.org/viewvc/felix/trunk/inventory/src/main/java/org/apache/felix/inventory/impl/helper/PlainTextConfigurationWriter.java?rev=1486594&view=auto
==============================================================================
--- felix/trunk/inventory/src/main/java/org/apache/felix/inventory/impl/helper/PlainTextConfigurationWriter.java (added)
+++ felix/trunk/inventory/src/main/java/org/apache/felix/inventory/impl/helper/PlainTextConfigurationWriter.java Mon May 27 12:34:46 2013
@@ -0,0 +1,46 @@
+/*
+ * 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.felix.inventory.impl.helper;
+
+import java.io.Writer;
+
+
+/**
+ * The plain text configuration writer outputs the status as plain text.
+ */
+public class PlainTextConfigurationWriter extends ConfigurationWriter
+{
+
+ public PlainTextConfigurationWriter(final Writer delegatee)
+ {
+ super(delegatee);
+ }
+
+ protected void title(final String title)
+ {
+ print("*** ");
+ print(title);
+ println(":");
+ }
+
+ protected void end()
+ {
+ println();
+ }
+}
\ No newline at end of file
Added: felix/trunk/inventory/src/main/java/org/apache/felix/inventory/impl/helper/SimpleJson.java
URL: http://svn.apache.org/viewvc/felix/trunk/inventory/src/main/java/org/apache/felix/inventory/impl/helper/SimpleJson.java?rev=1486594&view=auto
==============================================================================
--- felix/trunk/inventory/src/main/java/org/apache/felix/inventory/impl/helper/SimpleJson.java (added)
+++ felix/trunk/inventory/src/main/java/org/apache/felix/inventory/impl/helper/SimpleJson.java Mon May 27 12:34:46 2013
@@ -0,0 +1,105 @@
+/*
+ * 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.felix.inventory.impl.helper;
+
+/**
+ * The <code>SimpleJson</code> is an extremely simple and very limited
+ * helper class to create JSON formatted output. The limits are as follows:
+ * <ol>
+ * <li>There is no error checking</li>
+ * <li>Arrays are always expected to be inside an object</li>
+ * <li>At most one level of object nesting is supported</li>
+ * <li>Strings are not escaped</li>
+ * <li>Only string values are supported</li>
+ * </ol>
+ */
+class SimpleJson
+{
+
+ private StringBuffer index = new StringBuffer();
+
+ /*
+ * "o" - object; require ";" separator
+ * "f" - object; no separator; next "o"
+ * "a" - array; require "," separator
+ * "i" - array; no separator; next "a"
+ */
+ private char mode = 0;
+
+ SimpleJson object()
+ {
+ this.index.append('{');
+ this.mode = 'f';
+ return this;
+ }
+
+ SimpleJson endObject()
+ {
+ this.index.append('}');
+ this.mode = 'o';
+ return this;
+ }
+
+ SimpleJson array()
+ {
+ this.index.append('[');
+ this.mode = 'i';
+ return this;
+ }
+
+ SimpleJson endArray()
+ {
+ this.index.append(']');
+ this.mode = 'o';
+ return this;
+ }
+
+ SimpleJson key(final String key)
+ {
+ if (this.mode == 'f')
+ {
+ this.mode = 'o';
+ }
+ else if (mode == 'o')
+ {
+ this.index.append(',');
+ }
+ this.index.append('"').append(key).append("\":");
+ return this;
+ }
+
+ SimpleJson value(final String value)
+ {
+ if (this.mode == 'i')
+ {
+ this.mode = 'a';
+ }
+ else if (mode == 'a')
+ {
+ this.index.append(',');
+ }
+ this.index.append('"').append(value).append('"');
+ return this;
+ }
+
+ public String toString()
+ {
+ return this.index.toString();
+ }
+}
Added: felix/trunk/inventory/src/main/java/org/apache/felix/inventory/impl/helper/ZipConfigurationWriter.java
URL: http://svn.apache.org/viewvc/felix/trunk/inventory/src/main/java/org/apache/felix/inventory/impl/helper/ZipConfigurationWriter.java?rev=1486594&view=auto
==============================================================================
--- felix/trunk/inventory/src/main/java/org/apache/felix/inventory/impl/helper/ZipConfigurationWriter.java (added)
+++ felix/trunk/inventory/src/main/java/org/apache/felix/inventory/impl/helper/ZipConfigurationWriter.java Mon May 27 12:34:46 2013
@@ -0,0 +1,218 @@
+/*
+ * 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.felix.inventory.impl.helper;
+
+import java.io.IOException;
+import java.io.OutputStream;
+import java.io.OutputStreamWriter;
+import java.text.DateFormat;
+import java.text.MessageFormat;
+import java.util.Date;
+import java.util.Locale;
+import java.util.zip.Deflater;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipOutputStream;
+
+import org.apache.felix.inventory.Format;
+import org.apache.felix.inventory.impl.InventoryPrinterHandler;
+
+/**
+ * The ZIP configuration writer creates a zip with
+ * - txt output of a inventory printers (if supported)
+ * - json output of a inventory printers (if supported)
+ * - attachments from a inventory printer (if supported)
+ */
+public class ZipConfigurationWriter extends ConfigurationWriter
+{
+
+ private final ZipConfigurationWriter.ConfigZipOutputStream zip;
+
+ private int entryCounter;
+
+ public static ZipConfigurationWriter create(final OutputStream out) throws IOException
+ {
+ final ZipConfigurationWriter.ConfigZipOutputStream zip = new ConfigZipOutputStream(out)
+ {
+ };
+ zip.setLevel(Deflater.BEST_SPEED);
+ zip.setMethod(ZipOutputStream.DEFLATED);
+
+ return new ZipConfigurationWriter(zip);
+ }
+
+ private ZipConfigurationWriter(final ZipConfigurationWriter.ConfigZipOutputStream zip) throws IOException
+ {
+ super(new OutputStreamWriter(zip, "UTF-8"));
+
+ this.zip = zip;
+ this.entryCounter = -1;
+ }
+
+ public void finish() throws IOException
+ {
+ this.zip.finish();
+ }
+
+ /**
+ * Overwrites the
+ * {@link ConfigurationWriter#printInventory(Format, InventoryPrinterHandler)}
+ * method writing the plain text output, the JSON output and any
+ * attachements to the ZIP file. The {@code format} argument is ignored.
+ *
+ * @param formatIgnored Ignored, may be {@code null}.
+ * @param handler The handler to be called to generate the output
+ *
+ * @throws IOException if an error occurrs writing to the ZIP file.
+ */
+ public void printInventory(final Format formatIgnored, final InventoryPrinterHandler handler)
+ throws IOException
+ {
+ final String baseName = getBaseName(handler);
+
+ this.zip.handler(handler);
+
+ // print the plain text output
+ if (handler.supports(Format.TEXT))
+ {
+ final ZipEntry entry = new ZipEntry(baseName.concat(".txt"));
+ entry.setTime(System.currentTimeMillis());
+ this.zip.putNextEntry(entry, Format.TEXT);
+ handler.print(this, Format.TEXT, false);
+ this.flush();
+ this.zip.closeEntry();
+ }
+
+ // print the JSON format output
+ if (handler.supports(Format.JSON))
+ {
+ final ZipEntry entry = new ZipEntry("json/" + baseName + ".json");
+ entry.setTime(System.currentTimeMillis());
+ this.zip.putNextEntry(entry, Format.JSON);
+ handler.print(this, Format.JSON, true);
+ this.flush();
+ this.zip.closeEntry();
+ }
+
+ // any attachements from the handler
+ this.zip.attachements();
+ handler.addAttachments(this.zip, baseName.concat("/"));
+ this.zip.endAttachements();
+
+ this.zip.endHandler();
+ }
+
+ private String getBaseName(final InventoryPrinterHandler handler)
+ {
+ final String title = handler.getTitle();
+ final StringBuffer name = new StringBuffer(title.length());
+ for (int i = 0; i < title.length(); i++)
+ {
+ char c = title.charAt(i);
+ if ((c >= '0' && c <= '9') || (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z'))
+ {
+ name.append(c);
+ }
+ else
+ {
+ name.append('_');
+ }
+ }
+
+ this.entryCounter++;
+ return MessageFormat.format("{0,number,000}_{1}", new Object[]
+ { new Integer(this.entryCounter), name });
+ }
+
+ private static class ConfigZipOutputStream extends ZipOutputStream
+ {
+
+ private final SimpleJson json;
+
+ ConfigZipOutputStream(final OutputStream out)
+ {
+ super(out);
+
+ this.json = new SimpleJson();
+ this.json.object();
+
+ // timestamp in the "created" object
+ final Date now = new Date();
+ final String nowFormatted = DateFormat.getDateTimeInstance(DateFormat.LONG, DateFormat.LONG, Locale.US)
+ .format(now);
+ this.json.key("created");
+ this.json.object();
+ this.json.key("date").value(nowFormatted);
+ this.json.key("stamp").value(String.valueOf(now.getTime()));
+ this.json.endObject();
+
+ // output from the printers in the "files" object
+ this.json.key("files").object();
+ }
+
+ void handler(final InventoryPrinterHandler handler)
+ {
+ this.json.key(handler.getName());
+ this.json.object();
+ this.json.key("title").value(handler.getTitle());
+ }
+
+ void endHandler()
+ {
+ this.json.endObject();
+ }
+
+ void attachements()
+ {
+ this.json.key("attachements");
+ this.json.array();
+ }
+
+ void endAttachements()
+ {
+ this.json.endArray();
+ }
+
+ void putNextEntry(ZipEntry e, Format format) throws IOException
+ {
+ this.json.key(format.toString().toLowerCase());
+ this.putNextEntry(e);
+ }
+
+ public void putNextEntry(ZipEntry e) throws IOException
+ {
+ this.json.value(e.getName());
+ super.putNextEntry(e);
+ }
+
+ public void finish() throws IOException
+ {
+ // end "files" and root objects
+ this.json.endObject().endObject();
+
+ final ZipEntry entry = new ZipEntry("index.json");
+ entry.setTime(System.currentTimeMillis());
+ super.putNextEntry(entry); // don't write the index to the JSON
+ this.write(this.json.toString().getBytes("UTF-8"));
+ this.flush();
+ this.closeEntry();
+
+ super.finish();
+ }
+ }
+}
\ No newline at end of file