Package org.qi4j.runtime.types

Source Code of org.qi4j.runtime.types.ValueTypeFactory$ValueFinder

/*
* Copyright 2009 Niclas Hedhman.
*
* 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.qi4j.runtime.types;

import org.qi4j.api.common.InvalidApplicationException;
import org.qi4j.api.common.MetaInfo;
import org.qi4j.api.common.Visibility;
import org.qi4j.api.type.*;
import org.qi4j.api.util.Classes;
import org.qi4j.api.value.ValueComposite;
import org.qi4j.functional.HierarchicalVisitor;
import org.qi4j.functional.Iterables;
import org.qi4j.runtime.association.AssociationsModel;
import org.qi4j.runtime.association.ManyAssociationsModel;
import org.qi4j.runtime.composite.CompositeMethodsModel;
import org.qi4j.runtime.composite.MixinsModel;
import org.qi4j.runtime.property.PropertiesModel;
import org.qi4j.runtime.structure.LayerModel;
import org.qi4j.runtime.structure.ModuleModel;
import org.qi4j.runtime.structure.UsedLayersModel;
import org.qi4j.runtime.value.ValueModel;
import org.qi4j.runtime.value.ValueStateModel;
import org.qi4j.runtime.value.ValuesModel;

import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.lang.reflect.TypeVariable;

public class ValueTypeFactory
{
    private static final ValueTypeFactory instance = new ValueTypeFactory();

    public static ValueTypeFactory instance()
    {
        return instance;
    }

    public ValueType newValueType( Type type, Class declaringClass, Class compositeType, LayerModel layer, ModuleModel module )
    {
        ValueType valueType = null;
        if( CollectionType.isCollection( type ) )
        {
            if( type instanceof ParameterizedType )
            {
                ParameterizedType pt = (ParameterizedType) type;
                Type collectionType = pt.getActualTypeArguments()[ 0 ];
                if( collectionType instanceof TypeVariable )
                {
                    TypeVariable collectionTypeVariable = (TypeVariable) collectionType;
                    collectionType = Classes.resolveTypeVariable( collectionTypeVariable, declaringClass, compositeType );
                }
                ValueType collectedType = newValueType( collectionType, declaringClass, compositeType, layer, module );
                valueType = new CollectionType( Classes.RAW_CLASS.map(type) , collectedType );
            }
            else
            {
                valueType = new CollectionType( Classes.RAW_CLASS.map(type) , newValueType( Object.class, declaringClass, compositeType, layer, module ) );
            }
        }
        else if( MapType.isMap( type ) )
        {
            if( type instanceof ParameterizedType )
            {
                ParameterizedType pt = (ParameterizedType) type;
                Type keyType = pt.getActualTypeArguments()[ 0 ];
                if( keyType instanceof TypeVariable )
                {
                    TypeVariable keyTypeVariable = (TypeVariable) keyType;
                    keyType = Classes.resolveTypeVariable( keyTypeVariable, declaringClass, compositeType );
                }
                ValueType keyedType = newValueType( keyType, declaringClass, compositeType, layer, module );

                Type valType = pt.getActualTypeArguments()[ 1 ];
                if( valType instanceof TypeVariable )
                {
                    TypeVariable valueTypeVariable = (TypeVariable) valType;
                    valType = Classes.resolveTypeVariable( valueTypeVariable, declaringClass, compositeType );
                }
                ValueType valuedType = newValueType( valType, declaringClass, compositeType, layer, module );

                valueType = new MapType( Classes.RAW_CLASS.map(type) , keyedType, valuedType );
            }
            else
            {
                valueType = new MapType( Classes.RAW_CLASS.map(type) , newValueType( Object.class, declaringClass, compositeType, layer, module ), newValueType( Object.class, declaringClass, compositeType, layer, module ) );
            }
        }
        else if( ValueCompositeType.isValueComposite( type ) )
        {
            // Find ValueModel in module/layer/used layers
            ValueModel model = new ValueFinder(layer, module, Classes.RAW_CLASS.map( type )).getFoundModel();

            if (model == null)
            {
                if (type.equals( ValueComposite.class ))
                {
                    // Create default model
                    MixinsModel mixinsModel = new MixinsModel();
                    model = new ValueModel( ValueComposite.class, (Iterable) Iterables.iterable(ValueComposite.class), Visibility.application, new MetaInfo( ), mixinsModel, new ValueStateModel( new PropertiesModel(), new AssociationsModel(), new ManyAssociationsModel() ), new CompositeMethodsModel( mixinsModel ) );
                } else
                    throw new InvalidApplicationException("["+module.name()+"] Could not find ValueComposite of type "+type);
            }

            return model.valueType();
        }
        else if( EnumType.isEnum( type ) )
        {
            valueType = new EnumType( Classes.RAW_CLASS.map(type)  );
        }else
        {
            valueType = new ValueType(Classes.RAW_CLASS.map(type) );
        }

        return valueType;
    }

    private class ValueFinder
        extends HierarchicalVisitor<Object, Object, RuntimeException>
    {
        private Class type;
        private ValueModel foundModel;
        private Visibility visibility;

        private ValueFinder( LayerModel layer, ModuleModel module, Class type )
        {
            this.type = type;

            visibility = Visibility.module;
            module.accept( this );

            if (foundModel == null)
            {
                visibility = Visibility.layer;
                layer.accept( this );

                if (foundModel == null)
                {
                    visibility = Visibility.application;
                    layer.usedLayers().accept( this );
                }
            }
        }

        public ValueModel getFoundModel()
        {
            return foundModel;
        }

        @Override
        public boolean visitEnter( Object visited ) throws RuntimeException
        {
            if (visited instanceof ValuesModel )
                return true;
            else if (visited instanceof ModuleModel )
                return true;
            else if (visited instanceof UsedLayersModel )
                return true;
            else if (visited instanceof ValueModel )
            {
                ValueModel valueModel = (ValueModel) visited;
                if (valueModel.type().equals( type ) && valueModel.visibility().ordinal() >= visibility.ordinal())
                {
                    foundModel = valueModel;
                }
            }

            return false;
        }

        @Override
        public boolean visitLeave( Object visited ) throws RuntimeException
        {
            return foundModel == null;
        }
    }
}
TOP

Related Classes of org.qi4j.runtime.types.ValueTypeFactory$ValueFinder

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.