package org.ecgine.gradle; import java.io.BufferedOutputStream; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.nio.file.Files; 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 java.util.stream.Collectors; import java.util.stream.Stream; import java.util.stream.Stream.Builder; import java.util.zip.ZipEntry; import java.util.zip.ZipInputStream; import org.apache.commons.io.FileUtils; import org.apache.commons.io.IOUtils; import org.apache.commons.lang.StringUtils; import org.apache.http.HttpResponse; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpGet; import org.apache.http.impl.client.HttpClientBuilder; import org.apache.http.util.EntityUtils; import org.ecgine.gradle.extensions.Configuration; import org.ecgine.gradle.extensions.EcgineExtension; import org.ecgine.gradle.extensions.Master; import org.gradle.api.GradleException; import org.gradle.api.tasks.Exec; import org.json.JSONArray; import org.json.JSONObject; @SuppressWarnings("unchecked") public abstract class AbstractStart extends Exec { protected void prepareSetup(EcgineExtension ext, Configuration cfg, String type) { try { Master master = ext.getMaster(); cfg.property("ecgine.vimukti.master", master.getSubDomain() + ".ecgine.com"); JSONObject config = getConfiguration(ext, type); File plugins = new File(ext.getPlugins()); if (!plugins.exists()) { plugins.mkdirs(); } String setup = ext.getSetup(); String jreVersion = null; if (config.has("jreVersion")) { jreVersion = config.getString("jreVersion"); } else { jreVersion = EcgineExtension.DEFAULT_JRE_VERSION; } // Downloading JRE File jreZip = new File(plugins, ext.getJre(jreVersion)); if (!jreZip.exists()) { AbstractStart.downloadConfigFile(HttpClientBuilder.create().build(), jreZip, ext.getJREURL(jreZip.getName())); } // Extracting JRE File jreDir = new File(setup, "jre"); if (!jreDir.exists()) { unzip(new File(setup), jreZip); } List<String> cmds = prepareSetup(plugins, cfg, setup, type, config); setCommandLine(cmds); setWorkingDir(new File(ext.getSetup(), type)); super.exec(); } catch (IOException e) { getLogger().error("Unable to start ecgine", e); throw new GradleException("", e); } } protected JSONObject getConfiguration(EcgineExtension ext, String type) throws IOException { File plugins = new File(ext.getPlugins()); if (!plugins.exists()) { plugins.mkdirs(); } File config = new File(plugins, ".config"); if (!config.exists()) { downloadConfigFile(ext.getHttpClient(), config, ext.getConfigUrl()); } getLogger().debug("loading .config file->" + config.getAbsolutePath()); String string = new String(Files.readAllBytes(config.toPath())); JSONObject c = new JSONObject(string).getJSONObject(type); JSONObject bundles = c.getJSONObject("bundles"); getLogger().debug("adding developer bundles"); Set<EManifest> devBundles = EcgineUtils.getAllProjects(getProject(), this::filterDevBundle); if (getLogger().isDebugEnabled()) { getLogger().debug("Dev Bundles:" + devBundles); } Map<String, String> allDependencies = EcgineUtils.getDependencies(devBundles, s -> false, getProject()); if (getLogger().isDebugEnabled()) { getLogger().debug("All dependencies:" + allDependencies); } Set<String> allJars = collectAllBundles(bundles); if (getLogger().isDebugEnabled()) { getLogger().debug("All ecgine jars:" + allJars); } Set<String> remainingJars = new HashSet<>(); StringBuilder testBundles = new StringBuilder(); // need to remove existed bundles from this list allDependencies.forEach((n, v) -> { String fullName = n + "_" + v + ".jar"; testBundles.append(n).append(","); if (allJars.contains(fullName)) { return; } remainingJars.add(fullName); }); if (getLogger().isDebugEnabled()) { getLogger().debug("Remaining Jars:" + remainingJars); } // Here we have to collect not found jars. Set<String> notFound = remainingJars.stream().filter(f -> !new File(plugins, f).exists()) .collect(Collectors.toSet()); // throw exception that 'jar not found add it in dependencies' if (!notFound.isEmpty()) { System.err.println("following jars are not found, add these dependencies and run bundles task"); notFound.forEach(System.err::println); throw new RuntimeException(); } // add these depends in dev-bundles with 5 JSONArray devBundlesArray = new JSONArray(); remainingJars.forEach(jar -> { JSONObject obj = new JSONObject(); obj.put("jar", jar); obj.put("start", 5); devBundlesArray.put(obj); }); devBundles.forEach(m -> { testBundles.append(m.getSymbolicName()).append(","); File jar = m.getJar(); JSONObject obj = new JSONObject(); obj.put("jar", jar.getName()); obj.put("start", 5); devBundlesArray.put(obj); if (!EcgineUtils.copy(jar, new File(plugins, jar.getName()))) { notFound.add(m.getSymbolicName()); } }); if (!notFound.isEmpty()) { System.err.println("following jars are not found, run ecginePrepare task"); notFound.forEach(System.err::println); throw new RuntimeException(); } if (devBundles.size() != 0) { c.getJSONObject("properties").put("ecgine.tenent.testbundles", testBundles.substring(0, testBundles.length() - 1)); bundles.put("dev-bundles", devBundlesArray); } else { System.out.println("No developer bundles found"); } return c; } private Set<String> collectAllBundles(JSONObject bundles) { return bundles.keySet().stream() // Extract each group .map(bundles::getJSONArray) // get each jar from each group .flatMap(a -> { Builder<JSONObject> b = Stream.builder(); a.forEach(j -> b.add((JSONObject) j)); return b.build(); }) // Extract jar from each JSONObject .map(j -> j.getString("jar")) // Collect all jars .collect(Collectors.toSet()); } protected abstract boolean filterDevBundle(EManifest manifest); public static void downloadConfigFile(HttpClient client, File file, String url) { System.out.println(file.getName() + " file not found->" + file.getAbsolutePath()); try { System.out.println("Downloading " + file.getName() + " file->" + url); HttpGet request = new HttpGet(url); HttpResponse response = client.execute(request); int code = response.getStatusLine().getStatusCode(); if (code != 200) { EntityUtils.consume(response.getEntity()); throw new GradleException("StatusCode:" + code + " URL:" + url); } System.out.println("Got " + file.getName() + " file."); IOUtils.copy(response.getEntity().getContent(), new FileOutputStream(file)); } catch (Exception e) { throw new GradleException(e.getMessage(), e); } } protected List<String> prepareSetup(File plugins, Configuration con, String setup, String type, JSONObject config) throws IOException { File root = new File(setup, type); if (root.exists()) { FileUtils.deleteDirectory(root); } root.mkdirs(); Map<String, String> configProps = new HashMap<>(); // copy all bundles(jars) String bundles = copyAllJars(plugins, root, config.getJSONObject("bundles"), true); configProps.put("osgi.bundles", bundles); copyHomeJars(plugins, root, config.getJSONArray("home")); JSONObject props = config.getJSONObject("properties"); props.keySet().forEach(k -> configProps.put(k, props.getString(k))); configProps.putAll(con.getProperties()); File configuration = new File(root, "configuration"); Files.createDirectories(configuration.toPath()); configuration.mkdir(); EcgineUtils.writeProperties(getLogger(), new File(configuration, "config.ini"), configProps); return prepareRunner(root, config.getString("runJar"), con); } private void unzip(File destination, File source) throws IOException { if (!destination.exists()) { destination.mkdirs(); } System.out.println("Please wait unziping downloaded jre to " + destination.getAbsolutePath()); ZipInputStream zipIn = new ZipInputStream(new FileInputStream(source)); ZipEntry entry = zipIn.getNextEntry(); // iterates over entries in the zip file while (entry != null) { File file = new File(destination, entry.getName()); if (entry.isDirectory()) { // if the entry is a directory, make the directory file.mkdirs(); } else { // if the entry is a file, extracts it file.createNewFile(); extractFile(zipIn, file); } zipIn.closeEntry(); entry = zipIn.getNextEntry(); } zipIn.close(); System.out.println("Unziping jre completed"); } private void extractFile(ZipInputStream zipIn, File file) throws IOException { BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file)); byte[] bytesIn = new byte[4096]; int read = 0; while ((read = zipIn.read(bytesIn)) != -1) { bos.write(bytesIn, 0, read); } bos.close(); } private List<String> prepareRunner(File root, String jar, Configuration cfg) { List<String> cmds = new ArrayList<>(); // exec $JAVA $* -Xdebug // -Xrunjdwp:server=y,transport=dt_socket,address=4000,suspend=n -jar // org.eclipse.osgi_3.10.101.v20150820-1432.jar -console 2501 if (EcgineExtension.isWindows()) { cmds.add("cmd"); cmds.add("/c"); cmds.add("..\\jre\\bin\\java.exe"); } else { cmds.add("../jre/bin/java"); } String ms = cfg.getMs(); if (ms != null) { cmds.add("-Xms" + ms); } String mx = cfg.getMx(); if (mx != null) { cmds.add("-Xmx" + mx); } String ss = cfg.getSs(); if (ss != null) { cmds.add("-Xss" + ss); } int port = cfg.getDebugPort(); if (port > 0) { cmds.add("-Xrunjdwp:server=y,transport=dt_socket,address=" + port + ",suspend=n"); } cmds.add("-jar"); cmds.add(jar); cmds.add("."); int cp = cfg.getConsolePort(); if (cp > 0) { cmds.add("-console"); cmds.add(String.valueOf(cp)); } StringBuilder cmdString = new StringBuilder(); for (String cmd : cmds) { cmdString.append(" ").append(cmd); } getLogger().debug("Command:" + cmdString.toString()); return cmds; } private void copyHomeJars(File plugins, File server, JSONArray array) { Set<String> notFound = new HashSet<>(); array.forEach(j -> { File jar = new File(server, j.toString()); if (!jar.exists()) { if (!EcgineUtils.copy(new File(plugins, j.toString()), jar)) { notFound.add(jar.getName()); } } }); if (!notFound.isEmpty()) { System.err.println("following jars are not found in :" + plugins); System.err.println("run bundles task"); notFound.forEach(j -> getLogger().error(j)); throw new RuntimeException(); } } private String copyAllJars(File plugins, File root, JSONObject bundles, boolean needDownload) { getLogger().debug("Copy all jars from:" + plugins + " to setup folder"); Set<String> notFound = new HashSet<>(); StringBuilder property = new StringBuilder(); bundles.keySet().forEach(k -> { JSONArray array = bundles.getJSONArray(k); File folder = new File(root, k); folder.mkdir(); array.forEach(j -> { JSONObject obj = (JSONObject) j; File jar = new File(folder, obj.getString("jar")); if (!jar.exists()) { if (!EcgineUtils.copy(new File(plugins, jar.getName()), jar)) { notFound.add(jar.getName()); } } property.append("reference\\:file\\:./"); property.append(k).append("/"); property.append(jar.getName()); if (!obj.has("isFragment") || !obj.getBoolean("isFragment")) { if (obj.has("start")) { property.append("@").append(obj.getInt("start")).append("\\:start"); } else { property.append("@start"); } } property.append(","); }); }); if (needDownload && !notFound.isEmpty()) { EcgineExtension ext = (EcgineExtension) getProject().getExtensions().getByName(EcgineExtension.NAME); HttpClient client = ext.getHttpClient(); notFound.forEach(n -> { String[] split = n.split("_"); String version = split[split.length - 1]; n = n.replaceFirst("_" + version, ""); version = version.replaceFirst(".jar", ""); EcgineBundlesTask.downloadBundle(ext, client, n, version); }); return copyAllJars(plugins, root, bundles, false); } if (notFound.isEmpty()) { property.subSequence(0, property.length() - 2); return property.toString(); } System.err.println("following jars are not found in :" + plugins); System.err.println("run bundles task"); notFound.forEach(j -> getLogger().error(j)); throw new RuntimeException(); } }