Package lazyj.page

Source Code of lazyj.page.TemplateParser

/**
*
*/
package lazyj.page;

import java.util.Collections;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Observable;
import java.util.Observer;
import java.util.Set;
import java.util.StringTokenizer;
import java.util.concurrent.Delayed;

import lazyj.DBFunctions;
import lazyj.DateFileWatchdog;
import lazyj.ExtendedServlet;
import lazyj.Log;
import lazyj.StringFactory;
import lazyj.Utils;

/**
* This class loads a template from a file and parses it.
*
* @author costing
* @since May 23, 2007
*/
final class TemplateParser implements Observer {
 
  /**
   * Page elements, either strings or tags
   */
  private List<Object> llElements = null;
 
  /**
   * Keep an eye on the underlying template file
   */
  private DateFileWatchdog dfw;
 
  /**
   * File name on disk
   */
  private final String sFileName;
 
  /**
   * How big was the previous output, to generate a large enough object from the start
   */
  private volatile int iPrevSize;
 
  /**
   * Database tags
   */
  private Set<String> hsDBTags = null;
 
  /**
   * The rest of the tags, the ones that don't have "db" flag
   */
  private Set<String> hsNonDBTags = null;

  /**
   * All tags
   */
  private Set<String> hsAllTags = null;
 
  /**
   * Is everything ok?
   */
  private boolean bOk;
 
  /**
   * This constructor take a file name, reads the contents from it and parses the tags into the internal structures.
   *
   * @param sTemplateFileName complete file name to read the HTML template from
   * @param bCache whether or not to cache the contents. Caching also means that the file is scheduled to be re-read from disk when it changes
   *        (checks every one minute)
   */
  TemplateParser(final String sTemplateFileName, final boolean bCache){
    this.sFileName = sTemplateFileName;
   
    final String sText = Utils.readFile(sTemplateFileName);
   
    if (sText==null)
      return;
   
    try{
      this.bOk = parse(sText);
    }
    catch (Throwable t){
      Log.log(Log.ERROR, "lazyj.page.TemplateParser", "Cannot parse contents because", t); //$NON-NLS-1$ //$NON-NLS-2$
      this.bOk = false;
      return;
    }
   
    if (Log.isLoggable(Log.FINEST, "lazyj.page.TemplateParser")) //$NON-NLS-1$
      Log.log(Log.FINEST, "lazyj.page.TemplateParser", "Parse result : "+this.bOk, sText); //$NON-NLS-1$ //$NON-NLS-2$
   
    if (this.bOk && bCache){
      try{
        this.dfw = new DateFileWatchdog(sTemplateFileName, 1*60*1000);
        this.dfw.addObserver(this);
      }
      catch (Exception e){
        this.dfw = null;
      }
    }
    else{
      this.dfw = null;
    }
  }
 
  /**
   * This is a simpler constructor, that takes the given template and parses it, with no file operations.
   *
   * @param sTemplate html template to parse
   */
  TemplateParser(final String sTemplate){
    try{
      this.bOk = parse(sTemplate);
    }
    catch (Throwable t){
      Log.log(Log.ERROR, "lazyj.page.TemplateParser", "Cannot parse contents because", t); //$NON-NLS-1$ //$NON-NLS-2$
      this.bOk = false;
    }
   
    this.sFileName = null;
  }
 
  /**
   * @return true if everything went ok with the parsing
   */
  boolean isOk(){
    return this.bOk;
  }
 
  /**
   * Parse this text
   *
   * @param sText
   * @return true if parsing was ok
   */
  private boolean parse(final String sText){
    if (sText == null)
      return false;
   
    final int defaultDBTags = this.hsDBTags!=null ? this.hsDBTags.size()+1 : 8;
    final int defaultNonDBTags = this.hsNonDBTags!=null ? this.hsNonDBTags.size()+1 : 8;
   
    final LinkedList<Object> llParseElements = new LinkedList<Object>();
    final HashSet<String> hsParseDBTags = new HashSet<String>(defaultDBTags);
    final HashSet<String> hsParseNonDBTags = new HashSet<String>(defaultNonDBTags);
   
    int i = 0;
    int iOld = 0;
    int j = 0;

    this.iPrevSize = sText.length();
   
    String sTag, sComplete;

    while ((i = sText.indexOf("<<:", iOld)) >= 0) { //$NON-NLS-1$
      if (i > iOld)
        llParseElements.add(sText.substring(iOld, i));

      j = sText.indexOf(":>>", i); //$NON-NLS-1$

      final LinkedList<Object> llTag = new LinkedList<Object>();
     
      if (j > i) {
        sTag = sText.substring(i + 3, j);

        sComplete = sTag;

        final StringTokenizer st = new StringTokenizer(sTag, " "); //$NON-NLS-1$

        sTag = st.nextToken();
       
        // hack for migration of old html templates
        if (sTag.equals("continut")) //$NON-NLS-1$
          sTag = "content"; //$NON-NLS-1$
       
        sTag = StringFactory.get(sTag);
       
        llTag.add(sTag);

        if (sTag.indexOf('.') >= 1 && sTag.indexOf('/') < 0 && !sTag.endsWith(".res")) { //$NON-NLS-1$
          final int iSpaceIdx = sComplete.indexOf(' ');
         
          if (iSpaceIdx >= 0)
            sComplete = sComplete.substring(iSpaceIdx + 1).trim();
          else
            sComplete = ""; //$NON-NLS-1$

          llTag.add(sComplete);         
        }
       
        boolean bIsDBTag = false;

        while (st.hasMoreTokens()){
          final String sOpt = StringFactory.get(st.nextToken().trim());
         
          if (sOpt.length()>0){
            if (sOpt.equals("db")){ //$NON-NLS-1$
              bIsDBTag = true;
            }
            else{
              final StringFormat sf = BasePage.getExactClass(sOpt);
             
              llTag.add(sf==null ? sOpt : sf);
            }
          }
        }
       
        if (bIsDBTag)
          hsParseDBTags.add(sTag);
        else
          hsParseNonDBTags.add(sTag);

        llParseElements.add(llTag);
       
        i = j + 3; // sarim peste tagul acesta
      }
      else { // nu se inchide ultimul tag, punem tot ce a mai ramas
        llParseElements.add(sText.substring(i));
        i = sText.length();
        iOld = i;
        break;
      }

      iOld = i;
    }

    if (iOld == 0)
      llParseElements.add(sText);
    else if (iOld < sText.length())
      llParseElements.add(sText.substring(iOld));
   
    final HashSet<String> hsParseAllTags = new HashSet<String>(hsParseNonDBTags);
    hsParseAllTags.addAll(hsParseDBTags);
   
    // first make all collections read-only
    final List<Object> llElementsTemp = Collections.unmodifiableList(llParseElements);
    final Set<String> hsDBTagsTemp = Collections.unmodifiableSet(hsParseDBTags);
    final Set<String> hsNonDBTagsTemp = Collections.unmodifiableSet(hsParseNonDBTags);
    final Set<String> hsAllTagsTemp = Collections.unmodifiableSet(hsParseAllTags);
   
    // and then set the object fields to the read-only instances
    this.llElements = llElementsTemp;
    this.hsDBTags = hsDBTagsTemp;
    this.hsNonDBTags = hsNonDBTagsTemp;
    this.hsAllTags = hsAllTagsTemp;
   
    return true;
  }
 
  /**
   * Implementation of {@link Delayed}. This is called by the {@link DateFileWatchdog} when the file that holds this template has changed.
   * The contents of the file is read and parsed again.
   *
   * @param o ignored
   * @param arg ignored
   */
  public void update(final Observable o, final Object arg) {
    if (!parse(Utils.readFile(this.sFileName)) && this.dfw!=null){
      this.dfw.stopIt();
      this.dfw = null;
    }
  }
 
  /**
   * Get the list of parsed tags.
   */
  @Override
  public String toString(){
    return this.llElements!=null ? this.llElements.toString() : "null"; //$NON-NLS-1$
  }
 
  /**
   * Get the set of tag names that have the "db" option attached to them. This is to be used at {@link BasePage#fillFromDB(DBFunctions)}.
   *
   * @return the set of tag names with the "db" option
   */
  Set<String> getDBTags(){
    return this.hsDBTags;
  }
 
  /**
   * Get the set of tag names that don't have "db" option attached to them.
   *
   * @return set of non-"db" tags
   */
  Set<String> getNonDBTags(){
    return this.hsNonDBTags;
  }
 
  /**
   * Get all the distinct tags present in this template
   *
   * @return set of tags in this template
   */
  Set<String> getTagsSet(){
    return this.hsAllTags;
  }
 
  /**
   * Apply the set of dynamic values to the HTML template.
   *
   * @param mValues user specified <tag name, value> pairs
   * @param sComments commented out sections
   * @param callingServlet servlet that created the page, probably null unless {@link BasePage#setCallingServlet(ExtendedServlet)} is called
   * @return the string to be passed to the client
   */
  @SuppressWarnings({ "unchecked", "null" })
  StringBuilder process(final Map<String, StringBuilder> mValues, final Set<String> sComments, final ExtendedServlet callingServlet){
    final StringBuilder sb = new StringBuilder(this.iPrevSize);
   
    if (this.llElements==null || this.llElements.size()==0)
      return sb;
   
    final Iterator<Object> itElements = this.llElements.iterator();
   
    final boolean bComments = sComments!=null && sComments.size()>0;
   
    while (itElements.hasNext()){
      Object o = itElements.next();
     
      if (o instanceof String)
        sb.append((String) o);
      else
      if (o instanceof StringBuilder)
        sb.append((StringBuilder) o);
      else
      if (o instanceof List){
        final Iterator<String> itTag = ((List<String>) o).iterator();
       
        final String sTag = itTag.next();
       
        if (bComments && sTag.endsWith("_start") && sComments.contains(sTag.substring(0, sTag.lastIndexOf('_')))){ //$NON-NLS-1$
          // skip over a commented out section
          final String sSearch = sTag.substring(0, sTag.lastIndexOf('_'))+"_end"; //$NON-NLS-1$
         
          while (itElements.hasNext()){
            o = itElements.next();
           
            if (o instanceof List && ((List<?>)o).get(0).equals(sSearch)){
              break;
            }
          }
         
          continue;
        }
       
        final boolean bRes = sTag.endsWith(".res")//$NON-NLS-1$
       
        // if the tag looks like a module, the second element in the list is the complete parameter string
        // so if we consider that it's not a module then we have to skip that parameter and evaluate the rest
        boolean bSkipSecond = false;
       
        if (sTag.indexOf('.') >= 1 && sTag.indexOf('/') < 0 && !bRes) {         
          if (mValues.containsKey(sTag)){
            bSkipSecond = true;
          }
          else{
            Module cp = null;
            Throwable ex = null;
           
            try{
              cp = (Module) Class.forName(sTag).newInstance();
            }
            catch (Throwable t){
              ex = t;
            }
           
            if (cp==null && callingServlet!=null){
              final ClassLoader loader = callingServlet.getClass().getClassLoader();
             
              try{
                cp = (Module) Class.forName(sTag, true, loader).newInstance();
              }
              catch (Throwable t){
                ex = t;
              }
            }
           
            if (cp!=null)
              sb.append(cp.getContent(itTag.next()).toString());
            else
            if (ex!=null)
              Log.log(Log.ERROR, "lazyj.page.TemplateParser", "cannot instantiate module '"+sTag+"' from page='"+this.sFileName+"'", ex); //$NON-NLS-1$ //$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$
           
            continue;
          }
        }

        final StringBuilder sbValue = bRes ? new StringBuilder() : mValues.get(sTag);
       
        if (sbValue==null)
          continue;
       
        String sValue = sbValue.toString();
       
        while (itTag.hasNext() && sValue!=null){
          final Object oNext = itTag.next();
         
          if (bSkipSecond){
            // ignore the full list of parameters
            bSkipSecond = false;
            continue;
          }
         
          if (oNext instanceof StringFormat){
            sValue = ((StringFormat) oNext).format(sTag, null, sValue);
            continue;
          }
         
          final String sFormat = (String) oNext;
         
          final StringFormat sf = BasePage.getFormattingClass(sFormat);
         
          if (sf!=null)
            sValue = sf.format(sTag, sFormat, sValue);
          else
            Log.log(Log.WARNING, "lazyj.page.TemplateParser", "Unknown format option : '"+sFormat+"' (tag='"+sTag+"', page='"+this.sFileName+"')")//$NON-NLS-1$//$NON-NLS-2$ //$NON-NLS-3$ //$NON-NLS-4$ //$NON-NLS-5$
        }
       
        if (sValue!=null)
          sb.append(sValue);
      }
    }
   
    // limit the amount of memory we would allocate next time
    this.iPrevSize = Math.min(sb.length(), 100000);
   
    return sb;
  }
 
}
TOP

Related Classes of lazyj.page.TemplateParser

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.