All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.apache.tapestry5.internal.services.BeanModelSourceImpl Maven / Gradle / Ivy

Go to download

Central module for Tapestry, containing interfaces to the Java Servlet API and all core services and components.

There is a newer version: 5.8.6
Show newest version
// Copyright 2007, 2008, 2010 The Apache Software Foundation
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

package org.apache.tapestry5.internal.services;

import java.lang.reflect.Method;
import java.util.Collections;
import java.util.List;

import org.apache.tapestry5.beaneditor.BeanModel;
import org.apache.tapestry5.beaneditor.NonVisual;
import org.apache.tapestry5.beaneditor.ReorderProperties;
import org.apache.tapestry5.internal.beaneditor.BeanModelImpl;
import org.apache.tapestry5.internal.beaneditor.BeanModelUtils;
import org.apache.tapestry5.ioc.Location;
import org.apache.tapestry5.ioc.Messages;
import org.apache.tapestry5.ioc.ObjectLocator;
import org.apache.tapestry5.ioc.annotations.Primary;
import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
import org.apache.tapestry5.ioc.services.ClassFactory;
import org.apache.tapestry5.ioc.services.ClassPropertyAdapter;
import org.apache.tapestry5.ioc.services.PropertyAccess;
import org.apache.tapestry5.ioc.services.PropertyAdapter;
import org.apache.tapestry5.ioc.services.TypeCoercer;
import org.apache.tapestry5.services.BeanModelSource;
import org.apache.tapestry5.services.ComponentLayer;
import org.apache.tapestry5.services.DataTypeAnalyzer;
import org.apache.tapestry5.services.PropertyConduitSource;

public class BeanModelSourceImpl implements BeanModelSource
{
    private final TypeCoercer typeCoercer;

    private final PropertyAccess propertyAccess;

    private final PropertyConduitSource propertyConduitSource;

    private final ClassFactory classFactory;

    private final DataTypeAnalyzer dataTypeAnalyzer;

    private final ObjectLocator locator;

    private static class PropertyOrder implements Comparable
    {
        final String propertyName;

        final int classDepth;

        final int sortKey;

        public PropertyOrder(final String propertyName, int classDepth, int sortKey)
        {
            this.propertyName = propertyName;
            this.classDepth = classDepth;
            this.sortKey = sortKey;
        }

        public int compareTo(PropertyOrder o)
        {
            int result = classDepth - o.classDepth;

            if (result == 0)
                result = sortKey - o.sortKey;

            if (result == 0)
                result = propertyName.compareTo(o.propertyName);

            return result;
        }
    }

    /**
     * @param classAdapter
     *            defines the bean that contains the properties
     * @param propertyNames
     *            the initial set of property names, which will be rebuilt in the correct order
     */
    private void orderProperties(ClassPropertyAdapter classAdapter, List propertyNames)
    {
        List properties = CollectionFactory.newList();

        for (String name : propertyNames)
        {
            PropertyAdapter pa = classAdapter.getPropertyAdapter(name);

            Method readMethod = pa.getReadMethod();

            Location location = readMethod == null ? null : classFactory.getMethodLocation(readMethod);

            int line = location == null ? -1 : location.getLine();

            properties.add(new PropertyOrder(name, computeDepth(pa), line));
        }

        Collections.sort(properties);

        propertyNames.clear();

        for (PropertyOrder po : properties)
        {
            propertyNames.add(po.propertyName);
        }
    }

    private static int computeDepth(PropertyAdapter pa)
    {
        int depth = 0;
        Class c = pa.getDeclaringClass();

        // When the method originates in an interface, the parent may be null, not Object.

        while (c != null && c != Object.class)
        {
            depth++;
            c = c.getSuperclass();
        }

        return depth;
    }

    public BeanModelSourceImpl(TypeCoercer typeCoercer, PropertyAccess propertyAccess,
            PropertyConduitSource propertyConduitSource, @ComponentLayer
            ClassFactory classFactory, @Primary
            DataTypeAnalyzer dataTypeAnalyzer, ObjectLocator locator)
    {
        this.typeCoercer = typeCoercer;
        this.propertyAccess = propertyAccess;
        this.propertyConduitSource = propertyConduitSource;
        this.classFactory = classFactory;
        this.dataTypeAnalyzer = dataTypeAnalyzer;
        this.locator = locator;
    }

    public  BeanModel createDisplayModel(Class beanClass, Messages messages)
    {
        return create(beanClass, false, messages);
    }

    public  BeanModel createEditModel(Class beanClass, Messages messages)
    {
        return create(beanClass, true, messages);
    }

    public  BeanModel create(Class beanClass, boolean filterReadOnlyProperties, Messages messages)
    {
        assert beanClass != null;
        assert messages != null;
        ClassPropertyAdapter adapter = propertyAccess.getAdapter(beanClass);

        BeanModel model = new BeanModelImpl(beanClass, propertyConduitSource, typeCoercer, messages, locator);

        for (final String propertyName : adapter.getPropertyNames())
        {
            PropertyAdapter pa = adapter.getPropertyAdapter(propertyName);

            if (!pa.isRead())
                continue;

            if (pa.getAnnotation(NonVisual.class) != null)
                continue;

            if (filterReadOnlyProperties && !pa.isUpdate())
                continue;

            final String dataType = dataTypeAnalyzer.identifyDataType(pa);

            // If an unregistered type, then ignore the property.

            if (dataType == null)
                continue;

            model.add(propertyName).dataType(dataType);
        }

        // First, order the properties based on the location of the getter method
        // within the class.

        List propertyNames = model.getPropertyNames();

        orderProperties(adapter, propertyNames);

        model.reorder(propertyNames.toArray(new String[propertyNames.size()]));

        // Next, check for an annotation with specific ordering information.

        ReorderProperties reorderAnnotation = beanClass.getAnnotation(ReorderProperties.class);

        if (reorderAnnotation != null)
        {
            BeanModelUtils.reorder(model, reorderAnnotation.value());
        }

        return model;
    }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy