001/* 002 * Licensed to the Apache Software Foundation (ASF) under one 003 * or more contributor license agreements. See the NOTICE file 004 * distributed with this work for additional information 005 * regarding copyright ownership. The ASF licenses this file 006 * to you under the Apache License, Version 2.0 (the 007 * "License"); you may not use this file except in compliance 008 * with the License. You may obtain a copy of the License at 009 * 010 * http://www.apache.org/licenses/LICENSE-2.0 011 * 012 * Unless required by applicable law or agreed to in writing, 013 * software distributed under the License is distributed on an 014 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 015 * KIND, either express or implied. See the License for the 016 * specific language governing permissions and limitations 017 * under the License. 018 */ 019 020package org.apache.commons.compress.compressors.pack200; 021 022import java.io.IOException; 023import java.io.OutputStream; 024import java.util.Map; 025import java.util.jar.JarInputStream; 026import java.util.jar.Pack200; 027 028import org.apache.commons.compress.compressors.CompressorOutputStream; 029import org.apache.commons.compress.utils.IOUtils; 030 031/** 032 * An output stream that compresses using the Pack200 format. 033 * 034 * @NotThreadSafe 035 * @since 1.3 036 */ 037public class Pack200CompressorOutputStream extends CompressorOutputStream { 038 private boolean finished = false; 039 private final OutputStream originalOutput; 040 private final StreamBridge streamBridge; 041 private final Map<String, String> properties; 042 043 /** 044 * Compresses the given stream, caching the compressed data in 045 * memory. 046 * 047 * @param out the stream to write to 048 */ 049 public Pack200CompressorOutputStream(final OutputStream out) 050 throws IOException { 051 this(out, Pack200Strategy.IN_MEMORY); 052 } 053 054 /** 055 * Compresses the given stream using the given strategy to cache 056 * the results. 057 * 058 * @param out the stream to write to 059 * @param mode the strategy to use 060 */ 061 public Pack200CompressorOutputStream(final OutputStream out, 062 final Pack200Strategy mode) 063 throws IOException { 064 this(out, mode, null); 065 } 066 067 /** 068 * Compresses the given stream, caching the compressed data in 069 * memory and using the given properties. 070 * 071 * @param out the stream to write to 072 * @param props Pack200 properties to use 073 */ 074 public Pack200CompressorOutputStream(final OutputStream out, 075 final Map<String, String> props) 076 throws IOException { 077 this(out, Pack200Strategy.IN_MEMORY, props); 078 } 079 080 /** 081 * Compresses the given stream using the given strategy to cache 082 * the results and the given properties. 083 * 084 * @param out the stream to write to 085 * @param mode the strategy to use 086 * @param props Pack200 properties to use 087 */ 088 public Pack200CompressorOutputStream(final OutputStream out, 089 final Pack200Strategy mode, 090 final Map<String, String> props) 091 throws IOException { 092 originalOutput = out; 093 streamBridge = mode.newStreamBridge(); 094 properties = props; 095 } 096 097 @Override 098 public void write(int b) throws IOException { 099 streamBridge.write(b); 100 } 101 102 @Override 103 public void write(byte[] b) throws IOException { 104 streamBridge.write(b); 105 } 106 107 @Override 108 public void write(byte[] b, int from, int length) throws IOException { 109 streamBridge.write(b, from, length); 110 } 111 112 @Override 113 public void close() throws IOException { 114 finish(); 115 try { 116 streamBridge.stop(); 117 } finally { 118 originalOutput.close(); 119 } 120 } 121 122 public void finish() throws IOException { 123 if (!finished) { 124 finished = true; 125 Pack200.Packer p = Pack200.newPacker(); 126 if (properties != null) { 127 p.properties().putAll(properties); 128 } 129 JarInputStream ji = null; 130 boolean success = false; 131 try { 132 p.pack(ji = new JarInputStream(streamBridge.getInput()), 133 originalOutput); 134 success = true; 135 } finally { 136 if (!success) { 137 IOUtils.closeQuietly(ji); 138 } 139 } 140 } 141 } 142}