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

de.svws_nrw.base.ResourceUtils Maven / Gradle / Ivy

package de.svws_nrw.base;

import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.nio.file.DirectoryStream;
import java.nio.file.FileSystem;
import java.nio.file.FileSystems;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import com.fasterxml.jackson.databind.ObjectMapper;



/**
 * Eine Klasse mit Hilfsfunktionen zum Zugriff auf Java-Resourcen
 */
public final class ResourceUtils {

	/** Eine Map für die bereits geöffneten Jar-Dateisysteme */
	private static final HashMap jarFS = new HashMap<>();

	private static final String FILE_EXTENSION_JSON = ".json";


	private ResourceUtils() {
		throw new IllegalStateException("Instantiation not allowed");
	}

	/**
	 * Ermittelt alle Dateien, die in dem angebenen Pfad path liegen und zu dem
	 * Package mit dem Name packageName oder einem Sub-Package davon gehören
	 * sowie die angegebene Dateiendung haben.
	 *
	 * @param fs              das Dateisystem, auf dem die Dateien gesucht werden.
	 * @param path            der Pfad in den Classpath-Resourcen
	 * @param packagePath     der relative Pfad für das Packages
	 * @param fileextension   die Dateiendung
	 *
	 * @return eine List mit den Pfaden der gefundenen Dateien
	 *
	 * @throws IOException wenn ein Fehler beim Lesen der Dateien auftritt
	 */
	private static List getFilesInPath(final FileSystem fs, final String path, final String packagePath, final String fileextension) throws IOException {
		final List classes = new ArrayList<>();
		final Path fullPath = fs.getPath(path + (path.endsWith("/") ? "" : "/") + packagePath);
		if (!Files.isDirectory(fullPath))
			return classes;
		try (DirectoryStream dirStream = Files.newDirectoryStream(fullPath)) {
			for (final Path p : dirStream) {
				if (Files.isDirectory(p)) {
					classes.addAll(getFilesInPath(fs, path, packagePath + "/" + p.getFileName(), fileextension));
				} else if (Files.isRegularFile(p) && p.toString().endsWith(fileextension)) {
					classes.add(p);
				}
			}
		} catch (final IOException e) {
			throw new IOException("Fehler beim Lesen der Dateien im Pfad " + path, e);
		}
		return classes;
	}


	/**
	 * Erstellt einen Pfad auf das gezippte Dateisystem einer JAR-Datei, die
	 * mit der übergebene uri angegeben wird.
	 *
	 * @param uri   die URI für das JAR-Dateisystem
	 *
	 * @return der Pfad in das JAR-Dateisystem
	 *
	 * @throws IOException   falls das JAR-Dateisystem nicht erstellt werden kann
	 */
	@SuppressWarnings("resource")
	private static FileSystem getJARFileSystem(final URI uri) throws IOException {
		final String[] array = uri.toString().split("!");
		FileSystem fs = jarFS.get(array[0]);
		if (fs != null)
			return fs;
		try {
			fs = FileSystems.getFileSystem(URI.create(array[0]));
			jarFS.put(array[0], fs);
			return fs;
		} catch (@SuppressWarnings("unused") final RuntimeException e) {
			// try to create a new Filesystem...
			final Map env = new HashMap<>();
			fs = FileSystems.newFileSystem(URI.create(array[0]), env);
			jarFS.put(array[0], fs);
			return fs;
		}
	}


	/**
	 * Ermittelt das Path-Objekt für den Zugriff auf die Datei mit dem angegebenen Dateinamen.
	 *
	 * @param filename   der Dateiname
	 *
	 * @return das Path-Objekt
	 */
	@SuppressWarnings("resource")
	public static Path getFile(final String filename) {
		Path path = null;
		try {
			final URL url = ResourceUtils.class.getClassLoader().getResource(filename);
			final URI uri = url.toURI();
			if ("jar".equals(uri.getScheme())) {
				final FileSystem fs = getJARFileSystem(uri);
				final String[] array = uri.toString().split("!");
				path = fs.getPath(array[1]);
			} else {
				path = Paths.get(uri);
			}
		} catch (URISyntaxException | IOException e) {
			e.printStackTrace();
		}
		return path;
	}


	/**
	 * Liest den UTF8-kodierten Text aus der angebenen Datei ein und gibt
	 * diesen als String zurück.
	 *
	 * @param filename   der Dateiname
	 *
	 * @return der Text der Datei als String oder null im Fehlerfall
	 */
	public static String text(final String filename) {
		try {
			final Path path = getFile(filename);
			return Files.readString(path, StandardCharsets.UTF_8);
		} catch (final IOException e) {
			e.printStackTrace();
			return null;
		}
	}


	/**
	 * Hilfsmethode für {@link ResourceUtils#getFilesInPackage(String, String)}. Bestimmt
	 * für die übergebene URL die entsprechenden Dateien und schreibt {@link Path}-Objekt
	 * für diese in die Liste.
	 *
	 * @param url             die URL des Packages
	 * @param packagePath     der Pfad für das Package
	 * @param result          die Liste, wo die {@link Path}-Objekt für die Dateien ergänzt werden
	 * @param fileextension   die Dateiendung
	 *
	 * @throws IOException    bei einem Fehler beim Zugriff auf das Package
	 */
	@SuppressWarnings("resource")
	private static void getFilesInPackageFromURL(final URL url, final String packagePath, final List result, final String fileextension)
			throws IOException {
		final URI uri;
		try {
			uri = url.toURI();
		} catch (@SuppressWarnings("unused") final URISyntaxException e) {
			return;
		}
		Path path = null;
		if ("jar".equals(uri.getScheme())) {
			final FileSystem fs = getJARFileSystem(uri);
			final String[] array = uri.toString().split("!");
			path = fs.getPath(array[1]);
			final int j = Paths.get(packagePath).getNameCount();
			for (int i = 0; i < j; i++)
				path = path.getParent();
			result.addAll(getFilesInPath(fs, path.toString(), packagePath, fileextension));
		} else {
			path = Paths.get(uri);
			final int j = Paths.get(packagePath).getNameCount();
			for (int i = 0; i < j; i++)
				path = path.getParent();
			final FileSystem fs = FileSystems.getDefault();
			result.addAll(getFilesInPath(fs, path.toString(), packagePath, fileextension));
		}
	}

	/**
	 * Ermittelt alle Dateien, die mit dem Classloader dieser Klasse in dem Classpath in
	 * dem Package packageName oder einem Sub-Package davon verfügbar sind sowie
	 * die angegebene Dateiendung haben.
	 *
	 * @param packageName     das Package
	 * @param fileextension   die Dateiendung
	 *
	 * @return eine List mit den Pfaden der gefundenen Dateien
	 */
	public static List getFilesInPackage(final String packageName, final String fileextension) {
		final List result = new ArrayList<>();
		final Enumeration res;
		try {
			final String packagePath = packageName.replace(".", "/");
			res = ResourceUtils.class.getClassLoader().getResources(packagePath);
			while (res.hasMoreElements())
				getFilesInPackageFromURL(res.nextElement(), packagePath, result, fileextension);
		} catch (final IOException e1) {
			e1.printStackTrace();
		}
		return result;
	}


	/**
	 * Lädt alle JSON-Dateien aus dem angegebenen Package, welche das angegebene Präfix haben und
	 * die angegebene Dateiendung. Die JSON-Objekt werden dann in Objekte der angebenenen
	 * Klasse gemappt.
	 *
	 * @param    			die Klasse, von welcher die neuen Objekte erzeugt werden
	 * @param resourcePackage   das Package
	 * @param prefix			das benötigte Präfix im Dateinamen
	 * @param clazz             das Klassenobjekt der Klasse, von welcher neue Objekte ereugt werden
	 *
	 * @return eine Map, welche dem Teil des Dateinamens ohne Präfix und Endung das neu erzeugte Objekt zuordnet
	 *
	 * @throws IOException bei einem Fehler beim Laden der JSON-Daten
	 */
	public static  Map json2Classes(final String resourcePackage, final String prefix, final Class clazz) throws IOException {
		return json2Classes(resourcePackage, prefix, "", clazz);
	}


	/**
	 * Lädt alle JSON-Dateien aus dem angegebenen Package, welche das angegebene Präfix haben und
	 * die angegebene Dateiendung. Die JSON-Objekt werden dann in Objekte der angebenenen
	 * Klasse gemappt.
	 *
	 * @param    			die Klasse, von welcher die neuen Objekte erzeugt werden
	 * @param resourcePackage   das Package
	 * @param prefix			das benötigte Präfix im Dateinamen
	 * @param suffix            das benötigte Suffix im Dateinamen (vor dem .json)
	 * @param clazz             das Klassenobjekt der Klasse, von welcher neue Objekte ereugt werden
	 *
	 * @return eine Map, welche dem Teil des Dateinamens ohne Präfix und Endung das neu erzeugte Objekt zuordnet
	 *
	 * @throws IOException bei einem Fehler beim Laden der JSON-Daten
	 */
	public static  Map json2Classes(final String resourcePackage, final String prefix, final String suffix, final Class clazz)
			throws IOException {
		final Map classes = new TreeMap<>();
		final List paths = ResourceUtils.getFilesInPackage(resourcePackage, FILE_EXTENSION_JSON);
		final ObjectMapper mapper = new ObjectMapper();
		for (final Path filePath : paths) {
			final String filename = filePath.getFileName().toString();
			try {
				if (filename.toLowerCase().startsWith(prefix.toLowerCase()) && filename.toLowerCase().endsWith((suffix + FILE_EXTENSION_JSON).toLowerCase())) {
					final String name = filename.substring(prefix.length(), filename.length() - (suffix + FILE_EXTENSION_JSON).length());
					final String json = Files.readString(filePath, StandardCharsets.UTF_8);
					classes.put(name, mapper.readValue(json, clazz));
				}
			} catch (final IOException e) {
				throw new IOException("Fehler beim Lesen aus der Datei " + filename + "!", e);
			}
		}
		return classes;
	}

	/**
	 * Lädt alle JSON-Dateien aus dem angegebenen Package, welche das angegebene Präfix haben und
	 * die angegebene Dateiendung. Die JSON-Objekt werden dann in Objekte der angebenenen
	 * Klasse gemappt.
	 *
	 * @param    			die Klasse, von welcher die neuen Objekte erzeugt werden
	 * @param resourcePackage   das Package
	 * @param prefix			das benötigte Präfix im Dateinamen
	 * @param suffix            das benötigte Suffix im Dateinamen (vor dem .json)
	 * @param clazz             das Klassenobjekt der Klasse, von welcher neue Objekte ereugt werden
	 *
	 * @return eine Map, welche dem Teil des Dateinamens ohne Präfix und Endung das neu erzeugte Objekt zuordnet
	 *
	 * @throws IOException bei einem Fehler beim Laden der JSON-Daten
	 */
	public static  Map> json2Lists(final String resourcePackage, final String prefix, final String suffix, final Class clazz)
			throws IOException {
		final Map> classes = new TreeMap<>();
		final List paths = ResourceUtils.getFilesInPackage(resourcePackage, FILE_EXTENSION_JSON);
		final ObjectMapper mapper = new ObjectMapper();
		for (final Path filePath : paths) {
			final String filename = filePath.getFileName().toString();
			try {
				if (filename.toLowerCase().startsWith(prefix.toLowerCase()) && filename.toLowerCase().endsWith((suffix + FILE_EXTENSION_JSON).toLowerCase())) {
					final String name = filename.substring(prefix.length(), filename.length() - (suffix + FILE_EXTENSION_JSON).length());
					final String json = Files.readString(filePath, StandardCharsets.UTF_8);
					final List list = mapper.readValue(json, mapper.getTypeFactory().constructCollectionType(List.class, clazz));
					classes.put(name, list);
				}
			} catch (final IOException e) {
				throw new IOException("Fehler beim Lesen aus der Datei " + filename + "!", e);
			}
		}
		return classes;
	}

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy