/*************************GO-LICENSE-START*********************************
* Copyright 2014 ThoughtWorks, Inc.
*
* Licensed 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.
*************************GO-LICENSE-END***********************************/
package com.thoughtworks.go.server.service.support.toggle;
import com.google.gson.Gson;
import com.google.gson.GsonBuilder;
import com.google.gson.annotations.Expose;
import com.thoughtworks.go.server.domain.support.toggle.FeatureToggle;
import com.thoughtworks.go.server.domain.support.toggle.FeatureToggles;
import com.thoughtworks.go.util.SystemEnvironment;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.IOUtils;
import org.apache.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.InputStream;
import java.util.List;
import static com.thoughtworks.go.util.SystemEnvironment.AVAILABLE_FEATURE_TOGGLES_FILE_PATH;
import static com.thoughtworks.go.util.SystemEnvironment.USER_FEATURE_TOGGLES_FILE_PATH_RELATIVE_TO_CONFIG_DIR;
@Repository
public class FeatureToggleRepository {
private SystemEnvironment environment;
private final Logger LOGGER = Logger.getLogger(FeatureToggleRepository.class);
private Gson gson;
@Autowired
public FeatureToggleRepository(SystemEnvironment environment) {
this.environment = environment;
gson = new GsonBuilder().setPrettyPrinting().excludeFieldsWithoutExposeAnnotation().create();
}
public FeatureToggles availableToggles() {
String availableTogglesResourcePath = environment.get(AVAILABLE_FEATURE_TOGGLES_FILE_PATH);
InputStream streamForAvailableToggles = getClass().getResourceAsStream(availableTogglesResourcePath);
if (streamForAvailableToggles == null) {
LOGGER.error("Failed to read toggles from " + availableTogglesResourcePath + ". Saying there are no toggles.");
return new FeatureToggles();
}
return readTogglesFromStream(streamForAvailableToggles, "available");
}
public FeatureToggles userToggles() {
String userTogglesPath = userTogglesFile().getAbsolutePath();
if (!new File(userTogglesPath).exists()) {
LOGGER.warn("Toggles file, " + userTogglesPath + " does not exist. Saying there are no toggles.");
return new FeatureToggles();
}
try {
return readTogglesFromStream(new FileInputStream(userTogglesPath), "user");
} catch (FileNotFoundException e) {
LOGGER.warn("Toggles file, " + userTogglesPath + " does not exist. Saying there are no toggles.");
return new FeatureToggles();
}
}
public void changeValueOfToggle(String key, boolean newValue) {
FeatureToggles currentToggles = userToggles().changeToggleValue(key, newValue);
writeTogglesToFile(userTogglesFile(), currentToggles);
}
private FeatureToggles readTogglesFromStream(InputStream streamForToggles, String kindOfToggle) {
try {
String existingToggleJSONContent = IOUtils.toString(streamForToggles);
FeatureToggleFileContentRepresentation toggleContent = gson.fromJson(existingToggleJSONContent, FeatureToggleFileContentRepresentation.class);
return new FeatureToggles(toggleContent.toggles);
} catch (Exception e) {
LOGGER.error("Failed to read " + kindOfToggle + " toggles. Saying there are no toggles.", e);
return new FeatureToggles();
} finally {
IOUtils.closeQuietly(streamForToggles);
}
}
private void writeTogglesToFile(File file, FeatureToggles toggles) {
FeatureToggleFileContentRepresentation representation = new FeatureToggleFileContentRepresentation();
representation.toggles = toggles.all();
try {
FileUtils.writeStringToFile(file, gson.toJson(representation));
} catch (Exception e) {
throw new RuntimeException(e);
}
}
private File userTogglesFile() {
return new File(environment.configDir(), environment.get(USER_FEATURE_TOGGLES_FILE_PATH_RELATIVE_TO_CONFIG_DIR));
}
public static class FeatureToggleFileContentRepresentation {
@Expose
private String version = "1";
@Expose
private List<FeatureToggle> toggles;
}
}