org.echocat.nodoodle.transport.HandlerPacker.java Source code

Java tutorial

Introduction

Here is the source code for org.echocat.nodoodle.transport.HandlerPacker.java

Source

/*****************************************************************************************
 * *** BEGIN LICENSE BLOCK *****
 *
 * Version: MPL 2.0
 *
 * echocat NoDoodle, Copyright (c) 2010-2012 echocat
 *
 * This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this
 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
 *
 * *** END LICENSE BLOCK *****
 ****************************************************************************************/

package org.echocat.nodoodle.transport;

import org.echocat.nodoodle.Handler;
import org.echocat.nodoodle.NodoodleInformationFactory;
import org.echocat.nodoodle.resources.JarResource;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang.StringUtils;

import java.io.*;
import java.util.*;
import java.util.jar.Attributes;
import java.util.jar.JarEntry;
import java.util.jar.JarOutputStream;
import java.util.jar.Manifest;

import static org.echocat.nodoodle.transport.TransportConstants.*;
import static java.util.jar.Attributes.Name.*;

public class HandlerPacker {

    private final NodoodleInformationFactory _informationFactory;

    private Collection<Class<?>> _dependencyTypes;
    private Collection<JarResource> _jarResourceDependencies;

    public HandlerPacker(NodoodleInformationFactory informationFactory) {
        if (informationFactory == null) {
            throw new NullPointerException();
        }
        _informationFactory = informationFactory;
    }

    public void pack(Handler<?> handler, OutputStream to) throws IOException {
        if (handler == null) {
            throw new NullPointerException();
        }
        if (!(handler instanceof Serializable)) {
            throw new IllegalArgumentException(handler + " is not of type " + Serializable.class.getName() + ".");
        }
        if (to == null) {
            throw new NullPointerException();
        }
        final String dataFileName = getDataFileName();
        // noinspection unchecked
        final Class<? extends Handler<?>> handlerType = (Class<? extends Handler<?>>) handler.getClass();
        final Map<String, JarResource> fileNameToJarResource = buildFileNameToJarResource();
        final Manifest manifest = createManifest(dataFileName, fileNameToJarResource.keySet());
        final JarOutputStream jar = new JarOutputStream(to, manifest);

        final Set<String> namesOfWrittenTypeFiles = new HashSet<String>();
        writeTypes(handlerType, jar, namesOfWrittenTypeFiles);
        writeJarResourcesDependencies(fileNameToJarResource, jar);
        writeData(handler, jar, dataFileName);

        jar.finish();
    }

    protected Manifest createManifest(String dataFileName, Collection<String> dependencyFileNames) {
        if (dataFileName == null) {
            throw new NullPointerException();
        }
        if (dependencyFileNames == null) {
            throw new NullPointerException();
        }
        final Manifest manifest = new Manifest();
        final Attributes mainAttributes = manifest.getMainAttributes();
        mainAttributes.put(MANIFEST_VERSION, "1.0");
        mainAttributes.put(new Attributes.Name("Created-By"), getSmappserVersionString());
        mainAttributes.put(CLASS_PATH, StringUtils.join(dependencyFileNames, ' '));

        final Attributes extensionAttributes = new Attributes();
        extensionAttributes.put(MANIFEST_DATE_FILE, dataFileName);
        manifest.getEntries().put(MANIFEST_EXTENSION_NAME, extensionAttributes);
        return manifest;
    }

    private void writeTypes(Class<? extends Handler<?>> handlerType, JarOutputStream jar,
            Set<String> namesOfWrittenTypeFiles) throws IOException {
        if (handlerType == null) {
            throw new NullPointerException();
        }
        if (jar == null) {
            throw new NullPointerException();
        }
        if (namesOfWrittenTypeFiles == null) {
            throw new NullPointerException();
        }
        writeType(handlerType, jar, namesOfWrittenTypeFiles);
        if (_dependencyTypes != null) {
            for (Class<?> dependencyType : _dependencyTypes) {
                writeType(dependencyType, jar, namesOfWrittenTypeFiles);
            }
        }
    }

    protected void writeType(Class<?> type, JarOutputStream jar, Set<String> namesOfWrittenFiles)
            throws IOException {
        if (jar == null) {
            throw new NullPointerException();
        }
        if (namesOfWrittenFiles == null) {
            throw new NullPointerException();
        }
        if (type != null) {
            final String fileName = type.getName().replace('.', '/') + ".class";
            // noinspection UnnecessaryLocalVariable
            final String sourceFileName = fileName;
            final String targetFileName = TransportConstants.CLASSES_PREFIX + fileName;
            if (namesOfWrittenFiles.contains(targetFileName)) {
                throw new IllegalStateException("The target file '" + targetFileName
                        + "' was already written to jar file. Is '" + type
                        + "' the handler and in the list of dependencyTypes or is dependencyTypes simply not unique?");
            }
            final InputStream inputStream = type.getClassLoader().getResourceAsStream(sourceFileName);
            try {
                final JarEntry e = new JarEntry(targetFileName);
                jar.putNextEntry(e);
                IOUtils.copy(inputStream, jar);
                jar.closeEntry();
            } finally {
                inputStream.close();
            }
            namesOfWrittenFiles.add(targetFileName);
        }
    }

    protected void writeJarResourcesDependencies(Map<String, JarResource> fileNameToJarResource,
            JarOutputStream jar) throws IOException {
        if (fileNameToJarResource == null) {
            throw new NullPointerException();
        }
        if (jar == null) {
            throw new NullPointerException();
        }
        if (_jarResourceDependencies != null) {
            for (Map.Entry<String, JarResource> fileNameAndJarResource : fileNameToJarResource.entrySet()) {
                writeJarResource(fileNameAndJarResource.getValue(), jar, fileNameAndJarResource.getKey());
            }
        }
    }

    protected void writeJarResource(JarResource jarResource, JarOutputStream jar, String fileName)
            throws IOException {
        if (jar == null) {
            throw new NullPointerException();
        }
        if (fileName == null) {
            throw new NullPointerException();
        }
        if (jarResource != null) {
            final InputStream inputStream = jarResource.getResourceAsJar();
            try {
                final JarEntry e = new JarEntry(fileName);
                jar.putNextEntry(e);
                IOUtils.copy(inputStream, jar);
                jar.closeEntry();
            } finally {
                inputStream.close();
            }
        }
    }

    protected void writeData(Handler<?> handler, JarOutputStream jar, String dataFileName) throws IOException {
        if (handler == null) {
            throw new NullPointerException();
        }
        if (jar == null) {
            throw new NullPointerException();
        }
        final JarEntry entry = new JarEntry(dataFileName);
        jar.putNextEntry(entry);
        final ObjectOutputStream oos = new ObjectOutputStream(jar);
        oos.writeObject(handler);
        oos.flush();
        jar.closeEntry();
    }

    protected Map<String, JarResource> buildFileNameToJarResource() throws IOException {
        final Map<String, JarResource> fileNameToJarResource = new LinkedHashMap<String, JarResource>();
        if (_jarResourceDependencies != null) {
            for (JarResource jarResource : _jarResourceDependencies) {
                String targetFileName = LIB_PREFIX + jarResource.getName();
                int i = 1;
                while (fileNameToJarResource.containsKey(targetFileName)) {
                    targetFileName = LIB_PREFIX + (i++) + "-" + jarResource.getName();
                }
                fileNameToJarResource.put(targetFileName, jarResource);
            }
        }
        return Collections.unmodifiableMap(fileNameToJarResource);
    }

    protected String getDataFileName() {
        return "data.bin";
    }

    protected String getSmappserVersionString() {
        final String version = _informationFactory.getImplementationVersion();
        return "nodoodle " + (version != null ? version : "?");
    }

    public Collection<Class<?>> getDependencyTypes() {
        return _dependencyTypes;
    }

    public void setDependencyTypes(Collection<Class<?>> dependencyTypes) {
        _dependencyTypes = dependencyTypes;
    }

    public Collection<JarResource> getJarResourceDependencies() {
        return _jarResourceDependencies;
    }

    public void setJarResourceDependencies(Collection<JarResource> jarResourceDependencies) {
        _jarResourceDependencies = jarResourceDependencies;
    }
}