command.line/java/com/jetbrains/teamcity/Storage.java (102 lines of code) (raw):
package com.jetbrains.teamcity;
import com.thoughtworks.xstream.XStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.Serializable;
import java.nio.file.NoSuchFileException;
import java.util.HashMap;
import java.util.Map;
import jetbrains.buildServer.messages.XStreamHolder;
import jetbrains.buildServer.util.FileUtil;
import jetbrains.buildServer.xstream.ServerXStreamFormat;
import jetbrains.buildServer.xstream.XStreamWrapper;
//TODO: support parallel working!!!
public class Storage {
public static final String TC_STORAGE_PROPERTY_NAME = "teamcity.cli.configfile"; //$NON-NLS-1$
public static final String TC_STORAGE_ENVIRONMENT_VARIABLE_PROPERTY_NAME = "TEAMCITY_CLI_CONFIGFILE"; //$NON-NLS-1$
public static final String TC_CLI_HOME = "/.TeamCity-CommandLine"; //$NON-NLS-1$
public static final String TC_STORAGE_DEFAULT_FILENAME = TC_CLI_HOME + "/.tcstorage"; //$NON-NLS-1$
private static Storage ourInstance;
private static IStorageFS ourStorageFS;
private final HashMap<Object, Serializable> myStorage = new HashMap<Object, Serializable>();
private final String myStorageFile;
private Storage() {
// init storage
final String storageFile = System.getProperty(TC_STORAGE_PROPERTY_NAME);
if (storageFile != null) {// -D
myStorageFile = storageFile;
} else if (System.getenv(TC_STORAGE_ENVIRONMENT_VARIABLE_PROPERTY_NAME) != null) {// env
myStorageFile = System.getenv(TC_STORAGE_ENVIRONMENT_VARIABLE_PROPERTY_NAME);
} else {// default
final String home = System.getProperty("user.home"); //$NON-NLS-1$
myStorageFile = home + File.separator + TC_STORAGE_DEFAULT_FILENAME;
}
ourStorageFS = new XMLStorageFS(myStorageFile);
ourStorageFS.load(myStorage);
}
public synchronized static Storage getInstance() {
if (ourInstance == null) {
ourInstance = new Storage();
}
return ourInstance;
}
synchronized static void reload() {
ourInstance = new Storage();
}
@SuppressWarnings("unchecked")
public synchronized <T extends Serializable> T get(final IKey<T> key) {
return (T) myStorage.get(key.getKey());
}
public synchronized <T extends Serializable> void put(final IKey<T> key, T value, final boolean flush) {
myStorage.put(key.getKey(), value);
if (flush) {
flush();
}
}
public synchronized void flush() {
ourStorageFS.save(myStorage);
}
public synchronized <T extends Serializable> void put(final IKey<T> key, T value) {
put(key, value, true);
}
public static interface IKey<T extends Serializable> extends Serializable {
Object getKey();
}
private interface IStorageFS {
void save(final HashMap<Object, Serializable> storage);
Map<Object, Serializable> load(final HashMap<Object, Serializable> storage);
}
private static class XMLStorageFS implements IStorageFS {
private final String myStorageFile;
public XMLStorageFS(final String myStorageFile) {
this.myStorageFile = myStorageFile + ".xml"; //$NON-NLS-1$
}
// TODO: move to utils
private <T> T deserializeObject(final Object typeData) {
return XStreamWrapper.<T> deserializeObject((String) typeData, ourXStreamHolder);
}
// TODO: move to utils
private String serializeObject(final Object typeData) {
return XStreamWrapper.serializeObject(typeData, ourXStreamHolder);
}
// TODO: move to utils
private static final XStreamHolder ourXStreamHolder = new XStreamHolder() {
protected void configureXStream(XStream xStream) {
ServerXStreamFormat.formatXStream(xStream);
}
};
public Map<Object, Serializable> load(HashMap<Object, Serializable> storage) {
try {
storage.clear();
final String content = FileUtil.readText(new File(getStorageFile()));
storage.putAll((Map<?, ? extends Serializable>) deserializeObject(content));
} catch (FileNotFoundException|NoSuchFileException e) {
// do nothing
} catch (Exception e) {
throw new RuntimeException(e);
}
return storage;
}
public void save(HashMap<Object, Serializable> storage) {
final String xml = serializeObject(storage);
FileUtil.writeFile(new File(getStorageFile()), xml);
}
private String getStorageFile() {
return this.myStorageFile;
}
}
}