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 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    }