001/*
002 * Copyright (c) 2012-2018 Institut National des Sciences Appliquées de Lyon (INSA Lyon) and others
003 *
004 * This program and the accompanying materials are made available under the
005 * terms of the Eclipse Public License 2.0 which is available at
006 * http://www.eclipse.org/legal/epl-2.0.
007 *
008 * SPDX-License-Identifier: EPL-2.0
009 */
010package gololang;
011
012import org.eclipse.golo.cli.command.spi.CliCommand;
013import org.eclipse.golo.compiler.GoloClassLoader;
014import gololang.ir.GoloModule;
015
016import java.io.InputStream;
017import java.net.URL;
018
019import static java.util.Objects.requireNonNull;
020import static gololang.IO.toURL;
021
022/**
023 * A utility module containing functions to interact with the runtime environment.
024 */
025public final class Runtime {
026  private Runtime() {
027    // utility class
028  }
029
030  /**
031   * Get a boolean value from a system property or an environment variable.
032   *
033   * <p>Equivalent to {@code loadBoolean("true", prop, env, defaultValue)}
034   *
035   * @param prop system property to get the value from, ignored if {@code null}.
036   * @param env environment variable to get the value from, ignored if {@code null}.
037   * @param defaultValue value to return if neither the property nor the environment are defined.
038   */
039  public static boolean loadBoolean(String prop, String env, boolean defaultValue) {
040    return loadBoolean("true", prop, env, defaultValue);
041  }
042
043  /**
044   * Get a boolean value from a system property or an environment variable.
045   *
046   * <p>Checks if the property is defined and equals to the value (case insensitive), otherwise checks the environment
047   * variable, then use the default value.
048   *
049   * @param value content of the property.
050   * @param prop system property to get the value from, ignored if {@code null}.
051   * @param env environment variable to get the value from, ignored if {@code null}.
052   * @param defaultValue value to return if neither the property nor the environment are defined.
053   * @throws NullPointerException if {@code value} is null and one of the property or environment is defined.
054   */
055  public static boolean loadBoolean(String value, String prop, String env, boolean defaultValue) {
056    String val = null;
057    if (prop != null) {
058      val = System.getProperty(prop);
059    }
060    if (val == null && env != null) {
061      val = System.getenv(env);
062    }
063    if (val == null) {
064      return defaultValue;
065    }
066    return val.toLowerCase().equals(value.toLowerCase());
067  }
068
069  private static boolean debug = loadBoolean("golo.debug", "GOLO_DEBUG", false);
070  private static boolean showStackTrace = loadBoolean("golo.debug.trace", "GOLO_DEBUG_TRACE", true);
071
072  /**
073   * Checks if debug mode is active.
074   *
075   * <p>The initial value is false, but can be redefined using the {@code golo.debug} system property, or the
076   * {@code GOLO_DEBUG} environment variable.
077   */
078  public static boolean debugMode() {
079    return debug;
080  }
081
082  /**
083   * Defines debug mode.
084   */
085  public static void debugMode(boolean v) {
086    debug = v;
087  }
088
089  /**
090   * Checks if the main golo command should print stack traces on error.
091   */
092  public static boolean showStackTrace() {
093    return showStackTrace;
094  }
095
096  /**
097   * Defines if the main golo command should print stack traces on error.
098   */
099  public static void showStackTrace(boolean v) {
100    showStackTrace = v;
101  }
102
103  private static CliCommand command;
104
105  /**
106   * Defines the golo command currently used.
107   *
108   * <p>This command is called at init time and should not be called in userland code.
109   */
110  public static void command(CliCommand cmd) {
111    command = requireNonNull(cmd);
112  }
113
114  /**
115   * Returns the golo command currently used.
116   */
117  public static CliCommand command() {
118    return command;
119  }
120
121  /**
122   * Returns the current thread class loader.
123   * <p>
124   * Possibly wrapped in a {@code GoloClassLoader} if necessary.
125   */
126  public static GoloClassLoader classLoader() {
127    ClassLoader cl = Thread.currentThread().getContextClassLoader();
128    if (cl instanceof GoloClassLoader) {
129      return (GoloClassLoader) cl;
130    }
131    return new GoloClassLoader(cl);
132  }
133
134  /**
135   * Load a golo file given its path or URL.
136   *
137   * <p>Equivalent to {@code load(module, true)}.
138   *
139   * @param module can be a {@code String}, a {@code java.nio.file.Path}, a {@code java.net.URL} or a {@code java.net.URI} identifying the file to load, or directly a {@link GoloModule}.
140   * @return the loaded module class.
141   * @see #load(Object, boolean)
142   */
143  public static Class<?> load(Object module) throws Exception {
144    return load(module, true);
145  }
146
147  /**
148   * Load a golo file given its path or URL.
149   *
150   * <p>If {@code failOnException} is false, any exception is swallowed and null is return.
151   *
152   * @param module can be a {@code String}, a {@code java.nio.file.Path}, a {@code java.net.URL} or a {@code java.net.URI} identifying the file to load, or directly a {@link GoloModule}.
153   * @param failOnException re-raise exception or not
154   * @return the loaded module class, or {@code null} if an error occurred and {@code failOnException} is {@code false}
155   * @see #load(Object, boolean)
156   */
157  public static Class<?> load(Object module, boolean failOnException) throws Exception {
158    try {
159      if (module instanceof GoloModule) {
160        GoloModule mod = (GoloModule) module;
161        return classLoader().load(mod.sourceFile(), mod);
162      }
163      URL url = toURL(module);
164      try (InputStream is = url.openStream()) {
165        return classLoader().load(module.toString(), is);
166      }
167    } catch (Exception e) {
168      if (failOnException) {
169        throw e;
170      }
171      return null;
172    }
173  }
174
175  /**
176   * Returns the current golo version.
177   */
178  public static String version() {
179    return org.eclipse.golo.cli.command.Metadata.VERSION;
180  }
181}