All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.hazelcast.org.apache.calcite.util.javac.JaninoCompiler Maven / Gradle / Ivy

There is a newer version: 5.5.0
Show newest version
/*
 * 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 com.hazelcast.org.apache.calcite.util.javac;

import com.hazelcast.org.apache.calcite.config.CalciteSystemProperty;

import com.hazelcast.org.checkerframework.checker.nullness.qual.Nullable;
import com.hazelcast.org.codehaus.commons.compiler.util.resource.MapResourceFinder;
import com.hazelcast.org.codehaus.commons.compiler.util.resource.ResourceFinder;
import com.hazelcast.org.codehaus.janino.JavaSourceClassLoader;
import com.hazelcast.org.codehaus.janino.util.ClassFile;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.util.HashMap;
import java.util.Map;

import static java.util.Objects.requireNonNull;

/**
 * JaninoCompiler implements the {@link JavaCompiler} interface by
 * calling Janino.
 */
public class JaninoCompiler implements JavaCompiler {
  //~ Instance fields --------------------------------------------------------

  public JaninoCompilerArgs args = new JaninoCompilerArgs();

  // REVIEW jvs 28-June-2004:  pool this instance?  Is it thread-safe?
  private @Nullable AccountingClassLoader classLoader;

  //~ Constructors -----------------------------------------------------------

  public JaninoCompiler() {
  }

  //~ Methods ----------------------------------------------------------------

  // implement JavaCompiler
  @Override public void compile() {
    // REVIEW: SWZ: 3/12/2006: When this method is invoked multiple times,
    // it creates a series of AccountingClassLoader objects, each with
    // the previous as its parent ClassLoader.  If we refactored this
    // class and its callers to specify all code to compile in one
    // go, we could probably just use a single AccountingClassLoader.

    String destdir = requireNonNull(args.destdir, "args.destdir");
    String fullClassName = requireNonNull(args.fullClassName, "args.fullClassName");
    String source = requireNonNull(args.source, "args.source");

    ClassLoader parentClassLoader = args.getClassLoader();
    if (classLoader != null) {
      parentClassLoader = classLoader;
    }

    Map sourceMap = new HashMap<>();
    sourceMap.put(
        ClassFile.getSourceResourceName(fullClassName),
        source.getBytes(StandardCharsets.UTF_8));
    MapResourceFinder sourceFinder = new MapResourceFinder(sourceMap);

    AccountingClassLoader classLoader = this.classLoader =
        new AccountingClassLoader(
            parentClassLoader,
            sourceFinder,
            null,
            destdir == null ? null : new File(destdir));
    if (CalciteSystemProperty.DEBUG.value()) {
      // Add line numbers to the generated janino class
      classLoader.setDebuggingInfo(true, true, true);
    }
    try {
      classLoader.loadClass(fullClassName);
    } catch (ClassNotFoundException ex) {
      throw new RuntimeException("while compiling " + fullClassName, ex);
    }
  }

  // implement JavaCompiler
  @Override public JavaCompilerArgs getArgs() {
    return args;
  }

  // implement JavaCompiler
  @Override public ClassLoader getClassLoader() {
    return getAccountingClassLoader();
  }

  private AccountingClassLoader getAccountingClassLoader() {
    return requireNonNull(classLoader, "classLoader is null. Need to call #compile()");
  }

  // implement JavaCompiler
  @Override public int getTotalByteCodeSize() {
    return getAccountingClassLoader().getTotalByteCodeSize();
  }

  //~ Inner Classes ----------------------------------------------------------

  /**
   * Arguments to an invocation of the Janino compiler.
   */
  public static class JaninoCompilerArgs extends JavaCompilerArgs {
    @Nullable String destdir;
    @Nullable String fullClassName;
    @Nullable String source;

    public JaninoCompilerArgs() {
    }

    @Override public boolean supportsSetSource() {
      return true;
    }

    @Override public void setDestdir(String destdir) {
      super.setDestdir(destdir);
      this.destdir = destdir;
    }

    @Override public void setSource(String source, String fileName) {
      this.source = source;
      addFile(fileName);
    }

    @Override public void setFullClassName(String fullClassName) {
      this.fullClassName = fullClassName;
    }
  }

  /**
   * Refinement of JavaSourceClassLoader which keeps track of the total
   * bytecode length of the classes it has compiled.
   */
  private static class AccountingClassLoader extends JavaSourceClassLoader {
    private final @Nullable File destDir;
    private int nBytes;

    AccountingClassLoader(
        ClassLoader parentClassLoader,
        ResourceFinder sourceFinder,
        @Nullable String optionalCharacterEncoding,
        @Nullable File destDir) {
      super(
          parentClassLoader,
          sourceFinder,
          optionalCharacterEncoding);
      this.destDir = destDir;
    }

    int getTotalByteCodeSize() {
      return nBytes;
    }

    @Override public @Nullable Map generateBytecodes(String name)
        throws ClassNotFoundException {
      final Map map = super.generateBytecodes(name);
      if (map == null) {
        return null;
      }

      if (destDir != null) {
        try {
          for (Map.Entry entry : map.entrySet()) {
            File file = new File(destDir, entry.getKey() + ".class");
            FileOutputStream fos = new FileOutputStream(file);
            fos.write(entry.getValue());
            fos.close();
          }
        } catch (IOException e) {
          throw new RuntimeException(e);
        }
      }

      // NOTE jvs 18-Oct-2006:  Janino has actually compiled everything
      // to bytecode even before all of the classes have actually
      // been loaded.  So we intercept their sizes here just
      // after they've been compiled.
      for (Object obj : map.values()) {
        byte[] bytes = (byte[]) obj;
        nBytes += bytes.length;
      }
      return map;
    }
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy