001/*
002 * Copyright (c) 2012-2017 Institut National des Sciences Appliquées de Lyon (INSA-Lyon)
003 *
004 * All rights reserved. This program and the accompanying materials
005 * are made available under the terms of the Eclipse Public License v1.0
006 * which accompanies this distribution, and is available at
007 * http://www.eclipse.org/legal/epl-v10.html
008 */
009
010package org.eclipse.golo.compiler;
011
012import java.io.InputStream;
013import java.util.List;
014
015/**
016 * Provides a facility to dynamically load Golo source code and access the generated code from a dedicated class loader.
017 * <p>
018 * Golo source files can be compiled and the resulting JVM bytecode be injected into the class loader. It is important
019 * to note that this class loader definition is not thread safe.
020 * <p>
021 * This class loader does not support reloading. Attempts to load source files that may produce the same bytecode
022 * definitions will resulting in exceptions.
023 */
024public class GoloClassLoader extends ClassLoader {
025
026  private final GoloCompiler compiler = new GoloCompiler();
027
028  /**
029   * Creates a class loader from a parent.
030   *
031   * @param parent the parent classloader.
032   */
033  public GoloClassLoader(ClassLoader parent) {
034    super(parent);
035  }
036
037  /**
038   * Creates a class loader from the default parent.
039   */
040  public GoloClassLoader() {
041    super();
042  }
043
044  /**
045   * Compiles and loads the resulting JVM bytecode for a Golo source file.
046   *
047   * @param goloSourceFilename    the source file name.
048   * @param sourceCodeInputStream the source input stream.
049   * @return the class matching the Golo module defined in the source.
050   * @throws GoloCompilationException if either of the compilation phase failed.
051   */
052  public synchronized Class<?> load(String goloSourceFilename, InputStream sourceCodeInputStream) throws GoloCompilationException {
053    List<CodeGenerationResult> results = compiler.compile(goloSourceFilename, sourceCodeInputStream);
054    Class<?> lastClassIsModule = null;
055    for (CodeGenerationResult result : results) {
056      byte[] bytecode = result.getBytecode();
057      lastClassIsModule = defineClass(null, bytecode, 0, bytecode.length);
058    }
059    return lastClassIsModule;
060  }
061}