[538158] Node "Plug-in Dependencies" lost in a random number of plug-in
projects

Provide support for a deferred early start

https://bugs.eclipse.org/bugs/show_bug.cgi?id=538158
diff --git a/plugins/org.eclipse.oomph.launches/plugin.xml b/plugins/org.eclipse.oomph.launches/plugin.xml
index e0f4010..344a662 100644
--- a/plugins/org.eclipse.oomph.launches/plugin.xml
+++ b/plugins/org.eclipse.oomph.launches/plugin.xml
@@ -46,12 +46,10 @@
       </decorator>
       -->
    </extension>
-   
+
    <extension
-         point="org.eclipse.ui.startup">
-      <startup
-            class="org.eclipse.oomph.launches.EarlyStartup">
-      </startup>
+         point="org.eclipse.oomph.ui.deferredEarlyStart">
+      <startup class="org.eclipse.oomph.launches.EarlyStartup"/>
    </extension>
 
 </plugin>
diff --git a/plugins/org.eclipse.oomph.projectconfig.editor/plugin.xml b/plugins/org.eclipse.oomph.projectconfig.editor/plugin.xml
index e6a4123..32081d0 100644
--- a/plugins/org.eclipse.oomph.projectconfig.editor/plugin.xml
+++ b/plugins/org.eclipse.oomph.projectconfig.editor/plugin.xml
@@ -101,10 +101,8 @@
    </extension>
 
    <extension
-         point="org.eclipse.ui.startup">
-      <startup
-            class="org.eclipse.oomph.projectconfig.presentation.sync.ProjectConfigSynchronizer">
-      </startup>
+         point="org.eclipse.oomph.ui.deferredEarlyStart">
+      <startup class="org.eclipse.oomph.projectconfig.presentation.sync.ProjectConfigSynchronizer"/>
    </extension>
 
 </plugin>
diff --git a/plugins/org.eclipse.oomph.setup.ui/plugin.xml b/plugins/org.eclipse.oomph.setup.ui/plugin.xml
index d0bfe5d..1136ae0 100644
--- a/plugins/org.eclipse.oomph.setup.ui/plugin.xml
+++ b/plugins/org.eclipse.oomph.setup.ui/plugin.xml
@@ -17,10 +17,8 @@
    <extension-point id="preferencePolicies" name="Preference Policies" schema="schema/preferencePolicies.exsd"/>
 
    <extension
-         point="org.eclipse.ui.startup">
-      <startup
-            class="org.eclipse.oomph.setup.ui.EarlyStartup">
-      </startup>
+         point="org.eclipse.oomph.ui.deferredEarlyStart">
+      <startup class="org.eclipse.oomph.setup.ui.EarlyStartup"/>
    </extension>
 
    <extension
diff --git a/plugins/org.eclipse.oomph.targlets.ui/plugin.xml b/plugins/org.eclipse.oomph.targlets.ui/plugin.xml
index 96aee4e..0a39f0a 100644
--- a/plugins/org.eclipse.oomph.targlets.ui/plugin.xml
+++ b/plugins/org.eclipse.oomph.targlets.ui/plugin.xml
@@ -14,10 +14,8 @@
 <plugin>
 
    <extension
-         point="org.eclipse.ui.startup">
-      <startup
-            class="org.eclipse.oomph.targlets.internal.ui.EarlyStartup">
-      </startup>
+         point="org.eclipse.oomph.ui.deferredEarlyStart">
+      <startup class="org.eclipse.oomph.targlets.internal.ui.EarlyStartup"/>
    </extension>
 
    <extension
diff --git a/plugins/org.eclipse.oomph.ui/build.properties b/plugins/org.eclipse.oomph.ui/build.properties
index 1e9a1d4..654ec12 100644
--- a/plugins/org.eclipse.oomph.ui/build.properties
+++ b/plugins/org.eclipse.oomph.ui/build.properties
@@ -17,7 +17,8 @@
                plugin.properties,\
                plugin.xml,\
                icons/,\
-               about.mappings
+               about.mappings,\
+               schema/
 src.includes = about.html,\
                pom.xml,\
                IDE.launch
diff --git a/plugins/org.eclipse.oomph.ui/plugin.xml b/plugins/org.eclipse.oomph.ui/plugin.xml
index 631c35a..0f48bee 100644
--- a/plugins/org.eclipse.oomph.ui/plugin.xml
+++ b/plugins/org.eclipse.oomph.ui/plugin.xml
@@ -13,6 +13,8 @@
 
 <plugin>
 
+   <extension-point id="deferredEarlyStart" name="Deferred Early Start" schema="schema/deferredEarlyStart.exsd"/>
+
    <extension
          point="org.eclipse.ui.preferencePages">
       <page
@@ -112,5 +114,11 @@
             type="java.lang.Object">
       </propertyTester>
    </extension>
+   <extension
+         point="org.eclipse.ui.startup">
+      <startup
+            class="org.eclipse.oomph.internal.ui.EarlyStart">
+      </startup>
+   </extension>
 
 </plugin>
diff --git a/plugins/org.eclipse.oomph.ui/schema/deferredEarlyStart.exsd b/plugins/org.eclipse.oomph.ui/schema/deferredEarlyStart.exsd
new file mode 100644
index 0000000..a8518c2
--- /dev/null
+++ b/plugins/org.eclipse.oomph.ui/schema/deferredEarlyStart.exsd
@@ -0,0 +1,161 @@
+<?xml version='1.0' encoding='UTF-8'?>
+<!-- Schema file written by PDE -->
+<schema targetNamespace="org.eclipse.oomph.ui" xmlns="http://www.w3.org/2001/XMLSchema">
+<annotation>
+      <appInfo>
+         <meta.schema plugin="org.eclipse.oomph.ui" id="deferredEarlyStart" name="Deferred Early Start"/>
+      </appInfo>
+      <documentation>
+         This extension point allows clients to contribute early start registrations that are deferred, by default, to run in a low priority background job.
+&lt;p&gt;
+The following system properties can be used to control the behavior, with defaults shown in bold:
+&lt;ul&gt;
+&lt;li&gt;
+org.eclipse.oomph.ui.deferredEarlyStart
+&lt;ul&gt;
+&lt;li&gt;
+false
+&lt;/li&gt;
+&lt;li&gt;
+&lt;b&gt;true&lt;/b&gt;
+&lt;/li&gt;
+&lt;/ul&gt;
+&lt;/li&gt;
+&lt;li&gt;
+org.eclipse.oomph.ui.deferredEarlyStart.priority
+&lt;ul&gt;
+&lt;li&gt;
+INTERACTIVE
+&lt;/li&gt;
+&lt;li&gt;
+SHORT
+&lt;/li&gt;
+&lt;li&gt;
+LONG
+&lt;/li&gt;
+&lt;li&gt;
+BUILD
+&lt;/li&gt;
+&lt;li&gt;
+&lt;b&gt;DECORATE&lt;/b&gt;
+&lt;/li&gt;
+&lt;/ul&gt;
+&lt;/li&gt;
+&lt;li&gt;
+org.eclipse.oomph.ui.deferredEarlyStart.schedule
+&lt;ul&gt;
+&lt;li&gt;
+&lt;it&gt;A non-negative long value.&lt;/it&gt;
+&lt;/li&gt;
+&lt;li&gt;
+&lt;b&gt;5000&lt;/b&gt;
+&lt;/li&gt;
+&lt;/ul&gt;
+&lt;/li&gt;
+&lt;/ul&gt;
+
+
+
+      </documentation>
+   </annotation>
+
+   <element name="extension">
+      <annotation>
+         <appInfo>
+            <meta.element />
+         </appInfo>
+      </annotation>
+      <complexType>
+         <sequence>
+            <element ref="startup" minOccurs="1" maxOccurs="unbounded"/>
+         </sequence>
+         <attribute name="point" type="string" use="required">
+            <annotation>
+               <documentation>
+                  
+               </documentation>
+            </annotation>
+         </attribute>
+         <attribute name="id" type="string">
+            <annotation>
+               <documentation>
+                  
+               </documentation>
+            </annotation>
+         </attribute>
+         <attribute name="name" type="string">
+            <annotation>
+               <documentation>
+                  
+               </documentation>
+               <appInfo>
+                  <meta.attribute translatable="true"/>
+               </appInfo>
+            </annotation>
+         </attribute>
+      </complexType>
+   </element>
+
+   <element name="startup">
+      <complexType>
+         <attribute name="class" type="string" use="required">
+            <annotation>
+               <documentation>
+                  The class implementing IStartup.
+               </documentation>
+               <appInfo>
+                  <meta.attribute kind="java" basedOn=":org.eclipse.ui.IStartup"/>
+               </appInfo>
+            </annotation>
+         </attribute>
+      </complexType>
+   </element>
+
+   <annotation>
+      <appInfo>
+         <meta.section type="since"/>
+      </appInfo>
+      <documentation>
+         1.10
+      </documentation>
+   </annotation>
+
+   <annotation>
+      <appInfo>
+         <meta.section type="examples"/>
+      </appInfo>
+      <documentation>
+         The following example of a &lt;code&gt;deferredEarlyStart&lt;/code&gt; extension contributes one deferred early start class.
+
+&lt;pre&gt;
+   &lt;extension point=&quot;org.eclipse.oomph.ui.deferredEarlyStart&quot;&gt;
+      &lt;startup class=&quot;com.foo.bar.example.ExampleEarlyStart&quot;/&gt;
+   &lt;/extension&gt;
+&lt;/pre&gt;
+      </documentation>
+   </annotation>
+
+   <annotation>
+      <appInfo>
+         <meta.section type="apiinfo"/>
+      </appInfo>
+      <documentation>
+         A contributions must provide a class implementing org.eclipse.ui.IStartup.
+      </documentation>
+   </annotation>
+
+
+   <annotation>
+      <appInfo>
+         <meta.section type="copyright"/>
+      </appInfo>
+      <documentation>
+         Copyright (c) 2018 Eclipse contributors and others.&lt;br&gt;
+All rights reserved. This program and the accompanying materials
+are made available under the terms of the Eclipse Public License v2.0
+which accompanies this distribution, and is available at
+http://www.eclipse.org/legal/epl-v20.html
+      </documentation>
+   </annotation>
+
+</schema>
diff --git a/plugins/org.eclipse.oomph.ui/src/org/eclipse/oomph/internal/ui/EarlyStart.java b/plugins/org.eclipse.oomph.ui/src/org/eclipse/oomph/internal/ui/EarlyStart.java
new file mode 100644
index 0000000..9cbb126
--- /dev/null
+++ b/plugins/org.eclipse.oomph.ui/src/org/eclipse/oomph/internal/ui/EarlyStart.java
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2018 Eclipse contributors and others.
+ * All rights reserved. This program and the accompanying materials
+ * are made available under the terms of the Eclipse Public License v2.0
+ * which accompanies this distribution, and is available at
+ * http://www.eclipse.org/legal/epl-v20.html
+ */
+package org.eclipse.oomph.internal.ui;
+
+import org.eclipse.oomph.util.PropertiesUtil;
+
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtensionRegistry;
+import org.eclipse.core.runtime.IProgressMonitor;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.NullProgressMonitor;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.Status;
+import org.eclipse.core.runtime.jobs.Job;
+import org.eclipse.ui.IStartup;
+
+import java.util.LinkedHashMap;
+import java.util.Map;
+
+/**
+ * @author Ed Merks
+ */
+public class EarlyStart implements IStartup
+{
+  public static final String EXTENSION_POINT = "org.eclipse.oomph.ui.deferredEarlyStart";
+
+  public static final boolean DEFERR = "true".equals(PropertiesUtil.getProperty(EXTENSION_POINT, "true"));
+
+  private static final String PRIORITY_PROPERTY = EXTENSION_POINT + ".priority";
+
+  private static final String SCHEDULE_PROPERTY = EXTENSION_POINT + ".schedule";
+
+  private static final int PRIORITY;
+
+  private static final long SCHEDULE;
+
+  static
+  {
+    Map<String, Integer> priorities = new LinkedHashMap<String, Integer>();
+    priorities.put("INTERACTIVE", Job.INTERACTIVE);
+    priorities.put("SHORT", Job.SHORT);
+    priorities.put("LONG", Job.LONG);
+    priorities.put("BUILD", Job.BUILD);
+    priorities.put("DECORATE", Job.DECORATE);
+    String priorityProperty = PropertiesUtil.getProperty(PRIORITY_PROPERTY, "DECORATE");
+    Integer priority = priorities.get(priorityProperty);
+    if (priority == null)
+    {
+      UIPlugin.INSTANCE.log("The value '" + priorityProperty + "' of the property " + PRIORITY_PROPERTY + " must be one of " + priorities.keySet());
+      PRIORITY = Job.DECORATE;
+    }
+    else
+    {
+      PRIORITY = priority;
+    }
+
+    String scheduleProperty = PropertiesUtil.getProperty(SCHEDULE_PROPERTY, "5000");
+    long schedule;
+    try
+    {
+      schedule = Long.parseLong(scheduleProperty);
+      if (schedule < 0L)
+      {
+        UIPlugin.INSTANCE.log("The value '" + scheduleProperty + "' of the property " + SCHEDULE_PROPERTY + " must be a non-negative long value");
+        schedule = 5000;
+      }
+    }
+    catch (RuntimeException ex)
+    {
+      UIPlugin.INSTANCE.log("The value '" + scheduleProperty + "' of the property " + SCHEDULE_PROPERTY + " must be a non-negative long value");
+      schedule = 5000L;
+    }
+
+    SCHEDULE = schedule;
+  }
+
+  public void earlyStartup()
+  {
+    if (DEFERR)
+    {
+      Job job = new Job("Deferred Early Start")
+      {
+        @Override
+        protected IStatus run(IProgressMonitor monitor)
+        {
+          return EarlyStart.this.run(monitor);
+        }
+      };
+
+      job.setPriority(PRIORITY);
+      job.schedule(SCHEDULE);
+    }
+    else
+    {
+      run(new NullProgressMonitor());
+    }
+  }
+
+  protected IStatus run(IProgressMonitor monitor)
+  {
+    IExtensionRegistry extensionRegistry = Platform.getExtensionRegistry();
+    for (IConfigurationElement configurationElement : extensionRegistry.getConfigurationElementsFor(EXTENSION_POINT))
+    {
+      try
+      {
+        IStartup startup = (IStartup)configurationElement.createExecutableExtension("class");
+        startup.earlyStartup();
+      }
+      catch (Throwable throwable)
+      {
+        UIPlugin.INSTANCE.log(throwable);
+      }
+    }
+
+    return Status.OK_STATUS;
+  }
+
+}
diff --git a/plugins/org.eclipse.oomph.workingsets.editor/plugin.xml b/plugins/org.eclipse.oomph.workingsets.editor/plugin.xml
index e3c26fd..7f31122 100644
--- a/plugins/org.eclipse.oomph.workingsets.editor/plugin.xml
+++ b/plugins/org.eclipse.oomph.workingsets.editor/plugin.xml
@@ -14,10 +14,8 @@
 <plugin>
 
    <extension
-         point="org.eclipse.ui.startup">
-      <startup
-            class="org.eclipse.oomph.workingsets.presentation.EarlyStartup">
-      </startup>
+         point="org.eclipse.oomph.ui.deferredEarlyStart">
+      <startup class="org.eclipse.oomph.workingsets.presentation.EarlyStartup"/>
    </extension>
 
    <extension