org.ajax4jsf.templatecompiler.builder.AbstractCompilationContext.java Source code

Java tutorial

Introduction

Here is the source code for org.ajax4jsf.templatecompiler.builder.AbstractCompilationContext.java

Source

/**
 * 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.templatecompiler.builder;

import java.beans.PropertyDescriptor;
import java.io.StringWriter;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.ajax4jsf.builder.config.ClassVisitor;
import org.ajax4jsf.builder.config.ClassWalkingLogic;
import org.ajax4jsf.builder.model.JavaPrimitive;
import org.ajax4jsf.templatecompiler.elements.A4JRendererElementsFactory;
import org.ajax4jsf.templatecompiler.elements.ElementsFactory;
import org.ajax4jsf.templatecompiler.elements.TemplateElement;
import org.apache.commons.beanutils.MethodUtils;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.exception.ParseErrorException;
import org.apache.velocity.exception.ResourceNotFoundException;
import org.w3c.dom.Node;

/**
 * Component Beam.
 * 
 * @author ayukhovich@exadel.com (latest modification by $Author: alexsmirnov $)
 * @version $Revision: 1.1.2.2 $ $Date: 2007/02/26 20:48:42 $
 * 
 */
public abstract class AbstractCompilationContext implements CompilationContext {
    private static final Log log = LogFactory.getLog(AbstractCompilationContext.class);

    final private static String VCPBODY = "VCPBODY";

    final private static String regexComponent = "(.*)" + VCPBODY + "(.*)" + VCPBODY + "(.*)";

    final private static Pattern patternComponent = Pattern.compile(regexComponent,
            Pattern.UNIX_LINES + Pattern.DOTALL);

    private final static String DEFAULT_BASE_CLASS = "org.ajax4jsf.renderkit.RendererBase";

    private String packageName;

    private String className;

    private String baseClassName;

    private ArrayList<String> declarations;

    private ArrayList<String> imports;

    private String[] EncodeBegin;

    private String[] EncodeEnd;

    private String[] EncodeChildren;

    private Map<String, Map<String, PropertyDescriptor>> resolvedProperties = new HashMap<String, Map<String, PropertyDescriptor>>();

    private HashMap<String, Class<?>> variables = new HashMap<String, Class<?>>();

    private static String[] defaultImports = new String[] { "java.util.Iterator", "java.util.Collection",
            "java.util.Map", "java.io.IOException", "javax.faces.component.UIComponent",
            "javax.faces.context.FacesContext", "javax.faces.context.ResponseWriter",
            "org.ajax4jsf.renderkit.ComponentsVariableResolver", "org.ajax4jsf.renderkit.ComponentVariables" };

    private TemplateElement tree;

    private List<ElementsFactory> elementFactories = new ArrayList<ElementsFactory>();

    /**
     * Name of UIComponent class for this template - can be used for get properties and methods by introspection.
     */
    private String componentClass;

    /**
     * Ant Task related classloader for loat UIComponent and Renderer classes for introspection.
     */
    private ClassLoader classLoader;

    public AbstractCompilationContext() {
        this.baseClassName = DEFAULT_BASE_CLASS;
        this.declarations = new ArrayList<String>();
        this.imports = new ArrayList<String>();
        this.imports.addAll(Arrays.asList(defaultImports));
        // Init default elements factory.
        this.elementFactories.add(new A4JRendererElementsFactory());
    }

    /**
     * @param loader
     * @throws CompilationException
     */
    public AbstractCompilationContext(ClassLoader loader) throws CompilationException {
        this();
        this.classLoader = loader;
        setDefaultVariables();
    }

    public void addElementsFactory(ElementsFactory factory) {
        elementFactories.add(0, factory);
    }

    /**
     * @param componentClass
     *            The componentClass to set.
     * @throws CompilationException
     */
    public void setComponentClass(String componentClass) throws CompilationException {
        this.componentClass = componentClass;
        addVariable("component", componentClass);
    }

    /**
     * set a package name
     */
    public void setPackageName(final String packageName) {
        this.packageName = packageName;
    }

    /**
     * set a class name
     */
    public void setClassName(final String className) {
        this.className = className;
    }

    /**
     * 
     * @param fullClassName
     */
    public void setFullClassName(final String fullClassName) {
        int dotIndex = fullClassName.lastIndexOf(".");

        String tempPackageName = "";
        String tempClassName = fullClassName;

        if (dotIndex != -1) {
            tempPackageName = fullClassName.substring(0, dotIndex);
            tempClassName = fullClassName.substring(dotIndex + 1);
        } // if

        setPackageName(tempPackageName);
        setClassName(tempClassName);

    }

    public void setBaseclass(String baseclassName) throws CompilationException {
        this.baseClassName = baseclassName;
        addVariable("this", baseclassName);
    }

    // ------

    /**
     * @return package name
     */
    public String getPackageName() {
        return this.packageName;
    }

    /**
     * @return base class package name
     */
    public String getBaseclassPackageName() {
        String packageName = null;
        int dotIndex = this.baseClassName.lastIndexOf(".");

        if (dotIndex != -1) {
            packageName = this.baseClassName.substring(0, dotIndex);
        }

        return packageName;
    }

    /**
     * @return class name
     */
    public String getClassName() {
        return this.className;
    }

    /**
     * @return base class package name
     */
    public String getBaseclassName() {
        String className = null;

        if ((this.baseClassName != null) && (this.baseClassName.length() != 0)) {
            int dotIndex = this.baseClassName.lastIndexOf(".");

            if (dotIndex != -1) {
                className = this.baseClassName.substring(dotIndex + 1);
            } else {
                className = this.baseClassName;
            }
        }

        return className;
    }

    /**
     * @return full class name with package name
     */
    public String getFullClassName() {
        StringBuffer buf = new StringBuffer();

        if ((this.packageName != null) && (this.packageName.length() != 0)) {
            buf.append(this.packageName);
            buf.append('.');
        }

        buf.append(this.className);

        return buf.toString();
    }

    /**
     * @return base class package name
     */
    public String getFullBaseclass() {
        return this.baseClassName;
    }

    /**
     * @return
     */
    public String getComponentFileName() {
        return getFullClassName().replace('.', '/');
    }

    /**
     * @return Returns the componentClass.
     */
    public String getComponentClass() {
        String returnStr = this.componentClass;

        // if ( (componentClass != null) && ( !
        // componentClass.endsWith(".class")) ) {
        // returnStr = componentClass + ".class";
        // }

        return returnStr;
    }

    /**
     * return class loader
     */
    public ClassLoader getClassLoader() {
        return this.classLoader;
    }

    /**
     * @return string array contain declarations
     */
    public String[] getDeclarations() {
        return this.declarations.toArray(new String[0]);
    }

    /**
     * @return string array contain declarations
     */
    public String[] getImports() {
        return this.imports.toArray(new String[0]);
    }

    public void addToImport(String className) {
        this.imports.add(className);
    }

    public void addToDeclaration(String declaration) {
        this.declarations.add(declaration);
    }

    /**
     * Add variable with type String
     * 
     * @param variableName
     * @throws CompilationException
     */
    public void addVariable(String variableName) throws CompilationException {
        addVariable(variableName, "java.lang.String");
    }

    public void addVariable(String variableName, Class<?> clazz) {
        this.variables.put(variableName, clazz);
    }

    public void addVariable(String variableName, String typeName) throws CompilationException {
        try {
            Class<?> clazz = loadClass(typeName);
            this.variables.put(variableName, clazz);
        } catch (ClassNotFoundException e) {
            //         error("Error create variable "+variableName+" with type "+typeName, e);
            throw new CompilationException(
                    "Error create renderer variable " + variableName + " with type " + typeName, e);
        }
    }

    public boolean containsVariable(String variableName) {
        return this.variables.containsKey(variableName);
    }

    public Class<?> getVariableType(String variableName) {
        return this.variables.get(variableName);
    }

    public Class<?> loadClass(String className) throws ClassNotFoundException {
        Class<?> clazz = null;
        try {
            if (JavaPrimitive.isPrimitive(className)) {
                clazz = JavaPrimitive.forName(className);
            } else {
                clazz = this.classLoader.loadClass(className);
            }
        } catch (ClassNotFoundException e) {
            throw e;
        } catch (Throwable e) {
            log.error(e.getLocalizedMessage(), e);
        }

        if (null == clazz) {
            throw new ClassNotFoundException(className);
        }
        return clazz;
    }

    public void setDefaultVariables() throws CompilationException {
        addVariable("component", "javax.faces.component.UIComponent");
        addVariable("context", "javax.faces.context.FacesContext");
        addVariable("writer", "javax.faces.context.ResponseWriter");
        // addLocalVariable("component", "javax.faces.component.UIComponent" );
        addVariable("variables", "org.ajax4jsf.renderkit.ComponentVariables");
    }

    public Class<?> getMethodReturnedClass(Class<?> clazz, String methodName, Class<?>[] parametersTypes)
            throws NoSuchMethodException {
        Class<?> returnedType = null;
        log.debug("class : " + clazz.getName() + "\n\t method : " + methodName + "\n\t paramTypes : "
                + Arrays.asList(parametersTypes).toString());

        Method method = MethodUtils.getMatchingAccessibleMethod(clazz, methodName, parametersTypes);

        if (null != method) {
            returnedType = method.getReturnType();
            log.debug("Method found, return type : " + returnedType.getName());

            return returnedType;
        } else {
            throw new NoSuchMethodException(
                    clazz + "#" + methodName + "(" + Arrays.toString(parametersTypes) + ")");
        }

    }

    public PropertyDescriptor getPropertyDescriptor(Class<?> clazz, String propertyName) {

        Map<String, PropertyDescriptor> descriptors = resolvedProperties.get(clazz.getName());

        if (descriptors == null) {
            descriptors = resolveProperties(clazz);
            resolvedProperties.put(clazz.getName(), descriptors);
        }

        return descriptors.get(propertyName);
    }

    private Map<String, PropertyDescriptor> resolveProperties(Class<?> clazz) {
        final Map<String, PropertyDescriptor> descriptors = new HashMap<String, PropertyDescriptor>();

        new ClassWalkingLogic(clazz).walk(new ClassVisitor() {
            public void visit(Class<?> clazz) {
                PropertyDescriptor[] pds = PropertyUtils.getPropertyDescriptors(clazz);
                for (PropertyDescriptor descriptor : pds) {
                    descriptors.put(descriptor.getName(), descriptor);
                }
            }
        });
        return descriptors;
    }

    /**
     * 
     */
    public String[] getEncodeBegin() {
        return this.EncodeBegin;
    }

    /**
     * 
     */
    public String[] getEncodeChild() {
        return this.EncodeChildren;
    }

    /**
     * 
     */
    public String[] getEncodeEnd() {
        return this.EncodeEnd;
    }

    public void setCode(String code) {

        Matcher matcher = patternComponent.matcher(code);

        String strEncodeBegin;
        String strEncodeChildren;
        String strEncodeEnd;

        if (matcher.find()) {
            strEncodeBegin = matcher.group(1);
            strEncodeChildren = matcher.group(2);
            strEncodeEnd = matcher.group(3);
        } else {
            strEncodeBegin = "";
            strEncodeChildren = "";
            strEncodeEnd = code;
        }

        if ((strEncodeBegin != null) && (strEncodeBegin.length() != 0)) {
            this.EncodeBegin = strEncodeBegin.split(";\n");
        }

        if ((strEncodeChildren != null) && (strEncodeChildren.length() != 0)) {
            this.EncodeChildren = strEncodeChildren.split(";\n");
        }

        if ((strEncodeEnd != null) && (strEncodeEnd.length() != 0)) {
            this.EncodeEnd = strEncodeEnd.split(";\n");
        }

    }

    /**
     * @return the tree
     */
    public TemplateElement getTree() {
        return this.tree;
    }

    /**
     * @param tree the tree to set
     */
    public void setTree(TemplateElement tree) {
        this.tree = tree;
    }

    /* (non-Javadoc)
     * @see org.ajax4jsf.templatecompiler.builder.CompilationContext#getProcessor(org.w3c.dom.Node)
     */
    public TemplateElement getProcessor(Node nodeElement) throws CompilationException {
        for (Iterator<ElementsFactory> iter = elementFactories.listIterator(); iter.hasNext();) {
            ElementsFactory factory = iter.next();
            TemplateElement processor = factory.getProcessor(nodeElement, this);
            if (null != processor) {
                return processor;
            }
        }
        return null;
    }

    /* (non-Javadoc)
     * @see org.ajax4jsf.templatecompiler.builder.CompilationContext#processTemplate(java.lang.String, org.apache.velocity.VelocityContext)
     */
    public String processTemplate(String name, VelocityContext context) throws CompilationException {
        StringWriter out = new StringWriter();
        try {
            getTemplate(name).merge(context, out);
        } catch (ResourceNotFoundException e) {
            throw new CompilationException(e.getLocalizedMessage());
        } catch (ParseErrorException e) {
            throw new CompilationException(e.getLocalizedMessage());
        } catch (Exception e) {
            throw new CompilationException(e.getLocalizedMessage());
        }
        return out.toString();
    }

    public Map<String, Map<String, PropertyDescriptor>> getResolvedProperties() {
        return resolvedProperties;
    }
}