PathMap.java
package Hoot.Runtime.Maps;
import java.io.*;
import java.util.*;
import static Hoot.Runtime.Maps.Package.*;
import static Hoot.Runtime.Names.Operator.Dot;
import static Hoot.Runtime.Functions.Utils.*;
import Hoot.Runtime.Faces.Logging;
/**
* Maps the classes located in an element of a class path.
* Locates all package folders relative to a base path from the class path.
*
* @author nik <nikboyd@sonic.net>
* @see "Copyright 1999,2021 Nikolas S Boyd."
* @see "Permission is granted to copy this work provided this copyright statement is retained in all copies."
*/
public class PathMap implements Logging {
public PathMap(String folderPath) { basePath = folderPath; }
protected String basePath; // the absolute base path mapped by this instance
static String normalPath(String p) { return Package.normalPath(p); }
String normalBase() { return normalPath(basePath); }
public File locate(String folder) { File f = new File(normalBase(), normalPath(folder)); return (f.exists() ? f : null); }
File locateRelative(String folderPath) { // all paths are relative to the basePath
if (folderPath.isEmpty()) return new File(normalBase());
return normalPath(folderPath).startsWith(normalBase()) ?
new File(normalPath(folderPath)) : new File(normalBase(), normalPath(folderPath)) ; }
// maps a package folder name to a set of class names.
protected Map<String, List<String>> map = new HashMap<>();
public List<String> classesInPackage(Package p) { return classesInFolder(p.pathname()); }
public List<String> classesInFolder(String n) {
if (map.isEmpty()) load(); return map.getOrDefault(n, emptyList(String.class)); }
// maps a face name to its folder path
protected Map<String, String> faceMap = emptyWordMap();
String locateFace(String faceName) { return faceMap.get(faceName); }
public boolean hasFace(String faceName) { return faceMap.containsKey(faceName); }
String formatPath(String folder, String faceName) { return folder + Package.separator() + faceName; }
public List<String> listFaces() { return collectList(list -> faceMap.forEach((k,v) -> list.add(formatPath(v,k)))); }
public Set<Package> getPackages() { return collectSet(set -> faceMap.forEach((k,v) -> set.add(packageNamed(v)))); }
Package packageNamed(String name) { return Package.named(Package.nameFrom(name)); }
private String packageForFace(String faceName) { return Package.nameFrom(locateFace(faceName)); }
public String packageContaining(String faceName) { return hasFace(faceName) ? packageForFace(faceName) : Empty ; }
public static final String ClassFileType = ".class";
static String classNameWithoutType(String n) { return n.substring(0, n.length() - ClassFileType.length()); }
public static boolean namesClass(String n) { return hasSome(n) && n.endsWith(ClassFileType); }
public static String className(String n) { return (!namesClass(n)) ? n : classNameWithoutType(n); }
// skip this class that causes problems
static final String SkippedClass = "MulticastDnsAdvertiser";
protected void addMapped(String folderName, String fileName) {
String faceName = className(fileName);
if (SkippedClass.equals(faceName)) return;
List<String> faceNames = map.getOrDefault(folderName, emptyList(String.class));
packageNamed(folderName).loadFace(faceName);
faceMap.put(faceName, folderName);
faceNames.add(faceName);
}
public void load() { load(Empty); reportAdded(); }
protected void load(String folderName) {
File directory = locateRelative(folderName);
String[] list = directory.list();
// note: depth first recursive descent of folders
int count = list.length;
for (int n = 0; n < count; n++) {
String fileName = list[n];
File file = new File(directory, fileName);
if (file.isDirectory()) { // load subdirectory
load(folderName.isEmpty() ? fileName : file.getAbsolutePath());
}
else if (namesClass(fileName)) {
addMapped(folderName, classNameWithoutType(fileName));
}
}
}
public void println() { System.out.println(); }
static final String AddReport = "loaded %d faces into %s";
protected void reportAdded() {
map.forEach((folderName, faceNames) -> {
if (ClassPath.matchHoots(folderName))
report(format(AddReport, faceNames.size(), folderName));
});
}
} // PathMap