org.amplafi.flow.flowproperty.FixedFlowPropertyValueProvider.java Source code

Java tutorial

Introduction

Here is the source code for org.amplafi.flow.flowproperty.FixedFlowPropertyValueProvider.java

Source

/*
 * 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.amplafi.flow.flowproperty;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentMap;

import org.amplafi.flow.DataClassDefinition;
import org.amplafi.flow.FlowPropertyDefinition;
import org.amplafi.flow.FlowPropertyExpectation;
import org.amplafi.flow.FlowPropertyValueProvider;

import com.sworddance.util.ApplicationIllegalArgumentException;
import com.sworddance.util.ApplicationIllegalStateException;

import org.apache.commons.lang.ObjectUtils;

/**
 * {@link org.amplafi.flow.FlowPropertyValueProvider} that handles statically provided values.
 *
 */
public class FixedFlowPropertyValueProvider implements FlowPropertyValueProvider<FlowPropertyProvider> {

    private final Object defaultObject;
    private final Class<?> defaultClass;
    /**
     * Used to tell difference between null as the value and null as not initialized.
     * (This is not visible to outside code)
     */
    private static Object NULL = new Object() {
        @Override
        public String toString() {
            return "<null>";
        }
    };

    /**
     * Used when want to force a {@link FlowPropertyDefinition} to not have the default {@link FlowPropertyValueProvider} assignments happen.
     */
    public static FixedFlowPropertyValueProvider NULL_INSTANCE = new FixedFlowPropertyValueProvider(NULL);
    /**
     * key off of FlowPropertyDefinition so that different FPD can translate defaultObject differently
     */
    private ConcurrentMap<FlowPropertyDefinition, Object> map = new ConcurrentHashMap<FlowPropertyDefinition, Object>();

    public FixedFlowPropertyValueProvider(Object defaultObject) {
        ApplicationIllegalArgumentException.notNull(defaultObject,
                "Fixed value cannot be null. If explicit null is really intended use FixedFlowPropertyValueProvider.NULL_INSTANCE");
        this.defaultObject = defaultObject;
        this.defaultClass = defaultObject.getClass();
    }

    public FixedFlowPropertyValueProvider(Class<?> defaultClass) {
        ApplicationIllegalArgumentException.notNull(defaultClass, "Fixed defaultClass cannot be null.");
        ApplicationIllegalArgumentException.valid(
                !defaultClass.isAnnotation() && !defaultClass.isInterface() && !defaultClass.isPrimitive(),
                defaultClass, ": cannot be instantiated.");
        this.defaultObject = null;
        this.defaultClass = defaultClass;
    }

    /**
     * @param flowPropertyDefinition
     */
    public void convertable(FlowPropertyDefinition flowPropertyDefinition) {
        if (flowPropertyDefinition.getDataClassDefinition().isDataClassDefined()) {
            DataClassDefinition dataClassDefinition = flowPropertyDefinition.getDataClassDefinition();
            ApplicationIllegalStateException.checkState(
                    dataClassDefinition.isDeserializable(flowPropertyDefinition, this.getDefaultObject()), this,
                    " cannot convert value=", this.getDefaultObject());
        }
    }

    @Override
    @SuppressWarnings({ "unchecked" })
    public <T> T get(FlowPropertyProvider flowPropertyProvider, FlowPropertyDefinition flowPropertyDefinition) {
        T value;
        if (this.defaultObject == null) {
            // no default object but default class.

        }
        if (!map.containsKey(flowPropertyDefinition)) {
            convertable(flowPropertyDefinition);
            value = (T) flowPropertyDefinition.getDataClassDefinition().deserialize(flowPropertyProvider,
                    flowPropertyDefinition, this.getDefaultObject());
            if (value == null) {
                map.putIfAbsent(flowPropertyDefinition, NULL);
            } else {
                map.putIfAbsent(flowPropertyDefinition, value);
            }
        }
        value = (T) map.get(flowPropertyDefinition);
        if (value == NULL) {
            value = null;
        }
        return value;
    }

    /**
     * @return the value as a string.
     */
    public String getDefaultString() {
        return ObjectUtils.toString(getDefaultObject());
    }

    public Class<?> getSuggestedClass() {
        if (this.defaultClass == null) {
            return String.class;
        } else {
            return this.defaultClass;
        }
    }

    @Override
    public int hashCode() {
        return this.getDefaultObject() == null ? 1 : this.getDefaultObject().hashCode();
    }

    @Override
    public boolean equals(Object o) {
        if (o instanceof FixedFlowPropertyValueProvider) {
            return ObjectUtils.equals(this.getDefaultObject(),
                    ((FixedFlowPropertyValueProvider) o).getDefaultObject());
        } else {
            return ObjectUtils.equals(this.getDefaultObject(), o);
        }
    }

    /**
     * @return the defaultObject
     */
    public Object getDefaultObject() {
        return defaultObject == NULL ? null : this.defaultObject;
    }

    @Override
    public Class<FlowPropertyProvider> getFlowPropertyProviderClass() {
        return FlowPropertyProvider.class;
    }

    @Override
    public boolean isHandling(FlowPropertyExpectation flowPropertyExpectation) {
        return this.getDefaultObject() == null
                || flowPropertyExpectation.isAssignableFrom(this.getSuggestedClass());
    }

    @Override
    public String toString() {
        return "FixedProperty value=" + getDefaultString();
    }

    /**
     * @param <FPP>
     * @param defaultObject
     * @param flowPropertyDefinition
     * @param testAndConfigFlowPropertyDefinition if true then set the flowPropertyDefinition based on defaultObject.getClass()
     * @return the created fixedFlowPropertyValueProvider
     */
    public static <FPP extends FlowPropertyProvider> FixedFlowPropertyValueProvider newFixedFlowPropertyValueProvider(
            Object defaultObject, FlowPropertyDefinitionImplementor flowPropertyDefinition,
            boolean testAndConfigFlowPropertyDefinition) {
        FixedFlowPropertyValueProvider fixedFlowPropertyValueProvider = null;
        if (defaultObject != null) {
            fixedFlowPropertyValueProvider = new FixedFlowPropertyValueProvider(defaultObject);
            fixedFlowPropertyValueProvider.convertable(flowPropertyDefinition);
            if (testAndConfigFlowPropertyDefinition) {
                DataClassDefinition dataClassDefinition = flowPropertyDefinition.getDataClassDefinition();
                if (dataClassDefinition.isDataClassDefined()) {
                    if (!dataClassDefinition.getDataClass().isPrimitive()) {
                        // really need to handle the autobox issue better.
                        dataClassDefinition.getDataClass().cast(defaultObject);
                    }
                } else {
                    dataClassDefinition.setDataClass(defaultObject.getClass());
                }
            }
        } else {
            fixedFlowPropertyValueProvider = NULL_INSTANCE;
        }
        return fixedFlowPropertyValueProvider;
    }

    /**
     * EXPERIMENTAL:
     *
     * Sort of duplicates the default object from a FlowTranslator...
     * but could make the FlowPropertyDefinitionImpl code cleaner because we can get rid of isAutoCreate() and isDefauftClassAvailable() concepts.
     *
     * @param <FPP>
     * @param flowPropertyDefinition
     * @param testAndConfigFlowPropertyDefinition
     * @return the created fixedFlowPropertyValueProvider
     */
    public static <FPP extends FlowPropertyProvider> FixedFlowPropertyValueProvider newFixedFlowPropertyValueProvider(
            FlowPropertyDefinitionImplementor flowPropertyDefinition, boolean testAndConfigFlowPropertyDefinition) {

        return newFixedFlowPropertyValueProvider(flowPropertyDefinition.getDataClassDefinition().getPropertyClass(),
                flowPropertyDefinition, testAndConfigFlowPropertyDefinition);
    }

    @SuppressWarnings("unchecked")
    public static <FPP extends FlowPropertyProvider> FixedFlowPropertyValueProvider newFixedFlowPropertyValueProvider(
            Class<?> defaultClass, FlowPropertyDefinitionImplementor flowPropertyDefinition,
            boolean testAndConfigFlowPropertyDefinition) {
        FixedFlowPropertyValueProvider fixedFlowPropertyValueProvider = null;

        ApplicationIllegalArgumentException.valid(!defaultClass.isAnnotation(), defaultClass,
                "is an annotation. Annotations cannot be instatiated.");
        if (defaultClass == int.class) {
            return newFixedFlowPropertyValueProvider(Integer.valueOf(0), flowPropertyDefinition,
                    testAndConfigFlowPropertyDefinition);
        } else if (defaultClass == long.class) {
            return newFixedFlowPropertyValueProvider(Long.valueOf(0), flowPropertyDefinition,
                    testAndConfigFlowPropertyDefinition);
        } else if (defaultClass == boolean.class) {
            return newFixedFlowPropertyValueProvider(Boolean.valueOf(false), flowPropertyDefinition,
                    testAndConfigFlowPropertyDefinition);
        } else if (defaultClass.isEnum()) {
            // use the first enum as the default.
            return newFixedFlowPropertyValueProvider(((Class<Enum<?>>) defaultClass).getEnumConstants()[0],
                    flowPropertyDefinition, testAndConfigFlowPropertyDefinition);
        }
        Class<?> classToCreate;
        if (defaultClass == Set.class) {
            classToCreate = LinkedHashSet.class;
        } else if (defaultClass == List.class) {
            classToCreate = ArrayList.class;
        } else if (defaultClass == Map.class) {
            classToCreate = HashMap.class;
        } else {
            classToCreate = defaultClass;
        }
        fixedFlowPropertyValueProvider = new FixedFlowPropertyValueProvider(classToCreate);

        fixedFlowPropertyValueProvider.convertable(flowPropertyDefinition);
        if (testAndConfigFlowPropertyDefinition) {
            DataClassDefinition dataClassDefinition = flowPropertyDefinition.getDataClassDefinition();
            if (dataClassDefinition.isDataClassDefined()) {
                ApplicationIllegalArgumentException.valid(dataClassDefinition.isAssignableFrom(defaultClass),
                        dataClassDefinition, " cannot be assigned ");
            } else {
                dataClassDefinition.setDataClass(defaultClass);
            }
        }
        return fixedFlowPropertyValueProvider;
    }
}