FixedConfigSupplier.java

/*
 * Copyright 2017 Providence Authors
 *
 * Licensed to the Apache Software Foundation (ASF) under one
 * or more contributor license agreements. See the NOTICE file
 * distributed with this work for additional information
 * regarding copyright ownership. The ASF licenses this file
 * to you 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 net.morimekta.providence.config.impl;

import net.morimekta.providence.PMessage;
import net.morimekta.providence.config.ConfigListener;
import net.morimekta.providence.config.ConfigSupplier;
import net.morimekta.providence.config.parser.ConfigException;
import net.morimekta.providence.descriptor.PField;

import javax.annotation.Nonnull;
import javax.annotation.concurrent.Immutable;
import java.time.Clock;
import java.util.Objects;

import static net.morimekta.providence.config.impl.ReferenceConfigSupplier.getReference;
import static net.morimekta.providence.config.impl.ReferenceConfigSupplier.validate;

/**
 * A supplier and instance holder for an immutable config instance.
 */
@Immutable
public class FixedConfigSupplier<M extends PMessage<M>> implements ConfigSupplier<M> {
    private final M instance;
    private final long timestamp;
    private final Clock clock;

    /**
     * Initialize with an initial config instance.
     *
     * @param initialConfig The initial config instance.
     */
    public FixedConfigSupplier(@Nonnull M initialConfig) {
        this(initialConfig, Clock.systemUTC().millis(), Clock.systemUTC());
    }

    /**
     * This essentially makes a static snapshot of the config and keeps the
     * config instance as a fixed (unmodifiable) config.
     *
     * @param supplier The config supplier to copy.
     */
    public FixedConfigSupplier(@Nonnull ConfigSupplier<M> supplier) {
        synchronized (Objects.requireNonNull(supplier)) {
            this.instance = supplier.get();
            this.timestamp = supplier.configTimestamp();
            this.clock = supplier.getClock();
        }
    }

    /**
     * Initialize with an initial config instance.
     *
     * @param initialConfig The initial config instance.
     * @param timestamp The config timestamp.
     * @param clock Clock used to calculate timestamp.
     */
    public FixedConfigSupplier(@Nonnull M initialConfig, long timestamp, Clock clock) {
        this.instance = initialConfig;
        this.timestamp = timestamp;
        this.clock = clock;
    }

    @Nonnull
    @Override
    public final M get() {
        return instance;
    }

    @Override
    @SuppressWarnings("unchecked")
    public <RM extends PMessage<RM>> ConfigSupplier<RM> reference(PField... fields)
            throws ConfigException {
        return new FixedConfigSupplier<>((RM) getReference(instance, validate(instance.descriptor(), fields)));
    }

    @Override
    public final void addListener(@Nonnull ConfigListener<M> listener) {
    }

    @Override
    public final void removeListener(@Nonnull ConfigListener<M> listener) {
    }

    @Override
    public long configTimestamp() {
        return timestamp;
    }

    @Override
    public Clock getClock() {
        return clock;
    }

    @Override
    public String toString() {
        return getName();
    }

    @Override
    public String getName() {
        return "InMemoryConfig";
    }
}