Skip re-expanding properties for local properties

When only local task defined properties (no change nor inherited) are
used in a task, then skip expanding tasks on every change since they
cannot be different.

Change-Id: If5d1d625467cd1b0bdd357d7ed4e7b192716bb6f
diff --git a/src/main/java/com/googlesource/gerrit/plugins/task/Properties.java b/src/main/java/com/googlesource/gerrit/plugins/task/Properties.java
index 3225244..0812004 100644
--- a/src/main/java/com/googlesource/gerrit/plugins/task/Properties.java
+++ b/src/main/java/com/googlesource/gerrit/plugins/task/Properties.java
@@ -40,6 +40,8 @@
   protected final Task origTask;
   protected final CopyOnWrite<Task> task;
   protected Expander expander;
+  protected boolean init = true;
+  protected boolean isTaskRefreshNeeded;
 
   public Properties() {
     this(null, null);
@@ -57,11 +59,20 @@
     Loader loader = new Loader(changeData);
     expander = new Expander(n -> loader.load(n));
 
-    Map<String, String> exported = expander.expand(origTask.exported);
-    if (exported != origTask.exported) {
-      task.getForWrite().exported = exported;
+    if (isTaskRefreshNeeded || init) {
+      Map<String, String> exported = expander.expand(origTask.exported);
+      if (exported != origTask.exported) {
+        task.getForWrite().exported = exported;
+      }
+
+      expander.expand(task, Collections.emptySet());
+
+      if (init) {
+        init = false;
+        isTaskRefreshNeeded = loader.isNonTaskDefinedPropertyLoaded();
+      }
     }
-    return expander.expand(task, Collections.emptySet());
+    return task.getForRead();
   }
 
   /** Use to expand properties specifically for NamesFactories. */
@@ -75,7 +86,8 @@
   protected class Loader {
     protected final ChangeData changeData;
     protected final Function<String, String> inheritedMapper;
-    public Change change;
+    protected Change change;
+    protected boolean isInheritedPropertyLoaded;
 
     public Loader(ChangeData changeData) {
       this.changeData = changeData;
@@ -86,6 +98,10 @@
       }
     }
 
+    public boolean isNonTaskDefinedPropertyLoaded() {
+      return change != null || isInheritedPropertyLoaded;
+    }
+
     public String load(String name) {
       if (name.startsWith("_")) {
         return internal(name);
@@ -95,6 +111,9 @@
         value = origTask.properties.get(name);
         if (value == null) {
           value = inheritedMapper.apply(name);
+          if (!value.isEmpty()) {
+            isInheritedPropertyLoaded = true;
+          }
         }
       }
       return value;