org.ajax4jsf.builder.config.BuilderConfig.java Source code

Java tutorial

Introduction

Here is the source code for org.ajax4jsf.builder.config.BuilderConfig.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.builder.config;

import java.beans.PropertyDescriptor;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.TreeMap;

import javax.naming.ConfigurationException;

import org.ajax4jsf.builder.generator.Logger;
import org.apache.commons.beanutils.PropertyUtils;
import org.apache.commons.digester.Digester;
import org.apache.commons.digester.ExtendedBaseRules;
import org.apache.tools.ant.BuildException;
import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.ext.EntityResolver2;

/**
 * Parse builder config file for use with component creation.
 * 
 * @author asmirnov@exadel.com (latest modification by $Author: ishabalov $)
 * @version $Revision: 1.1.2.10 $ $Date: 2007/02/20 20:57:58 $
 * 
 */
public class BuilderConfig implements LoaderHolder {

    /**
     * Resource path to config file schemas and entities
     */
    public static final String COMPONENT_SCHEMA_BASE = "/META-INF/schema/";

    /**
     * Resource path to config file schemas and entities
     */
    public static final String ENTITIES_FOLDER = "entities";

    /**
     * default URI to dtd in classpath
     */
    private static final String COMPONENT_CONFIG_DTD_URI = COMPONENT_SCHEMA_BASE + "component-config.dtd";

    /**
     * root element of configuration file
     */
    private static final String GENERATOR_CONFIG_ROOT_ELEMENT = "components";

    /**
     * PUBLIC Id of configuration schema
     */
    private static final String GENERATOR_CONFIG_PUBLIC_ID = "-//AJAX4JSF//CDK Generator config/EN";

    /**
     * components described in this configuration
     */
    private List<ComponentBean> components = new ArrayList<ComponentBean>();

    /**
     * validators described in this configuration
     */
    private List<ValidatorBean> validators = new ArrayList<ValidatorBean>();

    /**
     * components described in this configuration
     */
    private List<ConverterBean> converters = new ArrayList<ConverterBean>();

    /**
     * renderers described in this configuration
     */
    private List<RendererBean> renderers = new ArrayList<RendererBean>();

    private List<ListenerBean> listeners = new ArrayList<ListenerBean>();

    private List<FunctionBean> functions = new ArrayList<FunctionBean>();

    private ClassLoader _loader;

    private Logger _log;

    /**
     * @param project -
     *                current ant project
     */
    public BuilderConfig(ClassLoader loader, Logger log) {
        _loader = loader;
        _log = log;
    }

    /**
     * Parsing builder configuration file
     * 
     * @param configFile
     * @throws ParsingException
     */
    public void parseConfig(final File configFile) throws ParsingException {
        getLog().info(" Parse config file " + configFile.toString());
        Digester digester = new Digester();
        digester.setRules(new ExtendedBaseRules());
        digester.setValidating(false);
        digester.setNamespaceAware(false);
        // try {
        // URL dtd =
        // this.getClass().getClassLoader().getResource(COMPONENT_CONFIG_DTD_URI);
        // new
        // URL("resource:/com/exadel/vcp/builder/config/component-config.dtd");
        getLog().debug("Register config DTD as URI " + COMPONENT_CONFIG_DTD_URI);
        digester.register(GENERATOR_CONFIG_PUBLIC_ID, COMPONENT_CONFIG_DTD_URI);
        // } catch (MalformedURLException e) {
        // throw new ParsingException("Malformed URL for internal DTD
        // reference",e);
        // }

        // setup custom entity resolver for handle file-resource path's
        // resolve DTD even it not pointed in file, and, for entities - resolve
        // it in
        // classpath if entity registered in DTD witn path /META-INF/schema
        digester.setEntityResolver(new EntityResolver2() {

            /*
             * (non-Javadoc)
             * 
             * @see org.xml.sax.EntityResolver#resolveEntity(java.lang.String,
             *      java.lang.String)
             */
            public InputSource resolveEntity(String publicId, String systemId) throws SAXException, IOException {
                getLog().debug("Request for entity with systemId " + systemId + " and publicId " + publicId);
                if (GENERATOR_CONFIG_PUBLIC_ID.equals(publicId)) {
                    return getDTDSource();
                } else if (null != publicId && null != systemId && systemId.contains(ENTITIES_FOLDER)) {
                    int base = systemId.indexOf(ENTITIES_FOLDER);
                    String entity = COMPONENT_SCHEMA_BASE + systemId.substring(base);
                    getLog().debug("attempt to load entity from classpath " + entity);
                    InputStream entityStream = BuilderConfig.class.getResourceAsStream(entity);
                    if (null != entityStream) {
                        return new InputSource(entityStream);
                    }
                }
                return null;
            }

            public InputSource getExternalSubset(String name, String baseURI) throws SAXException, IOException {
                getLog().debug("Request for ExternalSubset with name " + name + " and baseURI " + baseURI);
                if (GENERATOR_CONFIG_ROOT_ELEMENT.equals(name)) {
                    return getDTDSource();
                }
                return null;
            }

            public InputSource resolveEntity(String name, String publicId, String baseURI, String systemId)
                    throws SAXException, IOException {
                getLog().debug(
                        "Request for extended entity with systemId " + systemId + " and publicId " + publicId);
                getLog().debug("additional parameters with name " + name + " and baseURI " + baseURI);
                if ("[dtd]".equals(name) && GENERATOR_CONFIG_PUBLIC_ID.equals(publicId)) {
                    return getDTDSource();
                } else if (null == name || (!name.startsWith("[") && !name.startsWith("&"))) {
                    return resolveEntity(publicId, systemId);
                }
                return null;
            }

            /**
             * Resolve config DTD from classpath
             * 
             * @return source of config file DTD
             */
            private InputSource getDTDSource() {
                return new InputSource(BuilderConfig.class.getResourceAsStream(COMPONENT_CONFIG_DTD_URI));
            }

        });

        // Parsing rules.

        // Components
        String path = "components/component";
        digester.addObjectCreate(path, ComponentBean.class);
        digester.addBeanPropertySetter(path + "/name");
        digester.addBeanPropertySetter(path + "/family");
        digester.addBeanPropertySetter(path + "/classname");
        digester.addBeanPropertySetter(path + "/superclass");
        digester.addBeanPropertySetter(path + "/description");
        digester.addBeanPropertySetter(path + "/displayname");
        digester.addBeanPropertySetter(path + "/icon");
        // TODO - for superclass, populate from description in config file, if
        // exist
        digester.addSetProperties(path);
        digester.addSetNext(path, "addComponent");
        path = "components/renderer";
        digester.addObjectCreate(path, RendererBean.class);
        digester.addBeanPropertySetter(path + "/?");
        digester.addSetProperties(path);
        digester.addSetNext(path, "addRenderer");
        path = "components/component/renderer";
        digester.addObjectCreate(path, RendererBean.class);
        digester.addBeanPropertySetter(path + "/?");
        digester.addSetProperties(path);
        digester.addSetNext(path, "setRenderer");

        path = "components/component/facet";
        digester.addObjectCreate(path, JsfBean.class);
        digester.addBeanPropertySetter(path + "/?");
        digester.addSetProperties(path);
        digester.addSetNext(path, "addFacet");
        path = "components/component/event";
        digester.addObjectCreate(path, EventBean.class);
        digester.addBeanPropertySetter(path + "/?");
        digester.addSetProperties(path);
        digester.addSetNext(path, "addEvent");

        // Validators

        path = "components/validator";
        digester.addObjectCreate(path, ValidatorBean.class);
        digester.addBeanPropertySetter(path + "/id");
        digester.addBeanPropertySetter(path + "/classname");
        digester.addBeanPropertySetter(path + "/superclass");
        digester.addBeanPropertySetter(path + "/description");
        digester.addBeanPropertySetter(path + "/displayname");
        digester.addBeanPropertySetter(path + "/icon");
        // TODO - for superclass, populate from description in config file, if
        // exist
        digester.addSetProperties(path);
        digester.addSetNext(path, "addValidator");

        path = "components/validator/property";
        digester.addObjectCreate(path, PropertyBean.class);
        digester.addBeanPropertySetter(path + "/?");
        digester.addSetProperties(path);
        digester.addSetNext(path, "addProperty");

        // Converters

        path = "components/converter";
        digester.addObjectCreate(path, ConverterBean.class);
        digester.addBeanPropertySetter(path + "/id");
        digester.addBeanPropertySetter(path + "/classname");
        digester.addBeanPropertySetter(path + "/superclass");
        digester.addBeanPropertySetter(path + "/description");
        digester.addBeanPropertySetter(path + "/displayname");
        digester.addBeanPropertySetter(path + "/icon");
        digester.addBeanPropertySetter(path + "/forclass");
        // TODO - for superclass, populate from description in config file, if
        // exist
        digester.addSetProperties(path);
        digester.addSetNext(path, "addConverter");

        // Functions

        path = "components/function";
        digester.addObjectCreate(path, FunctionBean.class);
        digester.addBeanPropertySetter(path + "/name");
        digester.addBeanPropertySetter(path + "/description");
        digester.addBeanPropertySetter(path + "/method");
        digester.addSetNext(path, "addFunction");

        // - Tags & Tag handlers

        path = "components/component/tag";
        digester.addObjectCreate(path, TagBean.class);
        digester.addBeanPropertySetter(path + "/?");
        digester.addSetProperties(path);
        digester.addSetNext(path, "setTag");

        path = "components/validator/tag";
        digester.addObjectCreate(path, TagBean.class);
        digester.addBeanPropertySetter(path + "/?");
        digester.addSetProperties(path);
        digester.addSetNext(path, "setTag");

        path = "components/converter/tag";
        digester.addObjectCreate(path, TagBean.class);
        digester.addBeanPropertySetter(path + "/?");
        digester.addSetProperties(path);
        digester.addSetNext(path, "setTag");

        path = "components/component/tag/test";
        digester.addObjectCreate(path, TagTestClassHolder.class);
        digester.addBeanPropertySetter(path + "/?");
        digester.addSetProperties(path);
        digester.addSetNext(path, "setTest");

        path = "components/component/test";
        digester.addObjectCreate(path, TestClassHolder.class);
        digester.addBeanPropertySetter(path + "/?");
        digester.addSetProperties(path);
        digester.addSetNext(path, "setTest");

        path = "components/component/taghandler";
        digester.addObjectCreate(path, TagHandlerBean.class);
        digester.addBeanPropertySetter(path + "/?");
        digester.addSetProperties(path);
        digester.addSetNext(path, "setTaghandler");
        /*
              * path = "components/component/taghandler/test";
              * digester.addObjectCreate(path, TestClassHolder.class);
              * digester.addBeanPropertySetter(path+"/?");
              * digester.addSetProperties(path); digester.addSetNext(path,
              * "setTest");
              */

        // Properties
        path = "components/component/property";
        digester.addObjectCreate(path, PropertyBean.class);
        digester.addBeanPropertySetter(path + "/?");
        digester.addSetProperties(path);
        digester.addSetNext(path, "addProperty");

        // path = "components/validator/property";
        // digester.addObjectCreate(path, PropertyBean.class);
        // digester.addBeanPropertySetter(path+"/?");
        // digester.addSetProperties(path);
        // digester.addSetNext(path, "addProperty");

        path = "components/converter/property";
        digester.addObjectCreate(path, PropertyBean.class);
        digester.addBeanPropertySetter(path + "/?");
        digester.addSetProperties(path);
        digester.addSetNext(path, "addProperty");

        path = "*/properties/property";
        digester.addObjectCreate(path, PropertyBean.class);
        digester.addBeanPropertySetter(path + "/?");
        digester.addSetProperties(path);
        digester.addSetNext(path, "addProperty");

        // Listeners

        path = "components/listener";
        digester.addObjectCreate(path, ListenerBean.class);
        digester.addBeanPropertySetter(path + "/?");
        digester.addSetProperties(path);
        digester.addSetNext(path, "addListener");
        path = "components/listener/tag";
        digester.addObjectCreate(path, TagBean.class);
        digester.addBeanPropertySetter(path + "/?");
        digester.addSetProperties(path);
        digester.addSetNext(path, "setTag");
        path = "components/listener/taghandler";
        digester.addObjectCreate(path, TagHandlerBean.class);
        digester.addBeanPropertySetter(path + "/?");
        digester.addSetProperties(path);
        digester.addSetNext(path, "setTaghandler");
        path = "components/listener/property";
        digester.addObjectCreate(path, PropertyBean.class);
        digester.addBeanPropertySetter(path + "/?");
        digester.addSetProperties(path);
        digester.addSetNext(path, "addProperty");

        // Set this config as root.
        digester.push(this);
        try {
            digester.parse(configFile.toString());
        } catch (IOException e) {
            // TODO Auto-generated catch block
            throw new ParsingException("I/O error on parsing config file ", e);
        } catch (SAXException e) {
            // TODO Auto-generated catch block
            throw new ParsingException("SAX Parsing error in config file ", e);
        }
        // checkComopnentProperties();
        // return this;
    }

    /**
     * Check all components for existing and default properties.
     * 
     * @param classpath -
     *                classpath to find user components, renderers, tags
     * @throws ConfigurationException
     */
    public void checkComponentProperties() throws ParsingException {
        // ClassLoader loader = getProject().createClassLoader(classpath);
        // if(null == loader) {
        // loader = this.getClass().getClassLoader();
        // }
        // setLoader(loader);

        for (ListenerBean listener : getListeners()) {
            try {
                Class<?> listenerClass = Class.forName(listener.getComponentclass(), false, getLoader());

                for (ComponentBean bean : getComponents()) {
                    if (bean.getSuperclass() != null) {
                        Class<?> componentSClass = Class.forName(bean.getSuperclass(), false, getLoader());

                        if (listenerClass.isAssignableFrom(componentSClass)) {

                            PropertyBean listenerProperty = bean.getProperty(listener.getName());

                            if (null == listenerProperty) {
                                listenerProperty = new PropertyBean();
                                listenerProperty.setName(listener.getName());
                                bean.addProperty(listenerProperty);
                                listenerProperty.setClassname("javax.el.MethodExpression");
                            }

                            Map<String, PropertyDescriptor> map = getPropertyDescriptors(componentSClass);

                            PropertyDescriptor propertyDescriptor = map.get(listener.getName());

                            if (propertyDescriptor != null) {
                                String componentPropertyName = propertyDescriptor.getPropertyType().getName();

                                if (!componentPropertyName.equals(listenerProperty.getClassname())) {
                                    _log.error(String.format("Overriding property type %s with %s for %s.%s",
                                            listenerProperty.getClassname(), componentPropertyName,
                                            bean.getClassname(), listener.getName()));
                                }

                                listenerProperty.setClassname(componentPropertyName);
                            }

                            // TODO - check existing property for compability with this listener. 
                            listenerProperty.setEl(true);
                            listenerProperty.setElonly(true);
                            listenerProperty.setAttachedstate(true);
                            listenerProperty.setMethodargs(listener.getEventclass());
                            listener.addSuitableComponent(bean);
                        }
                    }
                }
            } catch (ClassNotFoundException e) {
                throw new BuildException(e);
            }

            listener.checkProperties();
        }

        for (Iterator iter = this.getComponents().iterator(); iter.hasNext();) {
            ComponentBaseBean component = (ComponentBaseBean) iter.next();
            component.checkProperties();
        }

        for (Iterator iter = this.getValidators().iterator(); iter.hasNext();) {
            ComponentBaseBean component = (ComponentBaseBean) iter.next();
            component.checkProperties();
        }

        for (Iterator iter = this.getConverters().iterator(); iter.hasNext();) {
            ComponentBaseBean component = (ComponentBaseBean) iter.next();
            component.checkProperties();
        }

    }

    private Map<String, PropertyDescriptor> getPropertyDescriptors(Class<?> clazz) {

        if (clazz.equals(Object.class)) {
            return Collections.emptyMap();
        }

        Map<String, PropertyDescriptor> m = new TreeMap<String, PropertyDescriptor>();

        Class<?> superclass = clazz.getSuperclass();
        if (superclass != null) {
            m.putAll(getPropertyDescriptors(superclass));
        }

        Class<?>[] interfaces = clazz.getInterfaces();
        if (interfaces != null) {
            for (Class<?> intrfc : interfaces) {
                m.putAll(getPropertyDescriptors(intrfc));
            }
        }

        PropertyDescriptor[] descriptors = PropertyUtils.getPropertyDescriptors(clazz);

        for (PropertyDescriptor propertyDescriptor : descriptors) {
            m.put(propertyDescriptor.getName(), propertyDescriptor);
        }

        return m;
    }

    /*
     * (non-Javadoc)
     * 
     * @see com.exadel.vcp.builder.config.LoaderHolder#getLoader()
     */
    public ClassLoader getLoader() {
        return _loader;
    }

    /*
     * (non-Javadoc)
     * 
     * @see com.exadel.vcp.builder.config.LoaderHolder#setLoader(java.lang.ClassLoader)
     */
    public void setLoader(ClassLoader loader) {
        _loader = loader;
    }

    public Logger getLog() {
        return _log;
    }

    public void addComponent(ComponentBean component) {
        this.components.add(component);
        component.setParent(this);
    }

    public void addValidator(ValidatorBean validator) {
        this.validators.add(validator);
        validator.setParent(this);
    }

    public void addConverter(ConverterBean converter) {
        this.converters.add(converter);
        converter.setParent(this);
    }

    public void addRenderer(RendererBean renderer) {
        this.renderers.add(renderer);
        renderer.setParent(this);
    }

    public void addListener(ListenerBean listener) {
        this.listeners.add(listener);
        listener.setParent(this);
    }

    public void addFunction(FunctionBean function) {
        this.functions.add(function);
        function.setParent(this);
    }

    /*
     * (non-Javadoc)
     * 
     * @see java.util.List#clear()
     */
    public void clear() {
        components.clear();
        renderers.clear();
    }

    /*
     * (non-Javadoc)
     * 
     * @see java.util.List#contains(java.lang.Object)
     */
    public boolean contains(Object o) {
        return components.contains(o);
    }

    /*
     * (non-Javadoc)
     * 
     * @see java.util.List#get(int)
     */
    public ComponentBaseBean get(int index) {
        return components.get(index);
    }

    /*
     * (non-Javadoc)
     * 
     * @see java.util.List#indexOf(java.lang.Object)
     */
    public int indexOf(ComponentBaseBean o) {
        return components.indexOf(o);
    }

    /*
     * (non-Javadoc)
     * 
     * @see java.util.List#isEmpty()
     */
    public boolean isEmpty() {
        return components.isEmpty();
    }

    /*
     * (non-Javadoc)
     * 
     * @see java.util.List#listIterator()
     */
    public List<ComponentBean> getComponents() {
        return components;
    }

    public List<ConverterBean> getConverters() {
        return converters;
    }

    public List<ValidatorBean> getValidators() {
        return validators;
    }

    public List<ListenerBean> getListeners() {
        return listeners;
    }

    /**
     * @return the renderers
     */
    public List<RendererBean> getRenderers() {
        return this.renderers;
    }

    public List<FunctionBean> getFunctions() {
        return functions;
    }

    /*
     * (non-Javadoc)
     * 
     * @see java.util.List#remove(int)
     */
    public ComponentBaseBean remove(int index) {
        return components.remove(index);
    }

    /*
     * (non-Javadoc)
     * 
     * @see java.util.List#remove(java.lang.Object)
     */
    public boolean remove(ComponentBaseBean o) {
        return components.remove(o);
    }

    /*
     * (non-Javadoc)
     * 
     * @see java.util.List#size()
     */
    public int size() {
        return components.size();
    }
}