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}