1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 | package Torello.Java.Build; import Torello.Java.FileNode; import Torello.Java.RTC; import Torello.Java.EXCC; import Torello.Java.Additional.ByteArrClassLoader; import Torello.Java.ReadOnly.ReadOnlyList; import Torello.Java.ReadOnly.ReadOnlyArrayList; import static Torello.Java.C.BYELLOW; import static Torello.Java.C.BGREEN; import static Torello.Java.C.BRED; import static Torello.Java.C.BWHITE; import static Torello.Java.C.BRED_BKGND; import static Torello.Java.C.RESET; import java.io.IOException; import java.io.File; // All this thing does is enter the "bp" directory that is passed to this class // only method. That directory is, suprisingly, "bp.pkgRootDirector" + "data-files/". // // It scans the *ENTIRE* directory-tree (which, literally, just means that directory and also any // and all sub-directories it has) for all Java '.class'-Files. // // Each '.class' File that is found is checked to see whether it is Assignable-To the interface // "Torello.Java.Build.DataFileBuilderClass.class". If a '.class'-File is assignable into that // interface, then it must have a 'build(String rootDir)' method. Any '.class' File which does // implement that interface (and therefore has the 'build' method just mention) is invoked! // // IT IS UP TO THE USER TO MAKE SURE THAT THE SPECIFIED 'build(String)' METHOD ACTUALLY OUTPUTS // ANY-AND-ALL DATA-FILES EXPECTED FOR THAT PACKAGE, INTO ITS "data-files/" SUB-DIRECTORY. class RunDataFilesBuilders { @SuppressWarnings({"unchecked", "rawtypes"}) static int run(final BuildPackage bp) throws IOException { final ByteArrClassLoader bacl = new ByteArrClassLoader(); final String rootDir = bp.pkgRootDirectory + "data-files" + File.separator; // Read All '.class' Files, and then generate a List<Class> of all of the Class-Files which // implement the DataFileBuilderClass interface. Save those classes into a ReadOnlyList @SuppressWarnings("rawtypes") final ReadOnlyList<Class> dfbClasses = FileNode .createRoot(rootDir) .loadTree(-1, FileNode.CLASS_FILES, null) .flattenJustFiles(RTC.FULLPATH_STREAM()) .map((String fileName) -> (Class) bacl.readJavaClassNOIOE(fileName)) .filter((Class c) -> DataFileBuilderClass.class.isAssignableFrom(c)) .collect(ReadOnlyArrayList.streamCollector()); // If there are no such classes, print a message and return immediately if (dfbClasses.size() == 0) { System.out.println( '\n' + "Data-Files Directory:\n " + BYELLOW + rootDir + RESET + '\n' + "Does not contain any '.class' Files which implement the DataFileBuilderClass " + "interface\n\n" + "Exiting..." ); return 0; } // Iterate all classes which implemented the DataFileBuilderClass interface! for (final Class c : dfbClasses) { final String cName = c.getCanonicalName(); System.out.println( '\n' + BRED_BKGND + BWHITE + " Running Class: " + RESET + ' ' + BGREEN + cName + RESET + '\n' ); final DataFileBuilderClass dfbc; try { dfbc = (DataFileBuilderClass) c.getDeclaredConstructor().newInstance(); } // NOTE: Catching Throwable-Class "Error" is extremely uncommon in Java, but this // really is one of the places where you have to do it.f // // The Method "newInstance" throws an "ExceptionInInitializerError" if the user's // Class throws an exception when attempting to build a new instance using the class' // Zero-Argument Constructor. // // Not Exactly sure why ExceptionInInitializerError is an Error, rather than Exception, // but I'm really not going to argue about it right now... catch (Exception | Error e) { System.out.println( EXCC.toString(e) + '\n' + e.getMessage() + "\n\n" + "For DataFileBuildClass:\n " + BYELLOW + cName + RESET + '\n' + "Unable to invoke the Zero-Argument Constructor for that Class.\n" + "Did you remember to declare a public, Zero-Argument Constructor?\n" ); System.exit(0); /* shhh compiler !! */ throw null; } dfbc.build(rootDir); } System.out.println(); // This is the count on how many Class-Files 'build(String)' methods were invoked. // It is placed into a Counts-Table, so that a Count-Summary may be printed at the end // of the "BuildDataFiles" experience! return dfbClasses.size(); } } |