/* This file is part of VoltDB. * Copyright (C) 2008-2017 VoltDB Inc. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU Affero General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Affero General Public License for more details. * * You should have received a copy of the GNU Affero General Public License * along with VoltDB. If not, see <http://www.gnu.org/licenses/>. */ package org.voltdb.settings; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.net.URI; import java.nio.file.Paths; import java.util.NavigableMap; import java.util.Properties; import java.util.UUID; import org.voltdb.common.Constants; import org.voltdb.utils.Digester; import org.voltdb.utils.VoltFile; import org.aeonbits.owner.Accessible; import org.aeonbits.owner.ConfigFactory; import com.google_voltpatches.common.base.Joiner; import com.google_voltpatches.common.collect.ImmutableSortedMap; public interface Settings extends Accessible { public final static String CONFIG_DIR = "org.voltdb.config.dir"; public static void initialize(File voltdbroot) { if (ConfigFactory.getProperty(Settings.CONFIG_DIR) == null) try { File confDH = new VoltFile(voltdbroot, Constants.CONFIG_DIR).getCanonicalFile(); String pathAsURI = confDH.toURI().getRawPath(); ConfigFactory.setProperty(Settings.CONFIG_DIR, pathAsURI); } catch (IOException e) { throw new SettingsException("failed to resolve the cluster settings directory", e); } } default NavigableMap<String, String> asMap() { ImmutableSortedMap.Builder<String, String> mb = ImmutableSortedMap.naturalOrder(); for (String name: propertyNames()) { mb.put(name, getProperty(name)); } return mb.build(); } default UUID getDigest() { return Digester.md5AsUUID(Joiner.on('#').withKeyValueSeparator("=").join(asMap())); } default byte [] asBytes() { return propertiesToBytes(asProperties()); } default void store(File settingsFH, String comment) { try (FileOutputStream fos = new FileOutputStream(settingsFH)){ asProperties().store(fos, comment); } catch (IOException e) { throw new SettingsException("failed to write properties to " + settingsFH, e); } } default Properties asProperties() { Properties props = new Properties(); fill(props); return props; } public static Properties bytesToProperties(byte [] bytes) { Properties props = new Properties(); try (ByteArrayInputStream bais = new ByteArrayInputStream(bytes)) { props.load(bais); } catch (IOException e) { throw new SettingsException("failed to read properties from a byte array",e); } return props; } public static byte [] propertiesToBytes(Properties props) { byte [] bytes = new byte[0]; try (ByteArrayOutputStream baos = new ByteArrayOutputStream(1024)) { props.store(baos, "VoltDB settings"); bytes = baos.toByteArray(); } catch (IOException e) { throw new SettingsException("failed to convert properties to a byte array",e); } return bytes; } static File getConfigDir() { final String configDN = ConfigFactory.getProperty(CONFIG_DIR).intern(); if (configDN == null || configDN.trim().isEmpty()) { throw new IllegalStateException("property " + CONFIG_DIR + " must be defined"); } URI uri = URI.create("file:" + configDN); File configDH = Paths.get(uri).toFile(); if (!configDH.exists() && !configDH.mkdirs()) { throw new SettingsException("failed to create " + configDN); } if ( !configDH.isDirectory() || !configDH.canRead() || !configDH.canWrite() || !configDH.canExecute()) { throw new SettingsException("cannot access " + configDN); } return configDH; } }