Package com.asakusafw.compiler.flow

Source Code of com.asakusafw.compiler.flow.VolatilePackager

/**
* Copyright 2011-2014 Asakusa Framework Team.
*
* Licensed 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 com.asakusafw.compiler.flow;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.nio.charset.Charset;
import java.text.MessageFormat;
import java.util.Collections;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.TreeMap;
import java.util.jar.JarEntry;
import java.util.jar.JarOutputStream;

import javax.tools.Diagnostic;
import javax.tools.DiagnosticCollector;
import javax.tools.FileObject;
import javax.tools.JavaCompiler;
import javax.tools.JavaCompiler.CompilationTask;
import javax.tools.JavaFileObject;
import javax.tools.ToolProvider;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.asakusafw.compiler.batch.batch.MockEmitter;
import com.asakusafw.utils.collections.Lists;
import com.asakusafw.utils.java.jsr199.testing.VolatileClassFile;
import com.asakusafw.utils.java.jsr199.testing.VolatileClassOutputManager;
import com.asakusafw.utils.java.jsr199.testing.VolatileJavaFile;
import com.asakusafw.utils.java.jsr199.testing.VolatileResourceFile;
import com.asakusafw.utils.java.model.syntax.CompilationUnit;
import com.asakusafw.utils.java.model.syntax.Name;

/**
* メモリ上に構成物を展開するパッケージャ。
*/
public class VolatilePackager
        extends FlowCompilingEnvironment.Initialized
        implements Packager {

    static final Logger LOG = LoggerFactory.getLogger(VolatilePackager.class);

    private static final Charset CHARSET = Charset.forName("UTF-8");

    private final MockEmitter emitter;

    Map<String, byte[]> contents;

    /**
     * インスタンスを生成する。
     */
    public VolatilePackager() {
        this.emitter = new MockEmitter();
        this.contents = new TreeMap<String, byte[]>();
    }

    /**
     * このパッケージャが利用するエミッタを返す。
     * @return 利用するエミッタ
     */
    public MockEmitter getEmitter() {
        return emitter;
    }

    @Override
    public PrintWriter openWriter(CompilationUnit source) throws IOException {
        if (source == null) {
            throw new IllegalArgumentException("source must not be null"); //$NON-NLS-1$
        }
        return emitter.openFor(source);
    }

    @Override
    public OutputStream openStream(Name packageNameOrNull, String relativePath)
            throws IOException {
        if (relativePath == null) {
            throw new IllegalArgumentException("relativePath must not be null"); //$NON-NLS-1$
        }
        StringBuilder buf = new StringBuilder();
        if (packageNameOrNull != null) {
            buf.append(packageNameOrNull.toNameString().replace('.', '/'));
            buf.append('/');
        }
        buf.append(relativePath.replace('\\', '/'));
        final String name = buf.toString();
        return new ByteArrayOutputStream() {
            @Override
            public void close() throws IOException {
                contents.put(name, toByteArray());
            }
        };
    }

    @Override
    public void build(OutputStream output) throws IOException {
        JarOutputStream jar = new JarOutputStream(output);
        try {
            compile(jar);
        } finally {
            jar.close();
        }
    }

    @Override
    public void packageSources(OutputStream output) throws IOException {
        JarOutputStream jar = new JarOutputStream(output);
        try {
            collect(jar);
        } finally {
            jar.close();
        }
    }

    private void collect(JarOutputStream jar) throws IOException {
        assert jar != null;
        for (VolatileJavaFile file : emitter.getEmitted()) {
            String path = file.toUri().getPath();
            JarEntry entry = new JarEntry(path);
            jar.putNextEntry(entry);
            jar.write(file.getCharContent(false).toString().getBytes(CHARSET));
            jar.closeEntry();
        }
    }

    private void compile(JarOutputStream jar) throws IOException {
        JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
        if (compiler == null) {
            throw new IllegalStateException(
                    "この環境ではJavaコンパイラーを利用できません (JREにはコンパイラーが含まれていません)");
        }
        compile(compiler, jar);
    }

    private void compile(
            JavaCompiler compiler,
            JarOutputStream jar) throws IOException {
        assert compiler != null;
        assert jar != null;

        DiagnosticCollector<JavaFileObject> diagnostics =
            new DiagnosticCollector<JavaFileObject>();
        VolatileClassOutputManager fileManager = new VolatileClassOutputManager(
                compiler.getStandardFileManager(
                        diagnostics,
                        Locale.getDefault(),
                        CHARSET));
        try {
            List<String> arguments = Lists.create();
            Collections.addAll(arguments, "-source", "1.6");
            Collections.addAll(arguments, "-target", "1.6");
            Collections.addAll(arguments, "-encoding", CHARSET.name());

            StringWriter errors = new StringWriter();
            PrintWriter pw = new PrintWriter(errors);

            CompilationTask task = compiler.getTask(
                    pw,
                    fileManager,
                    diagnostics,
                    arguments,
                    Collections.<String>emptyList(),
                    emitter.getEmitted());

            Boolean successed = task.call();
            pw.close();
            for (Diagnostic<?> diagnostic : diagnostics.getDiagnostics()) {
                switch (diagnostic.getKind()) {
                case ERROR:
                case MANDATORY_WARNING:
                    getEnvironment().error(diagnostic.getMessage(null));
                    break;
                case WARNING:
                    LOG.warn(diagnostic.getMessage(null));
                    break;
                default:
                    LOG.info(diagnostic.getMessage(null));
                    break;
                }
            }
            if(Boolean.TRUE.equals(successed) == false) {
                throw new IOException(MessageFormat.format(
                        "{0}のコンパイルに失敗しました: {1}",
                        getEnvironment().getTargetId(),
                        errors.toString()));
            }

            for (VolatileResourceFile file : fileManager.getResources()) {
                addEntry(jar, file);
            }
            for (VolatileClassFile file : fileManager.getCompiled()) {
                addEntry(jar, file);
            }
            for (Map.Entry<String, byte[]> entry : contents.entrySet()) {
                addEntry(jar, entry.getKey(), entry.getValue());
            }
        } finally {
            fileManager.close();
        }
    }

    private void addEntry(JarOutputStream jar, String path, byte[] content) throws IOException {
        assert jar != null;
        assert path != null;
        assert content != null;
        JarEntry entry = new JarEntry(path);
        jar.putNextEntry(entry);
        jar.write(content);
        jar.closeEntry();
    }

    private void addEntry(JarOutputStream jar, FileObject file) throws IOException {
        assert jar != null;
        String path = file.toUri().getPath();
        while (path.startsWith("/")) {
            path = path.substring(1);
        }
        JarEntry entry = new JarEntry(path);
        jar.putNextEntry(entry);
        InputStream input = file.openInputStream();
        try {
            byte[] buffer = new byte[1024];
            while (true) {
                int read = input.read(buffer);
                if (read < 0) {
                    break;
                }
                jar.write(buffer, 0, read);
            }
            jar.closeEntry();
        } finally {
            input.close();
        }
    }
}
TOP

Related Classes of com.asakusafw.compiler.flow.VolatilePackager

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.