package com.equalexperts.logging; import java.io.BufferedWriter; import java.io.File; import java.io.FileWriter; import java.io.PrintWriter; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.Arrays; import java.util.List; public class GenerateLogMessageDocumentation { public static void main(String... args) throws Exception { String head = args[0]; String[] tail = Arrays.copyOfRange(args, 1, args.length); new GenerateLogMessageDocumentation(head, tail).generate(); } private final File outputFile; private final List<String> classFoldersToDocument; GenerateLogMessageDocumentation(String outputFile, String... classFoldersToDocument) { this.outputFile = new File(outputFile); this.classFoldersToDocument = Arrays.asList(classFoldersToDocument); } public void generate() throws Exception { try(PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(outputFile)))) { for(String it : classFoldersToDocument) { Holder<Boolean> logMessageImplementationFound = new Holder<>(false); Path classFolder = Paths.get(it); Files.walk(classFolder) .filter(p -> !Files.isDirectory(p)) .filter(p -> p.toString().endsWith(".class")) .map(p -> loadClass(classFolder, p)) .filter(this::isValidClass) .peek(c -> logMessageImplementationFound.set(true)) .onClose(() -> { if (!logMessageImplementationFound.get()) { throw new RuntimeException("No LogMessage implementations found in " + classFolder.toString()); } }) .forEach(c -> documentLogMessageEnum(out, c)); } } } private Class<?> loadClass(Path classFolder, Path classFile) { Path relativePath = classFolder.relativize(classFile); String className = toClassName(relativePath); try { return Class.forName(className); } catch (ClassNotFoundException e) { //this is an inner class, or not a class, etc return null; } } private String toClassName(Path relativePath) { String classNameWithDotClassExtension = relativePath.toString().replace('/', '.').replace('$', '.'); return classNameWithDotClassExtension.substring(0, (classNameWithDotClassExtension.length() - ".class".length())); } private void documentLogMessageEnum(PrintWriter out, Class<?> clazz) { out.print(clazz.getName()); out.println(":"); out.println("Code\t\tMessage"); out.println("==========\t=========="); for(Object o : clazz.getEnumConstants()) { LogMessage message = (LogMessage) o; out.printf("%s\t%s\n", message.getMessageCode(), message.getMessagePattern()); } out.println(); } private boolean isValidClass(Class<?> clazz) { return clazz != null && clazz.isEnum() && LogMessage.class.isAssignableFrom(clazz); } private static class Holder<T> { private T instance; private Holder(T instance) { this.instance = instance; } public void set(T value) { instance = value; } public T get() { return instance; } } }