package restx.build;
import restx.build.org.json.JSONArray;
import restx.build.org.json.JSONObject;
import restx.build.org.json.JSONTokener;
import java.io.*;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.*;
import static restx.build.RestxBuildHelper.expandProperties;
/**
* User: xavierhanin
* Date: 4/14/13
* Time: 2:08 PM
*/
public class RestxJsonSupport implements RestxBuild.Parser, RestxBuild.Generator {
static class Generator {
public void generate(ModuleDescriptor md, Writer w) throws IOException {
w.write("{\n");
if (md.getParent() != null) {
w.write(String.format(" \"parent\": \"%s\",\n", md.getParent()));
}
w.write(String.format(" \"module\": \"%s\",\n", md.getGav()));
if (!"jar".equals(md.getPackaging())) {
w.write(String.format(" \"packaging\": \"%s\",\n", md.getPackaging()));
}
w.write("\n");
w.write(" \"properties\": {\n");
for (Iterator<Map.Entry<String, String>> iterator = md.getProperties().entrySet().iterator(); iterator.hasNext(); ) {
Map.Entry<String, String> entry = iterator.next();
w.write(String.format(" \"%s\": \"%s\"", entry.getKey(), entry.getValue()));
if (iterator.hasNext()) {
w.write(",");
}
w.write("\n");
}
w.write(" },\n\n");
w.write(" \"dependencies\": {\n");
Set<String> scopes = md.getDependencyScopes();
for (Iterator<String> itScopes = scopes.iterator(); itScopes.hasNext(); ) {
String scope = itScopes.next();
w.write(String.format(" \"%s\": [\n", scope));
for (Iterator<ModuleDependency> itDeps = md.getDependencies(scope).iterator(); itDeps.hasNext(); ) {
ModuleDependency dependency = itDeps.next();
w.write(String.format(" \"%s\"", dependency.getGav()));
if (itDeps.hasNext()) {
w.write(",");
}
w.write("\n");
}
w.write(" ]");
if (itScopes.hasNext()) {
w.write(",");
}
w.write("\n");
}
w.write(" }\n");
w.write("}\n");
}
}
static class Parser {
public ModuleDescriptor parse(Path path) throws IOException {
try (InputStream inputStream = Files.newInputStream(path)) {
return parse(path, inputStream);
}
}
public ModuleDescriptor parse(InputStream inputStream) throws IOException {
return parse(null, inputStream);
}
private ModuleDescriptor parse(Path path, InputStream inputStream) throws IOException {
JSONObject jsonObject = new JSONObject(new JSONTokener(new InputStreamReader(inputStream, "UTF-8")));
Map<String, String> properties = new LinkedHashMap<>();
if (jsonObject.has("properties")) {
loadJsonProperties(path == null ? null : path.getParent(), properties, jsonObject.getJSONObject("properties"));
}
GAV parent = null;
if (jsonObject.has("parent")) {
parent = GAV.parse(expandProperties(properties, jsonObject.getString("parent")));
}
GAV gav = GAV.parse(expandProperties(properties, jsonObject.getString("module")));
String packaging = jsonObject.has("packaging") ? jsonObject.getString("packaging") : "jar";
Map<String, List<ModuleDependency>> dependencies = new LinkedHashMap<>();
if (jsonObject.has("dependencies")) {
JSONObject scopes = jsonObject.getJSONObject("dependencies");
for (Object s : scopes.keySet()) {
String scope = s.toString();
List<ModuleDependency> scopeDeps = new ArrayList<>();
dependencies.put(scope, scopeDeps);
JSONArray deps = scopes.getJSONArray(scope);
for (int i = 0; i < deps.length(); i++) {
scopeDeps.add(new ModuleDependency(GAV.parse(deps.getString(i))));
}
}
}
Map<String, List<ModuleFragment>> fragments = new LinkedHashMap<>();
if (jsonObject.has("fragments")) {
JSONObject jsonFragments = jsonObject.getJSONObject("fragments");
for (Object key : jsonFragments.keySet()) {
String type = (String) key;
List<ModuleFragment> fragmentsForType = new ArrayList<>();
JSONArray array = jsonFragments.getJSONArray(type);
for (int i = 0; i < array.length(); i++) {
String url = expandProperties(properties, array.getString(i));
if (url.startsWith("classpath://")) {
String fragmentPath = url.substring("classpath://".length());
InputStream stream = getClass().getResourceAsStream(fragmentPath);
if (stream == null) {
throw new IllegalArgumentException("classpath fragment not found: '" + fragmentPath + "'" +
". Check your classpath.");
}
fragmentsForType.add(new ModuleFragment(RestxBuildHelper.toString(stream)));
} else {
URL fragmentUrl = new URL(url);
try (InputStream stream = fragmentUrl.openStream()) {
fragmentsForType.add(new ModuleFragment(RestxBuildHelper.toString(stream)));
}
}
}
fragments.put(type, fragmentsForType);
}
}
return new ModuleDescriptor(parent, gav, packaging, properties, fragments, dependencies);
}
private void loadJsonProperties(Path path, Map<String, String> properties, JSONObject props) throws IOException {
for (Object p : props.keySet()) {
String key = p.toString();
if (key.equals("@files")) {
JSONArray propertyFiles = props.getJSONArray(key);
for (int i = 0; i < propertyFiles.length(); i++) {
String propertyFile = propertyFiles.getString(i);
Path propertyFilePath = path == null ? Paths.get(propertyFile) : path.resolve(propertyFile);
if (!propertyFilePath.toFile().exists()) {
throw new IllegalArgumentException(
"can't resolve property file " + propertyFilePath.toAbsolutePath() + "." +
" Not found." +
(path == null ?
" Note that parsing from mere inputstream resolve files " +
"relative to current directory." :
""));
}
try (InputStreamReader reader = new InputStreamReader(Files.newInputStream(propertyFilePath))) {
loadJsonProperties(propertyFilePath.getParent(), properties, new JSONObject(new JSONTokener(reader)));
}
}
} else {
properties.put(key, props.getString(key));
}
}
}
}
private final Generator generator = new Generator();
private final Parser parser = new Parser();
public void generate(ModuleDescriptor md, Writer w) throws IOException {
generator.generate(md, w);
}
public ModuleDescriptor parse(InputStream inputStream) throws IOException {
return parser.parse(inputStream);
}
public ModuleDescriptor parse(Path path) throws IOException {
return parser.parse(path);
}
@Override
public String getDefaultFileName() {
return "md.restx.json";
}
}