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

net.sf.cuf.model.MixedAccessAdapter Maven / Gradle / Ivy

The newest version!
package net.sf.cuf.model;

import java.lang.reflect.Method;
import java.util.StringTokenizer;
import java.util.Map;

/**
 * This Adapter maps aspect names to a get/set method call
 * or to a Map get/put call.
 * The disadvantege to a MethodAccessAdapter is that isEditable always
 * returns true and most checks can't be done during the construction,
 * so the MapAccessAdapter is less fail fast than the MethodAccessAdapter.
 */
public class MixedAccessAdapter implements AspectAccessAdapter
{
    // the aspect names we use for access, never null
    private String[]       mAspectNames;
    // the getter methods to our aspect, never null, mGetMethods.length==mAspectNames.length
    private Method[]       mGetMethods;
    // the set method of our aspect, may be null if the aspect is not mutable or is a map access
    private Method         mSetMethod;
    // the get method prefix, never null
    private String         mGetPrefix;
    // the set method prefix, never null
    private String         mSetPrefix;

    private static final Class[]  NO_PARAMS   = new Class [0];
    private static final Object[] NO_ARGS     = new Object[0];

    /**
     * Creates a new adapter for a mixed map/reflection-based source. As get/set prefix "get"
     * and "set" are used.
     * @param pAspectName the aspect name, may be separated by AspectAdapter.SEPARATOR
     */
    public MixedAccessAdapter(final String pAspectName)
    {
        this(pAspectName, AspectAdapter.GET, AspectAdapter.SET);
    }

    /**
     * Creates a new adapter for a mixed map/reflection-based source. As get/set prefix "get"
     * and "set" are used.
     * @param pSourceClass the class expected in the source, may be null
     * @param pAspectName the aspect name, may be separated by AspectAdapter.SEPARATOR
     */
    public MixedAccessAdapter(final Class pSourceClass, final String pAspectName)
    {
        this(pSourceClass, pAspectName, AspectAdapter.GET, AspectAdapter.SET);
    }

    /**
     * Creates a new adapter for a mixed map/reflection-based source.
     * @param pAspectName the aspect name, may be separated by AspectAdapter.SEPARATOR
     * @param pGetterPrefix the prefix we use for the "getter", must not be null nor empty
     * @param pSetterPrefix the prefix we use for the "getter", must not be null nor empty nor the getter prefix
     */
    public MixedAccessAdapter( final String pAspectName, final String pGetterPrefix, final String pSetterPrefix)
    {
        this( null, pAspectName, pGetterPrefix, pSetterPrefix);
    }
    
    /**
     * Creates a new adapter for a mixed map/reflection-based source.
     * @param pSourceClass the class expected in the source, may be null
     * @param pAspectName the aspect name, may be separated by AspectAdapter.SEPARATOR
     * @param pGetterPrefix the prefix we use for the "getter", must not be null nor empty
     * @param pSetterPrefix the prefix we use for the "getter", must not be null nor empty nor the getter prefix
     */
    public MixedAccessAdapter(final Class pSourceClass, final String pAspectName, final String pGetterPrefix, final String pSetterPrefix)
    {
        // check the setter and getter name
        if (pGetterPrefix==null) throw new IllegalArgumentException("GetterPrefix must not be null");
        if (pSetterPrefix==null) throw new IllegalArgumentException("SetterPrefix must not be null");
        if (pGetterPrefix.length()==0) throw new IllegalArgumentException("GetterPrefix must not be empty");
        if (pSetterPrefix.length()==0) throw new IllegalArgumentException("SetterPrefix must not be empty");
        if (pSetterPrefix.equals(pGetterPrefix)) throw new IllegalArgumentException("get and set prefix must differ");
        mGetPrefix= pGetterPrefix;
        mSetPrefix= pSetterPrefix;

        // just extract the attribute strings
        StringTokenizer st= new StringTokenizer(pAspectName, AspectAdapter.SEPARATOR);
        mGetMethods = new Method[st.countTokens()];
        mAspectNames= new String[mGetMethods.length];

        for (int i= 0; i< mGetMethods.length; i++ )
        {
            mAspectNames[i]= st.nextToken();
        }
        
        if (pSourceClass!=null && !Map.class.isAssignableFrom( pSourceClass))
        {
            // check if the first aspect if it corresponds to a valid getter
            String getterName= mGetPrefix+
            mAspectNames[0].substring(0, 1).toUpperCase()+
            mAspectNames[0].substring(1);
            try
            {
                pSourceClass.getMethod(getterName, NO_PARAMS);
            }
            catch (NoSuchMethodException e)
            {
                throw new IllegalArgumentException("Class "+pSourceClass+
                                            " does not have a method "+
                                            getterName+"(). "+
                                            "If you want to use late binding you must not provide a source class.");
            }
        }
        
    }

    /**
     * Returns always true.
     * @return true
     */
    public boolean isEditable()
    {
        return true;
    }

    /**
     * Extract the value from the source.
     * @param pSource the source, may be null
     * @return null or the value
     */
    public Object getValue(final Object pSource)
    {
        if (pSource==null)
        {
            return null;
        }

        /*
         * we can't map everything staticly, but must check during a get/set if
         * the return type matches the stored Method or not.
         */
        Object aspect= pSource;
        for (int i = 0; i < mAspectNames.length; i++)
        {
            String aspectName= mAspectNames[i];

            if (aspect==null)
            {
                return null;
            }
            else if (aspect instanceof Map)
            {
                Map source= (Map)aspect;
                aspect= source.get(aspectName);
            }
            else
            {
                aspect = getAspect(aspect, i, aspectName);
            }
        }

        return aspect;
    }

    private Object getAspect(Object pAspect, final int pI, final String pAspectName)
    {
        Class  aspectClass= pAspect.getClass();
        // check if there is no method or or the known method doesn't match
        if ((mGetMethods[pI]==null) ||
            !mGetMethods[pI].getDeclaringClass().isAssignableFrom(aspectClass))
        {
            Method getter;
            String getterName= mGetPrefix+
                               pAspectName.substring(0, 1).toUpperCase()+
                               pAspectName.substring(1);
            try
            {
                getter = aspectClass.getMethod(getterName, NO_PARAMS);
            }
            catch (NoSuchMethodException e)
            {
                throw new IllegalArgumentException("Class "+aspectClass+
                                                   " does not have a method "+
                                                   getterName+"()");
            }
            mGetMethods[pI]= getter;
        }

        // we no have the method object, let's call it
        try
        {
            pAspect= mGetMethods[pI].invoke(pAspect, NO_ARGS);
        }
        catch (Exception e)
        {
            throw new IllegalArgumentException(
                    "While extracting aspect "+pAspectName+
                    " on object of class "+aspectClass+": "+e.getMessage(), e.getCause());
        }

        return pAspect;
    }

    /**
     * Sets a value to the source.
     * @param pSource the source, never null
     * @param pValue  the new value, may be null
     */
    public void setValue(final Object pSource, final Object pValue)
    {
        Object aspect= pSource;
        Object source= aspect;
        for (int i = 0; i < mAspectNames.length; i++)
        {
            String aspectName= mAspectNames[i];

            if (aspect instanceof Map)
            {
                aspect= ((Map)aspect).get(aspectName);
            }
            else
            {
                aspect = getAspect(aspect, i, aspectName);
            }

            if (i==mAspectNames.length-2)
            {
                source= aspect;
            }
        }

        // just to be sure that no accidential misuse can happen
        //noinspection UnusedAssignment
        aspect= null;

        // set the value
        String lastAspectName = mAspectNames[mAspectNames.length-1];
        if (source instanceof Map)
        {
            ((Map)source).put(lastAspectName, pValue);
        }
        else
        {
            Class  sourceClass = source.getClass();
            // check if there is no method or or the known method doesn't match
            if ((mSetMethod==null) ||
                !mSetMethod.getDeclaringClass().isAssignableFrom(sourceClass))
            {
                // we must extract a new setter
                String setterName = mSetPrefix+
                                    lastAspectName.substring(0, 1).toUpperCase()+
                                    lastAspectName.substring(1);
                Class getterReturnClass = mGetMethods[mAspectNames.length - 1].getReturnType();
                try
                {
                    mSetMethod = sourceClass.getMethod(setterName, new Class []{getterReturnClass});
                }
                catch (NoSuchMethodException e)
                {
                    String sb = "Class " + sourceClass.getName() +
                                " does not have a method " +
                                setterName +
                                '(' +
                                getterReturnClass.getName() +
                                ')';
                    throw new IllegalArgumentException(sb);
                }
            }

            // we now have the method object, let's call it
            try
            {
                mSetMethod.invoke(source, pValue);
            }
            catch (Exception e)
            {
                throw new IllegalArgumentException(
                        "While setting aspect "+lastAspectName +
                        " on object of class "+sourceClass +": "+
                        e.getMessage(), e.getCause());
            }
        }
    }
}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy