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 &quot;fallback&quot; 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/> &nbsp; &nbsp; <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/> &nbsp; &nbsp; <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/> &nbsp; &nbsp; <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/> &nbsp; &nbsp; <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/> &nbsp; &nbsp; <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/> &nbsp; &nbsp; {@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}