/*
* Copyright 2016 Red Hat, Inc.
* <p>
* Red Hat licenses this file to you 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
* <p>
* http://www.apache.org/licenses/LICENSE-2.0
* <p>
* 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.
*
*/
package io.fabric8.funktion.model;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.MappingIterator;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import com.fasterxml.jackson.dataformat.yaml.YAMLGenerator;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
public class Funktions {
public static final String FILE_NAME = "funktion.yml";
private static final transient Logger LOG = LoggerFactory.getLogger(Funktions.class);
protected static String toYaml(Object dto) throws JsonProcessingException {
ObjectMapper mapper = createObjectMapper();
return mapper.writeValueAsString(dto);
}
/**
* Tries to load the configuration file from the current directory
*/
public static Funktion load() throws IOException {
return findFromFolder(new File("."));
}
protected static Funktion loadFromFile(File file) throws IOException {
LOG.debug("Parsing funktion configuration from: " + file.getName());
try {
Funktion config = Funktions.parseFunktionConfig(file);
return validateConfig(config, file);
} catch (IOException e) {
throw new IOException("Failed to parse funktion config: " + file + ". " + e, e);
}
}
public static Funktion loadFromString(String yaml) throws IOException {
return parseFunktionConfig(yaml);
}
public static Funktion loadFromURL(URL resource) throws IOException {
return parseFunktionConfig(resource);
}
protected static Funktion validateConfig(Funktion config, File file) {
List<Flow> flows = config.getFlows();
if (flows.isEmpty()) {
throw new IllegalStateException("No Funktion flows defined in file: " + file.getPath());
}
return config;
}
protected static Funktion validateConfig(Funktion config, URL url) {
List<Flow> flows = config.getFlows();
if (flows.isEmpty()) {
throw new IllegalStateException("No Funktion flows defined in URL: " + url);
}
return config;
}
/**
* Tries to find the configuration from the current directory or a parent folder.
*/
public static Funktion findFromFolder(File folder) throws IOException {
if (folder.isDirectory()) {
File file = new File(folder, FILE_NAME);
if (file != null && file.exists() && file.isFile()) {
return loadFromFile(file);
}
File configFolder = new File(folder, "config");
file = new File(configFolder, FILE_NAME);
if (file != null && file.exists() && file.isFile()) {
return loadFromFile(file);
}
File parentFile = folder.getParentFile();
if (parentFile != null) {
return findFromFolder(parentFile);
}
Funktion answer = tryFindConfigOnClassPath();
if (answer != null) {
return answer;
}
throw new IOException("Funktion configuration file does not exist: " + file.getPath());
} else if (folder.isFile()) {
return loadFromFile(folder);
}
Funktion answer = tryFindConfigOnClassPath();
if (answer != null) {
return answer;
}
throw new IOException("Funktion configuration folder does not exist: " + folder.getPath());
}
protected static Funktion tryFindConfigOnClassPath() throws IOException {
URL url = Funktions.class.getClassLoader().getResource(FILE_NAME);
if (url != null) {
try {
Funktion config = parseFunktionConfig(url);
return validateConfig(config, url);
} catch (IOException e) {
throw new IOException("Failed to parse funktion config: " + url + ". " + e, e);
}
}
return null;
}
/**
* Returns true if the given folder has a configuration file called {@link #FILE_NAME}
*/
public static boolean hasConfigFile(File folder) {
File FunktionConfigFile = new File(folder, FILE_NAME);
return FunktionConfigFile != null && FunktionConfigFile.exists() && FunktionConfigFile.isFile();
}
/**
* Creates a configured Jackson object mapper for parsing YAML
*/
public static ObjectMapper createObjectMapper() {
YAMLFactory yamlFactory = new YAMLFactory();
yamlFactory.configure(YAMLGenerator.Feature.USE_NATIVE_TYPE_ID, false);
return new ObjectMapper(yamlFactory);
}
public static Funktion parseFunktionConfig(File file) throws IOException {
LOG.info("Loading Funktion flows from file: " + file);
return parseYaml(file, Funktion.class);
}
public static Funktion parseFunktionConfig(InputStream input) throws IOException {
return parseYaml(input, Funktion.class);
}
public static Funktion parseFunktionConfig(URL url) throws IOException {
LOG.info("Loading Funktion flows from URL: " + url);
return parseYaml(url, Funktion.class);
}
public static Funktion parseFunktionConfig(String yaml) throws IOException {
return parseYaml(yaml, Funktion.class);
}
private static <T> T parseYaml(File file, Class<T> clazz) throws IOException {
ObjectMapper mapper = createObjectMapper();
return mapper.readValue(file, clazz);
}
private static <T> T parseYaml(URL url, Class<T> clazz) throws IOException {
ObjectMapper mapper = createObjectMapper();
return mapper.readValue(url, clazz);
}
static <T> List<T> parseYamlValues(File file, Class<T> clazz) throws IOException {
ObjectMapper mapper = createObjectMapper();
MappingIterator<T> iter = mapper.readerFor(clazz).readValues(file);
List<T> answer = new ArrayList<>();
while (iter.hasNext()) {
answer.add(iter.next());
}
return answer;
}
private static <T> T parseYaml(InputStream inputStream, Class<T> clazz) throws IOException {
ObjectMapper mapper = createObjectMapper();
return mapper.readValue(inputStream, clazz);
}
private static <T> T parseYaml(String yaml, Class<T> clazz) throws IOException {
ObjectMapper mapper = createObjectMapper();
return mapper.readValue(yaml, clazz);
}
/**
* Saves the funktion.yml file to the given project directory
*/
public static boolean saveToFolder(File basedir, Funktion config, boolean overwriteIfExists) throws IOException {
File file = new File(basedir, Funktions.FILE_NAME);
if (file.exists()) {
if (!overwriteIfExists) {
LOG.warn("Not generating " + file + " as it already exists");
return false;
}
}
return saveConfig(config, file);
}
/**
* Saves the configuration as YAML in the given file
*/
public static boolean saveConfig(Funktion config, File file) throws IOException {
createObjectMapper().writeValue(file, config);
return true;
}
/**
* Saves the configuration as JSON in the given file
*/
public static void saveConfigJSON(Funktion funktion, File file) throws IOException {
ObjectMapper mapper = new ObjectMapper();
mapper.writerWithDefaultPrettyPrinter().writeValue(file, funktion);
}
}