org.apache.pluto.util.assemble.ear.EarAssembler.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.pluto.util.assemble.ear.EarAssembler.java

Source

/*
 * 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.pluto.util.assemble.ear;

import java.io.BufferedOutputStream;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.jar.JarEntry;
import java.util.jar.JarInputStream;
import java.util.jar.JarOutputStream;

import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.apache.pluto.util.UtilityException;
import org.apache.pluto.util.assemble.AbstractArchiveAssembler;
import org.apache.pluto.util.assemble.AssemblerConfig;
import org.apache.pluto.util.assemble.io.JarStreamingAssembly;

/**
 * Assembles war files contained inside of an EAR.  War files that do
 * not contain a portlet.xml are not assembled.  All files are copied
 * into the destination archive.
 */
public class EarAssembler extends AbstractArchiveAssembler {

    private static final Logger LOG = LoggerFactory.getLogger(EarAssembler.class);
    private static final int BUFLEN = 1024 * 8; // 8kb

    public void assembleInternal(AssemblerConfig config) throws UtilityException, IOException {

        File source = config.getSource();
        File dest = config.getDestination();

        JarInputStream earIn = new JarInputStream(new FileInputStream(source));
        JarOutputStream earOut = new JarOutputStream(new BufferedOutputStream(new FileOutputStream(dest), BUFLEN));

        try {

            JarEntry entry;

            // Iterate over entries in the EAR archive
            while ((entry = earIn.getNextJarEntry()) != null) {

                // If a war file is encountered, assemble it into a
                // ByteArrayOutputStream and write the assembled bytes
                // back to the EAR archive.
                if (entry.getName().toLowerCase().endsWith(".war")) {

                    if (LOG.isDebugEnabled()) {
                        LOG.debug("Assembling war file " + entry.getName());
                    }

                    // keep a handle to the AssemblySink so we can write out
                    // JarEntry metadata and the bytes later.
                    AssemblySink warBytesOut = getAssemblySink(config, entry);
                    JarOutputStream warOut = new JarOutputStream(warBytesOut);

                    JarStreamingAssembly.assembleStream(new JarInputStream(earIn), warOut,
                            config.getDispatchServletClass());

                    JarEntry warEntry = new JarEntry(entry);

                    // Write out the assembled JarEntry metadata
                    warEntry.setSize(warBytesOut.getByteCount());
                    warEntry.setCrc(warBytesOut.getCrc());
                    warEntry.setCompressedSize(-1);
                    earOut.putNextEntry(warEntry);

                    // Write out the assembled WAR file to the EAR
                    warBytesOut.writeTo(earOut);

                    earOut.flush();
                    earOut.closeEntry();
                    earIn.closeEntry();

                } else {

                    earOut.putNextEntry(entry);
                    IOUtils.copy(earIn, earOut);

                    earOut.flush();
                    earOut.closeEntry();
                    earIn.closeEntry();

                }
            }

        } finally {

            earOut.close();
            earIn.close();

        }
    }

    /**
     * Obtain a sink used as a temporary container for assembled war bytes.  By default a
     * filesystem based sink is used.
     * 
     * @param config the AssemblerConfig
     * @param entry the JarEntry
     * @return the AssemblySink
     * @throws IOException
     */
    protected AssemblySink getAssemblySink(AssemblerConfig config, JarEntry entry) throws IOException {
        File f = File.createTempFile("earAssemblySink", "tmp");
        f.deleteOnExit();
        return getFileAssemblySink(entry, f);
    }

    private AssemblySink getByteArrayAssemblySink(JarEntry entry) {
        // Create a buffer the size of the warfile, plus a little extra, to 
        // account for the additional bytes added to web.xml as a result of
        // assembly.

        ByteArrayAssemblySink warBytesOut = null;
        int defaultBuflen = 1024 * 1024 * 10; // 10Mb
        int assemblyBuflen = 1024 * 32; // 32kb additional bytes for assembly

        // ByteArrayOutputStream grows the buffer by a left bitshift each time
        // its internal buffer would overflow.  The goal is to prevent the
        // buffer from overflowing, otherwise the exponential growth of
        // the internal buffer can cause OOM errors.

        // note that we can only optimize the buffer for file sizes less than 
        // Integer.MAX_VALUE - assemblyBuf
        if (entry.getSize() > (Integer.MAX_VALUE - assemblyBuflen) || entry.getSize() < 1) {
            warBytesOut = new ByteArrayAssemblySink(new ByteArrayOutputStream(defaultBuflen));
        } else {
            int buflen = (int) entry.getSize() + assemblyBuflen;
            warBytesOut = new ByteArrayAssemblySink(new ByteArrayOutputStream(buflen));
        }

        return warBytesOut;
    }

    private AssemblySink getFileAssemblySink(JarEntry e, File f) {
        AssemblySink sink = null;
        try {
            sink = new FileAssemblySink(f);
        } catch (Exception ex) {
            throw new RuntimeException(ex);
        }
        return sink;
    }

}