org.locationtech.geogig.storage.memory.HeapConfigDatabase.java Source code

Java tutorial

Introduction

Here is the source code for org.locationtech.geogig.storage.memory.HeapConfigDatabase.java

Source

/* Copyright (c) 2017 Boundless and others.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Distribution License v1.0
 * which accompanies this distribution, and is available at
 * https://www.eclipse.org/org/documents/edl-v10.html
 *
 * Contributors:
 * Johnathan Garret (Prominent Edge) - initial implementation
 * Gabriel Roldan (Boundless) - moved from api to core
 */
package org.locationtech.geogig.storage.memory;

import static com.google.common.base.Optional.fromNullable;
import static com.google.common.base.Preconditions.checkNotNull;

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

import org.locationtech.geogig.storage.ConfigDatabase;
import org.locationtech.geogig.storage.ConfigException;
import org.locationtech.geogig.storage.ConfigException.StatusCode;

import com.google.common.base.CharMatcher;
import com.google.common.base.Optional;
import com.google.common.collect.Sets;

public class HeapConfigDatabase implements ConfigDatabase {

    private static final ConcurrentMap<String, String> global = new ConcurrentHashMap<>();

    private ConcurrentMap<String, String> local = new ConcurrentHashMap<>();

    public HeapConfigDatabase() {

    }

    @Override
    public void close() {
        local.clear();
    }

    @Override
    public Optional<String> get(String key) {
        checkKeyFormat(key);
        return fromNullable(local.get(key));
    }

    @Override
    public Optional<String> getGlobal(String key) {
        return fromNullable(global.get(key));
    }

    @Override
    public <T> Optional<T> get(String key, Class<T> c) {
        Optional<String> val = get(key);
        return cast(c, val);
    }

    @Override
    public <T> Optional<T> getGlobal(String key, Class<T> c) {
        Optional<String> val = getGlobal(key);
        return cast(c, val);
    }

    @SuppressWarnings("unchecked")
    private <T> Optional<T> cast(Class<T> c, Optional<String> s) {
        T val;
        if (!s.isPresent()) {
            val = null;
        } else if (String.class.equals(c)) {
            val = c.cast(s.get());
        } else if (int.class.equals(c) || Integer.class.equals(c)) {
            val = (T) Integer.valueOf(s.get());
        } else if (Boolean.class.equals(c)) {
            val = c.cast(Boolean.valueOf(s.get()));
        } else {
            throw new IllegalArgumentException("Unsupported type: " + c);
        }
        return fromNullable(val);
    }

    @Override
    public Map<String, String> getAll() {
        return new HashMap<>(local);
    }

    @Override
    public Map<String, String> getAllGlobal() {
        return new HashMap<>(global);
    }

    @Override
    public Map<String, String> getAllSection(String section) {
        return getAllSection(local, section);
    }

    @Override
    public Map<String, String> getAllSectionGlobal(String section) {
        return getAllSection(global, section);
    }

    private Map<String, String> getAllSection(ConcurrentMap<String, String> config, String section) {
        checkNotNull(section);
        CharMatcher matcher = CharMatcher.is('.');
        final int numSections = 1 + matcher.countIn(section);
        final String prefix = section + ".";

        Map<String, String> res = new HashMap<>();

        config.forEach((k, v) -> {
            if (k.startsWith(prefix) && numSections == matcher.countIn(k)) {
                res.put(k.substring(prefix.length()), v);
            }
        });

        return res;
    }

    @Override
    public List<String> getAllSubsections(String section) {
        return getAllSubSection(local, section);
    }

    @Override
    public List<String> getAllSubsectionsGlobal(String section) {
        return getAllSubSection(global, section);
    }

    private List<String> getAllSubSection(ConcurrentMap<String, String> config, String section) {
        checkNotNull(section);
        CharMatcher matcher = CharMatcher.is('.');
        final int numSections = 2 + matcher.countIn(section); // one separator for subsection and
                                                              // one for the leaf key
        final String prefix = section + ".";

        Set<String> subsections = new TreeSet<>();

        config.forEach((k, v) -> {
            if (k.startsWith(prefix) && matcher.countIn(k) >= numSections) {
                int keyIndex = k.lastIndexOf('.');
                String subsection = k.substring(prefix.length(), keyIndex);
                subsections.add(subsection);
            }
        });

        return new ArrayList<>(subsections);
    }

    @Override
    public void put(String key, Object value) {
        checkKeyFormat(key);
        if (value == null) {
            remove(key);
        } else {
            local.put(key, String.valueOf(value));
        }
    }

    @Override
    public void putGlobal(String key, Object value) {
        checkKeyFormat(key);
        if (value == null) {
            removeGlobal(key);
        } else {
            global.put(key, String.valueOf(value));
        }
    }

    @Override
    public void remove(String key) {
        checkKeyFormat(key);
        local.remove(key);
    }

    @Override
    public void removeGlobal(String key) {
        checkKeyFormat(key);
        global.remove(key);
    }

    @Override
    public void removeSection(String section) {
        removeSection(local, section);
    }

    @Override
    public void removeSectionGlobal(String section) {
        removeSection(global, section);
    }

    private void removeSection(ConcurrentMap<String, String> config, String section) {
        checkNotNull(section);
        final String prefix = section + ".";
        Set<String> matching = new HashSet<>(Sets.filter(config.keySet(), (k) -> k.startsWith(prefix)));
        if (matching.isEmpty()) {
            throw new ConfigException(StatusCode.MISSING_SECTION);
        }
        matching.forEach((k) -> {
            config.remove(k);
        });
    }

    private void checkKeyFormat(String qualifiedKey) {
        if (qualifiedKey == null) {
            throw new ConfigException(StatusCode.SECTION_OR_KEY_INVALID);
        }
        int firstQualifierIndex = qualifiedKey.indexOf('.');
        if (firstQualifierIndex < 1) {
            throw new ConfigException(StatusCode.SECTION_OR_NAME_NOT_PROVIDED);
        }
        if (qualifiedKey.length() == firstQualifierIndex + 1) {
            throw new ConfigException(StatusCode.SECTION_OR_NAME_NOT_PROVIDED);
        }
    }

}