package com.github.xbn.testdev; import java.util.Iterator; import java.util.Arrays; import java.io.File; import java.util.Objects; import java.io.IOException; import com.github.xbn.io.RTIOException; import java.util.List; import org.apache.commons.io.FileUtils; import com.github.xbn.lang.CrashIfObject; import static com.github.xbn.lang.XbnConstants.*; import com.github.xbn.regexutil.RegexGroupExtractor; import com.github.xbn.regexutil.RegexReplacer; import com.github.xbn.util.JavaRegexUtil; /** <p>Application that creates in composition stub functions (as in <a href="https://www.google.com/search?q=composition+versus+inheritance+java">composition versus inheritance</a>) for all {@code @CompositionContructor}s and {@code @CompositionFunction}s annotAted methods (as most commonly found in {@code "*Composer"} classes).</p> <p>{@code java com.github.xbn.testdev.CompositionStubUtil R:\jeffy\programming\sandbox\xbnjava\xbn\lang\chain\ChainableComposer.java}</p> <h3>Instructions for running this application as a tool in TextPad, on the current java file</h3> <pre>Command: cmd.exe Parameters: java xbn.testdev.CompositionStubUtil $File Initial directory: $FileDir</pre> **/ public class CompositionStubUtil { private CompositionStubUtil() { throw new IllegalStateException("Do not instantiate"); } private static final RegexGroupExtractor rexCNSTR = JavaRegexUtil.newRXForCnstrSigLineToNameAllParams(); private static final RegexGroupExtractor rexFUNC = JavaRegexUtil.newRXForFuncSigLineToRetTypNameAllParams(); private static final RegexReplacer rrPARAM_TYPE_NM_TO_NM = JavaRegexUtil.newRRForAllParamTypeNamesToNames(); private static final RegexReplacer rrPARAM_Y_NM_TO_Y = JavaRegexUtil.newRRForAllParamTypeNamesTo4FQTypes(); private static final String UNDR_GEN_UNDR = "_GENERICS_"; /** <p>YYY</p> * @exception RTIOException If an {@link java.io.IOException IOException} is thrown */ public static final void main(String[] as_1Rqd_pathToJavaFile) { /* String sCnstrNmInGrp = "\\b([\\w.]+)\\b"; String sOpenPrnThrPreParamNm1 = "\\((?:(?:[\\w.]+)\\b(?:|(?:<[?\\w\\[\\] ,.&]+>)|(?:<[^<]*<[?\\w\\[\\] ,.&]+>[^>]*>)|(?:<[^<]*<[^<]*<[?\\w\\[\\] ,.&]+>[^>]*>[^>]*>))((?:\\[\\]){0,})(\\.\\.\\.)?\\s+"; String sParamNmInGrp = "(\\w+)"; String sPostParam1ThrPreParamNm2 = "\\b(?![>\\[])\\s*(?:,\\s+\\b(?:[\\w.]+)\\b(?:|(?:<[?\\w\\[\\] ,.&]+>)|(?:<[^<]*<[?\\w\\[\\] ,.&]+>[^>]*>)|(?:<[^<]*<[^<]*<[?\\w\\[\\] ,.&]+>[^>]*>[^>]*>))((?:\\[\\]){0,})(\\.\\.\\.)?\\s+"; String sPostParam2 = "\\b(?![>\\[])\\s*){0,})?\\s*\\)"; String sRECnstr3Grps = "(" + sCnstrNmInGrp + sOpenPrnThrPreParamNm1 + sParamNmInGrp + sPostParam1ThrPreParamNm2 + sParamNmInGrp + sPostParam2 + ")"; */ String sPathJava = get1RqdParamPathToJavaFile(as_1Rqd_pathToJavaFile); try { appendForSourceX(System.out, sPathJava); } catch(IOException iox) { throw new RTIOException("Attempting get1RqdParamPathToJavaFile(as_1Rqd_pathToJavaFile): as_1Rqd_pathToJavaFile=" + Arrays.toString(as_1Rqd_pathToJavaFile), iox); } } /** <p>YYY</p> * @exception RTIOException If an {@link java.io.IOException IOException} is thrown */ public static final void appendForSource(Appendable to_appendTo, String sourceCode_path) { try { appendForSourceX(to_appendTo, (new File(sourceCode_path))); } catch(IOException iox) { throw new RTIOException("Attempting appendForSourceX(to_appendTo, (new File(sourceCode_path))): sourceCode_path=\"" + sourceCode_path + "\". to_appendTo=[" + to_appendTo + "]", iox); } } /** <p>YYY</p> * @exception RTIOException If an {@link java.io.IOException IOException} is thrown */ public static final void appendForSource(Appendable to_appendTo, File source_code) { try { appendForSourceX(to_appendTo, source_code); } catch(IOException iox) { throw new RTIOException("Attempting appendForSourceX(to_appendTo, source_code): source_code=\"" + source_code + "\". to_appendTo=[" + to_appendTo + "]", iox); } } public static final void appendForSourceX(Appendable to_appendTo, String sourceCode_path) throws IOException { appendForSourceX(to_appendTo, (new File(sourceCode_path))); } public static final void appendForSourceX(Appendable to_appendTo, File source_code) throws IOException { appendJavaFilePathWithDotsNoDtJava(to_appendTo, source_code); Iterator<String> lineItr = FileUtils.lineIterator(source_code); //Throws npx if null String sClassName = null; boolean bFuncsStarted = false; while(lineItr.hasNext()) { String sLn = lineItr.next().trim(); if(sLn.equals("@CompositionConstructor")) { String sCnstrSig = lineItr.next(); //CI !hasNext() // System.out.println("Constructor: " + sCnstrSig); // System.out.println("\t" + rexCNSTR.search(sCnstrSig).nextAsJoined(" // ")); List<String> ls = rexCNSTR.search(sCnstrSig).next(); if(sClassName == null) { StringBuilder sd = new StringBuilder(); sClassName = appendCompositionCnstrCallGetClsNm(sd, ls); to_appendTo.append("\tprivate final ").append(sClassName).append(UNDR_GEN_UNDR). append(" ").append(sXMK).append(";").append(LINE_SEP); to_appendTo.append(sd.toString()); } else { appendCompositionCnstrCallGetClsNm(to_appendTo, ls); } } else if(sLn.equals("@CompositionFunction")) { if(!bFuncsStarted) { to_appendTo.append("\t//Composition implementation: " + sClassName + "...START").append(LINE_SEP); bFuncsStarted = true; } String sFuncSig = getSigLinePastOtherAnnotations(sLn, lineItr); // System.out.println("Function: " + sFuncSig); // System.out.println("\t" + rexCNSTR.search(sFuncSig).nextAsJoined(" // ")); List<String> ls = rexFUNC.search(sFuncSig).next(); appendCompositionStubFunction(to_appendTo, ls, sClassName); } } to_appendTo.append("\t//Composition implementation: " + sClassName + "...END").append(LINE_SEP); } private static final String getSigLinePastOtherAnnotations(String selfCmprurrentLine, Iterator<String> line_itr) { while(selfCmprurrentLine.trim().startsWith("@")) { //The 1st call to trim is redundant //This passes through other annotation-only lines //that are between @Composition* and the signature selfCmprurrentLine = line_itr.next(); //CI !hasNext() } return selfCmprurrentLine; } public static final String appendCompositionCnstrCallGetClsNm(Appendable to_appendTo, List<String> ls_fromrex) throws IOException { String sCnstrName = ls_fromrex.get(0); String sAllParams = ls_fromrex.get(1); to_appendTo.append("\t\t").append(sXMK).append(" = new ").append(sCnstrName).append(UNDR_GEN_UNDR). append("("). append(rrPARAM_TYPE_NM_TO_NM.getReplaced(sAllParams)). append(");").append(LINE_SEP); return sCnstrName; } public static final String sU4PROT = "_4prot"; public static final void appendCompositionStubFunction(Appendable to_appendTo, List<String> ls_fromrex, String selfCmprlassName) throws IOException { String sReturnType = ls_fromrex.get(0); String sFuncName = ls_fromrex.get(1); String sAllParams = ls_fromrex.get(2); boolean b4Prot = sFuncName.endsWith(sU4PROT); boolean bVoid = sReturnType.equals("void"); String sAllParamNames = rrPARAM_TYPE_NM_TO_NM.getReplaced(sAllParams); to_appendTo.append("\t\t/").append("**").append(LINE_SEP); if(bVoid) { to_appendTo.append("\t\t\t<p>FUNC_JD_INTRO</p>").append(LINE_SEP); } to_appendTo.append("\t\t\t"); if(bVoid) { to_appendTo.append("<p>Equal to").append(LINE_SEP); to_appendTo.append("\t\t\t<br/>    "); } else { to_appendTo.append("@return "); } // rrPARAM_Y_NM_TO_Y.setDebug(System.out, true); to_appendTo.append("{@code <A HREF=\"" + sYMK + "/"). append(selfCmprlassName).append(".html\"><i>[").append(selfCmprlassName). append("]</i></a>.<A HREF=\"" + sYMK + "/").append(selfCmprlassName). append(".html#").append(sFuncName).append("("). append(rrPARAM_Y_NM_TO_Y.getReplaced(sAllParams)). append(")\">").append(sFuncName).append("</a>(" + sAllParamNames + ")}"); if(bVoid) { to_appendTo.append("</p>"); } to_appendTo.append(LINE_SEP); to_appendTo.append("\t\t **").append("/").append(LINE_SEP); to_appendTo.append("\t\t"); if(b4Prot) { to_appendTo.append("protected"); } else { to_appendTo.append("public"); } to_appendTo.append(" ").append(sReturnType).append(" "); if(b4Prot) { to_appendTo.append(sFuncName.substring(0, (sFuncName.length() - sU4PROT.length()))); } else { to_appendTo.append(sFuncName); } to_appendTo.append("(").append(sAllParams).append(")").append(" {").append(LINE_SEP); to_appendTo.append("\t\t\t"); if(!bVoid) { to_appendTo.append("return "); } to_appendTo.append(sXMK).append(".").append(sFuncName); to_appendTo.append("("). append(sAllParamNames). append(");").append(LINE_SEP); to_appendTo.append("\t\t}").append(LINE_SEP); } public static final String get1RqdParamPathToJavaFile(String[] as_1Rqd_pathToJavaFile) { try { return as_1Rqd_pathToJavaFile[0]; } catch(RuntimeException rx) { if(as_1Rqd_pathToJavaFile.length == 0) { throw new RuntimeException("Exactly one required parameter: The full path to the *Composer.java source file.", rx); } throw rx; } } public static final Appendable appendJavaFilePathWithDotsNoDtJava(Appendable to_appendTo, File source_code) throws IOException { try { return appendJavaFilePathWithDotsNoDtJava(to_appendTo, source_code.getPath()); } catch(RuntimeException rx) { throw CrashIfObject.nullOrReturnCause(source_code, "source_code", null, rx); } } public static final Appendable appendJavaFilePathWithDotsNoDtJava(Appendable to_appendTo, String srcCode_path) throws IOException { try { return to_appendTo.append(JavaRegexUtil.getJavaFilePathElimDtJvDtClsRplcFSToDot(srcCode_path)).append(LINE_SEP); } catch(RuntimeException rx) { Objects.requireNonNull(srcCode_path, "srcCode_path"); throw CrashIfObject.nullOrReturnCause(to_appendTo, "to_appendTo", null, rx); } } }