    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
    020    package org.apache.commons.compress.compressors.pack200;
    021
    022    import java.io.IOException;
    023    import java.io.OutputStream;
    024    import java.util.Map;
    025    import java.util.jar.JarInputStream;
    026    import java.util.jar.Pack200;
    027
    028    import org.apache.commons.compress.compressors.CompressorOutputStream;
    029
    030    /**
    031     * An output stream that compresses using the Pack200 format.
    032     *
    033     * @NotThreadSafe
    034     * @since Apache Commons Compress 1.3
    035     */
    036    public class Pack200CompressorOutputStream extends CompressorOutputStream {
    037        private boolean finished = false;
    038        private final OutputStream originalOutput;
    039        private final StreamBridge streamBridge;
    040        private final Map<String, String> properties;
    041
    042        /**
    043         * Compresses the given stream, caching the compressed data in
    044         * memory.
    045         */
    046        public Pack200CompressorOutputStream(final OutputStream out)
    047            throws IOException {
    048            this(out, Pack200Strategy.IN_MEMORY);
    049        }
    050
    051        /**
    052         * Compresses the given stream using the given strategy to cache
    053         * the results.
    054         */
    055        public Pack200CompressorOutputStream(final OutputStream out,
    056                                             final Pack200Strategy mode)
    057            throws IOException {
    058            this(out, mode, null);
    059        }
    060
    061        /**
    062         * Compresses the given stream, caching the compressed data in
    063         * memory and using the given properties.
    064         */
    065        public Pack200CompressorOutputStream(final OutputStream out,
    066                                             final Map<String, String> props)
    067            throws IOException {
    068            this(out, Pack200Strategy.IN_MEMORY, props);
    069        }
    070
    071        /**
    072         * Compresses the given stream using the given strategy to cache
    073         * the results and the given properties.
    074         */
    075        public Pack200CompressorOutputStream(final OutputStream out,
    076                                             final Pack200Strategy mode,
    077                                             final Map<String, String> props)
    078            throws IOException {
    079            originalOutput = out;
    080            streamBridge = mode.newStreamBridge();
    081            properties = props;
    082        }
    083
    084        /** {@inheritDoc} */
    085        @Override
    086        public void write(int b) throws IOException {
    087            streamBridge.write(b);
    088        }
    089
    090        /**
    091         * {@inheritDoc}
    092         */
    093        @Override
    094        public void write(byte[] b) throws IOException {
    095            streamBridge.write(b);
    096        }
    097
    098        /**
    099         * {@inheritDoc}
    100         */
    101        @Override
    102        public void write(byte[] b, int from, int length) throws IOException {
    103            streamBridge.write(b, from, length);
    104        }
    105
    106        @Override
    107        public void close() throws IOException {
    108            finish();
    109            try {
    110                streamBridge.stop();
    111            } finally {
    112                originalOutput.close();
    113            }
    114        }
    115
    116        public void finish() throws IOException {
    117            if (!finished) {
    118                finished = true;
    119                Pack200.Packer p = Pack200.newPacker();
    120                if (properties != null) {
    121                    p.properties().putAll(properties);
    122                }
    123                JarInputStream ji = null;
    124                boolean success = false;
    125                try {
    126                    p.pack(ji = new JarInputStream(streamBridge.getInput()),
    127                           originalOutput);
    128                    success = true;
    129                } finally {
    130                    if (!success && ji != null) {
    131                        try {
    132                            ji.close();
    133                        } catch (IOException ex) { // NOPMD
    134                            // swallow so original exception isn't masked
    135                        }
    136                    }
    137                }
    138            }
    139        }
    140    }