package org.ecgine.gradle;
import java.io.File;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import org.apache.commons.io.IOUtils;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.HttpClient;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.ecgine.gradle.extensions.EcgineExtension;
import org.gradle.api.DefaultTask;
import org.gradle.api.GradleException;
import org.gradle.api.tasks.TaskAction;
import org.json.JSONArray;
import org.json.JSONObject;
import com.google.common.io.Files;
public class EcgineBundlesTask extends DefaultTask {
@TaskAction
public void bundles() {
EcgineExtension ext = (EcgineExtension) getProject().getExtensions().getByName(EcgineExtension.NAME);
HttpClient client = ext.getHttpClient();
// Read from file
Map<String, JSONObject> allDepends = EcgineUtils.readJarDependencies(getProject());
// Get all project dependencies
Map<String, String> dependencies = ext.getBundles();
Map<String, String> allJars = new HashMap<>();
Map<String, String> notFound = new HashMap<>();
boolean needUpdate = prepareJarDependencies(ext, client, allDepends, dependencies, allJars, notFound, true);
if (needUpdate) {
EcgineUtils.updateJarDependencies(getLogger(), getProject(), allDepends);
}
Set<String> notFoundJars = new HashSet<>(notFound.keySet());
allJars.forEach((n, v) -> {
File jar = downloadBundle(ext, client, n, v);
if (!jar.exists()) {
notFoundJars.add(jar.getName());
}
});
if (!notFoundJars.isEmpty()) {
throw new GradleException();
}
System.out.println("add this path in eclipse TargetPlatform: " + ext.getPlugins());
}
private boolean prepareJarDependencies(EcgineExtension ext, HttpClient client, Map<String, JSONObject> allDepends,
Map<String, String> dependencies, Map<String, String> output, Map<String, String> notFound,
boolean needDownload) {
dependencies.forEach((k, v) -> {
JSONObject json = allDepends.get(k);
if (json == null || !json.getString("specifiedVersion").equals(v)) {
notFound.put(k, v);
} else {
if (!json.has("version")) {
notFound.put(k, v);
return;
}
output.put(k, json.getString("version"));
addDependencies(output, notFound, allDepends, json);
}
});
if (needDownload && !notFound.isEmpty()) {
JSONObject result = getDependenciesFromServer(ext, client, notFound);
Map<String, JSONObject> depends = new HashMap<>();
result.keySet().forEach(e -> {
JSONObject jar = result.getJSONObject(e);
if (!jar.has("version")) {
System.err.println("Bundle not found:" + e);
}
depends.put(e, jar);
});
Map<String, String> next = new HashMap<>(notFound);
notFound.clear();
prepareJarDependencies(ext, client, depends, next, output, notFound, false);
allDepends.putAll(depends);
return true;
}
return false;
}
private void addDependencies(Map<String, String> output, Map<String, String> notFound,
Map<String, JSONObject> allDepends, JSONObject json) {
// Exists, add all dependencies
JSONArray array = json.getJSONArray("dependents");
array.forEach(a -> {
JSONObject obj = allDepends.get(a.toString());
if (!obj.has("version")) {
notFound.put(a.toString(), obj.getString("specifiedVersion"));
return;
}
String version = obj.getString("version");
output.put(a.toString(), version);
addDependencies(output, notFound, allDepends, obj);
});
}
private JSONObject getDependenciesFromServer(EcgineExtension ext, HttpClient client,
Map<String, String> notExisting) {
try {
String url = ext.getDependenciesUrl();
System.out.println("Downloading dependencies: " + url);
HttpPost request = new HttpPost(url);
request.addHeader("apikey", ext.getApiKey());
JSONObject obj = new JSONObject();
notExisting.forEach(obj::put);
request.setEntity(new StringEntity(obj.toString()));
HttpResponse response = client.execute(request);
int code = response.getStatusLine().getStatusCode();
if (code != 200) {
EntityUtils.consume(response.getEntity());
if (code == 401) {
throw new GradleException("Invalid api key");
} else {
throw new GradleException("StatusCode:" + code + " URL:" + url);
}
}
String json = EntityUtils.toString(response.getEntity());
JSONObject result = new JSONObject(json);
System.out.println("Got dependencies");
return result;
} catch (Exception e) {
throw new RuntimeException(e);
}
}
public static File downloadBundle(EcgineExtension ext, HttpClient client, String name, String version) {
File plugins = new File(ext.getPlugins());
if (!plugins.exists()) {
plugins.mkdirs();
}
File jar = new File(plugins, name + "_" + version + ".jar");
if (jar.exists()) {
return jar;
}
try {
System.out.println("Downloading bundle " + jar.getName());
String url = ext.getDownloadUrl();
HttpPost request = new HttpPost(url);
request.addHeader("apikey", ext.getApiKey());
List<NameValuePair> urlParameters = new ArrayList<NameValuePair>();
urlParameters.add(new BasicNameValuePair("name", name));
urlParameters.add(new BasicNameValuePair("version", version));
request.setEntity(new UrlEncodedFormEntity(urlParameters));
HttpResponse response = client.execute(request);
int code = response.getStatusLine().getStatusCode();
if (code == 200) {
File temp = new File(plugins, "temp");
if (temp.exists()) {
temp.delete();
}
temp.createNewFile();
IOUtils.copy(response.getEntity().getContent(), new FileOutputStream(temp));
Files.copy(temp, jar);
} else {
EntityUtils.consume(response.getEntity());
if (code == 401) {
throw new GradleException("Invalid api key");
} else {
System.err.println("Bundle not found in ecgine repository " + jar.getName());
}
}
} catch (Exception e) {
throw new GradleException(e.getMessage(), e);
}
return jar;
}
}