Logo
Distributed Genetic Programming Framework
print print

File org.jfree.xml.generator.ModelBuilder.java

Here you can find all the information about the file org.jfree.xml.generator.ModelBuilder.java. You may explore it here or download it onto your local disk.
/* ========================================================================
 * JCommon : a free general purpose class library for the Java(tm) platform
 * ========================================================================
 *
 * (C) Copyright 2000-2005, by Object Refinery Limited and Contributors.
 * 
 * Project Info:  http://www.jfree.org/jcommon/index.html
 *
 * This library is free software; you can redistribute it and/or modify it 
 * under the terms of the GNU Lesser General Public License as published by 
 * the Free Software Foundation; either version 2.1 of the License, or 
 * (at your option) any later version.
 *
 * 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.  
 *
 * [Java is a trademark or registered trademark of Sun Microsystems, Inc. 
 * in the United States and other countries.]
 * 
 * -----------------
 * ModelBuilder.java
 * -----------------
 * (C)opyright 2003, 2004, by Thomas Morgner and Contributors.
 *
 * Original Author:  Thomas Morgner;
 * Contributor(s):   David Gilbert (for Object Refinery Limited);
 *
 * $Id: ModelBuilder.java,v 1.3 2005/10/18 13:32:20 mungady Exp $
 *
 * Changes
 * -------
 * 21-Jun-2003 : Initial version (TM);
 * 26-Nov-2003 : Updated header and Javadocs (DG);
 * 
 */


package org.jfree.xml.generator;

import java.beans.BeanInfo;
import java.beans.IndexedPropertyDescriptor;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Iterator;
import java.util.Properties;

import org.jfree.util.HashNMap;
import org.jfree.xml.generator.model.ClassDescription;
import org.jfree.xml.generator.model.DescriptionModel;
import org.jfree.xml.generator.model.MultiplexMappingInfo;
import org.jfree.xml.generator.model.PropertyInfo;
import org.jfree.xml.generator.model.PropertyType;
import org.jfree.xml.generator.model.TypeInfo;
import org.jfree.xml.util.BasicTypeSupport;

/**
 * A model builder.  This class performs the work of creating a class description model from
 * a set of source files.
 */

public final class ModelBuilder {

    /** The single instance. */
    private static ModelBuilder instance;

    /**
     * Returns the single instance of this class.
     * 
     * @return the single instance of this class.
     */

    public static ModelBuilder getInstance() {
        if (instance == null) {
            instance = new ModelBuilder();
        }
        return instance;
    }

    /** The handler mapping. */
    private Properties handlerMapping;

    /**
     * Creates a single instance.
     */

    private ModelBuilder() {
        this.handlerMapping = new Properties();
    }

    /**
     * Adds attribute handlers.
     * 
     * @param p  the handlers.
     */

    public void addAttributeHandlers(final Properties p) {
        this.handlerMapping.putAll(p);
    }

    /**
     * Builds a model from the classes provided by the {@link SourceCollector}. 
     * <P>
     * The {@link DescriptionGenerator} class invokes this.
     * 
     * @param c  the source collector.
     * @param model  the model under construction (<code>null</code> permitted).
     * 
     * @return The completed model.
     */

    public DescriptionModel buildModel(final SourceCollector c, DescriptionModel model) {
        
        Class[] classes = c.getClasses();

        if (model == null) {
            model = new DescriptionModel();
        }

        while (classes.length != 0) {
            classes = fillModel(classes, model);
        }

        fillSuperClasses(model);
        // search for multiplexer classes

        // first search all classes used in parameters and add them to
        // our list of possible base classes
        final Class[] baseClasses = findElementTypes(model);

        final HashNMap classMap = new HashNMap();
        for (int i = 0; i < baseClasses.length; i++) {

            final Class base = baseClasses[i];

            for (int j = 0; j < baseClasses.length; j++) {

                final Class child = baseClasses[j];
                if (Modifier.isAbstract(child.getModifiers())) {
                    continue;
                }
                if (base.isAssignableFrom(child)) {
                    classMap.add(base, child);
                }
            }
        }

        // at this point, the keys of 'classMap' represent all required
        // multiplexers, while the values assigned to these keys define the
        // possible childs
        final Iterator keys = classMap.keys();
        while (keys.hasNext()) {
            final Class base = (Class) keys.next();
            final Class[] childs = (Class[]) classMap.toArray(base, new Class[0]);
            if (childs.length < 2) {
                continue;
            }

            boolean isNew = false;
            MultiplexMappingInfo mmi = model.getMappingModel().lookupMultiplexMapping(base);
            final ArrayList typeInfoList;
            if (mmi == null) {
                mmi = new MultiplexMappingInfo(base);
                typeInfoList = new ArrayList();
                isNew = true;
            }
            else {
                typeInfoList = new ArrayList(Arrays.asList(mmi.getChildClasses()));
            }

            for (int i = 0; i < childs.length; i++) {
                // the generic information is only added, if no other information
                // is already present ...
                final TypeInfo typeInfo = new TypeInfo(childs[i].getName(), childs[i]);
                if (!typeInfoList.contains(typeInfo)) {
                    typeInfoList.add(typeInfo);
                }
            }

            mmi.setChildClasses((TypeInfo[]) typeInfoList.toArray(new TypeInfo[0]));
            if (isNew) {
                model.getMappingModel().addMultiplexMapping(mmi);
            }
        }

        // when resolving a class to an handler, the resolver first has to
        // search for an multiplexer before searching for handlers. Otherwise
        // non-abstract baseclasses will be found before the multiplexer can
        // resolve the situation.
        return model;
    }

    private Class[] findElementTypes(final DescriptionModel model) {
        final ArrayList baseClasses = new ArrayList();

        for (int i = 0; i < model.size(); i++) {
            final ClassDescription cd = model.get(i);
            if (!baseClasses.contains(cd.getObjectClass())) {
                baseClasses.add(cd.getObjectClass());
            }

            final PropertyInfo[] properties = cd.getProperties();
            for (int p = 0; p < properties.length; p++) {
                // filter primitive types ... they cannot form a generalization
                // relation
                if (!properties[p].getPropertyType().equals(PropertyType.ELEMENT)) {
                    continue;
                }
                final Class type = properties[p].getType();
                if (baseClasses.contains(type)) {
                    continue;
                }
                // filter final classes, they too cannot have derived classes
                if (Modifier.isFinal(type.getModifiers())) {
                    continue;
                }
                baseClasses.add(type);
            }
        }
        return (Class[]) baseClasses.toArray(new Class[baseClasses.size()]);
    }

    /**
     * Fills the super class for all object descriptions of the model. The
     * super class is only filled, if the object's super class is contained
     * in the model.
     *
     * @param model the model which should get its superclasses updated.
     */

    private void fillSuperClasses(final DescriptionModel model) {
        // Fill superclasses
        for (int i = 0; i < model.size(); i++) {
            final ClassDescription cd = model.get(i);
            final Class parent = cd.getObjectClass().getSuperclass();
            if (parent == null) {
                continue;
            }
            final ClassDescription superCD = model.get(parent);
            if (superCD != null) {
                cd.setSuperClass(superCD.getObjectClass());
            }
        }
    }

    /**
     * Updates the model to contain the given classes.
     *
     * @param classes  a list of classes which should be part of the model.
     * @param model  the model which is updated
     * 
     * @return A list of super classes which should also be contained in the model.
     */

    private Class[] fillModel(final Class[] classes, final DescriptionModel model) {
        // first check all direct matches from the source collector.
        // but make sure that we also detect external superclasses -
        // we have to get all properties ...
        final ArrayList superClasses = new ArrayList();
        for (int i = 0; i < classes.length; i++) {

            Class superClass = classes[i].getSuperclass();
            if (superClass != null) {
                if (!Object.class.equals(superClass) 
                    && !contains(classes, superClass) 
                    && !superClasses.contains(superClass)) {
                    superClasses.add(superClass);
                }
            }
            else {
                superClass = Object.class;
            }

            try {
                final BeanInfo bi = Introspector.getBeanInfo(classes[i], superClass);
                final ClassDescription parent = model.get(classes[i]);
                final ClassDescription cd = createClassDescription(bi, parent);
                if (cd != null) {
                    model.addClassDescription(cd);
                }
            }
            catch (IntrospectionException ie) {
                // swallowed....
            }
        }
        return (Class[]) superClasses.toArray(new Class[0]);
    }

    /**
     * Creates a {@link ClassDescription} object for the specified bean info.
     * 
     * @param beanInfo  the bean info.
     * @param parent  the parent class description.
     * 
     * @return The class description.
     */

    private ClassDescription createClassDescription (final BeanInfo beanInfo, final ClassDescription parent) {
        final PropertyDescriptor[] props = beanInfo.getPropertyDescriptors();
        final ArrayList properties = new ArrayList();
        for (int i = 0; i < props.length; i++) {
            final PropertyDescriptor propertyDescriptor = props[i];
            PropertyInfo pi;
            if (parent != null) {
                pi = parent.getProperty(propertyDescriptor.getName());
                if (pi != null) {
                    // Property already found, don't touch it
//                    Log.info (new Log.SimpleMessage
//                        ("Ignore predefined property: ", propertyDescriptor.getName()));
                    properties.add(pi);
                    continue;
                }
            }

            if (props[i] instanceof IndexedPropertyDescriptor) {
                // this would handle lists and array access. We don't support
                // this in the direct approach. We will need some cheating:
                // <Chart>
                //    <Subtitle-list>
                //         <title1 ..>
                //         <title2 ..>
                // pi = createIndexedPropertyInfo((IndexedPropertyDescriptor) props[i]);
            }
            else {
                pi = createSimplePropertyInfo(props[i]);
                if (pi != null) {
                    properties.add(pi);
                }
            }
        }

        final PropertyInfo[] propArray = (PropertyInfo[])
            properties.toArray(new PropertyInfo[properties.size()]);

        final ClassDescription cd;
        if (parent != null) {
            cd = parent;
        }
        else {
            cd = new ClassDescription(beanInfo.getBeanDescriptor().getBeanClass());
            cd.setDescription(beanInfo.getBeanDescriptor().getShortDescription());
        }

        cd.setProperties(propArray);
        return cd;
    }

    /**
     * Checks, whether the given method can be called from the generic object factory.
     *
     * @param method the method descriptor
     * @return true, if the method is not null and public, false otherwise.
     */

    public static boolean isValidMethod(final Method method) {
        if (method == null) {
            return false;
        }
        if (!Modifier.isPublic(method.getModifiers())) {
            return false;
        }
        return true;
    }

    /**
     * Creates a {@link PropertyInfo} object from a {@link PropertyDescriptor}.
     * 
     * @param pd  the property descriptor.
     * 
     * @return the property info (<code>null</code> possible).
     */

    public PropertyInfo createSimplePropertyInfo(final PropertyDescriptor pd) {

        final boolean readMethod = isValidMethod(pd.getReadMethod());
        final boolean writeMethod = isValidMethod(pd.getWriteMethod());
        if (!writeMethod || !readMethod) {
            // a property is useless for our purposes without having a read or write method.
            return null;
        }

        final PropertyInfo pi = new PropertyInfo(pd.getName(), pd.getPropertyType());
        pi.setConstrained(pd.isConstrained());
        pi.setDescription(pd.getShortDescription());
        pi.setNullable(true);
        pi.setPreserve(false);
        pi.setReadMethodAvailable(readMethod);
        pi.setWriteMethodAvailable(writeMethod);
        pi.setXmlName(pd.getName());
        if (isAttributeProperty(pd.getPropertyType())) {
            pi.setPropertyType(PropertyType.ATTRIBUTE);
            pi.setXmlHandler(getHandlerClass(pd.getPropertyType()));
        }
        else {
            pi.setPropertyType(PropertyType.ELEMENT);
        }
        return pi;
    }

    /**
     * Checks, whether the given class can be handled as attribute.
     * All primitive types can be attributes as well as all types which have
     * a custom attribute handler defined.
     *
     * @param c the class which should be checked
     * @return true, if the class can be handled as attribute, false otherwise.
     */

    private boolean isAttributeProperty(final Class c) {
        if (BasicTypeSupport.isBasicDataType(c)) {
            return true;
        }
        return this.handlerMapping.containsKey(c.getName());
    }

    /**
     * Returns the class name for the attribute handler for a property of the specified class.
     *
     * @param c the class for which to search an attribute handler
     * @return the handler class or null, if this class cannot be handled
     * as attribute.
     */

    private String getHandlerClass(final Class c) {
        if (BasicTypeSupport.isBasicDataType(c)) {
            final String handler = BasicTypeSupport.getHandlerClass(c);
            if (handler != null) {
                return handler;
            }
        }
        return this.handlerMapping.getProperty(c.getName());
    }

    /**
     * Checks, whether the class <code>c</code> is contained in the given
     * class array.
     *
     * @param cAll the list of all classes
     * @param c the class to be searched
     * @return true, if the class is contained in the array, false otherwise.
     */

    private boolean contains(final Class[] cAll, final Class c) {
        for (int i = 0; i < cAll.length; i++) {
            if (cAll[i].equals(c)) {
                return true;
            }
        }
        return false;
    }


//  private PropertyInfo createIndexedPropertyInfo(IndexedPropertyDescriptor prop)
//  {
//
//    MethodInfo readMethod = createMethodInfo(prop.getIndexedReadMethod());
//    MethodInfo writeMethod = createMethodInfo(prop.getIndexedWriteMethod());
//    if (writeMethod == null)
//    {
//      return null;
//    }
//    IndexedPropertyInfo pi = new IndexedPropertyInfo(prop.getName());
//    pi.setConstrained(prop.isConstrained());
//    pi.setDescription(prop.getShortDescription());
//    pi.setNullable(true);
//    pi.setPreserve(false);
//    pi.setType(prop.getIndexedPropertyType());
//    pi.setReadMethod(readMethod);
//    pi.setWriteMethod(writeMethod);
//
//    TypeInfo keyInfo = new TypeInfo("index");
//    keyInfo.setType(Integer.TYPE);
//    keyInfo.setNullable(false);
//    keyInfo.setConstrained(true); // throws indexoutofboundsexception
//    keyInfo.setDescription("Generic index value");
//    KeyDescription kd = new KeyDescription(new TypeInfo[]{keyInfo});
//    pi.setKey(kd);
//    return pi;
//  }
}

File Information:

file name:ModelBuilder.java
package:org.jfree.xml.generator
qualified name:org.jfree.xml.generator.ModelBuilder.java
file type:Java Source File
download location:download http://dgpf.sourceforge.net/source/org/jfree/xml/generator/ModelBuilder.java
size:17.082 KB (17492 B)
uploaded: 2015-07-22 04:11:10 GMT+0000
last update: 2006-09-26 10:30:38 GMT+0000
last access: 2018-01-24 01:39:10 GMT+0000

statistics online since 2006-01-02.   RSS Feed
Contact us by sending an email to tweise@gmx.de to receive further information, to report errors, or to join our project.
All content on this site (http://dgpf.sourceforge.net/) is LGPL-licensed.
http://dgpf.sourceforge.net/scripts/source/source.php last modified at 2015-07-22 04:10:53 GMT+0000 served at 2018-01-24 01:39:10 GMT+0000.
Valid CSS Valid XHTML 1.1
Valid RSS SourceForge.net Logo