Package org.apache.felix.deploymentadmin

Source Code of org.apache.felix.deploymentadmin.ContentCopyingJarInputStream

/*
* 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.deploymentadmin;

import java.io.Closeable;
import java.io.File;
import java.io.FileOutputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.jar.JarFile;
import java.util.jar.JarInputStream;
import java.util.jar.Manifest;
import java.util.zip.GZIPOutputStream;
import java.util.zip.ZipEntry;

/**
* Provides a custom {@link JarInputStream} that copies all entries read from the original {@link InputStream} to a
* given directory and index file. It does this by tracking thecommon usage of the {@link JarInputStream} API. For each
* entry that is read it streams all read bytes to a separate file compressing it on the fly. The caller does not notice
* anything, although it might be that the {@link #read(byte[], int, int)} is blocked for a little while during the
* writing of the file contents.
* <p>
* This implementation replaces the old <tt>ExplodingOutputtingInputStream</tt> that used
* at least two threads and was difficult to understand and maintain. See FELIX-4486.
* </p>
*/
class ContentCopyingJarInputStream extends JarInputStream {
    private static final String MANIFEST_FILE = JarFile.MANIFEST_NAME;

    private final File m_contentDir;

    private PrintWriter m_indexFileWriter;
    /** Used to copy the contents of the *next* entry. */
    private OutputStream m_entryOS;

    public ContentCopyingJarInputStream(InputStream in, File indexFile, File contentDir) throws IOException {
        super(in);

        m_contentDir = contentDir;

        m_indexFileWriter = new PrintWriter(new FileWriter(indexFile));
        m_entryOS = null;

        // the manifest of the JAR is already read by JarInputStream, so we need to write this one as well...
        Manifest manifest = getManifest();
        if (manifest != null) {
            copyManifest(manifest);
        }
    }

    public void close() throws IOException {
        closeCopy();
        closeIndex();
        super.close();
    }

    public void closeEntry() throws IOException {
        closeCopy();
        super.closeEntry();
    }

    public ZipEntry getNextEntry() throws IOException {
        closeCopy();

        ZipEntry entry = super.getNextEntry();
        if (entry != null) {
            File current = new File(m_contentDir, entry.getName());
            if (!entry.isDirectory()) {
                addToIndex(entry.getName());

                m_entryOS = createOutputStream(current);
            }
        }

        return entry;
    }

    public int read(byte[] b, int off, int len) throws IOException {
        int r = super.read(b, off, len);
        if (m_entryOS != null) {
            if (r > 0) {
                m_entryOS.write(b, off, r);
            }
            else {
                closeCopy();
            }
        }
        return r;
    }

    private void addToIndex(String name) throws IOException {
        m_indexFileWriter.println(name);
        m_indexFileWriter.flush();
    }

    private void closeCopy() {
        closeSilently(m_entryOS);
        m_entryOS = null;
    }

    private void closeIndex() {
        closeSilently(m_indexFileWriter);
        m_indexFileWriter = null;
    }

    private void closeSilently(Closeable resource) {
        try {
            if (resource != null) {
                resource.close();
            }
        }
        catch (IOException e) {
            // Ignore, not much we can do about this...
        }
    }

    /**
     * Creates a verbatim copy of the manifest, when it is read from the original JAR.
     */
    private void copyManifest(Manifest manifest) throws IOException {
        addToIndex(MANIFEST_FILE);

        OutputStream os = createOutputStream(new File(m_contentDir, MANIFEST_FILE));
        try {
            manifest.write(os);
        }
        finally {
            closeSilently(os);
        }
    }

    private OutputStream createOutputStream(File file) throws IOException {
        File parent = file.getParentFile();
        if (parent != null) {
            parent.mkdirs();
        }
        if (!file.createNewFile()) {
            throw new IOException("Attempt to overwrite file: " + file);
        }
        return new GZIPOutputStream(new FileOutputStream(file));
    }
}
TOP

Related Classes of org.apache.felix.deploymentadmin.ContentCopyingJarInputStream

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.