org.apache.ojb.broker.metadata.fieldaccess.PersistentFieldIntrospectorImpl.java Source code

Java tutorial

Introduction

Here is the source code for org.apache.ojb.broker.metadata.fieldaccess.PersistentFieldIntrospectorImpl.java

Source

package org.apache.ojb.broker.metadata.fieldaccess;

/* Copyright 2003-2005 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.
 */

import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

import org.apache.commons.lang.StringUtils;
import org.apache.ojb.broker.core.proxy.ProxyHelper;
import org.apache.ojb.broker.metadata.MetadataException;
import org.apache.ojb.broker.util.ClassHelper;
import org.apache.ojb.broker.util.logging.Logger;

/**
 * A {@link PersistentField} implementation using
 * JavaBeans compliant calls only to access persistent attributes.
 * No Reflection is needed. But for each attribute xxx there must be
 * public getXxx() and setXxx() methods. In metadata the field name must be
 * the bean compliant 'xxx'.
 *
 * @version $Id: PersistentFieldIntrospectorImpl.java,v 1.11.2.2 2005/12/21 22:26:41 tomdz Exp $
 */
public class PersistentFieldIntrospectorImpl extends PersistentFieldBase {
    private static final long serialVersionUID = 8805309492150404444L;
    private Class type;
    private transient List propertyGraph;

    public PersistentFieldIntrospectorImpl() {
        super();
    }

    public PersistentFieldIntrospectorImpl(Class aClass, String aPropertyName) {
        super(aClass, aPropertyName);
    }

    public Class getType() {
        if (type == null) {
            type = getPropertyDescriptor().getPropertyType();
        }
        return type;
    }

    public void set(Object target, Object value) throws MetadataException {
        if (target == null)
            return;
        List propertyDescriptors = getPropertyGraph();
        int size = propertyDescriptors.size() - 1;
        PropertyDescriptor pd;
        for (int i = 0; i < size; i++) {
            Object attribute;
            pd = (PropertyDescriptor) propertyDescriptors.get(i);
            attribute = getValueFrom(pd, target);
            if (attribute != null || value != null) {
                if (attribute == null) {
                    try {
                        attribute = ClassHelper.newInstance(pd.getPropertyType());
                    } catch (Exception e) {
                        throw new MetadataException("Can't instantiate nested object of type '"
                                + pd.getPropertyType() + "' for field '" + pd.getName() + "'", e);
                    }
                }
                setValueFor(pd, target, attribute);
            } else {
                return;
            }
            target = attribute;
        }
        pd = (PropertyDescriptor) propertyDescriptors.get(size);
        setValueFor(pd, target, value);
    }

    public Object get(Object target) throws MetadataException {
        List propertyDescriptors = getPropertyGraph();
        for (int i = 0; i < propertyDescriptors.size(); i++) {
            PropertyDescriptor pd = (PropertyDescriptor) propertyDescriptors.get(i);
            target = getValueFrom(pd, target);
            if (target == null)
                break;
        }
        return target;
    }

    private Object getValueFrom(PropertyDescriptor pd, Object target) {
        if (target == null)
            return null;
        Method m = pd.getReadMethod();
        if (m != null) {
            try {
                return m.invoke(ProxyHelper.getRealObject(target), null);
            } catch (Throwable e) {
                logProblem(pd, target, null, "Can't read value from given object");
                throw new MetadataException(
                        "Error invoking method:" + m.getName() + " in object " + target.getClass().getName(), e);
            }
        } else {
            throw new MetadataException("Can't get ReadMethod for property:" + pd.getName() + " in object "
                    + target.getClass().getName());
        }
    }

    private void setValueFor(PropertyDescriptor pd, Object target, Object value) {
        Method m = pd.getWriteMethod();
        Object[] args = { value };
        if (m != null) {
            try {
                /**
                 * MBAIRD: it is safe to call getParameterTypes()[0] because this is
                 * the "set" method and it needs to take one parameter only.
                 * we need to be able to set values to null. We can only set something to null if
                 * the type is not a primitive (assignable from Object).
                 */
                if ((value != null) || !m.getParameterTypes()[0].isPrimitive()) {
                    m.invoke(ProxyHelper.getRealObject(target), args);
                }
            } catch (Throwable e) {
                logProblem(pd, target, value, "Can't set value on given object.");
                throw new MetadataException(
                        "Error invoking method:" + m.getName() + " in object:" + target.getClass().getName(), e);
            }
        } else {
            throw new MetadataException("Can't get WriteMethod for property:" + pd.getName() + " in object:"
                    + target.getClass().getName());
        }
    }

    private List getPropertyGraph() {
        if (propertyGraph == null) {
            propertyGraph = buildPropertyGraph();
        }
        return propertyGraph;
    }

    private List buildPropertyGraph() {
        List result = new ArrayList();
        String[] fields = StringUtils.split(getName(), PATH_TOKEN);
        PropertyDescriptor pd = null;
        for (int i = 0; i < fields.length; i++) {
            String fieldName = fields[i];
            if (pd == null) {
                pd = findPropertyDescriptor(getDeclaringClass(), fieldName);
            } else {
                pd = findPropertyDescriptor(pd.getPropertyType(), fieldName);
            }
            result.add(pd);
        }
        return result;
    }

    /**
     * Get the PropertyDescriptor for aClass and aPropertyName
     */
    protected static PropertyDescriptor findPropertyDescriptor(Class aClass, String aPropertyName) {
        BeanInfo info;
        PropertyDescriptor[] pd;
        PropertyDescriptor descriptor = null;

        try {
            info = Introspector.getBeanInfo(aClass);
            pd = info.getPropertyDescriptors();
            for (int i = 0; i < pd.length; i++) {
                if (pd[i].getName().equals(aPropertyName)) {
                    descriptor = pd[i];
                    break;
                }
            }
            if (descriptor == null) {
                /*
                * Daren Drummond:    Throw here so we are consistent
                *                with PersistentFieldDefaultImpl.
                */
                throw new MetadataException("Can't find property " + aPropertyName + " in " + aClass.getName());
            }
            return descriptor;
        } catch (IntrospectionException ex) {
            /*
            * Daren Drummond:    Throw here so we are consistent
            *                with PersistentFieldDefaultImpl.
            */
            throw new MetadataException("Can't find property " + aPropertyName + " in " + aClass.getName(), ex);
        }
    }

    /**
     * Returns the PropertyDescriptor.
     *
     * @return java.beans.PropertyDescriptor
     */
    protected PropertyDescriptor getPropertyDescriptor() {
        return (PropertyDescriptor) getPropertyGraph().get(getPropertyGraph().size() - 1);
    }

    /**
     * This implementation returns always 'false'.
     */
    public boolean makeAccessible() {
        return false;
    }

    /**
     * Always returns 'false'.
     *
     * @see PersistentField#usesAccessorsAndMutators
     */
    public boolean usesAccessorsAndMutators() {
        return true;
    }

    /**
     * Let's give the user some hints as to what could be wrong.
     */
    protected void logProblem(PropertyDescriptor pd, Object anObject, Object aValue, String msg) {
        Logger logger = getLog();
        logger.error("Error in [PersistentFieldPropertyImpl], " + msg);
        logger.error("Declaring class [" + getDeclaringClass().getName() + "]");
        logger.error("Property Name [" + getName() + "]");
        logger.error("Property Type [" + pd.getPropertyType().getName() + "]");

        if (anObject != null) {
            logger.error("anObject was class [" + anObject.getClass().getName() + "]");
        } else {
            logger.error("anObject was null");
        }
        if (aValue != null) {
            logger.error("aValue was class [" + aValue.getClass().getName() + "]");
        } else {
            logger.error("aValue was null");
        }
    }
}