/* Copyright (c) 2014 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:
* David Winslow (Boundless) - initial implementation
*/
package org.locationtech.geogig.storage.fs;
import java.io.File;
import java.io.IOException;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.List;
import java.util.Map;
import java.util.NoSuchElementException;
import org.locationtech.geogig.api.Platform;
import org.locationtech.geogig.api.plumbing.ResolveGeogigDir;
import org.locationtech.geogig.api.porcelain.ConfigException;
import org.locationtech.geogig.api.porcelain.ConfigException.StatusCode;
import org.locationtech.geogig.storage.ConfigDatabase;
import com.google.common.base.Optional;
import com.google.inject.Inject;
public class IniFileConfigDatabase implements ConfigDatabase {
private INIFile local;
private INIFile global;
@Inject
public IniFileConfigDatabase(final Platform platform) {
this.local = new INIFile() {
@Override
public File iniFile() {
final Optional<URL> url = new ResolveGeogigDir(platform).call();
if (!url.isPresent()) {
throw new ConfigException(StatusCode.INVALID_LOCATION);
}
/*
* See http://weblogs.java.net/blog/kohsuke/archive/2007/04/how_to_convert.html for
* explanation on this idiom.
*/
File localConfigFile;
try {
localConfigFile = new File(new File(url.get().toURI()), "config");
} catch (URISyntaxException e) {
localConfigFile = new File(url.get().getPath(), "config");
}
return localConfigFile;
}
};
this.global = new INIFile() {
@Override
public File iniFile() {
File home = platform.getUserHome();
if (home == null) {
throw new ConfigException(StatusCode.USERHOME_NOT_SET);
}
File globalConfig = new File(home.getPath(), ".geogigconfig");
try {
globalConfig.createNewFile();
} catch (IOException e) {
throw new ConfigException(e, StatusCode.CANNOT_WRITE);
}
return globalConfig;
}
};
}
public Optional<String> get(String key) {
try {
String[] parsed = parse(key);
Optional<String> result = local.get(parsed[0], parsed[1]);
if (result.isPresent() && result.get().length() > 0) {
return result;
} else {
return Optional.absent();
}
} catch (StringIndexOutOfBoundsException e) {
throw new ConfigException(e, StatusCode.SECTION_OR_KEY_INVALID);
} catch (IllegalArgumentException e) {
throw new ConfigException(e, null);
} catch (IOException e) {
throw new ConfigException(e, null);
}
}
public <T> Optional<T> get(String key, Class<T> c) {
Optional<String> text = get(key);
if (text.isPresent()) {
return Optional.of(cast(c, text.get()));
} else {
return Optional.absent();
}
}
public Optional<String> getGlobal(String key) {
try {
String[] parsed = parse(key);
Optional<String> result = global.get(parsed[0], parsed[1]);
if (result.isPresent() && result.get().length() > 0) {
return result;
} else {
return Optional.absent();
}
} catch (StringIndexOutOfBoundsException e) {
throw new ConfigException(e, StatusCode.SECTION_OR_KEY_INVALID);
} catch (IllegalArgumentException e) {
throw new ConfigException(e, null);
} catch (IOException e) {
throw new ConfigException(e, null);
}
}
public <T> Optional<T> getGlobal(String key, Class<T> c) {
Optional<String> text = getGlobal(key);
if (text.isPresent()) {
return Optional.of(cast(c, text.get()));
} else {
return Optional.absent();
}
}
public Map<String, String> getAll() {
try {
return local.getAll();
} catch (StringIndexOutOfBoundsException e) {
throw new ConfigException(e, StatusCode.SECTION_OR_KEY_INVALID);
} catch (IllegalArgumentException e) {
throw new ConfigException(e, null);
} catch (IOException e) {
throw new ConfigException(e, null);
}
}
public Map<String, String> getAllGlobal() {
try {
return global.getAll();
} catch (StringIndexOutOfBoundsException e) {
throw new ConfigException(e, StatusCode.SECTION_OR_KEY_INVALID);
} catch (IllegalArgumentException e) {
throw new ConfigException(e, null);
} catch (IOException e) {
throw new ConfigException(e, null);
}
}
public Map<String, String> getAllSection(String section) {
try {
return local.getSection(section);
} catch (StringIndexOutOfBoundsException e) {
throw new ConfigException(e, StatusCode.SECTION_OR_KEY_INVALID);
} catch (IllegalArgumentException e) {
throw new ConfigException(e, null);
} catch (IOException e) {
throw new ConfigException(e, null);
}
}
public Map<String, String> getAllSectionGlobal(String section) {
try {
return global.getSection(section);
} catch (StringIndexOutOfBoundsException e) {
throw new ConfigException(e, StatusCode.SECTION_OR_KEY_INVALID);
} catch (IllegalArgumentException e) {
throw new ConfigException(e, null);
} catch (IOException e) {
throw new ConfigException(e, null);
}
}
public List<String> getAllSubsections(String section) {
try {
return local.listSubsections(section);
} catch (StringIndexOutOfBoundsException e) {
throw new ConfigException(e, StatusCode.SECTION_OR_KEY_INVALID);
} catch (IllegalArgumentException e) {
throw new ConfigException(e, null);
} catch (IOException e) {
throw new ConfigException(e, null);
}
}
public List<String> getAllSubsectionsGlobal(String section) {
try {
return global.listSubsections(section);
} catch (StringIndexOutOfBoundsException e) {
throw new ConfigException(e, StatusCode.SECTION_OR_KEY_INVALID);
} catch (IllegalArgumentException e) {
throw new ConfigException(e, null);
} catch (IOException e) {
throw new ConfigException(e, null);
}
}
public void put(String key, Object value) {
String[] parsed = parse(key);
try {
local.set(parsed[0], parsed[1], stringify(value));
} catch (StringIndexOutOfBoundsException e) {
throw new ConfigException(e, StatusCode.SECTION_OR_KEY_INVALID);
} catch (IllegalArgumentException e) {
throw new ConfigException(e, null);
} catch (IOException e) {
throw new ConfigException(e, null);
}
}
public void putGlobal(String key, Object value) {
String[] parsed = parse(key);
try {
global.set(parsed[0], parsed[1], stringify(value));
} catch (StringIndexOutOfBoundsException e) {
throw new ConfigException(e, StatusCode.SECTION_OR_KEY_INVALID);
} catch (IllegalArgumentException e) {
throw new ConfigException(e, null);
} catch (IOException e) {
throw new ConfigException(e, null);
}
}
public void remove(String key) {
String[] parsed = parse(key);
try {
local.remove(parsed[0], parsed[1]);
} catch (StringIndexOutOfBoundsException e) {
throw new ConfigException(e, StatusCode.SECTION_OR_KEY_INVALID);
} catch (IllegalArgumentException e) {
throw new ConfigException(e, null);
} catch (IOException e) {
throw new ConfigException(e, null);
}
}
public void removeGlobal(String key) {
String[] parsed = parse(key);
try {
global.remove(parsed[0], parsed[1]);
} catch (StringIndexOutOfBoundsException e) {
throw new ConfigException(e, StatusCode.SECTION_OR_KEY_INVALID);
} catch (IllegalArgumentException e) {
throw new ConfigException(e, null);
} catch (IOException e) {
throw new ConfigException(e, null);
}
}
public void removeSection(String key) {
try {
local.removeSection(key);
} catch (NoSuchElementException e) {
throw new ConfigException(e, StatusCode.MISSING_SECTION);
} catch (StringIndexOutOfBoundsException e) {
throw new ConfigException(e, StatusCode.SECTION_OR_KEY_INVALID);
} catch (IllegalArgumentException e) {
throw new ConfigException(e, null);
} catch (IOException e) {
throw new ConfigException(e, null);
}
}
public void removeSectionGlobal(String key) {
try {
global.removeSection(key);
} catch (NoSuchElementException e) {
throw new ConfigException(e, StatusCode.MISSING_SECTION);
} catch (StringIndexOutOfBoundsException e) {
throw new ConfigException(e, StatusCode.SECTION_OR_KEY_INVALID);
} catch (IllegalArgumentException e) {
throw new ConfigException(e, null);
} catch (IOException e) {
throw new ConfigException(e, null);
}
}
@SuppressWarnings("unchecked")
private <T> T cast(Class<T> c, String s) {
if (String.class.equals(c)) {
return c.cast(s);
}
if (int.class.equals(c) || Integer.class.equals(c)) {
return (T) Integer.valueOf(s);
}
if (Boolean.class.equals(c)) {
return c.cast(Boolean.valueOf(s));
}
throw new IllegalArgumentException("Unsupported type: " + c);
}
private String stringify(Object o) {
return o == null ? "" : o.toString();
}
private String[] parse(String qualifiedKey) {
if (qualifiedKey == null) {
throw new IllegalArgumentException("Config key may not be null.");
}
int splitAt = qualifiedKey.lastIndexOf(".");
return new String[] { qualifiedKey.substring(0, splitAt),
qualifiedKey.substring(splitAt + 1) };
}
}