Package org.ajax4jsf.renderkit.compiler

Source Code of org.ajax4jsf.renderkit.compiler.HtmlCompiler$CompiledError

/**
* License Agreement.
*
* Rich Faces - Natural Ajax for Java Server Faces (JSF)
*
* Copyright (C) 2007 Exadel, Inc.
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1 as published by the Free Software Foundation.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
*/

package org.ajax4jsf.renderkit.compiler;

import java.io.IOException;
import java.io.InputStream;
import java.io.Reader;
import java.io.StringReader;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.faces.FacesException;
import javax.faces.component.UIComponent;
import javax.faces.context.FacesContext;

import org.ajax4jsf.Messages;
import org.ajax4jsf.renderkit.RendererBase;
import org.apache.commons.digester.Digester;
import org.apache.commons.digester.Rule;
import org.apache.commons.digester.RulesBase;
import org.apache.commons.digester.SetNextRule;
import org.apache.commons.digester.SetPropertiesRule;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.xml.sax.SAXException;
import org.xml.sax.SAXParseException;
import org.xml.sax.helpers.LocatorImpl;


/**
* Compiler for XML string or stream for creation of {@link javax.faces.render.Renderer} internal
* interpretator. Use Apache Digitester for parse .
* @author asmirnov@exadel.com (latest modification by $Author: alexsmirnov $)
* @version $Revision: 1.1.2.1 $ $Date: 2007/01/09 18:57:48 $
*
*/
public class HtmlCompiler {
 
  public static final String NS_PREFIX = "f:";
  public static final String NS_UTIL_PREFIX = "u:";
  public static final String ROOT_TAG = "template";
  public static final String CALL_TAG = "call";
  public static final String VALUE_CALL_TAG = "valueCall";
  public static final String CALL_PARAM_TAG = "parameter";
  public static final String VERBATUM_TAG = "verbatim";
  public static final String BREAK_TAG = "break";
  public static final String FACET_TAG = "insertFacet";
  public static final String CHILDREN_TAG = "insertChildren";
  public static final String IF_TAG = "if";
  public static final String CHILD_TAG = "insertChild";
  public static final String STYLE_TAG = "style";
  public static final String CHILD_METHOD = "addChild";
  public static final String RESOURCE_TAG = "resource";
  public static final String ATTRIBUTE_TAG = "attribute";
  public static final String CHILD_PARAM_METHOD = "addParameter";
  public static final String ANY_PARENT = "*/";
  public static final String SELECTOR_TAG = "selector";
 

  private static final Log log = LogFactory.getLog(HtmlCompiler.class);
 
  private Digester digestr = new Digester();
 
 
  /**
   * Constructor with initialisation.
   */
  public HtmlCompiler(){
    WithDefaultsRulesWrapper rules = new WithDefaultsRulesWrapper(new RulesBase());
    // Add default rules to process plain tags.
      rules.addDefault(new PlainElementCreateRule());
      rules.addDefault(new SetNextRule(CHILD_METHOD));
      digestr.setDocumentLocator(new LocatorImpl());
      digestr.setRules(rules);
      digestr.setValidating(false);
      digestr.setNamespaceAware(false);
      digestr.setUseContextClassLoader(true);
      // Concrete renderer method call rules.
      setCustomRules(digestr);
  }

  /**
   * Build custom rules for parse special tags and attributes.
   * For most tags, value can be in next forms ( for resource, preffixed with f: ):
   * <ul>
   * <li><b>value</b> as string or EL-expression</li>
   * <li><b>property</b> name for property of current component</li>
   * <li><b>baseSkin</b> name for property of base skin</li>
   * <li><b>skin</b> name for property of current skin</li>
   * <li><b>context</b> name for property of {@link TemplateContext} for trmplate encoding</li>
   * <li><b>default</b> use as value if main property <code>null</code></li>
   * </ul>
   * Supported :
   * <ul>
   * <li>Call renderer or utils method &lt;f:call name='xxx'  /&gt;</li>
   * <li>Call  method parameter &lt;f:parameter name='xxx'  (value='....' | property='style' | baseSkin='paramName' | skin='paramName' | context='propertyName ) /&gt;</li>
   * <li>Encode plain text &lt;f:verbatim [value='....' | property='style' | baseSkin='paramName' | skin='paramName' | context='propertyName ] &gt;Some Text&lt;/f:text&gt;</li>
   * <li>Encode as text in HTML CSS parameter format &lt;u:style name='background' (value='....' | property='style' | baseSkin='paramName' | skin='paramName' | context='propertyName )/&gt;</li>
   * <li>Get and encode resource &lt;f:resource f:key='images/spacer.gif' [ ... any attributes ... ] /&gt;</li>
   * <li>Encode custom attribute &lt;f:attribute name='style' (value='....' | property='style' | baseSkin='paramName' | skin='paramName' | context='propertyName )  [endorsed='true'] /&gt;</li>
   * <li>Template breakpoint &lt;f:break name='xxxxx'  /&gt;</li>
   * <li>Encode named facet &lt;u:facet ( name='head  | property='style' | baseSkin='paramName' | skin='paramName' | context='propertyName )' /&gt;</li>
   * <li>Encode children components for current &lt;u:children /&gt;</li>
   * <li>Encode one child component for enclosed u:facet or u:children  &lt;u:child /'&gt;</li>
   * </ul>
   * @param digestr
   */
  protected void setCustomRules( Digester digestr){
    // Root element. not instantiate - already set by compile method.
    String pattern = NS_PREFIX+ROOT_TAG;
    digestr.addSetProperties(pattern);
    // call renderer method <f:call methodName='xxx' [methodParam='yyy'] />
    pattern = ANY_PARENT+NS_PREFIX+CALL_TAG;
    digestr.addObjectCreate(pattern,MethodCallElement.class);
    digestr.addSetNext(pattern,CHILD_METHOD);
    digestr.addSetProperties(pattern);
    // for value of parent call renderer method <f:valueCall methodName='xxx' [methodParam='yyy'] />
    pattern = ANY_PARENT+NS_PREFIX+VALUE_CALL_TAG;
    digestr.addObjectCreate(pattern,ValueMethodCallElement.class);
    digestr.addSetNext(pattern,CHILD_METHOD);
    digestr.addSetProperties(pattern);
    // call parameter <f:parapeter methodName='xxx' [methodParam='yyy'] />   
//    pattern = ANY_PARENT+NS_PREFIX+CALL_TAG+"/"+NS_PREFIX+CALL_PARAM_TAG;
    pattern = ANY_PARENT+NS_PREFIX+CALL_PARAM_TAG;
    digestr.addObjectCreate(pattern,MethodParameterElement.class);
    digestr.addSetNext(pattern,CHILD_PARAM_METHOD);
    digestr.addSetProperties(pattern);
    // Encode plain text <f:text>Some Text</f:text>
    pattern = ANY_PARENT+NS_PREFIX+VERBATUM_TAG;
    digestr.addObjectCreate(pattern,TextElement.class);
    digestr.addSetNext(pattern,CHILD_METHOD);
    digestr.addSetProperties(pattern);
    digestr.addBeanPropertySetter(pattern,"text");
    // resource <f:resource f:key='images/spacer.gif' [f:data='...'] [ ... any attributes ... ] />
    pattern =ANY_PARENT+NS_PREFIX+RESOURCE_TAG;
    digestr.addObjectCreate(pattern,ResourceElement.class);
    digestr.addSetNext(pattern,CHILD_METHOD);
    {
    Rule rule = new PutAttributesRule(digestr,new String[]{NS_PREFIX+"key",NS_PREFIX+"property",NS_PREFIX+"baseSkin",NS_PREFIX+"skin",NS_PREFIX+"context"});
    digestr.addRule(pattern,rule);
    }
    {
    SetPropertiesRule rule = new SetPropertiesRule(new String[]{NS_PREFIX+"key",NS_PREFIX+"property",NS_PREFIX+"baseSkin",NS_PREFIX+"skin",NS_PREFIX+"context"},new String[]{"value","property","baseSkin","skin","context"});   
    digestr.addRule(pattern,rule);
    }
    // custom attribute <f:attribute name='style' (value='....' | property='style' | skin='paramName' | call='methodName' | utilCall='methodName') [notNull='true'] />
    pattern = ANY_PARENT+NS_PREFIX+ATTRIBUTE_TAG;
    digestr.addObjectCreate(pattern,AttributeElement.class);
    digestr.addSetNext(pattern,CHILD_METHOD);
    digestr.addSetProperties(pattern);
    // component clientId <f:id [f:required='true'] />
    // breakpoint <f:break name="name">
    pattern = ANY_PARENT+NS_PREFIX+BREAK_TAG;
    digestr.addObjectCreate(pattern,BreakPoint.class);
    digestr.addSetProperties(pattern);
    digestr.addSetNext(pattern,CHILD_METHOD);
    // conditional rendering  <f:if then="true">
    pattern = ANY_PARENT+NS_PREFIX+IF_TAG;
    digestr.addObjectCreate(pattern,IfElement.class);
    digestr.addSetProperties(pattern);
    digestr.addSetNext(pattern,CHILD_METHOD);
    // facet <u:insertFacet name="name">
    pattern = ANY_PARENT+NS_UTIL_PREFIX+FACET_TAG;
    digestr.addObjectCreate(pattern,FacetElement.class);
    digestr.addSetProperties(pattern);
    digestr.addSetNext(pattern,CHILD_METHOD);
   
    // childrens <u:insertChildren>
    pattern = ANY_PARENT+NS_UTIL_PREFIX+CHILDREN_TAG;
    digestr.addObjectCreate(pattern,ChildrensElement.class);
    digestr.addSetNext(pattern,CHILD_METHOD);
//    {
//      Rule rule = new PutAttributesRule(digestr,new String[]{NS_PREFIX+"key",NS_PREFIX+"property",NS_PREFIX+"skin",NS_PREFIX+"context"});
//      digestr.addRule(pattern,rule);
//      }
      {
      SetPropertiesRule rule = new SetPropertiesRule(new String[]{NS_PREFIX+"key",NS_PREFIX+"property",NS_PREFIX+"skin",NS_PREFIX+"context"},new String[]{"value","property","skin","context"});   
      digestr.addRule(pattern,rule);
      }


   
    // style(sheet) property <u:style>
    pattern = ANY_PARENT+NS_UTIL_PREFIX+STYLE_TAG;
    digestr.addObjectCreate(pattern,ClassElement.class);
    digestr.addSetProperties(pattern);
    digestr.addSetNext(pattern,CHILD_METHOD);
    // breakpoint <f:break name="name">
    pattern = ANY_PARENT+NS_UTIL_PREFIX+CHILD_TAG;
    digestr.addObjectCreate(pattern,ChildElement.class);
    digestr.addSetProperties(pattern);
    digestr.addSetNext(pattern,CHILD_METHOD);
   
    //Selector element <u:selector></u:selector>
    pattern = ANY_PARENT+NS_UTIL_PREFIX+SELECTOR_TAG;
    digestr.addObjectCreate(pattern,SelectorElement.class);
    digestr.addSetProperties(pattern);
    digestr.addSetNext(pattern,CHILD_METHOD);
  }
 
 
  /**
   * Compile template for XML from simple string.
   * @param xml - String with template code
   * @return compiled template, ready for rendering.
   */
  public PreparedTemplate compile(String xml){
    Reader input = new StringReader(xml);
    return compile(input);
  }
 
  /**
   * Compile set of templates at time. Templates gets from resources in
   * classpath relative to base class. Used for initialisation set of templates in {@link RendererBase} subclasses constructor
   * @param base - base class for resources paths
   * @param templates - array with templates names.
   * @return {@link Map } , with keys - templates name, value - compiled template.
   */
  public Map compileResources(Class base,String[] templates) {
    Map result = new HashMap(templates.length);
    for (int i = 0; i < templates.length; i++) {
      String template = templates[i];
      result.put(template,compileResource(base,template));
    }
    return result;
  }
  /**
   * Compile XML from resource in classpath. Resource always readed
   * as UTF-8 text , to avoid xml declarations.
   * @param base - class of base object.
   * @param resource - path to resource ( if not start with / , relative to base object )
   * @return compiled XML, or Exception-generated stub, if parsing error occurs.
   */
  public static PreparedTemplate compileResource(Class base, String resource)  {
    String path;
    if (resource.startsWith("/")) {
      path = base.getPackage().getName().replace('.','/')+resource;
    } else {
      path = base.getPackage().getName().replace('.','/')+"/"+resource;
    }
    return compileResource(path);
  }
 
 
  /**
   * Compile XML from resource in classpath. Resource always readed
   * as UTF-8 text , to avoid xml declarations.
   * @param resource - absolute path to resource
   * @return compiled XML, or Exception-generated stub, if parsing error occurs.
   */
  public static PreparedTemplate compileResource(String resource)  {
    HtmlCompiler compiler = new HtmlCompiler();
    ClassLoader loader = Thread.currentThread().getContextClassLoader();
    InputStream input = loader.getResourceAsStream(resource);
    // Since parsing exceptions handled by compiler, we can not check parameter.
    PreparedTemplate compile = compiler.compile(input, resource);
    if(null != input){
      try {
        input.close();
      } catch (IOException e) {
        // can be ignored
      }
    }
    return compile;
  }
 
  public PreparedTemplate compile(Reader input){
    // By default - empty result. we not throw any exceptions in compile phase -
    // since it can be in static class initialization.
    PreparedTemplate result = null;
    try {
      digestr.clear();
      digestr.push(new RootElement());
      result = (PreparedTemplate) digestr.parse(input);
    } catch (SAXParseException e) {
//      TODO - locate compilation error. How get name ?
      String errorstr = Messages.getMessage(Messages.PARSING_TEMPLATE_ERROR, new Object[]{"" + e.getLineNumber(), "" + e.getColumnNumber(), e.toString()});
//      errorstr.append(digestr.getDocumentLocator().getLineNumber()).append(" and position ").append(digestr.getDocumentLocator().getColumnNumber());
      log.error(errorstr, e);
      result = new CompiledError(errorstr.toString(),e);
    } catch (IOException e) {
      String errorstr = Messages.getMessage(Messages.TEMPLATE_IO_ERROR, e.toString());
      log.error(errorstr, e);
      result = new CompiledError(errorstr.toString(),e);
    } catch (SAXException e) {
      String errorstr = Messages.getMessage(Messages.PARSING_TEMPLATE_ERROR_2, e.toString());
      log.error(errorstr, e);
      result = new CompiledError(errorstr.toString(),e);
    }
    return result;
  }
 
  /**
   * Compile input {@link InputStream} to {@link PreparedTemplate} - set of Java classes to encode as JSF output.
   * @param input stream with template XML text.
   * @param sourcename ( optional ) name of resource, for debug purposes.
   * @return compiled template.
   */
  public PreparedTemplate compile(InputStream input, String sourcename){
    // By default - empty result. we not throw any exceptions in compile phase -
    // since it can be in static class initialization.
    PreparedTemplate result = null;
    try {
      if (log.isDebugEnabled()) {
        log.debug(Messages.getMessage(Messages.START_COMPILE_TEMPLATE_INFO, sourcename));
      }
      digestr.clear();
      RootElement root = new RootElement();
      root.setTemplateName(sourcename);
      digestr.push(root);
      result = (PreparedTemplate) digestr.parse(input);
    } catch (SAXParseException e) {
//      TODO - locate compilation error. How get name ?
      String errorstr = Messages.getMessage(Messages.PARSING_TEMPLATE_ERROR_a, new Object[]{sourcename, "" + e.getLineNumber(), "" + e.getColumnNumber(), e.toString()});
//      errorstr.append(digestr.getDocumentLocator().getLineNumber()).append(" and position ").append(digestr.getDocumentLocator().getColumnNumber());
      log.error(errorstr, e);
      result = new CompiledError(errorstr.toString(),e);
    } catch (IOException e) {
      String errorstr = Messages.getMessage(Messages.TEMPLATE_IO_ERROR_a, sourcename, e.toString());
      log.error(errorstr, e);
      result = new CompiledError(errorstr.toString(),e);
    } catch (SAXException e) {
      String errorstr = Messages.getMessage(Messages.PARSING_TEMPLATE_ERROR_2a, sourcename, e.toString());
      log.error(errorstr, e);
      result = new CompiledError(errorstr.toString(),e);
    }
    if (log.isDebugEnabled()) {
      log.debug(Messages.getMessage(Messages.FINISH_COMPILE_TEMPLATE_INFO, sourcename));
    }
    return result;
  }

  /**
   * Incapsulate parsing - compilation errors to throw at encoding.
   * Allow static / constructor initialisation, all errors will be
   * see in page at request time. For debugging purposes.
   * @author asmirnov@exadel.com (latest modification by $Author: alexsmirnov $)
   * @version $Revision: 1.1.2.1 $ $Date: 2007/01/09 18:57:48 $
   *
   */
  private static class CompiledError implements PreparedTemplate {
    private Exception cause = null;
    private String message = Messages.getMessage(Messages.TEMPLATE_NOT_COMPILED_ERROR);

    /**
     * @param cause
     * @param message
     */
    public CompiledError(String message,Exception cause) {
      super();
      this.cause = cause;
      this.message = message;
    }

    /**
     * @param cause
     */
    CompiledError(Exception cause) {
      this.cause = cause;
    }

    public void encode(RendererBase renderer, FacesContext context, UIComponent component) throws IOException {
      // TODO - concrete compilation error.
      throw new FacesException(message,cause);
    }

    public List getChildren() {
      return Collections.EMPTY_LIST;
    }

    public void addChild(PreparedTemplate child) throws SAXException {
      // DO Nothing.
      throw new SAXException(Messages.getMessage(Messages.NO_CHILD_ALLOWED));
    }

    public void encode(TemplateContext context) throws IOException {
      throw new FacesException(message,cause);
     
    }

    public void encode(TemplateContext context, String breakPoint) throws IOException {
      throw new FacesException(message,cause);
     
    }

    public void setParent(PreparedTemplate parent) {
      // DO Nothing.
    }

    public String getTag() {
      // TODO Auto-generated method stub
      return "f:error";
    }

    public Object getValue(TemplateContext context) {
      // error don't have value
      return null;
    }
   
  };

}
TOP

Related Classes of org.ajax4jsf.renderkit.compiler.HtmlCompiler$CompiledError

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.