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 */
010
011package org.eclipse.golo.runtime;
012
013import java.util.function.Function;
014
015/**
016 * A {@code Loader} just encapsulate a {@code ClassLoader}. The class implements
017 * {@code java.util.function.Function<String, Class<?>>} so that a loader can be directly mapped to a stream of the
018 * names of the classes to load. Moreover, the {@code ClassNotFoundException} is catched to return
019 * {@code null}, allowing a more "flowing" use. For instance:
020 * <pre class="listing"><code class="lang-java" data-lang="java">
021 * Loader loader = Loader.forObject(this);
022 * Stream.of("java.lang.String", "gololang.Tuple", "foo.bar.Baz", "java.util.LinkedList")
023 *     .map(loader)
024 *     .filter(java.util.Objects::nonNull)
025 *     .map(klass -> dealWithTheClass(klass))
026 * </code></pre>
027 */
028public final class Loader implements Function<String, Class<?>> {
029  private final ClassLoader loader;
030
031  Loader(ClassLoader loader) {
032    this.loader = loader;
033  }
034
035  public static Loader forClassLoader(ClassLoader loader) {
036    return new Loader(loader);
037  }
038
039  /**
040   * Create a loader using the {@code ClassLoader} of the current thread.
041   *
042   * @return a {@code Loader}
043   */
044  public static Loader forCurrentThread() {
045    return new Loader(Thread.currentThread().getContextClassLoader());
046  }
047
048  /**
049   * Create a loader using the {@code ClassLoader} of the given class
050   *
051   * @param klass the class whose {@code ClassLoader} to use
052   * @return a {@code Loader}
053   */
054  public static Loader forClass(Class<?> klass) {
055    return new Loader(klass.getClassLoader());
056  }
057
058  /**
059   * Create a loader using the {@code ClassLoader} of the class of the given object
060   *
061   * @param obj the object whose class {@code ClassLoader} to use
062   * @return a {@code Loader}
063   */
064  static Loader forObject(Object obj) {
065    return forClass(obj.getClass());
066  }
067
068  /**
069   * Load the given class.
070   * <p>
071   * This only delegates to the underlying class loader, but returns {@code null} instead
072   * of throwing a {@code ClassNotFoundException} exception.
073   *
074   * @return the class if load succeed, {@code null} otherwise.
075   */
076  public Class<?> load(String name) {
077    try {
078      return loader.loadClass(name);
079    } catch (ClassNotFoundException e) {
080      return null;
081    }
082  }
083
084  /**
085   * Just delegate to {@link #load(java.lang.String)} to implement {@code Function}.
086   *
087   * @see #load(java.lang.String)
088   */
089  @Override
090  public Class<?> apply(String name) {
091    return load(name);
092  }
093}
094
095