Package org.qi4j.runtime.property

Source Code of org.qi4j.runtime.property.PropertyInstance

/*
* Copyright (c) 2007, Rickard Öberg. All Rights Reserved.
* Copyright (c) 2008, Edward Yakop. All Rights Reserved.
*
* 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.property;

import java.util.ArrayList;
import java.util.Collection;
import java.util.Collections;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.qi4j.api.property.Property;
import org.qi4j.api.property.PropertyDescriptor;
import org.qi4j.api.property.PropertyWrapper;
import org.qi4j.api.type.CollectionType;
import org.qi4j.api.type.MapType;
import org.qi4j.api.type.ValueCompositeType;
import org.qi4j.api.value.ValueComposite;
import org.qi4j.runtime.value.ValueInstance;

/**
* {@code PropertyInstance} represents a property.
*/
public class PropertyInstance<T>
    implements Property<T>
{
    protected volatile T value;
    protected PropertyInfo model;

    /**
     * Construct an instance of {@code PropertyInstance} with the specified arguments.
     *
     * @param model  The property model. This argument must not be {@code null}.
     * @param aValue The property value.
     */
    public PropertyInstance( PropertyInfo model, T aValue )
    {
        this.model = model;
        value = aValue;
    }

    public PropertyInfo propertyInfo()
    {
        return model;
    }

    /**
     * @param model The property model. This argument must not be {@code null}.
     */
    public void setPropertyInfo( PropertyInfo model )
    {
        this.model = model;
    }

    /**
     * Returns this property value.
     *
     * @return This property value.
     */
    @Override
    public T get()
    {
        return value;
    }

    /**
     * Sets this property value.
     *
     * @param aNewValue The new value.
     */
    @Override
    public void set( T aNewValue )
    {
        if( model.isImmutable() )
        {
            throw new IllegalStateException( "Property [" + model.qualifiedName() + "] is immutable." );
        }

        model.checkConstraints( aNewValue );

        value = aNewValue;
    }

    /**
     * Perform equals with {@code o} argument.
     * <p>
     *     The definition of equals() for the Property is that if both the state and descriptor are equal,
     *     then the properties are equal.
     * </p>
     *
     * @param o The other object to compare.
     * @return Returns a {@code boolean} indicator whether this object is equals the other.
     */
    @Override
    public boolean equals( Object o )
    {
        if( this == o )
        {
            return true;
        }
        if( o == null || getClass() != o.getClass() )
        {
            return false;
        }

        Property<?> that = (Property<?>) o;
        // Unwrap if needed
        while( that instanceof PropertyWrapper )
        {
            that = ( (PropertyWrapper) that ).next();
        }
        // Descriptor equality
        PropertyDescriptor thatDescriptor = (PropertyDescriptor) ( (PropertyInstance) that ).propertyInfo();
        if( !model.equals( thatDescriptor ) )
        {
            return false;
        }
        // State equality
        T value = get();
        if( value == null )
        {
            return that.get() == null;
        }
        return value.equals( that.get() );
    }

    /**
     * Calculate hash code.
     *
     * @return the hashcode of this instance.
     */
    @Override
    public int hashCode()
    {
        int hash = model.hashCode() * 19; // Descriptor
        T value = get();
        if( value != null )
        {
            hash += value.hashCode() * 13; // State
        }
        return hash;
    }

    /**
     * Returns the value as string.
     *
     * @return The value as string.
     */
    @Override
    public String toString()
    {
        Object value = get();
        return value == null ? "" : value.toString();
    }

    @SuppressWarnings( {"raw", "unchecked"} )
    public void prepareToBuild( PropertyModel propertyDescriptor )
    {
        // Check if state has to be modified
        model = propertyDescriptor.getBuilderInfo();
        if( propertyDescriptor.valueType() instanceof ValueCompositeType )
        {
            Object value = get();
            if( value != null )
            {
                ValueInstance.valueInstanceOf( (ValueComposite) value ).prepareToBuild();
            }
        }
        else if( propertyDescriptor.valueType() instanceof CollectionType )
        {
            Object value = get();

            if( value != null )
            {
                if( value instanceof List )
                {
                    value = new ArrayList( (Collection) value );
                }
                else if( value instanceof Set )
                {
                    value = new LinkedHashSet( (Collection) value );
                }

                // Check if items are Values
                CollectionType collection = (CollectionType) propertyDescriptor.valueType();
                if( collection.collectedType() instanceof ValueCompositeType )
                {
                    Collection coll = (Collection) value;
                    for( Object instance : coll )
                    {
                        ValueInstance.valueInstanceOf( (ValueComposite) instance ).prepareToBuild();
                    }
                }

                set( (T) value );
            }
        }
        else if( propertyDescriptor.valueType() instanceof MapType )
        {
            Object value = get();

            if( value != null )
            {
                Map map = new LinkedHashMap( (Map) value );

                // Check if keys/values are Values
                MapType mapType = (MapType) propertyDescriptor.valueType();
                if( mapType.keyType() instanceof ValueCompositeType )
                {
                    for( Object instance : map.keySet() )
                    {
                        ValueInstance.valueInstanceOf( (ValueComposite) instance ).prepareToBuild();
                    }
                }
                if( mapType.valueType() instanceof ValueCompositeType )
                {
                    for( Object instance : map.values() )
                    {
                        ValueInstance.valueInstanceOf( (ValueComposite) instance ).prepareToBuild();
                    }
                }

                set( (T) value );
            }
        }
    }

    @SuppressWarnings( {"raw", "unchecked"} )
    public void prepareBuilderState( PropertyModel propertyDescriptor )
    {
        // Check if state has to be modified
        if( propertyDescriptor.valueType() instanceof ValueCompositeType )
        {
            Object value = get();
            if( value != null )
            {
                ValueInstance.valueInstanceOf( (ValueComposite) value ).prepareBuilderState();
            }
        }
        else if( propertyDescriptor.valueType() instanceof CollectionType )
        {
            T value = get();
            if( value != null )
            {
                if( propertyDescriptor.isImmutable() )
                {
                    if( value instanceof List )
                    {
                        value = (T) Collections.unmodifiableList( (List<? extends Object>) value );
                    }
                    else if( value instanceof Set )
                    {
                        value = (T) Collections.unmodifiableSet( (Set<? extends Object>) value );
                    }
                    else
                    {
                        value = (T) Collections.unmodifiableCollection( (Collection<? extends Object>) value );
                    }

                    this.value = value;
                }

                CollectionType collection = (CollectionType) propertyDescriptor.valueType();
                if( collection.collectedType() instanceof ValueCompositeType )
                {
                    Collection coll = (Collection) value;
                    for( Object instance : coll )
                    {
                        ValueInstance.valueInstanceOf( (ValueComposite) instance ).prepareBuilderState();
                    }
                }
            }
        }
        else if( propertyDescriptor.valueType() instanceof MapType )
        {
            T value = get();

            if( value != null )
            {
                MapType mapType = (MapType) propertyDescriptor.valueType();
                if( mapType.keyType() instanceof ValueCompositeType )
                {
                    Map map = (Map) value;
                    for( Object instance : map.keySet() )
                    {
                        ValueInstance.valueInstanceOf( (ValueComposite) instance ).prepareBuilderState();
                    }
                }
                if( mapType.valueType() instanceof ValueCompositeType )
                {
                    Map map = (Map) value;
                    for( Object instance : map.values() )
                    {
                        ValueInstance.valueInstanceOf( (ValueComposite) instance ).prepareBuilderState();
                    }
                }
                if( propertyDescriptor.isImmutable() )
                {
                    value = (T) Collections.unmodifiableMap( (Map<?, ?>) value );
                }

                this.value = value;
            }
        }

        model = propertyDescriptor;
    }
}
TOP

Related Classes of org.qi4j.runtime.property.PropertyInstance

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.