001// Copyright (c) FIRST and other WPILib contributors.
002// Open Source Software; you can modify and/or share it under the terms of
003// the WPILib BSD license file in the root directory of this project.
004
005package edu.wpi.first.util;
006
007import java.io.BufferedReader;
008import java.io.IOException;
009import java.io.InputStream;
010import java.io.InputStreamReader;
011import java.nio.charset.StandardCharsets;
012import java.nio.file.Files;
013import java.nio.file.NoSuchFileException;
014import java.nio.file.Paths;
015
016/**
017 * Loads classes by name. Can be used at any time, but is most commonly used to preload classes at
018 * the start of the program to avoid unpredictable delays due to lazy classloading later in program
019 * execution.
020 */
021public final class ClassPreloader {
022  private ClassPreloader() {}
023
024  /**
025   * Loads classes from an iterable.
026   *
027   * @param classNames iterable of class names
028   * @return Number of classes loaded.
029   */
030  public static int preload(Iterable<String> classNames) {
031    int count = 0;
032    for (String i : classNames) {
033      try {
034        Class.forName(i);
035        count++;
036      } catch (ClassNotFoundException e) {
037        System.out.println("Could not preload " + i);
038      }
039    }
040    return count;
041  }
042
043  /**
044   * Loads classes.
045   *
046   * @param classNames array of class names
047   * @return Number of classes loaded.
048   */
049  public static int preload(String... classNames) {
050    int count = 0;
051    for (String i : classNames) {
052      try {
053        Class.forName(i);
054        count++;
055      } catch (ClassNotFoundException e) {
056        System.out.println("Could not preload " + i);
057      }
058    }
059    return count;
060  }
061
062  /**
063   * Loads classes from a buffered reader. The input is expected to be one class name per line.
064   * Blank lines and lines starting with a semicolon are ignored.
065   *
066   * @param reader Reader
067   * @return Number of classes loaded.
068   */
069  public static int preload(BufferedReader reader) {
070    int count = 0;
071    try {
072      String line = reader.readLine();
073      while (line != null) {
074        if (!line.isEmpty() && !line.startsWith(";")) {
075          try {
076            Class.forName(line);
077            count++;
078          } catch (ClassNotFoundException e) {
079            System.out.println("Could not preload " + line);
080          }
081        }
082        line = reader.readLine();
083      }
084    } catch (IOException e) {
085      System.out.println("Error when reading preload file: " + e);
086    }
087    return count;
088  }
089
090  /**
091   * Loads classes from an input stream. The input is expected to be one class name per line. Blank
092   * lines and lines starting with a semicolon are ignored.
093   *
094   * @param stream input stream
095   * @return Number of classes loaded.
096   */
097  public static int preload(InputStream stream) {
098    return preload(new BufferedReader(new InputStreamReader(stream)));
099  }
100
101  /**
102   * Loads classes from a file. The input is expected to be one class name per line. Blank lines and
103   * lines starting with a semicolon are ignored.
104   *
105   * @param filename filename
106   * @return Number of classes loaded.
107   */
108  public static int preloadFile(String filename) {
109    try (BufferedReader reader =
110        Files.newBufferedReader(Paths.get(filename), StandardCharsets.UTF_8)) {
111      return preload(reader);
112    } catch (NoSuchFileException e) {
113      System.out.println("Could not open preload file " + filename + ": " + e);
114    } catch (IOException e) {
115      System.out.println("Could not close preload file " + filename + ": " + e);
116    }
117    return 0;
118  }
119}