001/*license*\ 002 Codelet: Copyright (C) 2014, Jeff Epstein (aliteralmind __DASH__ github __AT__ yahoo __DOT__ com) 003 004 This software is dual-licensed under the: 005 - Lesser General Public License (LGPL) version 3.0 or, at your option, any later version; 006 - Apache Software License (ASL) version 2.0. 007 008 Either license may be applied at your discretion. More information may be found at 009 - http://en.wikipedia.org/wiki/Multi-licensing. 010 011 The text of both licenses is available in the root directory of this project, under the names "LICENSE_lgpl-3.0.txt" and "LICENSE_asl-2.0.txt". The latest copies may be downloaded at: 012 - LGPL 3.0: https://www.gnu.org/licenses/lgpl-3.0.txt 013 - ASL 2.0: http://www.apache.org/licenses/LICENSE-2.0.txt 014\*license*/ 015package com.github.aliteralmind.codelet; 016 import com.github.xbn.text.StringWithNullDefault; 017 import com.github.xbn.io.PlainTextFileUtil; 018 import org.apache.commons.io.FilenameUtils; 019 import com.github.xbn.lang.CrashIfObject; 020 import com.github.xbn.text.CrashIfString; 021 import com.github.xbn.lang.reflect.InvokeMethodWithRtx; 022 import com.github.xbn.lang.reflect.ReflectRtxUtil; 023 import com.github.aliteralmind.codelet.simplesig.SimpleMethodSignature; 024 import java.lang.reflect.Method; 025 import java.nio.file.AccessDeniedException; 026 import java.nio.file.NoSuchFileException; 027 import java.util.Iterator; 028 import java.util.List; 029 import java.util.Objects; 030 import static com.github.aliteralmind.codelet.CodeletBaseConfig.*; 031 import static com.github.xbn.lang.XbnConstants.*; 032/** 033 <p>Base class for type-specific Codelet processors. Called by {@link com.github.aliteralmind.codelet.TagletProcessor}.</p> 034 035 * @since 0.1.0 036 * @author Copyright (C) 2014, Jeff Epstein ({@code aliteralmind __DASH__ github __AT__ yahoo __DOT__ com}), dual-licensed under the LGPL (version 3.0 or later) or the ASL (version 2.0). See source code for details. <a href="http://codelet.aliteralmind.com">{@code http://codelet.aliteralmind.com}</a>, <a href="https://github.com/aliteralmind/codelet">{@code https://github.com/aliteralmind/codelet}</a> 037 **/ 038public class TagletOfTypeProcessor<T extends CodeletTemplateBase> { 039 private final CodeletInstance instance ; 040 private final String objTagTxt ; 041 private final String procTagTxt; 042 private String fullyProcessedOutput; 043 /** 044 <p>The name of the class in each package that <i>uses</i> codelets, that is the "fallback" location for IXC-customizers--Equal to {@code "zCodeletCustomizers"}. This class is only applicable for customizers that are<ul> 045 <li>Not in {@link com.github.aliteralmind.codelet.BasicCustomizers BasicCustomizers},</li> 046 <li>Not in the taglet's {@linkplain CodeletInstance#getEnclosingPackage() enclosing class}, and</li> 047 <li>Not explicitely specified in the taglet's text (after the customizer {@linkplain CodeletInstance#CUSTOMIZER_PREFIX_CHAR prefix character}).</li> 048 </ul></p> 049 */ 050 public static final String DEFAULT_CUSTOMIZER_CLASS_NAME = "zCodeletCustomizers"; 051 /** 052 <p>Create a new instance.</p> 053 054 <p>Steps:<ol> 055 <li>If a Codelet customizer is<ul> 056 <li>specified (meaning its {@linkplain CodeletInstance#CUSTOMIZER_PREFIX_CHAR prefix character} is found anywhere in {@code tag_text}), this sets<ol> 057 <li>{@link #getClassOrFilePortion() getClassOrFilePortion}{@code ()} to the text preceding the prefix char.</li> 058 <li>{@link #getCustomizerPortion() getCustomizerPortion}{@code ()} to the text following it.</li> 059 </ol></li> 060 <li>Not specified, this sets<ol> 061 <li>{@link #getClassOrFilePortion() getClassOrFilePortion}{@code ()} to <code>instance.{@link com.github.aliteralmind.codelet.CodeletInstance#getText() getText}()</code>.</li> 062 <li>{@link #getCustomizerPortion() getCustomizerPortion}{@code ()} to {@code null}.</li> 063 </ol></li> 064 </ul></li> 065 </ol></p> 066 <p></p> 067 068 * @param sub_classType The taglet type of the sub-class. May not be {@code null}. Discarded after construction. 069 * @param instance May not be {@code null}, and its {@linkplain CodeletInstance#getType() type} must be the same as {@code sub_classType}. Get with {@link #getInstance() getInstance}{@code ()}. 070 * @exception NoSuchMethodException If the customizer function does not exist, either in the specified or default classes, or with the required attributes, such as missing parameters, an unexpected return value, or if it's non-static. 071 * @exception NoSuchFileException If the source-code or plain-text file does not exist. 072 * @exception AccessDeniedException If the file exists, but cannot be read. 073 */ 074 public TagletOfTypeProcessor(CodeletType sub_classType, CodeletInstance instance) { 075 if(sub_classType != instance.getType()) { 076 throw new IllegalStateException("sub_classType is " + sub_classType + ", instance.getType()=" + instance.getType() + ""); 077 } 078 Objects.requireNonNull(instance, "instance"); 079 080 this.instance = instance; 081 082 String[] rawObjectProcStrs = TagletTextUtil.getTagletTextSplitOnLineProcDelim(instance); 083 084 objTagTxt = rawObjectProcStrs[0]; 085 procTagTxt = ((rawObjectProcStrs.length == 1) ? null 086 : rawObjectProcStrs[1]); 087 088 if(isDebugOn(instance, "zzTagletOfTypeProcessor.classcustomizersplit")) { 089 debugln(" Example-class/file-text portion: \"" + objTagTxt + "\""); 090 debugln(" Customizer portion: " + StringWithNullDefault.get("\"", procTagTxt, "\"", null)); 091 } 092 093 fullyProcessedOutput = null; 094 } 095 /** 096 <p>The current taglet instance.</p> 097 098 * @see #TagletOfTypeProcessor(CodeletType, CodeletInstance) 099 */ 100 public CodeletInstance getInstance() { 101 return instance; 102 } 103 /** 104 <p>The example code's fully-qualified class name (plus any command-line parameters), or the path to the plain-text file. This is the portion of the taglet's text that follows the {@linkplain CodeletType#getName() name} and precedes the optional customizer {@linkplain CodeletInstance#CUSTOMIZER_PREFIX_CHAR prefix character}. If no customizer is specified, this is equal to <code>{@link #getInstance() getInstance}().{@link com.github.aliteralmind.codelet.CodeletInstance#getText() getText}()</code></p> 105 106 * @see #TagletOfTypeProcessor(CodeletType, CodeletInstance) 107 */ 108 public String getClassOrFilePortion() { 109 return objTagTxt; 110 } 111 /** 112 <p>If the class or file is not allowed to use the customizer, crash. Otherwise, do nothing.</p> 113 114 * @exception IllegalStateException If 115 <br/> <code>{@link org.apache.commons.io.FilenameUtils}.{@link org.apache.commons.io.FilenameUtils#wildcardMatch(String, String) wildcardMatch}({@link #getClassOrFilePortion() getClassOrFilePortion}(), instructions.{@link CustomizationInstructions#getClassNameOrFilePathRestricter() getClassNameOrFilePathRestricter})</code> 116 <br/>is {@code false}. 117 */ 118 protected void crashIfClassOrFileCannotUseCustomizer(CustomizationInstructions<T> instructions) { 119 if(isDebugOn(instance, "zzSourceCodeProcessor.progress")) { 120 debugln("Verifying class/file name (\"" + getClassOrFilePortion() + "\") against instructions.getClassNameOrFilePathRestricter() (\"" + instructions.getClassNameOrFilePathRestricter() + "\")"); 121 } 122 if(!FilenameUtils.wildcardMatch(getClassOrFilePortion(), instructions.getClassNameOrFilePathRestricter())) { 123 throw new IllegalStateException("getClassOrFilePortion()=\"" + getClassOrFilePortion() + "\", instructions.getClassNameOrFilePathRestricter()=\"" + instructions.getClassNameOrFilePathRestricter() + "\""); 124 } 125 } 126 127 /** 128 <p>The optional customizer part of a codelet, as found after its prefix character. If no customizer is specified, this is {@code null}.</p> 129 130 * @see #TagletOfTypeProcessor(CodeletType, CodeletInstance) 131 * @see com.github.aliteralmind.codelet.CodeletInstance#CUSTOMIZER_PREFIX_CHAR CodeletInstance#CUSTOMIZER_PREFIX_CHAR 132 */ 133 public String getCustomizerPortion() { 134 return procTagTxt; 135 } 136 public String getFullyCustomizedOutput() { 137 return fullyProcessedOutput; 138 } 139 protected void setFullyProcessedOutput(String fully_processed) { 140 CrashIfString.nullEmpty(fully_processed, "fully_processed", null); 141 fullyProcessedOutput = fully_processed; 142 } 143/* 144 public T getTemplateFromInstructionsOverrideOrDefault(T tmpl_fromCustomInstructions, Appendable debugDest_ifNonNull) { 145 T t = null; 146 if(tmpl_fromCustomInstructions != null) { 147 t = tmpl_fromCustomInstructions; 148 t.setDebug(debugDest_ifNonNull, (debugDest_ifNonNull != null)); 149 } else { 150 t = TemplateOverrides.INSTANCE.<T>get(getInstance(), debugDest_ifNonNull); 151 } 152 return t; 153 } 154 */ 155 public T getTemplateFromInstructionsOverrideOrDefault(CustomizationInstructions<T> instructions) { 156 T t = null; 157 if(instructions.getTemplate() != null) { 158 t = instructions.getTemplate(); 159 t.setDebug(instructions.getDefaultTemplateDebug(), 160 (instructions.getDefaultTemplateDebug() != null)); 161 } else { 162 t = TemplateOverrides.<T>get(getInstance(), 163 instructions.getDefaultTemplateDebug()); 164 } 165 return t; 166 } 167 /** 168 <p>Get the string-signature for executing the example code.</p> 169 170 * @return {@code clsNm + "#main(" + params + ")"} 171 <br/>Where {@code clsNm} is 172 <br/> <code>{@link com.github.aliteralmind.codelet.TagletTextUtil TagletTextUtil}.{@link com.github.aliteralmind.codelet.TagletTextUtil#getExampleClassFQName(CodeletInstance) getExampleClassFQName}(instance)</code> 173 <br/>and {@code params} is 174 <br/> <code>{@link com.github.aliteralmind.codelet.TagletTextUtil TagletTextUtil}.{@link com.github.aliteralmind.codelet.TagletTextUtil#getExampleCommandLineParams(CodeletInstance) getExampleCommandLineParams}(instance)</code> 175 */ 176 public String getExampleCodeStringSig() { 177 String clsNm = TagletTextUtil.getExampleClassFQName(getInstance()); 178 String params = TagletTextUtil.getExampleCommandLineParams(getInstance()); 179 180 String strSig = clsNm + "#main(" + params + ")"; 181 182 if(isDebugOn(getInstance(), 183 "zzTagletOfTypeProcessor.getCustomizerSigFromString")) { 184 debugln(" Example code string sig: " + strSig); 185 } 186 187 return strSig; 188 } 189 public CustomizationInstructions<T> getCustomCustomizationInstructions(CodeletType needed_defaultAlterType) throws ClassNotFoundException, NoSuchMethodException, SecurityException { 190 String strSig = getStringSignature(); 191 SimpleMethodSignature sig = getCustomizerSigFromString(strSig); 192 return getInstructionsFromSig(sig, needed_defaultAlterType); 193 } 194 /** 195 <p>Invoke the customizer and get its return value, as required by the taglet-processor--For {@code {@.codelet.and.out}} taglets only.</p> 196 197 <p>This {@linkplain com.github.aliteralmind.codelet.simplesig.SimpleMethodSignature#getMethodFromParamValueList(List) obtains} and then {@linkplain java.lang.reflect.Method#invoke(Object, Object...) invokes} the customizer signature, and returns its return value, which must be a {@code CustomizationInstructions} of the type required by the processor.</p> 198 199 * @param customizer_sig May not be {@code null}, and the function in represents must conform to the requirements. 200 * @exception IllegalArgumentException If 201 <br/> <code><i>[the-instructions-returned-by-the-customizer]</i>.{@link CustomizationInstructions#getNeededAlterArrayType() getNeededAlterArrayType}()</code> 202 <br/>is different than <code>needed_defaultAlterType</code>. See 203 <br/> <code>{@link CustomizationInstructions#CustomizationInstructions(CodeletInstance, CodeletType)}</code> 204 */ 205 public CustomizationInstructions<T> getInstructionsFromSig(SimpleMethodSignature customizer_sig, CodeletType needed_defaultAlterType) throws ClassNotFoundException, NoSuchMethodException, SecurityException { 206 207 List<Object> paramValueList = null; 208 try { 209 //Must add the non-extra parameters to the object list. Since they're 210 //not "simple" types (primitives or strings), they can't added to the string-signature. 211 paramValueList = customizer_sig.getParamValueObjectList(); 212 paramValueList.add(0, getInstance()); 213 paramValueList.add(1, needed_defaultAlterType); 214 } catch(RuntimeException rx) { 215 throw CrashIfObject.nullOrReturnCause(customizer_sig, "customizer_sig", null, rx); 216 } 217 218 Method customizer = null; 219 try { 220 customizer = customizer_sig.getMethodFromParamValueList(paramValueList); 221 } catch(NoSuchMethodException nsmx) { 222 throw new NoSuchMethodException("Customizer function not found (is its containing class compiled?):" + LINE_SEP + 223 " - class.function: " + customizer_sig.getStringSig_ret_class_func_params(false, true, true, true) + LINE_SEP + 224 " - Taglet: " + getInstance() + 225 LINE_SEP + " - Original error: <<" + nsmx + ">>"); 226 } 227 228 boolean doDebug = isDebugOn(getInstance(), 229 "zzTagletOfTypeProcessor.getCustomizerSigFromString"); 230 if(doDebug) { 231 debugln(" Customizer method obtained..."); 232 } 233 234 customizer.setAccessible(true); 235 236 if(doDebug) { 237 debugln(" ...made accessible..."); 238 } 239 240/* 241 //The below call to sstatic() makes this redundant 242 if(!Modifier.isStatic(customizer.getModifiers())) { 243 throw new NoSuchMethodException("Method found, but not static: " + customizer_sig); 244 } 245 */ 246 247 Object o = new InvokeMethodWithRtx(customizer). 248 sstatic().parameters(paramValueList.toArray()). 249 invokeGetReturnValueWXtraInfo("Attempting to execute the *static* Codelet customizer."); 250 251 252 if(doDebug) { 253 debugln(" ...invoked..."); 254 } 255 256 try { 257 @SuppressWarnings("unchecked") 258 CustomizationInstructions<T> instructions = (CustomizationInstructions<T>)o; 259 260 if(doDebug) { 261 debugln(" ...return-value cast properly to CustomizationInstructions<T> (done)"); 262 } 263 264 if(instructions.getNeededAlterArrayType() != needed_defaultAlterType) { 265 throw new IllegalArgumentException("The returned CustomizationInstructions' getNeededAlterArrayType() (" + instructions.getNeededAlterArrayType() + ") is different than needed_defaultAlterType (" + needed_defaultAlterType + ")."); 266 } 267 268 return instructions; 269 } catch(ClassCastException ccx) { 270 throw new IllegalStateException("Customizer invoked properly, but its return value cannot be cast to a C (CustomizationInstructions): return-type=" + o.getClass().getName() + ", value=[" + o + "]"); 271 } 272 } 273 /** 274 <p>Given the customizer's fully-expanded string-signature, get its simple-signature.</p> 275 276 <p>Steps:<ol> 277 <li>If there is no customizer: This <i><b>returns</b></i> {@code null}.</li> 278 <li>If the fully-qualified class-name, in which the customizer function exists, is<ul> 279 <li>not specified (before the {@code '#'}): The following classes are set as its defaults, one in which the customizer function must exist (although that's verified externally--not by this function). They are search in order:<ol> 280 <li>{@link com.github.aliteralmind.codelet.BasicCustomizers BasicCustomizers}</li> 281 <li>The taglet's {@linkplain CodeletInstance#getEnclosingPackage() enclosing class}</li> 282 <li>And <i>if it exists:</i> The {@linkplain CodeletInstance#getEnclosingPackage() enclosing package}'s {@linkplain #DEFAULT_CUSTOMIZER_CLASS_NAME default processor class}.</li> 283 </ol></li> 284 <li><i><b>Returns</b></i> a new {@link com.github.aliteralmind.codelet.simplesig.SimpleMethodSignature#newFromStringAndDefaults(Class, Object, String, Class[], Appendable) simple signature}</li> 285 </ol></p> 286 287 * @param customizer_strSig The expanded string-signature. If {@code null}, no customizer is specified. 288 * @exception ClassNotFoundException If the class name, but not its package, is in the string-signature, and the class does not exist in the enclosing package. 289 * @see #getStringSignature() 290 */ 291 public SimpleMethodSignature getCustomizerSigFromString(String customizer_strSig) throws ClassNotFoundException { 292 if(customizer_strSig == null) { 293 return null; 294 } 295/* 296 //The line processor's class is explicitly specified. 297 Class<?> lineProcCls = null; 298 String lineProcClsNm = customizer_strSig.substring(0, hashIdx); 299 try { 300 lineProcCls = Class.forName(lineProcClsNm); 301 } catch(ClassNotFoundException cnfx) { 302 throw new CodeletFormatException(getInstance(), "Unknown line processor class: \"" + lineProcClsNm + "\"."); 303 } 304 */ 305 306 boolean doDebug = isDebugOn(getInstance(), 307 "zzTagletOfTypeProcessor.getCustomizerSigFromString"); 308 309 Class<?>[] allPossibleClasses = null; 310 int openParenIdx = customizer_strSig.indexOf("("); 311 int hashIdx = customizer_strSig.indexOf("#"); 312 if(hashIdx != -1 && hashIdx < openParenIdx) { 313 if(doDebug) { 314 debugln(" Customizer-function's containing class specified in taglet: [" + customizer_strSig.substring(0, hashIdx) + "]"); 315 } 316 } else { 317 318 if(doDebug) { 319 debugln(" Customizer-function's containing class not specified. Searching for potential containing classes..."); 320 } 321 322 Class<?> defaultCustomizerClsForPkg = null; 323 Class<?> containingClass = null; 324 325 if(getInstance().getEnclosingPackage().length() == 0) { 326 if(doDebug) { 327 debugln(" Enclosing file (" + getInstance().getEnclosingFullyQualifiedName() + ") has no package. The default customizer class for packages (" + DEFAULT_CUSTOMIZER_CLASS_NAME + ") does not (cannot) exist for this taglet. Classes not in a package (if this is indeed a class) cannot hold customizer functions."); 328 } 329 } else { 330 String defaultCstmzrClsNmForPkg = getInstance().getEnclosingPackage() + "." + DEFAULT_CUSTOMIZER_CLASS_NAME; 331 if(doDebug) { 332 debugln(" Testing package-default customizer class for existence: \"" + defaultCstmzrClsNmForPkg + "\""); 333 } 334 335 defaultCustomizerClsForPkg = ReflectRtxUtil.getClassIfExistsOrNull(defaultCstmzrClsNmForPkg); 336 337 if(doDebug) { 338 debugln(" Exists? " + (defaultCustomizerClsForPkg != null)); 339 } 340 341 containingClass = getInstance().getEnclosingClass(); 342 343 if(doDebug) { 344 debugln(" Enclosing file, " + getInstance().getEnclosingFullyQualifiedName() + ", is " + ((containingClass == null) 345 ? "not a class (or is a class, but is not yet compiled)" 346 : "a class") + "."); 347 } 348 } 349 350 351 int arraySize = 1 + 352 ((containingClass == null) ? 0 : 1) + 353 ((defaultCustomizerClsForPkg == null) ? 0 : 1); 354 355 allPossibleClasses = new Class[arraySize]; 356 357 //Definitely one 358 allPossibleClasses[0] = BasicCustomizers.class; 359 360 //Possibly two 361 if(containingClass != null) { 362 allPossibleClasses[1] = containingClass; 363 364 //Possibly three 365 if(defaultCustomizerClsForPkg != null) { 366 allPossibleClasses[2] = defaultCustomizerClsForPkg; 367 } 368 369 //ELSE: Possibly two 370 } else if(defaultCustomizerClsForPkg != null) { 371 allPossibleClasses[1] = defaultCustomizerClsForPkg; 372 } 373 374 if(doDebug) { 375 debugln(" ...Done. All potential containing classes:"); 376 for(int i = 0; i < allPossibleClasses.length; i++) { 377 debugln(" - " + i + ": " + allPossibleClasses[i].getName()); 378 } 379 } 380 } 381 382// String pkg = getInstance().getEnclosingPackage(); 383// pkg = ((pkg == "") ? null : pkg); 384 SimpleMethodSignature sig = SimpleMethodSignature.newFromStringAndDefaults( 385 CustomizationInstructions.class, customizer_strSig, null, allPossibleClasses, 386 getDebugApblIfOn(getInstance(), 387 "zzTagletOfTypeProcessor.getCustomizerSigFromString")); 388 389 if(doDebug) { 390 debugln(" Customizer: " + sig); 391 } 392 393 return sig; 394 } 395 /** 396 <p>Expands a potentially-shortened customizer signature (shortcut) to its full string-signature, for {@link com.github.aliteralmind.codelet.CodeletType#SOURCE_CODE {@.codelet}} and {@link com.github.aliteralmind.codelet.CodeletType#CONSOLE_OUT {@.codelet.out}} taglets only. This does not validate the taglet text or the returned signature.</p> 397 398 <p>Steps:<ol> 399 <li>If no {@linkplain TagletOfTypeProcessor#getCustomizerPortion() customizer} is in the taglet, this <i><b>returns</b></i> {@code null}.</li> 400 <li>If it is equal to {@code "()"}, this <i><b>returns</b></i> the default Codelet customizer function name<ol> 401 <li>The taglet-type's {@linkplain CodeletType#getDefaultLineProcNamePrefix() default prefix}</li> 402 <li>The example classes {@linkplain java.lang.Class#getSimpleName() simple name} (the text after the final dot: {@code '.'} in the example code's {@linkplain TagletTextUtil#getExampleClassFQName(CodeletInstance) fully-qualified class name}).</li> 403 <li>{@code "()"}</li> 404 </ol>Example: {@code "getSourceConfigAGreatExample()"}</li> 405 <li>If the line-proc starts with an underscore ({@code '_'}), it is the function name's postfix, which is appended after the classes simple name. This <i><b>returns</b></i> (for example) 406 <br/> {@code "getSourceConfigAGreatExample_DoSpecialStuff()"}</li> 407 <li>This <i><b>returns</b></i> the line-proc portion of the taglet's text unchanged.</li> 408 </ol><i>In all cases, if there are no paremeters specified, empty parentheses are appended to the signature: {@code "()"}</i></p> 409 */ 410 public String getStringSignature() { 411 String sig = getCustomizerPortion(); 412// String xmplFqName = TagletTextUtil.getExampleClassFQName(getInstance()); 413 414 boolean doDebug = isDebugOn(getInstance(), 415 "zzTagletOfTypeProcessor.getCustomizerSigFromString"); 416 417 if(sig == null) { 418 419 if(doDebug) { 420 debugln(" No Customizer"); 421 } 422 423 return null; 424 } 425 426 if(sig.equals("()")) { 427 String strSig = getInstance().getType().getDefaultLineProcNamePrefix() + 428 TagletTextUtil.getExampleSimpleClassName(getInstance()) + 429 sig; //sig equals "()" 430 431 if(doDebug) { 432 debugln(" Customizer string-sig (using \":()\" shortcut): " + strSig); 433 } 434 435 return strSig; 436 } 437 438 String fileOrClsSimpleName = ((getInstance().getType().isFileText()) 439 ? TagletTextUtil.getFileNameWithExtension(getInstance()) 440 : TagletTextUtil.getExampleSimpleClassName(getInstance())); 441 442 String strSig = getSig2PrnsApnddForNameOrPostfix(fileOrClsSimpleName + "_", sig, doDebug); 443 444 if(doDebug) { 445 debugln(" Customizer string-sig: " + strSig); 446 } 447 448 return strSig; 449 } 450 protected String getSig2PrnsApnddForNameOrPostfix(String betweenPre_andPostInclUndrScr, String sig, boolean do_debug) { 451 if(!sig.endsWith(")")) { 452 throw new CodeletFormatException(getInstance(), "No parentheses in customizer portion [last character not a ')' ]."); 453 } 454 if(sig.charAt(0) == '_') { 455 //No class specified. 456 457 if(do_debug) { 458 debugln(" Customizer portion (\"" + sig + "\") starts with '_' postfix. Expanding:"); 459 } 460 461 try { 462 sig = getInstance().getType().getDefaultLineProcNamePrefix() + betweenPre_andPostInclUndrScr + sig.substring(1); 463 } catch(StringIndexOutOfBoundsException sbx) { 464 throw new CodeletFormatException(getInstance(), "Customizer portion is *equal* to the underscore. Function-name postfix must follow the underscore.", sbx); 465 } 466 467 if(do_debug) { 468 debugln(" Expanded: \"" + sig + "\""); 469 } 470 return sig; 471 } 472 473 int idxHashUnder = sig.indexOf("#_"); 474 if(idxHashUnder == -1) { 475 return sig; 476 } 477 478 //Class specified, but only func-name postfix specified 479 480 try { 481 return sig.substring(0, idxHashUnder) + "#" + getInstance().getType().getDefaultLineProcNamePrefix() + betweenPre_andPostInclUndrScr + sig.substring(idxHashUnder + 2); 482 } catch(StringIndexOutOfBoundsException sbx) { 483 throw new CodeletFormatException(getInstance(), "Customizer portion *ends with* '#_'. Function-name postfix must follow the underscore.", sbx); 484 } 485 } 486/* 487 public CustomizationInstructions<T> newInstructionsForDefaults(CodeletInstance instance) { 488 return newInstructionsForDefaults(new CustomizationInstructions<T>(instance)); 489 } 490 */ 491 public CustomizationInstructions<T> newInstructionsForDefaults(CustomizationInstructions<T> instructions) { 492 String prefix = "zzTagletOfTypeProcessor.newInstructionsForDefaults."; 493 return instructions.defaults( 494 getDebugApblIfOn(getInstance(), prefix + "filter.alllines"), null, 495 getDebugApblIfOn(getInstance(), prefix + "allalterer"), 496 getDebugApblIfOn(getInstance(), prefix + "templateparseandfill")). 497 build(); 498 } 499 public Iterator<String> getSourceCodeLineIterator(CodeletInstance instance) { 500 if(isDebugOn(instance, "zzSourceCodeProcessor.progress")) { 501 debugln("Obtaining line-iterator to source code."); 502 } 503 504 return PlainTextFileUtil.getLineIterator(TagletTextUtil.getJavaSourceFilePath(instance), "TagletTextUtil.getJavaSourceFilePath(instance)"); 505 } 506 public CustomizationInstructions<T> getCustomizationInstructions(CodeletType needed_defaultAlterType) throws ClassNotFoundException, NoSuchMethodException, NoSuchFileException, AccessDeniedException { 507 if(isDebugOn(getInstance(), "zzSourceCodeProcessor.progress")) { 508 debugln(" Obtaining instructions for customizer portion: " + 509 StringWithNullDefault.get("\"", getCustomizerPortion(), "\"", 510 null)); 511 } 512 513 CustomizationInstructions<T> instructions = 514 ((getCustomizerPortion() != null) 515 ? getCustomCustomizationInstructions(needed_defaultAlterType) 516 : newInstructionsForDefaults(new CustomizationInstructions<T>(instance, needed_defaultAlterType))); 517 518 crashIfClassOrFileCannotUseCustomizer(instructions); 519 520 return instructions; 521 } 522}