| /** |
| * Copyright (c) 2020 Eclipse contributors and others. |
| * |
| * This program and the accompanying materials |
| * are made available under the terms of the Eclipse Public License 2.0 |
| * which accompanies this distribution, and is available at |
| * https://www.eclipse.org/legal/epl-2.0/ |
| * |
| * SPDX-License-Identifier: EPL-2.0 |
| */ |
| package org.eclipse.justj.codegen.model.util; |
| |
| |
| import java.io.IOException; |
| import java.io.InputStream; |
| import java.io.OutputStream; |
| import java.io.PrintStream; |
| import java.nio.file.Files; |
| import java.nio.file.Path; |
| import java.nio.file.Paths; |
| import java.nio.file.attribute.PosixFilePermission; |
| import java.util.Arrays; |
| import java.util.Collections; |
| import java.util.HashSet; |
| import java.util.LinkedHashMap; |
| import java.util.LinkedHashSet; |
| import java.util.List; |
| import java.util.Map; |
| import java.util.Objects; |
| import java.util.Properties; |
| import java.util.Set; |
| import java.util.TreeMap; |
| import java.util.TreeSet; |
| import java.util.concurrent.ExecutionException; |
| import java.util.concurrent.ExecutorService; |
| import java.util.concurrent.Executors; |
| import java.util.concurrent.Future; |
| import java.util.concurrent.TimeUnit; |
| import java.util.concurrent.atomic.AtomicInteger; |
| import java.util.regex.Matcher; |
| import java.util.regex.Pattern; |
| import java.util.stream.Collectors; |
| |
| import org.eclipse.core.runtime.IProgressMonitor; |
| import org.eclipse.core.runtime.NullProgressMonitor; |
| import org.eclipse.core.runtime.SubMonitor; |
| import org.eclipse.emf.common.CommonPlugin; |
| import org.eclipse.emf.common.util.ECollections; |
| import org.eclipse.emf.common.util.EList; |
| import org.eclipse.emf.common.util.EMap; |
| import org.eclipse.emf.common.util.URI; |
| import org.eclipse.emf.ecore.resource.Resource; |
| import org.eclipse.emf.ecore.resource.ResourceSet; |
| import org.eclipse.emf.ecore.resource.URIConverter; |
| import org.eclipse.emf.ecore.resource.impl.ResourceSetImpl; |
| import org.eclipse.emf.ecore.util.EcoreUtil; |
| import org.eclipse.equinox.app.IApplication; |
| import org.eclipse.equinox.app.IApplicationContext; |
| import org.eclipse.justj.codegen.model.Annotation; |
| import org.eclipse.justj.codegen.model.Copyrightable; |
| import org.eclipse.justj.codegen.model.JVM; |
| import org.eclipse.justj.codegen.model.Model; |
| import org.eclipse.justj.codegen.model.ModelFactory; |
| import org.eclipse.justj.codegen.model.ModelPackage; |
| import org.eclipse.justj.codegen.model.ModelPlugin; |
| import org.eclipse.justj.codegen.model.Phase; |
| import org.eclipse.justj.codegen.model.Touchable; |
| import org.eclipse.justj.codegen.model.Touchpoint; |
| import org.eclipse.justj.codegen.model.Variant; |
| |
| |
| public class Reconciler |
| { |
| private final Model model; |
| |
| private final URIConverter uriConverter; |
| |
| private final URI source; |
| |
| private Path localCache; |
| |
| public static void main(String[] args) throws IOException, InterruptedException |
| { |
| ModelPackage.eINSTANCE.eClass(); |
| Path path = Paths.get(args[0]); |
| Path realPath = path.toRealPath(); |
| System.out.println("Reconciling: " + realPath); |
| Reconciler reconciler = new Reconciler(URI.createFileURI(realPath.toString())); |
| Model reconciledModel = reconciler.reconcile(new PrintingProgressMonitor()); |
| |
| Model model = reconciler.getModel(); |
| EcoreUtil.replace(model, reconciledModel); |
| reconciledModel.eResource().save(Collections.singletonMap(Resource.OPTION_SAVE_ONLY_IF_CHANGED, Resource.OPTION_SAVE_ONLY_IF_CHANGED_MEMORY_BUFFER)); |
| } |
| |
| public Reconciler(URI modelURI) throws IOException |
| { |
| ResourceSet resourceSet = new ResourceSetImpl(); |
| uriConverter = resourceSet.getURIConverter(); |
| resourceSet.getResourceFactoryRegistry().getExtensionToFactoryMap().put("jregen", new ModelResourceFactoryImpl()); |
| |
| Resource resource = resourceSet.getResource(modelURI, true); |
| model = (Model)resource.getContents().get(0); |
| this.source = computeSource(model); |
| this.localCache = computeLocalCache(model); |
| } |
| |
| public Reconciler(Model model) |
| { |
| this.model = model; |
| Resource resource = model.eResource(); |
| uriConverter = resource.getResourceSet().getURIConverter(); |
| this.source = computeSource(model); |
| this.localCache = computeLocalCache(model); |
| } |
| |
| private static URI computeSource(Model model) |
| { |
| String source = model.getSource(); |
| URI resourceURI = model.eResource().getURI(); |
| if (source == null || source.trim().isEmpty()) |
| { |
| return CommonPlugin.resolve(resourceURI.trimSegments(0)).appendSegment("justj.manifest"); |
| } |
| else |
| { |
| URI sourceURI = URI.createURI(source); |
| if (sourceURI.isRelative()) |
| { |
| sourceURI = sourceURI.resolve(CommonPlugin.resolve(resourceURI.trimSegments(0))); |
| } |
| return sourceURI; |
| } |
| } |
| |
| static Path computeLocalCache(Model model) |
| { |
| String localCache = model.getLocalCache(); |
| if (localCache == null) |
| { |
| return null; |
| } |
| else |
| { |
| Path path = Paths.get(localCache); |
| if (path.isAbsolute()) |
| { |
| return path; |
| } |
| else |
| { |
| URI resourceURI = model.eResource().getURI(); |
| URI resolvedURI = CommonPlugin.resolve(resourceURI).trimSegments(1); |
| Path result = Paths.get(resolvedURI.toFileString()).resolve(path).normalize(); |
| return result; |
| } |
| } |
| } |
| |
| public Model getModel() |
| { |
| return model; |
| } |
| |
| public URI getSource() |
| { |
| return source; |
| } |
| |
| public Model reconcile(IProgressMonitor monitor) throws IOException, InterruptedException |
| { |
| SubMonitor overallMonitor = SubMonitor.convert(monitor); |
| overallMonitor.beginTask("Reconciling " + source, 10); |
| |
| Map<URI, Path> manifest = loadManifest(overallMonitor.split(9)); |
| |
| Model modelCopy = EcoreUtil.copy(model); |
| |
| modelCopy.getJVMs().clear(); |
| |
| Exception failure = null; |
| SubMonitor manifestMonitor = overallMonitor.split(1); |
| manifestMonitor.setWorkRemaining(manifest.size()); |
| for (Map.Entry<URI, Path> entry : manifest.entrySet()) |
| { |
| URI jreURI = entry.getKey(); |
| Path localCache = entry.getValue(); |
| |
| manifestMonitor.subTask("Processing " + jreURI); |
| |
| try |
| { |
| TarAnalyzer handler = new TarAnalyzer(); |
| CodeGenUtil.untar(localCache, handler); |
| |
| Variant variant = handler.reconcile(modelCopy); |
| variant.setSource(jreURI.toString()); |
| } |
| catch (Exception ex) |
| { |
| Files.deleteIfExists(localCache); |
| ModelPlugin.INSTANCE.log(ex); |
| failure = ex; |
| } |
| |
| manifestMonitor.worked(1); |
| } |
| |
| refactorCommonProperties(modelCopy); |
| |
| if (failure instanceof IOException) |
| { |
| throw (IOException)failure; |
| } |
| else if (failure instanceof RuntimeException) |
| { |
| throw (RuntimeException)failure; |
| } |
| else if (failure instanceof InterruptedException) |
| { |
| throw (InterruptedException)failure; |
| } |
| else if (failure != null) |
| { |
| throw new RuntimeException(failure); |
| } |
| |
| if (Boolean.FALSE) |
| { |
| Resource resource = model.eResource(); |
| URI uri = resource.getURI(); |
| URI targetURI = uri.trimFileExtension().appendFileExtension("reconciled").appendFileExtension(uri.fileExtension()); |
| resource.setURI(targetURI); |
| resource.save(null); |
| } |
| |
| return modelCopy; |
| } |
| |
| protected void refactorCommonProperties(Model model) |
| { |
| EList<JVM> jvms = model.getJVMs(); |
| for (JVM jvm : jvms) |
| { |
| EList<Variant> variants = jvm.getVariants(); |
| Map<String, String> commonProperties = new TreeMap<>(); |
| Set<String> conflictingKeys = new HashSet<String>(); |
| for (Variant variant : variants) |
| { |
| Annotation annotation = ModelUtil.getAnnotation(variant, ModelUtil.MODEL_PROPERTIES_ANNOTATION_URI); |
| if (annotation == null) |
| { |
| commonProperties.clear(); |
| break; |
| } |
| |
| for (Map.Entry<String, String> entry : annotation.getDetails().entrySet()) |
| { |
| String key = entry.getKey(); |
| String value = entry.getValue(); |
| if (commonProperties.containsKey(key)) |
| { |
| String oldValue = commonProperties.put(key, value); |
| if (!Objects.equals(oldValue, value)) |
| { |
| conflictingKeys.add(key); |
| } |
| } |
| else |
| { |
| commonProperties.put(key, value); |
| } |
| } |
| } |
| |
| commonProperties.keySet().removeAll(conflictingKeys); |
| |
| if (!commonProperties.isEmpty()) |
| { |
| for (Variant variant : variants) |
| { |
| Annotation annotation = ModelUtil.getAnnotation(variant, ModelUtil.MODEL_PROPERTIES_ANNOTATION_URI); |
| EMap<String, String> details = annotation.getDetails(); |
| details.keySet().removeAll(commonProperties.keySet()); |
| if (details.isEmpty()) |
| { |
| EcoreUtil.delete(annotation); |
| } |
| } |
| |
| Annotation annotation = ModelFactory.eINSTANCE.createAnnotation(); |
| annotation.getDetails().putAll(commonProperties); |
| annotation.setSource(ModelUtil.MODEL_PROPERTIES_ANNOTATION_URI); |
| jvm.getAnnotations().add(annotation); |
| } |
| } |
| } |
| |
| private static class TarAnalyzer extends CodeGenUtil.UntarHandler |
| { |
| private final Map<Path, Set<PosixFilePermission>> allPosixFilePermissions = new TreeMap<>(); |
| |
| private final Set<Path> regularFiles = new TreeSet<>(); |
| |
| private final Map<Path, Path> symbolicLinks = new TreeMap<>(); |
| |
| private final Properties properties; |
| |
| public TarAnalyzer() |
| { |
| properties = new Properties(); |
| } |
| |
| @Override |
| public void handleRegularFile(InputStream inputStream, Path path, Set<PosixFilePermission> posixFilePermissions) throws IOException |
| { |
| allPosixFilePermissions.put(path, posixFilePermissions); |
| if (path.endsWith("org.eclipse.justj.properties")) |
| { |
| properties.load(inputStream); |
| } |
| |
| regularFiles.add(path); |
| } |
| |
| @Override |
| public void handleDirectory(Path path, Set<PosixFilePermission> posixFilePermissions) |
| { |
| allPosixFilePermissions.put(path, posixFilePermissions); |
| } |
| |
| @Override |
| public void handleSymbolicLink(Path path, Path linkPath) |
| { |
| symbolicLinks.put(path, linkPath); |
| } |
| |
| public Variant reconcile(Model model) |
| { |
| String jreName = properties.getProperty("org.eclipse.justj.name"); |
| String label = properties.getProperty("org.eclipse.justj.label"); |
| String description = properties.getProperty("org.eclipse.justj.description"); |
| |
| String javaVersion = getCleanVersion(properties.getProperty("java.version")); |
| |
| JVM jvm = getJVM(model, jreName, javaVersion); |
| jvm.setLabel(label); |
| jvm.setDescription(description); |
| |
| TreeMap<String, String> details = new TreeMap<>(); |
| for (Map.Entry<Object, Object> entry : properties.entrySet()) |
| { |
| details.put(entry.getKey().toString(), entry.getValue().toString()); |
| } |
| |
| String os = properties.getProperty("osgi.os"); |
| String arch = properties.getProperty("osgi.arch"); |
| Variant variant = getVariant(jvm, os, arch); |
| |
| Annotation annotation = ModelFactory.eINSTANCE.createAnnotation(); |
| annotation.setSource(ModelUtil.MODEL_PROPERTIES_ANNOTATION_URI); |
| annotation.getDetails().putAll(details); |
| variant.getAnnotations().add(annotation); |
| |
| if (jvm.getAboutTextExtra() == null) |
| { |
| String aboutTextExtra = "\nVisit http://www.eclipse.org/justj"; |
| String vendor = properties.getProperty("org.eclipse.justj.url.vendor"); |
| aboutTextExtra += "\n\nProvides Java Runtimes derived from " + vendor + "."; |
| jvm.setAboutTextExtra(aboutTextExtra); |
| } |
| |
| EList<Touchpoint> touchpoints = variant.getTouchpoints(); |
| Touchpoint touchpoint = ModelFactory.eINSTANCE.createTouchpoint(); |
| touchpoint.setPhase(Phase.INSTALL); |
| touchpoints.add(touchpoint); |
| |
| EList<String> instructions = touchpoint.getInstructions(); |
| String vmArg = properties.getProperty("org.eclipse.justj.vm.arg"); |
| instructions.add("org.eclipse.equinox.p2.touchpoint.eclipse.setJvm(jvm:${artifact.location}/jre/" + vmArg + ")"); |
| |
| if (!"win32".equals(os)) |
| { |
| Set<Path> ignore = new HashSet<>(); |
| Set<Path> executableFolders = new TreeSet<>(); |
| Set<Path> executableFiles = new TreeSet<>(); |
| for (Map.Entry<Path, Set<PosixFilePermission>> entry : allPosixFilePermissions.entrySet()) |
| { |
| Path path = entry.getKey(); |
| if (ignore.add(path)) |
| { |
| Set<PosixFilePermission> posixPermissions = entry.getValue(); |
| if (regularFiles.contains(path) && posixPermissions.contains(PosixFilePermission.OWNER_EXECUTE)) |
| { |
| Path parent = path.getParent(); |
| if (parent != null) |
| { |
| boolean allDescendantsOfParentExecutable = true; |
| Set<Path> allDescendants = new HashSet<>(); |
| for (Map.Entry<Path, Set<PosixFilePermission>> otherEntry : allPosixFilePermissions.entrySet()) |
| { |
| Path otherPath = otherEntry.getKey(); |
| if (otherPath.startsWith(parent)) |
| { |
| Set<PosixFilePermission> otherPosixFilePermissions = otherEntry.getValue(); |
| if (otherPosixFilePermissions.contains(PosixFilePermission.OWNER_EXECUTE)) |
| { |
| allDescendants.add(otherPath); |
| } |
| else if (!symbolicLinks.containsKey(otherPath)) |
| { |
| allDescendantsOfParentExecutable = false; |
| break; |
| } |
| } |
| } |
| |
| if (allDescendantsOfParentExecutable) |
| { |
| executableFolders.add(parent); |
| } |
| else |
| { |
| executableFiles.add(path); |
| } |
| |
| ignore.addAll(allDescendants); |
| } |
| } |
| } |
| } |
| |
| if (executableFolders.isEmpty() || !executableFiles.isEmpty()) |
| { |
| for (Path executableFolder : executableFolders) |
| { |
| String chmodTouchpointInstruction = "org.eclipse.equinox.p2.touchpoint.eclipse.chmod(targetDir:${artifact.location},targetFile:jre/" |
| + executableFolder.normalize().toString().replace('\\', '/') + ",permissions:+x,options:-R)"; |
| instructions.add(chmodTouchpointInstruction); |
| } |
| |
| for (Path executableFile : executableFiles) |
| { |
| String chmodTouchpointInstruction = "org.eclipse.equinox.p2.touchpoint.eclipse.chmod(targetDir:${artifact.location},targetFile:jre/" |
| + executableFile.normalize().toString().replace('\\', '/') + ",permissions:+x)"; |
| instructions.add(chmodTouchpointInstruction); |
| } |
| } |
| } |
| |
| return variant; |
| } |
| |
| private JVM getJVM(Model model, String name, String javaVersion) |
| { |
| EList<JVM> jvms = model.getJVMs(); |
| for (JVM jvm : jvms) |
| { |
| if (name.equals(jvm.getName()) && javaVersion.equals(jvm.getVersion())) |
| { |
| return jvm; |
| } |
| } |
| |
| JVM jvm = ModelFactory.eINSTANCE.createJVM(); |
| jvm.setName(name); |
| jvm.setVersion(javaVersion); |
| jvms.add(jvm); |
| |
| sortJVMs(jvms); |
| return jvm; |
| } |
| |
| private Variant getVariant(JVM jvm, String os, String arch) |
| { |
| EList<Variant> variants = jvm.getVariants(); |
| for (Variant variant : variants) |
| { |
| if (os.equals(variant.getOs()) && arch.equals(variant.getArch())) |
| { |
| return variant; |
| } |
| } |
| |
| Variant variant = ModelFactory.eINSTANCE.createVariant(); |
| variant.setOs(os); |
| variant.setArch(arch); |
| |
| String label; |
| switch (os) |
| { |
| case "linux": |
| { |
| label = "Linux"; |
| break; |
| } |
| case "win32": |
| { |
| label = "Windows"; |
| break; |
| } |
| case "macosx": |
| { |
| label = "MacOS"; |
| break; |
| } |
| default: |
| { |
| label = os; |
| break; |
| } |
| } |
| |
| switch (arch) |
| { |
| case "x86_64": |
| { |
| label += " x86 64 bit"; |
| break; |
| } |
| case "aarch64": |
| { |
| label += " aarch 64 bit"; |
| break; |
| } |
| default: |
| { |
| label += " " + arch; |
| break; |
| } |
| } |
| |
| variant.setLabel(label); |
| variants.add(variant); |
| sortVariants(variants); |
| return variant; |
| } |
| } |
| |
| public static void sortVariants(EList<Variant> variants) |
| { |
| ECollections.sort(variants, (v1, v2) -> v1.getOs().compareTo(v2.getOs())); |
| } |
| |
| public static void sortJVMs(EList<JVM> jvms) |
| { |
| ECollections.sort(jvms, (j1, j2) -> j1.getName().compareTo(j2.getName())); |
| } |
| |
| private Map<URI, Path> loadManifest(SubMonitor monitor) throws IOException, InterruptedException |
| { |
| String content = load(source); |
| List<String> jreURIs = Arrays.asList(content.split("\r?\n")); |
| |
| int originalSize = jreURIs.size(); |
| monitor.subTask("Fetching " + originalSize + " JREs"); |
| monitor.setWorkRemaining(originalSize); |
| |
| ExecutorService executor = Executors.newFixedThreadPool(Runtime.getRuntime().availableProcessors() * 4); |
| Map<URI, Future<Path>> jres = new LinkedHashMap<>(); |
| AtomicInteger size = new AtomicInteger(originalSize); |
| jreURIs.forEach(jre -> |
| { |
| URI uri = URI.createURI(jre); |
| URI jreURI = uri.isRelative() ? uri.resolve(source) : uri; |
| jres.put(jreURI, executor.submit(() -> |
| { |
| try |
| { |
| monitor.subTask("Fetching " + originalSize + " JREs; starting " + jreURI); |
| return CodeGenUtil.getCache(localCache, uriConverter, jreURI); |
| } |
| finally |
| { |
| synchronized (monitor) |
| { |
| monitor.subTask("Fetcthing " + originalSize + " JREs; " + size.decrementAndGet() + " remaining; finished " + jreURI); |
| monitor.worked(1); |
| } |
| } |
| })); |
| }); |
| |
| executor.shutdown(); |
| |
| // Wait for at most 20 minutes. |
| for (int elapsed = 0; elapsed < 60 * 20; elapsed += 2) |
| { |
| try |
| { |
| executor.awaitTermination(2, TimeUnit.SECONDS); |
| monitor.checkCanceled(); |
| break; |
| } |
| catch (InterruptedException ex) |
| { |
| //$FALL-THROUGH$ |
| } |
| } |
| |
| Set<Path> cachePaths = new TreeSet<>(); |
| Map<URI, Path> result = jres.entrySet().stream().collect(Collectors.toMap(entry -> entry.getKey(), entry -> |
| { |
| try |
| { |
| Path cache = entry.getValue().get(); |
| cachePaths.add(cache); |
| return cache; |
| } |
| catch (InterruptedException | ExecutionException e) |
| { |
| throw new RuntimeException(e); |
| } |
| })); |
| |
| StringBuilder manifestContent = new StringBuilder(); |
| cachePaths.stream().forEach(cachePath -> |
| { |
| manifestContent.append(cachePath.getFileName()).append('\n'); |
| }); |
| |
| save(manifestContent.toString(), URI.createFileURI(this.localCache.toString()).appendSegment("justj.manifest")); |
| |
| return result; |
| } |
| |
| protected void save(String text, URI target) throws IOException |
| { |
| try (OutputStream out = uriConverter.createOutputStream(target); PrintStream print = new PrintStream(out, true, "UTF-8")) |
| { |
| print.print(text); |
| } |
| } |
| |
| protected void save(URI source, URI target) throws IOException |
| { |
| try (InputStream in = uriConverter.createInputStream(source); OutputStream out = uriConverter.createOutputStream(target)) |
| { |
| byte[] buffer = new byte [10000]; |
| int length = in.read(buffer); |
| out.write(buffer, 0, length); |
| } |
| } |
| |
| protected String load(URI source) throws IOException |
| { |
| try (InputStream in = uriConverter.createInputStream(source)) |
| { |
| byte[] buffer = new byte [100000]; |
| int length = in.read(buffer); |
| return new String(buffer, 0, length, "UTF-8"); |
| } |
| } |
| |
| protected void save(byte[] source, URI target) throws IOException |
| { |
| try (OutputStream out = uriConverter.createOutputStream(target); PrintStream print = new PrintStream(out, true, "UTF-8")) |
| { |
| out.write(source); |
| } |
| } |
| |
| public static String getCopyright(Object argument, String prefix, String separator) |
| { |
| String copyrightText = null; |
| String copyrightYear = null; |
| String copyrightHolder = null; |
| for (Object object = argument; object instanceof Copyrightable;) |
| { |
| Copyrightable copyrightable = (Copyrightable)object; |
| if (copyrightText == null) |
| { |
| copyrightText = copyrightable.getCopyrightText(); |
| } |
| |
| if (copyrightYear == null) |
| { |
| copyrightYear = copyrightable.getCopyrightYear(); |
| } |
| |
| if (copyrightHolder == null) |
| { |
| copyrightHolder = copyrightable.getCopyrightHolder(); |
| } |
| |
| object = copyrightable.eContainer(); |
| } |
| |
| if (copyrightText != null) |
| { |
| if (copyrightHolder != null) |
| { |
| copyrightText = copyrightText.replace("${copyrightHolder}", copyrightHolder); |
| } |
| |
| if (copyrightYear != null) |
| { |
| copyrightText = copyrightText.replace("${copyrightYear}", copyrightYear); |
| } |
| |
| return composeLines(copyrightText, prefix, separator); |
| } |
| |
| return ""; |
| } |
| |
| public static Map<String, Set<String>> getTouchpoints(Object argument) |
| { |
| Map<String, Set<String>> result = new LinkedHashMap<String, Set<String>>(); |
| for (Object object = argument; object instanceof Touchable;) |
| { |
| Touchable touchable = (Touchable)object; |
| for (Touchpoint touchpoint : touchable.getTouchpoints()) |
| { |
| EList<String> instructions = touchpoint.getInstructions(); |
| if (!instructions.isEmpty()) |
| { |
| Phase phase = touchpoint.getPhase(); |
| Set<String> composedInstructions = result.get(phase.getLiteral()); |
| if (composedInstructions == null) |
| { |
| composedInstructions = new LinkedHashSet<String>(); |
| result.put(phase.getLiteral(), composedInstructions); |
| } |
| composedInstructions.addAll(instructions); |
| } |
| } |
| |
| object = touchable.eContainer(); |
| } |
| |
| return result; |
| } |
| |
| public static String composeLines(String body, String prefix, String separator) |
| { |
| if (body != null) |
| { |
| String[] lines = body.split("\r?\n", -1); |
| StringBuilder result = new StringBuilder(); |
| for (int i = 0; i < lines.length; i++) |
| { |
| String line = lines[i]; |
| result.append(prefix); |
| result.append(line); |
| if (i != lines.length - 1) |
| { |
| result.append(separator); |
| } |
| } |
| |
| return result.toString(); |
| } |
| |
| return ""; |
| } |
| |
| public static String getVersionRange(String version) |
| { |
| int[] versionValue = getVersion(version); |
| |
| return "[" + version + "," + versionValue[0] + '.' + versionValue[1] + '.' + (versionValue[2] + 1) + ")"; |
| } |
| |
| public static Map<String, Set<String>> getEECapabilities(String version) |
| { |
| int[] versionValue = getVersion(version); |
| Map<String, Set<String>> result = new LinkedHashMap<>(); |
| |
| Set<String> osgiMinimum = new LinkedHashSet<>(); |
| result.put("OSGi/Minimum", osgiMinimum); |
| for (int i = 0; i <= 2; ++i) |
| { |
| osgiMinimum.add("1." + i); |
| } |
| |
| Set<String> jre = new LinkedHashSet<>(); |
| result.put("JRE", jre); |
| for (int i = 0; i <= 1; ++i) |
| { |
| jre.add("1." + i); |
| } |
| |
| Set<String> javaSE = new LinkedHashSet<>(); |
| result.put("JavaSE", javaSE); |
| for (int i = 0; i <= 8; ++i) |
| { |
| javaSE.add("1." + i); |
| } |
| for (int i = 9; i <= versionValue[0]; ++i) |
| { |
| javaSE.add("" + i + ".0"); |
| } |
| |
| for (int compact = 1; compact <= 3; ++compact) |
| { |
| Set<String> javaCompact = new LinkedHashSet<>(); |
| result.put("JavaSE/compact" + compact, javaCompact); |
| javaCompact.add("1.8"); |
| for (int i = 9; i <= versionValue[0]; ++i) |
| { |
| javaCompact.add("" + i + ".0"); |
| } |
| } |
| |
| return result; |
| } |
| |
| private static Pattern CLEAN_VERSION_PATTERN = Pattern.compile("([0-9]+)(?:\\.([0-9]+)(?:\\.([0-9]+))?)?(.*)"); |
| |
| private static String getCleanVersion(String version) |
| { |
| Matcher matcher = CLEAN_VERSION_PATTERN.matcher(version); |
| if (!matcher.matches()) |
| { |
| throw new IllegalArgumentException("Invalid version " + version); |
| } |
| |
| String major = matcher.group(1); |
| String minor = matcher.group(2); |
| String micro = matcher.group(3); |
| |
| int majorValue = Integer.parseInt(major); |
| int minorValue = minor == null ? 0 : Integer.parseInt(minor); |
| int microValue = micro == null ? 0 : Integer.parseInt(micro); |
| return majorValue + "." + minorValue + "." + microValue; |
| } |
| |
| private static Pattern VERSION_PATTERN = Pattern.compile("([0-9]+)\\.([0-9]+)\\.([0-9]+)"); |
| |
| private static int[] getVersion(String version) |
| { |
| Matcher matcher = VERSION_PATTERN.matcher(version); |
| if (!matcher.matches()) |
| { |
| throw new IllegalArgumentException("Invalid version " + version); |
| } |
| |
| return new int []{ Integer.parseInt(matcher.group(1)), Integer.parseInt(matcher.group(2)), Integer.parseInt(matcher.group(3)) }; |
| } |
| |
| public static class Application implements IApplication |
| { |
| @Override |
| public Object start(IApplicationContext context) throws Exception |
| { |
| main((String[])context.getArguments().get("application.args")); |
| return 0; |
| } |
| |
| @Override |
| public void stop() |
| { |
| } |
| } |
| |
| static class PrintingProgressMonitor extends NullProgressMonitor |
| { |
| @Override |
| public void beginTask(String name, int totalWork) |
| { |
| System.out.println("beginTask: " + name); |
| } |
| |
| @Override |
| public void setTaskName(String name) |
| { |
| System.out.println("setTaskName: " + name); |
| } |
| |
| @Override |
| public void subTask(String name) |
| { |
| System.out.println("subTask: " + name); |
| } |
| } |
| } |