/* * 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, true); 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(); } } }