<commit_before>/*
 * Copyright 2016 Crown Copyright
 *
 * 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 stroom.config.global.shared;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonValue;
import stroom.docref.SharedObject;
import stroom.util.shared.HasAuditInfo;
import stroom.util.shared.PropertyPath;

import java.util.Objects;
import java.util.Optional;

/**
 * This class records config properties that are derived from the following
 * sources in increasing order of precedence (larger number == higher precedence)
 * 1. Cluster wide compile time default values
 * 2. Cluster wide database values (as displayed/edited in the UI properties screen)
 * 3. Node specific values from the dropwizard YAML file
 *
 * The object holds the values from all available sources from which the effective value
 * can be derived.
 *
 * The effective value of a property on a node will be governed by the above precedence rules.
 * Properties can be changed by means of the UI (database level) or via changes to the YAML
 * which are hot-loaded in. A change at the DB level may not be effective if there is value
 * in the YAML.
 *
 * The source of config properties for the application is the Guice bound AppConfig class and its
 * child objects. Changes to the YAML or database will result in updates to the Guice bound AppConfig
 * object.
 *
 * TODO At present the UI is unable to show the value from the YAML so may give a misleading picture
 */
public class ConfigProperty implements HasAuditInfo, SharedObject, Comparable<ConfigProperty> {

    private static final long serialVersionUID = 8440384191352234225L;

    private Integer id;
    private Integer version;
    private Long createTimeMs;
    private String createUser;
    private Long updateTimeMs;
    private String updateUser;
    private PropertyPath name;

    // TODO now that properties are typed in AppConfig we should really be dealing with typed
    // values here so the UI can edit/display/validate them appropriately according to their type,
    // e.g. a custom UI control for managing List/Map/boolean types


    // The values are held inside an OverrideValue so we can one of three things:
    // A null reference - indicating no override value has been supplied
    // A OverrideValue holding null - indicating a null value has been supplied, e.g. an empty maintenanceMessage
    // A OverrideValue holding a non-null value - indicating a non-null value has been supplied

    // The cluster wide compile-time default value set in the AppConfig object tree
    @JsonProperty("defaultValue")
    private String defaultValue = null;

    // The cluster wide value held in the database and set by the user in the UI, may be null.
    private OverrideValue<String> databaseOverrideValue = OverrideValue.unSet();


    // These fields are not saved to the database,
    // they come from the annotations on the java config classes

    // The node specific value as set by the dropwizard YAML file
    private OverrideValue<String> yamlOverrideValue = OverrideValue.unSet();

    private String description;
    private boolean isEditable;
    private boolean isPassword;
    private boolean requireRestart;
    private boolean requireUiRestart;
    // TODO this is a stopgap until we have fully typed values
    private String dataTypeName;

    public ConfigProperty() {
        // Required for GWT serialisation
    }

    @JsonProperty("id")
    public Integer getId() {
        return id;
    }

    public void setId(final Integer id) {
        this.id = id;
    }

    @JsonProperty("version")
    public Integer getVersion() {
        return version;
    }

    public void setVersion(final Integer version) {
        this.version = version;
    }

    @Override
    @JsonProperty("createTimeMs")
    public Long getCreateTimeMs() {
        return createTimeMs;
    }

    public void setCreateTimeMs(final Long createTimeMs) {
        this.createTimeMs = createTimeMs;
    }

    @Override
    @JsonProperty("createUser")
    public String getCreateUser() {
        return createUser;
    }

    public void setCreateUser(final String createUser) {
        this.createUser = createUser;
    }

    @Override
    @JsonProperty("updateTimeMs")
    public Long getUpdateTimeMs() {
        return updateTimeMs;
    }

    public void setUpdateTimeMs(final Long updateTimeMs) {
        this.updateTimeMs = updateTimeMs;
    }

    @Override
    @JsonProperty("updateUser")
    public String getUpdateUser() {
        return updateUser;
    }

    public void setUpdateUser(final String updateUser) {
        this.updateUser = updateUser;
    }

    /**
     * @return The fully qualified name of the property, e.g. "stroom.temp.path"
     */
    @JsonProperty("name")
    public String getNameAsString() {
        return name.toString();
    }

    @JsonIgnore
    public PropertyPath getName() {
        return name;
    }

    public void setName(final PropertyPath name) {
        this.name = name;
    }

    /**
     * @return The effective value of the property on this node taking into account the precedence order
     * of default, database and yaml values
     */
    @JsonIgnore
    public Optional<String> getEffectiveValue() {
        return getEffectiveValue(defaultValue, databaseOverrideValue, yamlOverrideValue);
    }

    static Optional<String> getEffectiveValue(final String defaultValue,
                                       final OverrideValue<String> databaseOverrideValue,
                                       final OverrideValue<String> yamlOverrideValue) {<commit_msg>Fix json serialisation on ConfigProperty<commit_after>/*
 * Copyright 2016 Crown Copyright
 *
 * 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 stroom.config.global.shared;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.fasterxml.jackson.annotation.JsonValue;
import stroom.docref.SharedObject;
import stroom.util.shared.HasAuditInfo;
import stroom.util.shared.PropertyPath;

import java.util.Objects;
import java.util.Optional;

/**
 * This class records config properties that are derived from the following
 * sources in increasing order of precedence (larger number == higher precedence)
 * 1. Cluster wide compile time default values
 * 2. Cluster wide database values (as displayed/edited in the UI properties screen)
 * 3. Node specific values from the dropwizard YAML file
 *
 * The object holds the values from all available sources from which the effective value
 * can be derived.
 *
 * The effective value of a property on a node will be governed by the above precedence rules.
 * Properties can be changed by means of the UI (database level) or via changes to the YAML
 * which are hot-loaded in. A change at the DB level may not be effective if there is value
 * in the YAML.
 *
 * The source of config properties for the application is the Guice bound AppConfig class and its
 * child objects. Changes to the YAML or database will result in updates to the Guice bound AppConfig
 * object.
 *
 * TODO At present the UI is unable to show the value from the YAML so may give a misleading picture
 */
public class ConfigProperty implements HasAuditInfo, SharedObject, Comparable<ConfigProperty> {

    private static final long serialVersionUID = 8440384191352234225L;

    private Integer id;
    private Integer version;
    private Long createTimeMs;
    private String createUser;
    private Long updateTimeMs;
    private String updateUser;
    private PropertyPath name;

    // TODO now that properties are typed in AppConfig we should really be dealing with typed
    // values here so the UI can edit/display/validate them appropriately according to their type,
    // e.g. a custom UI control for managing List/Map/boolean types


    // The values are held inside an OverrideValue so we can one of three things:
    // A null reference - indicating no override value has been supplied
    // A OverrideValue holding null - indicating a null value has been supplied, e.g. an empty maintenanceMessage
    // A OverrideValue holding a non-null value - indicating a non-null value has been supplied

    // The cluster wide compile-time default value set in the AppConfig object tree
    @JsonProperty("defaultValue")
    private String defaultValue = null;

    // The cluster wide value held in the database and set by the user in the UI, may be null.
    private OverrideValue<String> databaseOverrideValue = OverrideValue.unSet();


    // These fields are not saved to the database,
    // they come from the annotations on the java config classes

    // The node specific value as set by the dropwizard YAML file
    private OverrideValue<String> yamlOverrideValue = OverrideValue.unSet();

    private String description;
    private boolean isEditable;
    private boolean isPassword;
    private boolean requireRestart;
    private boolean requireUiRestart;
    // TODO this is a stopgap until we have fully typed values
    private String dataTypeName;

    public ConfigProperty() {
        // Required for GWT serialisation
    }

    @JsonProperty("id")
    public Integer getId() {
        return id;
    }

    public void setId(final Integer id) {
        this.id = id;
    }

    @JsonProperty("version")
    public Integer getVersion() {
        return version;
    }

    public void setVersion(final Integer version) {
        this.version = version;
    }

    @Override
    @JsonProperty("createTimeMs")
    public Long getCreateTimeMs() {
        return createTimeMs;
    }

    public void setCreateTimeMs(final Long createTimeMs) {
        this.createTimeMs = createTimeMs;
    }

    @Override
    @JsonProperty("createUser")
    public String getCreateUser() {
        return createUser;
    }

    public void setCreateUser(final String createUser) {
        this.createUser = createUser;
    }

    @Override
    @JsonProperty("updateTimeMs")
    public Long getUpdateTimeMs() {
        return updateTimeMs;
    }

    public void setUpdateTimeMs(final Long updateTimeMs) {
        this.updateTimeMs = updateTimeMs;
    }

    @Override
    @JsonProperty("updateUser")
    public String getUpdateUser() {
        return updateUser;
    }

    public void setUpdateUser(final String updateUser) {
        this.updateUser = updateUser;
    }

    /**
     * @return The fully qualified name of the property, e.g. "stroom.temp.path"
     */
    @JsonProperty("name")
    public String getNameAsString() {
        return name == null ? null : name.toString();
    }

    @JsonIgnore
    public PropertyPath getName() {
        return name;
    }

    @JsonIgnore
    public void setName(final PropertyPath name) {
        this.name = name;
    }

    @JsonProperty("name")
    public void setName(final String propertyPathString) {
        if (propertyPathString == null) {
            this.name = null;
        } else {
            this.name = PropertyPath.fromPathString(propertyPathString);
        }
    }

    /**
     * @return The effective value of the property on this node taking into account the precedence order
     * of default, database and yaml values
     */
    @JsonIgnore
    public Optional<String> getEffectiveValue() {
        return getEffectiveValue(defaultValue, databaseOverrideValue, yamlOverrideValue);
    }

    static Optional<String> getEffectiveValue(final String defaultValue,
                                       final OverrideValue<String> databaseOverrideValue,
                                       final OverrideValue<String> yamlOverrideValue) {
{'fraction_non_alphanumeric': 0.06440198159943383, 'fraction_numerical': 0.004718093890068413, 'mean_word_length': 3.0619610348131587, 'pattern_counts': {'":': 0, '<': 17, '<?xml version=': 0, '>': 17, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 6}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 4, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '7153983', 'n_tokens_mistral': 3302, 'n_tokens_neox': 3136, 'n_words': 1340}