com.reprezen.genflow.api.target.GenTargetUtils Maven / Gradle / Ivy
/*******************************************************************************
* Copyright © 2013, 2016 Modelsolv, Inc.
* All Rights Reserved.
*
* NOTICE: All information contained herein is, and remains the property
* of ModelSolv, Inc. See the file license.html in the root directory of
* this project for further information.
*******************************************************************************/
package com.reprezen.genflow.api.target;
import java.io.File;
import java.io.IOException;
import java.util.ArrayDeque;
import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Queue;
import java.util.Set;
import java.util.logging.Logger;
import com.fasterxml.jackson.core.JsonParser.Feature;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.dataformat.yaml.YAMLFactory;
import com.google.common.collect.HashMultimap;
import com.google.common.collect.Lists;
import com.google.common.collect.Multimap;
import com.google.common.collect.Sets;
import com.reprezen.genflow.api.GenerationException;
import com.reprezen.genflow.api.template.GenTemplateProperty;
import com.reprezen.genflow.api.template.GenTemplateProperty.StandardProperties;
import com.reprezen.genflow.api.template.GenTemplateRegistry;
import com.reprezen.genflow.api.template.IGenTemplate;
import com.reprezen.genflow.api.trace.GenTemplateTrace;
import com.reprezen.genflow.api.trace.GenTemplateTraceSerializer;
import com.reprezen.genflow.api.trace.GenTemplateTraces;
/**
* Utility methods to load and save {@link GenTarget}
*
* @author Konstantin Zaitsev
* @date Jun 22, 2015
*/
public final class GenTargetUtils {
private static final ObjectMapper mapper = new ObjectMapper(new YAMLFactory()).enable(Feature.ALLOW_COMMENTS);
public GenTargetUtils() {
// prevent instantiation
}
public static GenTarget load(File genTargetFile) throws IncorrectGenTargetException {
try {
GenTarget target = mapper.readValue(genTargetFile, GenTarget.class);
target.setBaseDir(genTargetFile.getCanonicalFile().getParentFile());
return target;
} catch (Exception e) {
throw new IncorrectGenTargetException(
"GenTarget file has an invalid format, property names or values: " + genTargetFile.toString(), e);
}
}
public static void save(GenTarget target, String name, boolean force) throws GenerationException {
File file = getGenTargetFile(name, target.getBaseDir());
try {
if (!file.exists() || force) {
mapper.writeValue(file, target);
}
} catch (IOException e) {
throw new GenerationException("Failed to save GenTarget " + name + " to " + file, e);
}
}
public static void saveTrace(GenTarget target, GenTemplateTrace trace) throws GenerationException {
File file = getTraceFile(target);
GenTemplateTraceSerializer.save(trace, file);
}
public static GenTemplateTraces execute(Logger logger, boolean log, boolean withPrerequisites,
GenTemplateTraces allTraces, Collection targets) throws GenerationException {
if (allTraces == null) {
allTraces = new GenTemplateTraces();
}
if (withPrerequisites) {
targets = resolveTargetList(targets);
}
for (GenTarget target : targets) {
if (log) {
logger.info(String.format("Executing GenTarget %s [%s]", target.getName(), getProvider(target)));
}
GenTemplateTrace trace = target.execute(allTraces, logger);
if (log) {
logger.info("Saving trace data");
}
saveTrace(target, trace);
allTraces.addTrace(target, trace);
}
return allTraces;
}
public static GenTemplateTraces execute(Logger logger, boolean log, boolean withPrerequisites,
GenTemplateTraces allTraces, GenTarget... targets) throws GenerationException {
return execute(logger, log, withPrerequisites, allTraces, Arrays.asList(targets));
}
public static List resolveTargetList(Collection targets) throws GenerationException {
Queue todo = new ArrayDeque(targets);
Multimap graph = HashMultimap.create();
Set allTargets = Sets.newHashSet();
while (!todo.isEmpty()) {
GenTarget target = todo.remove();
if (allTargets.contains(target)) {
continue;
}
allTargets.add(target);
for (GenTargetPrerequisite prereq : target.getPrerequisites().values()) {
GenTarget prereqTarget = load(target.resolvePath(prereq.getGenFilePath()));
if (!allTargets.contains(prereqTarget)) {
todo.add(prereqTarget);
}
graph.put(target, prereqTarget);
}
}
// Reverse because graph has target -> prereq edges, and we want target to
// follow prereq
return TopSort.sortReverse(allTargets, graph);
}
public static File getGenTargetFile(String name, File baseDir) {
return new File(baseDir, name + ".gen");
}
public static File getGenTargetFile(GenTarget target) {
return getGenTargetFile(target.getName(), target.getBaseDir());
}
public static File getTraceFile(GenTarget target) {
return new File(target.getBaseDir(), target.getName() + ".trace.json");
}
private static String getProvider(GenTarget target) throws GenerationException {
IGenTemplate template = GenTemplateRegistry.getDefaultGenTemplate(target.getGenTemplateId()).getInstance();
String unknown = "unknown provider";
if (template == null) {
return unknown;
} else {
GenTemplateProperty provider = null;
try {
provider = template.getProperty(StandardProperties.PROVIDER.name());
} catch (GenerationException e) {
}
return provider != null ? provider.getValue() : unknown;
}
}
// TOOD This should replace the top sorter in cmr.gentemplates.common.graph,
// getting rid of all the existing
// digraph stuff that's not otherwise needed
public static class TopSort {
public static List sortReverse(Collection nodes, Multimap graph) {
List result = Lists.newArrayList();
Set visited = Sets.newHashSet();
for (T node : nodes) {
visit(node, graph, result, visited, new HashSet());
}
return result;
}
public static List sort(Collection nodes, Multimap graph) {
// sortReverse is actually the more efficient option, since nodes are placed
// after all their graph
// descendants have been placed, and the only core List implementation with
// efficient front-loading is the
// generally inefficient LinkedList.
List result = sortReverse(nodes, graph);
Collections.reverse(result);
return result;
}
private static void visit(T node, Multimap graph, List result, Set visited, Set inProgress) {
if (inProgress.contains(node)) {
throw new IllegalArgumentException("Graph contains at least one cycle");
} else if (!visited.contains(node)) {
inProgress.add(node);
for (T dependant : graph.get(node)) {
visit(dependant, graph, result, visited, inProgress);
}
visited.add(node);
inProgress.remove(node);
result.add(node);
}
}
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy