[569111] Provide Installer also for aarch64

https://bugs.eclipse.org/bugs/show_bug.cgi?id=569111

We should be careful not to offer JustJ JREs if there isn't actually a
specific JRE fragment available for the current platform.

So we should record this information in the generator and should
consider it when building the list of external JREs.
diff --git a/features/org.eclipse.oomph.setup-feature/feature.xml b/features/org.eclipse.oomph.setup-feature/feature.xml
index f0fe24f..4e775c0 100644
--- a/features/org.eclipse.oomph.setup-feature/feature.xml
+++ b/features/org.eclipse.oomph.setup-feature/feature.xml
@@ -12,7 +12,7 @@
 <feature
       id="org.eclipse.oomph.setup"
       label="%featureName"
-      version="1.18.0.qualifier"
+      version="1.19.0.qualifier"
       provider-name="%providerName"
       license-feature="org.eclipse.oomph.license"
       license-feature-version="0.0.0">
diff --git a/features/org.eclipse.oomph.setup-feature/pom.xml b/features/org.eclipse.oomph.setup-feature/pom.xml
index 42d25cc..9e11e36 100644
--- a/features/org.eclipse.oomph.setup-feature/pom.xml
+++ b/features/org.eclipse.oomph.setup-feature/pom.xml
@@ -20,6 +20,6 @@
   </parent>
   <groupId>org.eclipse.oomph.features</groupId>
   <artifactId>org.eclipse.oomph.setup</artifactId>
-  <version>1.18.0-SNAPSHOT</version>
+  <version>1.19.0-SNAPSHOT</version>
   <packaging>eclipse-feature</packaging>
 </project>
diff --git a/plugins/org.eclipse.oomph.setup.installer/META-INF/MANIFEST.MF b/plugins/org.eclipse.oomph.setup.installer/META-INF/MANIFEST.MF
index bb0a565..eb8ecc9 100644
--- a/plugins/org.eclipse.oomph.setup.installer/META-INF/MANIFEST.MF
+++ b/plugins/org.eclipse.oomph.setup.installer/META-INF/MANIFEST.MF
@@ -12,7 +12,7 @@
  org.eclipse.emf.edit.ui;bundle-version="[2.10.0,3.0.0)",
  org.eclipse.oomph.setup;bundle-version="[1.18.0,2.0.0)",
  org.eclipse.oomph.setup.edit;bundle-version="[1.15.0,2.0.0)",
- org.eclipse.oomph.setup.ui;bundle-version="[1.18.0,2.0.0)",
+ org.eclipse.oomph.setup.ui;bundle-version="[1.19.0,2.0.0)",
  org.eclipse.equinox.p2.operations;bundle-version="[2.0.0,3.0.0)",
  org.eclipse.equinox.p2.metadata;bundle-version="[2.0.0,3.0.0)",
  org.eclipse.equinox.p2.core;bundle-version="[2.0.0,3.0.0)",
diff --git a/plugins/org.eclipse.oomph.setup.installer/src/org/eclipse/oomph/setup/internal/installer/ProductCatalogGenerator.java b/plugins/org.eclipse.oomph.setup.installer/src/org/eclipse/oomph/setup/internal/installer/ProductCatalogGenerator.java
index 0800cb5..952d826 100644
--- a/plugins/org.eclipse.oomph.setup.installer/src/org/eclipse/oomph/setup/internal/installer/ProductCatalogGenerator.java
+++ b/plugins/org.eclipse.oomph.setup.installer/src/org/eclipse/oomph/setup/internal/installer/ProductCatalogGenerator.java
@@ -150,6 +150,8 @@
 
   private static final String EPP_INSTALL_ROOTS_FILTER = "(org.eclipse.epp.install.roots=true)";
 
+  private static final Pattern ARCH_OS_FILTER_PATTERN = Pattern.compile("\\(\\&\\(osgi\\.arch=([^)]+)\\)\\(osgi\\.os=([^)]+)\\)\\)");
+
   private static final boolean IS_RANGE_NARROW = Boolean.FALSE;
 
   private static final String JUSTJ_JRES = "http://download.eclipse.org/justj/jres";
@@ -2097,7 +2099,7 @@
     }
 
     // Boil them down by versions, excluding minor versions.
-    // Because they are sorted this will grab the version with the larget micro version.
+    // Because they are sorted this will grab the version with the largest micro version.
     Map<Version, IInstallableUnit> jreVersions = new TreeMap<Version, IInstallableUnit>();
     for (IInstallableUnit iu : ius)
     {
@@ -2120,6 +2122,35 @@
       System.out.println("jre=" + iu + " -> " + childRepository.getLocation());
 
       Requirement jreRequirement = P2Factory.eINSTANCE.createRequirement(iu.getId());
+      StringBuilder compositeFilter = new StringBuilder();
+      for (IRequirement requirement : iu.getRequirements())
+      {
+        if (requirement instanceof IRequiredCapability)
+        {
+          IRequiredCapability capability = (IRequiredCapability)requirement;
+          IMatchExpression<IInstallableUnit> filter = capability.getFilter();
+          if (filter != null)
+          {
+            String value = RequirementImpl.formatMatchExpression(filter);
+            Matcher matcher = ARCH_OS_FILTER_PATTERN.matcher(value);
+            if (matcher.matches())
+            {
+              if (compositeFilter.length() == 0)
+              {
+                compositeFilter.append("(|");
+              }
+
+              compositeFilter.append(value);
+            }
+          }
+        }
+      }
+
+      if (compositeFilter.length() != 0)
+      {
+        jreRequirement.setFilter(compositeFilter.append(')').toString());
+      }
+
       Repository jreChildRepository = P2Factory.eINSTANCE.createRepository(childRepository.getLocation().toString());
 
       P2Task p2Task = SetupP2Factory.eINSTANCE.createP2Task();
diff --git a/plugins/org.eclipse.oomph.setup.ui/META-INF/MANIFEST.MF b/plugins/org.eclipse.oomph.setup.ui/META-INF/MANIFEST.MF
index 03fcd79..93b067d 100644
--- a/plugins/org.eclipse.oomph.setup.ui/META-INF/MANIFEST.MF
+++ b/plugins/org.eclipse.oomph.setup.ui/META-INF/MANIFEST.MF
@@ -2,17 +2,17 @@
 Bundle-ManifestVersion: 2
 Bundle-Name: %pluginName
 Bundle-SymbolicName: org.eclipse.oomph.setup.ui;singleton:=true
-Bundle-Version: 1.18.0.qualifier
+Bundle-Version: 1.19.0.qualifier
 Bundle-ClassPath: .
 Bundle-Activator: org.eclipse.oomph.setup.ui.SetupUIPlugin$Implementation
 Bundle-Vendor: %providerName
 Bundle-Localization: plugin
 Bundle-RequiredExecutionEnvironment: J2SE-1.5
-Export-Package: org.eclipse.oomph.setup.ui;version="1.18.0";x-internal:=true,
- org.eclipse.oomph.setup.ui.actions;version="1.18.0";x-internal:=true,
- org.eclipse.oomph.setup.ui.recorder;version="1.18.0";x-internal:=true,
- org.eclipse.oomph.setup.ui.synchronizer;version="1.18.0";x-internal:=true,
- org.eclipse.oomph.setup.ui.wizards;version="1.18.0";x-internal:=true
+Export-Package: org.eclipse.oomph.setup.ui;version="1.19.0";x-internal:=true,
+ org.eclipse.oomph.setup.ui.actions;version="1.19.0";x-internal:=true,
+ org.eclipse.oomph.setup.ui.recorder;version="1.19.0";x-internal:=true,
+ org.eclipse.oomph.setup.ui.synchronizer;version="1.19.0";x-internal:=true,
+ org.eclipse.oomph.setup.ui.wizards;version="1.19.0";x-internal:=true
 Require-Bundle: org.eclipse.core.runtime;bundle-version="[3.5.0,4.0.0)",
  org.eclipse.core.expressions;bundle-version="[3.4.0,4.0.0)",
  org.eclipse.core.filesystem;bundle-version="[1.0.0,2.0.0)",
diff --git a/plugins/org.eclipse.oomph.setup.ui/pom.xml b/plugins/org.eclipse.oomph.setup.ui/pom.xml
index 92c0b95..295136a 100644
--- a/plugins/org.eclipse.oomph.setup.ui/pom.xml
+++ b/plugins/org.eclipse.oomph.setup.ui/pom.xml
@@ -20,7 +20,7 @@
   </parent>
   <groupId>org.eclipse.oomph</groupId>
   <artifactId>org.eclipse.oomph.setup.ui</artifactId>
-  <version>1.18.0-SNAPSHOT</version>
+  <version>1.19.0-SNAPSHOT</version>
   <packaging>eclipse-plugin</packaging>
 
   <build>
diff --git a/plugins/org.eclipse.oomph.setup.ui/src/org/eclipse/oomph/setup/ui/wizards/SetupWizard.java b/plugins/org.eclipse.oomph.setup.ui/src/org/eclipse/oomph/setup/ui/wizards/SetupWizard.java
index 5dc3ee2..96bf797 100644
--- a/plugins/org.eclipse.oomph.setup.ui/src/org/eclipse/oomph/setup/ui/wizards/SetupWizard.java
+++ b/plugins/org.eclipse.oomph.setup.ui/src/org/eclipse/oomph/setup/ui/wizards/SetupWizard.java
@@ -17,6 +17,7 @@
 import org.eclipse.oomph.jreinfo.JRE;
 import org.eclipse.oomph.jreinfo.JREManager;
 import org.eclipse.oomph.p2.Repository;
+import org.eclipse.oomph.p2.Requirement;
 import org.eclipse.oomph.p2.internal.core.CacheUsageConfirmer;
 import org.eclipse.oomph.p2.internal.ui.CacheUsageConfirmerUI;
 import org.eclipse.oomph.setup.AnnotationConstants;
@@ -50,6 +51,7 @@
 import org.eclipse.oomph.util.CollectionUtil;
 import org.eclipse.oomph.util.OS;
 import org.eclipse.oomph.util.PropertiesUtil;
+import org.eclipse.oomph.util.StringUtil;
 
 import org.eclipse.emf.common.ui.ImageURIRegistry;
 import org.eclipse.emf.common.util.EList;
@@ -69,6 +71,8 @@
 import org.eclipse.core.runtime.IProgressMonitor;
 import org.eclipse.core.runtime.IStatus;
 import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.equinox.p2.metadata.IInstallableUnit;
+import org.eclipse.equinox.p2.metadata.expression.IMatchExpression;
 import org.eclipse.jface.dialogs.IDialogSettings;
 import org.eclipse.jface.dialogs.IPageChangeProvider;
 import org.eclipse.jface.dialogs.IPageChangedListener;
@@ -1374,6 +1378,7 @@
           {
             Macro jresMacro = (Macro)eObject;
             EList<SetupTask> setupTasks = jresMacro.getSetupTasks();
+            LOOP: //
             for (SetupTask setupTask : setupTasks)
             {
               if (setupTask instanceof P2Task)
@@ -1384,6 +1389,17 @@
                 if (matcher.find())
                 {
                   EList<Repository> repositories = jreP2Task.getRepositories();
+                  for (Requirement requirement : jreP2Task.getRequirements())
+                  {
+                    // The requirements capture filter information about arch/os combinations for which JREs are available.
+                    // We should not offer a JRE feature for which there isn't really an actual JRE fragment for the current arch/os available.
+                    String filter = requirement.getFilter();
+                    if (!matchesFilterContext(filter))
+                    {
+                      continue LOOP;
+                    }
+                  }
+
                   Repository repository = repositories.get(0);
                   JRE.Descriptor descriptor = new JRE.Descriptor(label + " - " + repository.getURL(), //$NON-NLS-1$
                       Integer.parseInt(matcher.group(1)), //
@@ -1403,6 +1419,35 @@
       JREManager.INSTANCE.setJREs(jreDescriptors);
     }
 
+    @SuppressWarnings("restriction")
+    private boolean matchesFilterContext(String filter)
+    {
+      if (StringUtil.isEmpty(filter))
+      {
+        return true;
+      }
+
+      OS os = wizard.getOS();
+      Map<String, String> filterContext = new LinkedHashMap<String, String>();
+      filterContext.put("osgi.ws", os.getOsgiWS()); //$NON-NLS-1$
+      filterContext.put("osgi.os", os.getOsgiOS()); //$NON-NLS-1$
+      filterContext.put("osgi.arch", os.getOsgiArch()); //$NON-NLS-1$
+
+      org.eclipse.equinox.internal.p2.metadata.InstallableUnit filterContextIU = (org.eclipse.equinox.internal.p2.metadata.InstallableUnit)org.eclipse.equinox.internal.p2.metadata.InstallableUnit
+          .contextIU(filterContext);
+
+      try
+      {
+        IMatchExpression<IInstallableUnit> matchExpression = org.eclipse.equinox.internal.p2.metadata.InstallableUnit.parseFilter(filter);
+        return matchExpression.isMatch(filterContextIU);
+      }
+      catch (RuntimeException ex)
+      {
+        // If the filter can't be parsed, assume it matches nothing.
+        return false;
+      }
+    }
+
     protected boolean shouldReload(EClass eClass)
     {
       return true;