com.feedzai.fos.api.ModelConfig.java Source code

Java tutorial

Introduction

Here is the source code for com.feedzai.fos.api.ModelConfig.java

Source

/*
 * $#
 * FOS API
 * 
 * Copyright (C) 2013 Feedzai SA
 * 
 * This software is licensed under the Apache License, Version 2.0 (the "Apache License") or the GNU
 * Lesser General Public License version 3 (the "GPL License"). You may choose either license to govern
 * your use of this software only upon the condition that you accept all of the terms of either the Apache
 * License or the LGPL License.
 * 
 * You may obtain a copy of the Apache License and the LGPL License at:
 * 
 * http://www.apache.org/licenses/LICENSE-2.0.txt
 * http://www.gnu.org/licenses/lgpl-3.0.txt
 * 
 * Unless required by applicable law or agreed to in writing, software distributed under the Apache License
 * or the LGPL License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
 * either express or implied. See the Apache License and the LGPL License for the specific language governing
 * permissions and limitations under the Apache License and the LGPL License.
 * #$
 */
package com.feedzai.fos.api;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.feedzai.fos.common.validation.NotBlank;
import com.feedzai.fos.common.validation.NotEmpty;
import com.feedzai.fos.common.validation.NotNull;
import com.feedzai.fos.common.validation.Nullable;

import java.io.File;
import java.io.IOException;
import java.io.Serializable;
import java.util.*;

import static com.google.common.base.Objects.toStringHelper;
import static com.google.common.base.Preconditions.checkNotNull;
import static org.apache.commons.lang3.Validate.notEmpty;

/**
 * Represents the configuration of a classifier.
 *
 * @author Marco Jorge (marco.jorge@feedzai.com)
 */
public final class ModelConfig implements Serializable {
    private List<Attribute> attributes = new ArrayList<>();
    private Map<String, String> properties = new HashMap<>();
    /**
     * Flag to indicate if the model should be stored by FOS.
     */
    private boolean storeModel = true;

    public ModelConfig() {
    }

    /**
     * Creates a new configuration with the given <code>attributes</code> and <code>properties</code>.
     *
     * @param attributes the list of instances this model supports
     * @param properties a list of custom properties to send to the concrete implementation )
     */
    public ModelConfig(@NotEmpty List<Attribute> attributes, Map<String, String> properties) {
        checkNotNull(properties, "Custom properties cannot be null");
        notEmpty(attributes, "Instance fields cannot be empty");

        this.attributes.addAll(attributes);
        this.properties.putAll(properties);
    }

    /**
     * Gets the instance fields of this configuration (unmodifiable).
     *
     * @return the list of fields
     */
    @NotEmpty
    public List<Attribute> getAttributes() {
        if (attributes == null) {
            this.attributes = new ArrayList<>();
        }
        return attributes;
    }

    /**
     * Gets the custom properties of this configuration (unmodifiable).
     *
     * @return a map from custom property name to custom property value
     */
    @NotNull
    public Map<String, String> getProperties() {
        if (this.properties == null) {
            this.properties = new HashMap<>();
        }
        return properties;
    }

    /**
     * Updates this model with inputs from the given <code>ModelConfig</code>.
     * <p/>
     * For the <code>InstanceFields</code>, the internal state is clean and the provided <code>ModelConfig.attributes</code> are copied over.
     * For the <code>Properties</code>, the provided <code>ModelConfig.properties</code> overwrite matching existing values (non matching values are kept as is).
     *
     * @param modelConfig the model config that has the information to update this instance
     */
    public void update(ModelConfig modelConfig) {
        checkNotNull(modelConfig, "Model config cannot be null");

        if (this.equals(modelConfig)) {
            // nothing to update!
            return;
        }

        // if the new model instances is empty then do not update
        if (modelConfig.getAttributes().size() != 0) {
            this.attributes.clear();
            this.attributes.addAll(modelConfig.attributes);
        }

        /* does not clear properties, only adds */
        this.properties.putAll(modelConfig.getProperties());
    }

    /**
     * Add the given property to the current custom properties.
     *
     * @param key   the key of the property
     * @param value the value of the property
     * @return the already existing value in the map (or null if it doesn't exist).
     */
    @Nullable
    public String setProperty(@NotBlank String key, String value) {
        return this.properties.put(key, value);
    }

    /**
     * Remove the given property from the current custom properties.
     *
     * @param key   the key of the property
     * @return the already existing value in the map (or null if it doesn't exist).
     */
    @Nullable
    public String removeProperty(@NotBlank String key) {
        return this.properties.remove(key);
    }

    @Override
    public int hashCode() {
        return Objects.hash(attributes, properties, storeModel);
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj) {
            return true;
        }
        if (obj == null || getClass() != obj.getClass()) {
            return false;
        }
        final ModelConfig other = (ModelConfig) obj;
        return Objects.equals(this.attributes, other.attributes)
                && Objects.equals(this.properties, other.properties)
                && Objects.equals(this.storeModel, other.storeModel);
    }

    @Override
    public String toString() {
        return toStringHelper(this).add("attributes", attributes).add("properties", properties)
                .add("storeModel", storeModel).toString();
    }

    /**
     * Returns properties as an integer value
     *
     * @param name property name
     * @return property value
     */
    public int getIntProperty(String name, int defaultValue) {
        try {
            return getIntProperty(name);
        } catch (Exception e) {
            return defaultValue;
        }
    }

    /**
     * Returns properties as an integer value
     *
     * @param name property name
     * @return property value
     * @throws FOSException if property name is invalid or if it wasn't possible to parse an integer from the value
     */
    public int getIntProperty(String name) throws FOSException {
        checkNotNull(name, "Configuration option must be defined");
        notEmpty(name, "Configuration option must not be blank");
        String svalue = properties.get(name);
        checkNotNull(svalue, "Configuration option '" + name + "' does not exist");
        notEmpty(name, "Configuration option '" + name + "' must not be blank");

        int value = 0;
        try {
            value = Integer.parseInt(svalue);
        } catch (NumberFormatException e) {
            throw new FOSException(e.getMessage(), e);
        }

        return value;
    }

    /**
     * Returns a model property value
     *
     * @param name property name
     * @return property value
     * @throws FOSException if property name is null or empty
     */
    public String getProperty(String name) throws FOSException {
        checkNotNull(name, "Configuration option must be defined");
        notEmpty(name, "Configuration option must not be blank");
        String svalue = properties.get(name);
        return svalue;
    }

    /**
     * Gets flag to indicate if the model should be stored by FOS.
     *
     * @return {@code true} if FOS is storing the model, {@code false} otherwise.
     */
    public boolean isStoreModel() {
        return storeModel;
    }

    /**
     * Sets flag to indicate if the model should be stored by FOS.
     *
     * @param storeModel {@code true} if FOS should the model, {@code false} otherwise.
     */
    public void setStoreModel(boolean storeModel) {
        this.storeModel = storeModel;
    }

    /**
     * Reads a model configuration from a file.
     *
     * @param path configuration file path
     * @return ModelConfig read from a file
     * @throws FOSException if it wasn't possible to parse a file
     */
    public static ModelConfig fromFile(String path) throws FOSException {
        ObjectMapper mapper = new ObjectMapper();
        ModelConfig deserialized;

        try {
            deserialized = mapper.readValue(new File(path), ModelConfig.class);
        } catch (IOException e) {
            throw new FOSException(e.getMessage(), e);
        }

        return deserialized;

    }

}