feature[F20509]: CAT Plugin Default Preference Initializer

Implement an org.eclipse.core.runtime.preferences initialize extension using an extension of the class AbstractPreferenceInitializer for the CAT Plugin.

Change-Id: I313766651bc4a8bd1e4175f201b44f894fcb2c79
diff --git a/org.eclipse.ote.cat.plugin/META-INF/MANIFEST.MF b/org.eclipse.ote.cat.plugin/META-INF/MANIFEST.MF
index 575e6fc..72a7fea 100644
--- a/org.eclipse.ote.cat.plugin/META-INF/MANIFEST.MF
+++ b/org.eclipse.ote.cat.plugin/META-INF/MANIFEST.MF
@@ -13,6 +13,7 @@
  com.fasterxml.jackson.databind,
  org.eclipse.core.resources,
  org.eclipse.core.runtime,
+ org.eclipse.core.runtime.preferences,
  org.eclipse.e4.core.services.log,
  org.eclipse.jface.dialogs,
  org.eclipse.jface.preference,
diff --git a/org.eclipse.ote.cat.plugin/plugin.xml b/org.eclipse.ote.cat.plugin/plugin.xml
index e8d8495..cbbd7a9 100644
--- a/org.eclipse.ote.cat.plugin/plugin.xml
+++ b/org.eclipse.ote.cat.plugin/plugin.xml
@@ -19,17 +19,52 @@
    <extension
       point = "org.eclipse.ui.preferencePages">
       
+      <!--
+         == Set the "name" attribute value to the display name for the preference page implemented
+         == by the class specified by the "class" attribute value.
+         ==
+         == The "category" attribute needs to be specified for subordinate pages. The value of the
+         == "category" attribute should be set to the "id" attribute value for its parent preference
+         == page.
+      -->
+      
       <page
          class    = "org.eclipse.ote.cat.plugin.preferencepage.CatSettingsPreferencePage"
-         id       = "org.eclipse.ote.cat.plugin.preferencePages.cat"
+         id       = "org.eclipse.ote.cat.plugin.preferencepage.cat"
          name     = "CAT" />
 
       <page
-         category = "org.eclipse.ote.cat.plugin.preferencePages.cat"
+         category = "org.eclipse.ote.cat.plugin.preferencepage.cat"
          class    = "org.eclipse.ote.cat.plugin.preferencepage.PleConfigurationCachePreferencePage"
-         id       = "org.eclipse.ote.cat.plugin.preferencePages.pleConfigurationCache"
+         id       = "org.eclipse.ote.cat.plugin.preferencepages.pleconfigurationcache"
          name     = "PLE Configuration Cache" />
       
    </extension>
    
+   <!--
+      == The "id" attribute is expected to be set to:
+      ==
+      ==    <bundle-symbolic-name> ".defaultpreferenceinitializer"
+      ==
+      ==    where bundle-symbolic-name is the value for "Bundle-SymbolicName" set in the file
+      ==    "MANIFEST.MF". 
+   -->
+   
+   <extension
+         point = "org.eclipse.core.runtime.preferences"
+         id    = "org.eclipse.ote.cat.plugin.defaultpreferenceinitializer">
+         
+      <!--
+         == Set the value of the "option" attribute to be the command line option used to
+         == specify a JSON file containing the default preference values. If the command line
+         == option is to have a leading dash or dashes those are to be included in the attribute
+         == value. 
+      -->
+      
+      <initializer
+            class  = "org.eclipse.ote.cat.plugin.preferencepage.PreferenceInitializer"
+            option = "-org.eclipse.ote.cat.plugin.defaultpreferences" />
+      
+   </extension>
+   
 </plugin>
diff --git a/org.eclipse.ote.cat.plugin/src/org/eclipse/ote/cat/plugin/CatPlugin.java b/org.eclipse.ote.cat.plugin/src/org/eclipse/ote/cat/plugin/CatPlugin.java
index 2c17f33..07ad5f7 100644
--- a/org.eclipse.ote.cat.plugin/src/org/eclipse/ote/cat/plugin/CatPlugin.java
+++ b/org.eclipse.ote.cat.plugin/src/org/eclipse/ote/cat/plugin/CatPlugin.java
@@ -31,13 +31,6 @@
 public class CatPlugin extends AbstractUIPlugin {
 
    /**
-    * When the {@link CatPlugin#instance} is not yet set or the symbolic bundle name of the plug-in cannot be found, the
-    * {@link CatPlugin} class name is used for the plug-in identifier.
-    */
-
-   private static final String defaultIdentifier = CatPlugin.class.getName();
-
-   /**
     * Saves the single instance of the {@link CatPlugin} class.
     * 
     * @implNote The static <code>instance</code> variable is expected to never be <code>null</code> on access. To access
@@ -49,39 +42,28 @@
    private static CatPlugin instance = null;
 
    /**
-    * Gets the {@link CatPlugin} OSGi bundle symbolic name as the identifier. When the OSGi bundle symbolic name cannot
-    * be determined the {@link CatPlugin} class name is returned.
+    * Gets the {@link CatPlugin} OSGi bundle symbolic name as the identifier.
     * 
     * @return an identification string for the {@link CatPlugin}.
     */
 
    public static String getIdentifier() {
-
-      if (Objects.isNull(CatPlugin.instance)) {
-         return CatPlugin.defaultIdentifier;
-      }
-
-      if (Objects.isNull(CatPlugin.instance.catPluginIdentifier)) {
-
-         Bundle bundle = CatPlugin.instance.getBundle();
-
-         if (Objects.isNull(bundle)) {
-            return CatPlugin.defaultIdentifier;
-         }
-
-         String symbolicName = bundle.getSymbolicName();
-
-         if (Objects.isNull(symbolicName)) {
-            return CatPlugin.defaultIdentifier;
-         }
-
-         CatPlugin.instance.catPluginIdentifier = symbolicName;
-      }
-
+      assert Objects.nonNull(CatPlugin.instance) : "CatPlugin instance is unexpectedly null.";
       return CatPlugin.instance.catPluginIdentifier;
    }
 
    /**
+    * Gets the expected OSGi extension identifier for the extension that implements the
+    * "org.eclipse.core.runtime.preferences" extension point of the plug-in.
+    * 
+    * @return the extension identifier.
+    */
+
+   public static String getDefaultPreferenceInitializerExtensionIdentifier() {
+      return CatPlugin.getIdentifier() + ".defaultpreferenceinitializer";
+   }
+
+   /**
     * Gets the {@IPreferenceStore} implementation of the {@link CatPlugin}.
     * 
     * @return the {@link CatPlugin} {@link IPreferenceStore} instance.
@@ -111,7 +93,8 @@
    public CatPlugin() {
       super();
       CatPlugin.instance = this;
-      this.catPluginIdentifier = null;
+      Bundle bundle = this.getBundle();
+      this.catPluginIdentifier = bundle.getSymbolicName();
    }
 
    /**
diff --git a/org.eclipse.ote.cat.plugin/src/org/eclipse/ote/cat/plugin/preferencepage/Constants.java b/org.eclipse.ote.cat.plugin/src/org/eclipse/ote/cat/plugin/preferencepage/Constants.java
new file mode 100644
index 0000000..4f26091
--- /dev/null
+++ b/org.eclipse.ote.cat.plugin/src/org/eclipse/ote/cat/plugin/preferencepage/Constants.java
@@ -0,0 +1,34 @@
+/*********************************************************************
+ * Copyright (c) 2024 Boeing
+ * 
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ * 
+ * SPDX-License-Identifier: EPL-2.0
+ * 
+ * Contributors: Boeing - initial API and implementation
+ **********************************************************************/
+
+package org.eclipse.ote.cat.plugin.preferencepage;
+
+/**
+ * This package private class contains constants used within the package.
+ * 
+ * @author Loren K. Ashley
+ * @implNote The preference store names of the plug-in preferences are also used as object names in the default
+ * preference value JSON file. They are defined as constants so that they may be used as
+ * {@link com.fasterxml.jackson.annotation} values. For general access, the method
+ * {@link Preference#getPreferenceStoreName} should be used to obtain the preference store names.
+ */
+
+class Constants {
+
+   static final String catJarPreferenceStoreName = "CAT_JAR_PATH";
+   static final String sourceLocationMethodPreferenceStoreName = "SOURCE_LOCATION_METHOD";
+   static final String jtsProjectsPreferenceStoreName = "JTS_PROJECTS";
+   static final String pleConfigurationPreferenceStoreName = "PLE_CONFIGURATION";
+   static final String pleConfigurationCacheFolderPreferenceStoreName = "PLE_CONFIGURATION_CACHE_FOLDER";
+   static final String pleConfigurationLoaderPreferenceStoreName = "OPLE_SERVER";
+
+}
diff --git a/org.eclipse.ote.cat.plugin/src/org/eclipse/ote/cat/plugin/preferencepage/DefaultPreferences.java b/org.eclipse.ote.cat.plugin/src/org/eclipse/ote/cat/plugin/preferencepage/DefaultPreferences.java
new file mode 100644
index 0000000..ca4b335
--- /dev/null
+++ b/org.eclipse.ote.cat.plugin/src/org/eclipse/ote/cat/plugin/preferencepage/DefaultPreferences.java
@@ -0,0 +1,112 @@
+/*********************************************************************
+ * Copyright (c) 2024 Boeing
+ * 
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ * 
+ * SPDX-License-Identifier: EPL-2.0
+ * 
+ * Contributors: Boeing - initial API and implementation
+ **********************************************************************/
+
+package org.eclipse.ote.cat.plugin.preferencepage;
+
+import com.fasterxml.jackson.annotation.JsonIgnore;
+import com.fasterxml.jackson.annotation.JsonProperty;
+import java.util.Arrays;
+import java.util.Objects;
+import java.util.stream.Collectors;
+
+/**
+ * A POJO for deserialization of default preference values from a JSON file.
+ * 
+ * @author Loren K. Ashley
+ */
+
+public class DefaultPreferences {
+
+   @JsonProperty(Constants.catJarPreferenceStoreName)
+   private String catJar;
+
+   @JsonProperty(Constants.jtsProjectsPreferenceStoreName)
+   private String[] jtsProjects;
+
+   @JsonProperty(Constants.pleConfigurationPreferenceStoreName)
+   private String pleConfiguration;
+
+   @JsonProperty(Constants.pleConfigurationCacheFolderPreferenceStoreName)
+   private String pleConfigurationCacheFolder;
+
+   @JsonProperty(Constants.pleConfigurationLoaderPreferenceStoreName)
+   private String pleConfigurationLoader;
+
+   @JsonProperty(Constants.sourceLocationMethodPreferenceStoreName)
+   private String sourceLocationMethod;
+
+   public DefaultPreferences() {
+      this.catJar = null;
+      this.sourceLocationMethod = null;
+      this.jtsProjects = null;
+      this.pleConfiguration = null;
+      this.pleConfigurationCacheFolder = null;
+      this.pleConfigurationLoader = null;
+   }
+
+   public String getCatJar() {
+      return this.catJar;
+   }
+
+   public String[] getJtsProjects() {
+      return this.jtsProjects;
+   }
+
+   @JsonIgnore
+   public String getJtsProjectsCommaList() {
+      return //
+      Objects.nonNull(this.jtsProjects) //
+         ? Arrays.stream(this.jtsProjects).collect(Collectors.joining(",")) //
+         : null;
+   }
+
+   public String getPleConfiguration() {
+      return this.pleConfiguration;
+   }
+
+   public String getPleConfigurationCacheFolder() {
+      return this.pleConfigurationCacheFolder;
+   }
+
+   public String getPleConfigurationLoader() {
+      return this.pleConfigurationLoader;
+   }
+
+   public String getSourceLocationMethod() {
+      return this.sourceLocationMethod;
+   }
+
+   public void setCatJar(String catJar) {
+      this.catJar = catJar;
+   }
+
+   public void setJtsProjects(String[] jtsProjects) {
+      this.jtsProjects = jtsProjects;
+   }
+
+   public void setPleConfiguration(String pleConfiguration) {
+      this.pleConfiguration = pleConfiguration;
+   }
+
+   public void setPleConfigurationCacheFolder(String pleConfigurationCacheFolder) {
+      this.pleConfigurationCacheFolder = pleConfigurationCacheFolder;
+   }
+
+   public void setPleConfigurationLoader(String pleConfigurationLoader) {
+      this.pleConfigurationLoader = pleConfigurationLoader;
+   }
+
+   public void setSourceLocationMethod(String sourceLocationMethod) {
+      this.sourceLocationMethod = sourceLocationMethod;
+   }
+
+}
diff --git a/org.eclipse.ote.cat.plugin/src/org/eclipse/ote/cat/plugin/preferencepage/Preference.java b/org.eclipse.ote.cat.plugin/src/org/eclipse/ote/cat/plugin/preferencepage/Preference.java
index b73133b..1c21775 100644
--- a/org.eclipse.ote.cat.plugin/src/org/eclipse/ote/cat/plugin/preferencepage/Preference.java
+++ b/org.eclipse.ote.cat.plugin/src/org/eclipse/ote/cat/plugin/preferencepage/Preference.java
@@ -12,8 +12,11 @@
 
 package org.eclipse.ote.cat.plugin.preferencepage;
 
+import java.io.File;
+import java.nio.file.Paths;
 import java.util.Objects;
 import java.util.Optional;
+import java.util.function.Function;
 import org.eclipse.core.runtime.IStatus;
 import org.eclipse.jface.preference.ComboFieldEditor;
 import org.eclipse.jface.preference.DirectoryFieldEditor;
@@ -26,6 +29,7 @@
 import org.eclipse.ote.cat.plugin.fieldeditors.PleConfigurationLoader;
 import org.eclipse.ote.cat.plugin.fieldeditors.Project;
 import org.eclipse.swt.widgets.Composite;
+import org.eclipse.ui.part.Page;
 import org.eclipse.ui.statushandlers.StatusManager;
 
 /**
@@ -54,7 +58,6 @@
  */
 
 public enum Preference {
-
    //@formatter:off
    
    /**
@@ -62,20 +65,66 @@
     * <dl>
     * <dt>{@link Page}:</dt>
     * <dd>{@link Page#CAT CAT}</dt>
+    * <dt>Preference Store Name:</dt>
+    * <dd>{@value Constants#catJarPreferenceStoreName}</dd>
     * </dl>
     */
 
    CAT_JAR
       (
          PreferencePage.CAT_SETTINGS,
-         "CAT_JAR_PATH",
-         "CAT Jar File:"
+         Constants.catJarPreferenceStoreName,
+         "CAT Jar File:",
+         DefaultPreferences::getCatJar
+         
       ) {
 
+      /**
+       * {@inheritDoc}
+       */
+      
       public FieldEditor createFieldEditorInternal(Composite parentComposite) {
          return
             new FileFieldEditor(this.getPreferenceStoreName(),this.getFieldEditorLabel(), parentComposite);
       }
+      
+      /**
+       * Validates the default <code>value</code> is the path of a file that can be read.
+       * <p>
+       * {@inheritDoc}
+       * @return <code>true</code> when the <code>value</code> is the path of a readable file; otherwise, <code>false</code>.
+       */
+      
+      public boolean validateDefaultValue(String value) {
+         
+         Exception cause = null;
+         
+         try {
+         
+            if( Paths.get(value).toFile().canRead() ) {
+               return true;
+            }
+         } catch( Exception e ) {
+            cause = e;
+         }
+         
+         CatPluginException catJarDefaultValueException =
+            new CatPluginException
+                   (
+                      StatusManager.BLOCK | StatusManager.LOG,
+                      "CAT Plugin Default Preferences",
+                      IStatus.WARNING,
+                        "The CAT Jar file at the default location does not exist or cannot be read."                      + "\n"
+                      + "   Default Cat Jar File: " + value                                                               + "\n"
+                                                                                                                          + "\n"
+                      + "The default value for the preference \"" + this.getPreferenceStoreName() + "\" will be ignored." + "\n",
+                      cause
+                   );
+
+         catJarDefaultValueException.log();
+         
+         return false;
+      }
    },
 
    /**
@@ -83,14 +132,17 @@
     * <dl>
     * <dt>{@link Page}:</dt>
     * <dd>{@link Page#CAT CAT}</dt>
+    * <dt>Preference Store Name:</dt>
+    * <dd>{@value Constants#sourceLocationMethodPreferenceStoreName}</dd>
     * </dl>
     */
 
    SOURCE_LOCATION_METHOD
       (
          PreferencePage.CAT_SETTINGS,
-         "SOURCE_LOCATION_METHOD",
-         "Source Location Method:"
+         Constants.sourceLocationMethodPreferenceStoreName,
+         "Source Location Method:",
+         DefaultPreferences::getSourceLocationMethod
       ) {
       
       private final String[][] sourceLocationMethods =
@@ -109,6 +161,43 @@
          return 
             new ComboFieldEditor(this.getPreferenceStoreName(), this.getFieldEditorLabel(), sourceLocationMethods, parentComposite);
       }
+      
+      /**
+       * Validates the default Source Location Method is a supported Source Location Method.
+       * <p>
+       * {@inheritDoc}
+       * @return <code>true</code> when the value is a valid Source Location Method; otherwise, <code>false</code>.
+       */
+      
+      public boolean validateDefaultValue(String value) {
+         for( int i = 0; i < sourceLocationMethods.length; i++ ) {
+            if( sourceLocationMethods[i][0].equals( value ) ) {
+               return true;
+            }
+         }
+         
+         StringBuilder validValues = new StringBuilder( 1024 );
+         for( int i = 0; i < sourceLocationMethods.length; i++ ) {
+            validValues.append( "      " ).append( sourceLocationMethods[i][0] ).append( "\n" );
+         }
+         
+         CatPluginException sourceLocationMethodDefaultValueException =
+            new CatPluginException
+                   (
+                      StatusManager.BLOCK | StatusManager.LOG,
+                      "CAT Plugin Default Preferences",
+                      IStatus.WARNING,
+                        "The Source Location Method specified in the default preferences file is not a valid Source Location Method." + "\n"
+                      + "   Specified Default Source Location Method: " + value                                                       + "\n"
+                      + "   Valid Source Location Methods: "                                                                          + "\n"
+                      + validValues.toString(),
+                      null
+                   );
+         
+         sourceLocationMethodDefaultValueException.log();
+         
+         return false;
+      }
    },
          
    /**
@@ -116,14 +205,17 @@
     * <dl>
     * <dt>{@link Page}:</dt>
     * <dd>{@link Page#CAT CAT}</dt>
+    * <dt>Preference Store Name:</dt>
+    * <dd>{@value Constants#jtsProjectsPreferenceStoreName}</dd>
     * </dl>
     */
 
    JTS_PROJECTS
       (
          PreferencePage.CAT_SETTINGS,
-         "JTS_PROJECTS",
-         "Java Test Script Projects:"
+         Constants.jtsProjectsPreferenceStoreName,
+         "Java Test Script Projects:",
+         DefaultPreferences::getJtsProjectsCommaList
       ) {
       
       /**
@@ -135,6 +227,15 @@
          return
             new Project(this.getPreferenceStoreName(), this.getFieldEditorLabel(), parentComposite);
       }
+      
+      /**
+       * {@inheritDoc}
+       */
+      
+      public boolean validateDefaultValue(String value) {
+         //TODO: This will be completed when JTS project management is implemented.
+         return true;
+      }
    },
 
    /**
@@ -142,14 +243,17 @@
     * <dl>
     * <dt>{@link Page}:</dt>
     * <dd>{@link Page#CAT CAT}</dt>
+    * <dt>Preference Store Name:</dt>
+    * <dd>{@value Constants#pleConfigurationPreferenceStoreName}</dd>
     * </dl>
     */
 
    PLE_CONFIGURATION
       (
          PreferencePage.CAT_SETTINGS,
-         "PLE_CONFIGURATION",
-         "PLE Configuration:"
+         Constants.pleConfigurationPreferenceStoreName,
+         "PLE Configuration:",
+         DefaultPreferences::getPleConfiguration
       ) {
    
       private static final String buttonLabel = "Select";
@@ -166,6 +270,17 @@
          return directoryFieldEditor;
          
       }
+      
+      /**
+       * This <code>value</code> is always accepted as it will not cause an invalid preference page error.
+       * <p> 
+       * {@inheritDoc}
+       * @return <code>true</code>
+       */
+      
+      public boolean validateDefaultValue(String value) {
+         return true;
+      }
    },
       
    /**
@@ -173,14 +288,17 @@
     * <dl>
     * <dt>{@link Page}:</dt>
     * <dd>{@link Page#PLE_CONFIGURATION_CACHE PLE_CONFIGURATION_CACHE}</dt>
+    * <dt>Preference Store Name:</dt>
+    * <dd>{@value Constants#pleConfigurationCacheFolderPreferenceStoreName}</dd>
     * </dl>
     */
 
    PLE_CONFIGURATION_CACHE_FOLDER
       (
          PreferencePage.PLE_CONFIGURATION_CACHE,
-         "PLE_CONFIGURATION_CACHE_FOLDER",
-         "Folder:"
+         Constants.pleConfigurationCacheFolderPreferenceStoreName,
+         "Folder:",
+         DefaultPreferences::getPleConfigurationCacheFolder
       ) {
       
       /**
@@ -192,6 +310,53 @@
          return
             new DirectoryAutoStore(this.getPreferenceStoreName(),this.getFieldEditorLabel(), parentComposite);
       }
+      
+      /**
+       * Validates the default <code>value</code> is the path of a directory that can be read.
+       * <p>
+       * {@inheritDoc}
+       * @return <code>true</code> when the <code>value</code> is the path of a directory that can be read; otherwise, <code>false</code>.
+       */
+      
+      public boolean validateDefaultValue(String value) {
+         
+         Exception cause = null;
+         
+         try {
+         
+            File file = Paths.get(value).toFile();
+            
+            if( !file.canRead() ) {
+               cause = new RuntimeException();
+            } else if( !file.isDirectory() ) {
+               cause = new RuntimeException();
+            }
+            
+         } catch( Exception e ) {
+            cause = e;
+         }
+         
+         if( Objects.isNull(cause) ) {
+            return true;
+         }
+         
+         CatPluginException catJarDefaultValueException =
+            new CatPluginException
+                   (
+                      StatusManager.BLOCK | StatusManager.LOG,
+                      "CAT Plugin Default Preferences",
+                      IStatus.WARNING,
+                        "The PLE Configuration Cache Folder at the default location does not exist or cannot be read."                      + "\n"
+                      + "   Default PLE Configuration Cache Folder: " + value                                             + "\n"
+                                                                                                                          + "\n"
+                      + "The default value for the preference \"" + this.getPreferenceStoreName() + "\" will be ignored." + "\n",
+                      cause
+                   );
+
+         catJarDefaultValueException.log();
+         
+         return false;
+      }
    }, 
 
    /**
@@ -200,14 +365,17 @@
     * <dl>
     * <dt>{@link Page}:</dt>
     * <dd>{@link Page#PLE_CONFIGURATION_CACHE PLE_CONFIGURATION_CACHE}</dt>
+    * <dt>Preference Store Name:</dt>
+    * <dd>{@value Constants#pleConfigurationLoaderPreferenceStoreName}</dd>
     * </dl>
     */
 
    PLE_CONFIGURATION_LOADER
       (
          PreferencePage.PLE_CONFIGURATION_CACHE, 
-         "OPLE_SERVER",
-         "OPLE Server:"
+         Constants.pleConfigurationLoaderPreferenceStoreName,
+         "OPLE Server:",
+         DefaultPreferences::getPleConfigurationLoader
       ) {
       
       /**
@@ -218,6 +386,17 @@
          return
             new PleConfigurationLoader(this.getPreferenceStoreName(), this.getFieldEditorLabel(), parentComposite );
       }
+      
+      /**
+       * This <code>value</code> is always accepted as it will not cause an invalid preference page error.
+       * <p> 
+       * {@inheritDoc}
+       * @return <code>true</code>
+       */
+      
+      public boolean validateDefaultValue(String value) {
+         return true;
+      }
    };
    //@formatter:on
 
@@ -232,10 +411,22 @@
    abstract FieldEditor createFieldEditorInternal(Composite parentComposite);
 
    /**
+    * Determines if the default value read from the default preferences file is OK to be set as the default value. The
+    * user may be presented with the option to correct the situation that makes the default value invalid. However, the
+    * user cannot change the default value.
+    * 
+    * @param value the default value for the preference to be tested.
+    * @return <code>true</code> when it is OK to set the <code>value</code> as the default value in the preference
+    * store; otherwise, <code>false</code>.
+    */
+
+   abstract boolean validateDefaultValue(String value);
+
+   /**
     * Saves the key (name) used to access the preference value in the {@link IPrefernceStore}.
     */
 
-   private final String preferenceStoreName;
+   public final String preferenceStoreName;
 
    /**
     * Saves the preference page that the preference's field editor will appear on.
@@ -250,6 +441,12 @@
    private final String fieldEditorLabel;
 
    /**
+    * Saves the {@link Function} used to extract the preference value from a {@link DefaultPreferences} POJO.
+    */
+
+   private final Function<DefaultPreferences, String> defaultPreferenceValueExtractor;
+
+   /**
     * Predicate to determine if the preference's field editor appears on the specified <code>page</code>.
     * 
     * @param page the {@link PreferencePage} to be tested.
@@ -268,9 +465,11 @@
     * @param preferenceStoreName the key (name) used to access the preference's value in the Cat Plugin's preference
     * store.
     * @param fieldEditorLabel the label used for the preference's field editor upon the preference page.
+    * @param defaultPreferenceValueExtractor a {@link Function} used to extract the default value for the preference
+    * from a {@link DefaultPreferences} POJO
     */
 
-   private Preference(PreferencePage page, String preferenceStoreName, String fieldEditorLabel) {
+   private Preference(PreferencePage page, String preferenceStoreName, String fieldEditorLabel, Function<DefaultPreferences, String> defaultPreferenceValueExtractor) {
       //@formatter:off
       assert 
            Objects.nonNull(page)
@@ -288,6 +487,7 @@
       this.page = page;
       this.preferenceStoreName = preferenceStoreName;
       this.fieldEditorLabel = fieldEditorLabel;
+      this.defaultPreferenceValueExtractor = defaultPreferenceValueExtractor;
    }
 
    /**
@@ -321,26 +521,6 @@
    }
 
    /**
-    * Get the name used by the {@link IPreferenceStore} to access and set the preference value.
-    * 
-    * @return the preference store name.
-    */
-
-   public String getPreferenceStoreName() {
-      return this.preferenceStoreName;
-   }
-
-   /**
-    * Gets the label to be used for the preference's {@link FieldEditor}.
-    * 
-    * @return the field editor label.
-    */
-
-   public String getFieldEditorLabel() {
-      return this.fieldEditorLabel;
-   }
-
-   /**
     * Gets the value of the preference as a {@link String}.
     * 
     * @return the preference value.
@@ -373,6 +553,42 @@
    }
 
    /**
+    * Extracts the default value for the preference from a {@link DefaultPreferences} POJO.
+    * 
+    * @param defaultPreference the {@link Preference} to extract a default value for.
+    * @return an {@link Optional} containing the the default value for the preference when it is present in
+    * <code>defaultPreference</code>; otherwise, an empty {@link Optional}.
+    */
+
+   public Optional<String> getDefault(DefaultPreferences defaultPreference) {
+      String defaultValue = this.defaultPreferenceValueExtractor.apply(defaultPreference);
+      if (Objects.nonNull(defaultValue) && this.validateDefaultValue(defaultValue)) {
+         return Optional.of(defaultValue);
+      }
+      return Optional.empty();
+   }
+
+   /**
+    * Gets the label to be used for the preference's {@link FieldEditor}.
+    * 
+    * @return the field editor label.
+    */
+
+   public String getFieldEditorLabel() {
+      return this.fieldEditorLabel;
+   }
+
+   /**
+    * Get the name used by the {@link IPreferenceStore} to access and set the preference value.
+    * 
+    * @return the preference store name.
+    */
+
+   public String getPreferenceStoreName() {
+      return this.preferenceStoreName;
+   }
+
+   /**
     * Sets the {@link String} value of the preference.
     * 
     * @param value the value to be set.
diff --git a/org.eclipse.ote.cat.plugin/src/org/eclipse/ote/cat/plugin/preferencepage/PreferenceInitializer.java b/org.eclipse.ote.cat.plugin/src/org/eclipse/ote/cat/plugin/preferencepage/PreferenceInitializer.java
new file mode 100644
index 0000000..e870123
--- /dev/null
+++ b/org.eclipse.ote.cat.plugin/src/org/eclipse/ote/cat/plugin/preferencepage/PreferenceInitializer.java
@@ -0,0 +1,455 @@
+/*********************************************************************
+ * Copyright (c) 2024 Boeing
+ * 
+ * This program and the accompanying materials are made available under the
+ * terms of the Eclipse Public License 2.0 which is available at
+ * https://www.eclipse.org/legal/epl-2.0/
+ * 
+ * SPDX-License-Identifier: EPL-2.0
+ * 
+ * Contributors: Boeing - initial API and implementation
+ **********************************************************************/
+
+package org.eclipse.ote.cat.plugin.preferencepage;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import java.io.File;
+import java.nio.file.Path;
+import java.nio.file.Paths;
+import java.util.Objects;
+import org.eclipse.core.runtime.IConfigurationElement;
+import org.eclipse.core.runtime.IExtension;
+import org.eclipse.core.runtime.IExtensionPoint;
+import org.eclipse.core.runtime.IExtensionRegistry;
+import org.eclipse.core.runtime.IStatus;
+import org.eclipse.core.runtime.Platform;
+import org.eclipse.core.runtime.preferences.AbstractPreferenceInitializer;
+import org.eclipse.jface.preference.IPreferenceStore;
+import org.eclipse.ote.cat.plugin.CatPlugin;
+import org.eclipse.ote.cat.plugin.CatPluginException;
+import org.eclipse.ui.statushandlers.StatusManager;
+
+/**
+ * An extension of the {@link AbstractPreferenceInitializer} used to provide default preference values from a JSON file
+ * specified by the command line option {@value PreferenceInitializer#commandLineOption}. This method is invoked by the
+ * Eclipse framework only when a default preference value is needed.
+ * 
+ * @author Loren K. Ashley
+ */
+
+public class PreferenceInitializer extends AbstractPreferenceInitializer {
+
+   /**
+    * The name of the attribute in the OSGi Configuration Element that specifies the name of the command line option for
+    * the default preferences file.
+    */
+
+   private static final String commandLineOptionNameAttribute = "option";
+
+   /**
+    * The name of the OSGi Configuration Element that specifies this class as the default value initializer.
+    */
+
+   private static final String configurationElementName = "initializer";
+
+   /**
+    * The dialog box title used for status dialogs.
+    */
+
+   private static final String exceptionTitle = "CAT Plugin Default Preferences";
+
+   /**
+    * The name of the OSGi Extension Point implemented by this class.
+    */
+
+   private static final String extensionPointName = "org.eclipse.core.runtime.preferences";
+
+   /**
+    * Searches the application command line options for one starting with the string <code>commandLineOptionName</code>.
+    * 
+    * @param commandLineOptionName the name of the command line option to search for.
+    * @return the first found matching command line option.
+    * @throws CatPluginException when the command line option is not present.
+    */
+
+   private static String getCommandLineOption(String commandLineOptionName) {
+
+      String[] arguments = Platform.getApplicationArgs();
+
+      int i;
+
+      for (i = 0; i < arguments.length; i++) {
+
+         if (arguments[i].startsWith(commandLineOptionName)) {
+            return arguments[i];
+         }
+
+      }
+
+      //@formatter:off
+      CatPluginException commandLineOptionNotPresent =
+         new CatPluginException
+                (
+                   StatusManager.LOG,
+                   PreferenceInitializer.exceptionTitle,
+                   IStatus.INFO,
+                     "The command line option \"" + commandLineOptionName + "\" was not specified." + "\n"
+                   + "Default preference values for the CAT Plugin were not loaded."                + "\n",
+                   null
+                );
+      //@formatter:on
+      throw commandLineOptionNotPresent;
+   }
+
+   /**
+    * Obtains the default preferences file command line option name from the CAT Plugin &quot;plugin.xml&quot; file. The
+    * command line option is specified by the {@value #commandLineOptionNameAttribute} attribute of the Configuration
+    * Element {@value #configurationElementName} of the Extension element for the Extension Point
+    * {@value #extensionPointName}.
+    * 
+    * @return the command line option name for the CAT Plugin default preferences file.
+    * @throws CatPluginException when unable to determine the command line option name.
+    */
+
+   private static String getCommandLineOptionName() {
+
+      String defaultPreferenceInitializerExtensionIdentifier =
+         CatPlugin.getDefaultPreferenceInitializerExtensionIdentifier();
+
+      IExtensionRegistry extensionRegistry = Platform.getExtensionRegistry();
+
+      if (Objects.isNull(extensionRegistry)) {
+         //@formatter:off
+         CatPluginException osgiExtensionRegistryNotAvailable =
+            new CatPluginException
+                   (
+                      StatusManager.LOG,
+                      PreferenceInitializer.exceptionTitle,
+                      IStatus.ERROR,
+                        "The OSGi Extension Registry is not available. Unable to determine the command line option" + "\n"
+                      + "name for the CAT Plugin default preferences file."                                         + "\n",
+                      null
+                   );
+         //@formatter:on
+         throw osgiExtensionRegistryNotAvailable;
+      }
+
+      IExtensionPoint extensionPoint = extensionRegistry.getExtensionPoint(PreferenceInitializer.extensionPointName);
+
+      if (Objects.isNull(extensionPoint)) {
+         //@formatter:off
+         CatPluginException osgiExtensionPointNotFound =
+            new CatPluginException
+                   (
+                      StatusManager.LOG,
+                      PreferenceInitializer.exceptionTitle,
+                      IStatus.ERROR,
+                        "The OSGi Extension Point \"" + PreferenceInitializer.extensionPointName + "\" was not found."  + "\n" 
+                      + "Unable to determine the command line option name for the CAT Plugin default preferences file." + "\n",
+                      null
+                   );
+         //@formatter:on
+         throw osgiExtensionPointNotFound;
+      }
+
+      IExtension extension = null;
+      Exception extensionCause = null;
+
+      try {
+         extension = extensionPoint.getExtension(defaultPreferenceInitializerExtensionIdentifier);
+      } catch (Exception e) {
+         extensionCause = e;
+      }
+
+      if (Objects.isNull(extension)) {
+         //@formatter:off
+         CatPluginException osgiExtensionNotFound =
+            new CatPluginException
+                   (
+                      StatusManager.LOG,
+                      PreferenceInitializer.exceptionTitle,
+                      IStatus.ERROR,
+                        "The OSGi Extension \"" + defaultPreferenceInitializerExtensionIdentifier + "\" was not found."  + "\n" 
+                      + "Unable to determine the command line option name for the CAT Plugin default preferences file."  + "\n",
+                      extensionCause // <- might be null
+                   );
+         //@formatter:on
+         throw osgiExtensionNotFound;
+      }
+
+      IConfigurationElement[] configurationElements = null;
+      Exception configurationElementsCause = null;
+
+      try {
+         configurationElements = extension.getConfigurationElements();
+      } catch (Exception e) {
+         configurationElementsCause = e;
+      }
+
+      if (Objects.isNull(extension)) {
+         //@formatter:off
+         CatPluginException osgiConfigurationElementsNotFound =
+            new CatPluginException
+                   (
+                      StatusManager.LOG,
+                      PreferenceInitializer.exceptionTitle,
+                      IStatus.ERROR,
+                        "The OSGi Configuration Elments of the Extension \"" + defaultPreferenceInitializerExtensionIdentifier + "\""    + "\n" 
+                      + "were not found. Unable to determine the command line option name for the CAT Plugin default preferences file."  + "\n",
+                      configurationElementsCause
+                   );
+         //@formatter:on
+         throw osgiConfigurationElementsNotFound;
+      }
+
+      IConfigurationElement configurationElement = null;
+      Exception configurationElementCause = null;
+
+      try {
+         for (int i = 0; i < configurationElements.length; i++) {
+            if (Objects.nonNull(configurationElements[i]) && PreferenceInitializer.configurationElementName.equals(
+               configurationElements[i].getName())) {
+               configurationElement = configurationElements[i];
+               break;
+            }
+         }
+      } catch (Exception e) {
+         configurationElementCause = e;
+      }
+
+      if (Objects.isNull(configurationElement)) {
+         //@formatter:off
+         CatPluginException cannotFindInitializerConfigurationElement =
+            new CatPluginException
+                   (
+                      StatusManager.LOG,
+                      PreferenceInitializer.exceptionTitle,
+                      IStatus.INFO,
+                        "The command line option used to specify the default preference values file cannot be determined."    + "\n"
+                      + "Ensure the \"initializer\" element for the extension point \"org.eclipse.core.runtime.preferences\"" + "\n"
+                      + "is specified in the \"plugin.xml\" file of the CAT Plugin."                                          + "\n",
+                      configurationElementCause // <- might be null
+                   );
+         //@formatter:on
+         throw cannotFindInitializerConfigurationElement;
+      }
+
+      String option = null;
+      Exception optionCause = null;
+
+      try {
+         option = configurationElement.getAttribute(PreferenceInitializer.commandLineOptionNameAttribute);
+      } catch (Exception e) {
+         optionCause = e;
+      }
+
+      if (Objects.isNull(option)) {
+         //@formatter:off
+         CatPluginException cannotDetermineCommandLineOptionNameForDefaults =
+            new CatPluginException
+                   (
+                      StatusManager.LOG,
+                      PreferenceInitializer.exceptionTitle,
+                      IStatus.INFO,
+                        "The command line option used to specify the default preference values file cannot be determined." + "\n"
+                      + "Ensure the attribute \"option\" of the \"initializer\" element for the extension point"           + "\n" 
+                      + "\"org.eclipse.core.runtime.preferences\" is set in the \"plugin.xml\" file of the CAT Plugin."    + "\n",
+                      optionCause // <- might be null
+                   );
+         //@formatter:on
+         throw cannotDetermineCommandLineOptionNameForDefaults;
+      }
+
+      return option;
+   }
+
+   /**
+    * Parses the default preferences file path from the command line option.
+    * 
+    * @param commandLineOptionName the name of the command line option.
+    * @param commandLineOption the command line option and value from the application.
+    * @return the command line option value
+    * @throws CatPluginException when unable to parse the value from the <code>commandLineOption</code>.
+    */
+
+   private static String getCommandLineOptionValue(String commandLineOptionName, String commandLineOption) {
+
+      int p = commandLineOption.indexOf('=');
+      int pMax = commandLineOption.length() - 1;
+
+      if ((p < 0) || (p >= pMax)) {
+         //@formatter:off
+         CatPluginException noOptionValueException =
+            new CatPluginException
+                   (
+                      StatusManager.LOG,
+                      PreferenceInitializer.exceptionTitle,
+                      IStatus.WARNING,
+                      "A value was not specified for the command line option \"" + commandLineOptionName + "\"." + "\n",
+                      null
+                   );
+         //@formatter:on
+         throw noOptionValueException;
+      }
+
+      p++;
+
+      String value = commandLineOption.substring(p);
+
+      return value;
+
+   }
+
+   /**
+    * Creates the default preference initializer.
+    * 
+    * @implNote This class is not instantiated unless a default value is requested from the CAT Plugin preference store.
+    */
+
+   public PreferenceInitializer() {
+      super();
+   }
+
+   /**
+    * When the default preferences file command line option is present and the specified JSON file is successfully
+    * parsed, the CAT Plugin preference store default values are set with those from the default preferences file.
+    * 
+    * @throws CatPluginException when:
+    * <ul>
+    * <li>unable to determine the name of the default preferences file command line option,</li>
+    * <li>unable to parse the command line option,</li>
+    * <li>unable to read the default preferences file,</li>
+    * <li>unable to parse the default preferences file, or</li>
+    * <li>a default preference cannot be validated.</li>
+    * </ul>
+    * @implNote This method is only called by the Eclipse framework when a default value is requested from the CAT
+    * Plugin preference store.
+    */
+
+   @Override
+   public void initializeDefaultPreferences() {
+
+      String commandLineOptionName = null;
+      String commandLineOption = null;
+      String commandLineOptionValue = null;
+      try {
+         commandLineOptionName = PreferenceInitializer.getCommandLineOptionName();
+         commandLineOption = PreferenceInitializer.getCommandLineOption(commandLineOptionName);
+         commandLineOptionValue =
+            PreferenceInitializer.getCommandLineOptionValue(commandLineOptionName, commandLineOption);
+
+         File file = null;
+         Exception fileException = null;
+
+         try {
+
+            Path filePath = Paths.get(commandLineOptionValue);
+            file = filePath.toFile();
+
+            if (!file.canRead()) {
+            //@formatter:off
+            fileException =
+               new CatPluginException
+                      (
+                         StatusManager.BLOCK | StatusManager.LOG,
+                         PreferenceInitializer.exceptionTitle,
+                         IStatus.ERROR,
+                           "The CAT Plugin default preferences file does not exsit or cannot be read." + "\n"
+                         + "   Default Preferences File: " + commandLineOptionValue                    + "\n"
+                         + "   Command Line Option:      " + commandLineOptionName                     + "\n",
+                         null
+                      );
+            //@formatter:on
+            }
+
+         } catch (Exception e) {
+            fileException = e;
+         }
+
+         if (Objects.nonNull(fileException)) {
+            if (fileException instanceof CatPluginException) {
+               throw fileException;
+            } else {
+            //@formatter:off
+            CatPluginException systemFileException =
+               new CatPluginException
+                      (
+                         StatusManager.BLOCK | StatusManager.LOG,
+                         PreferenceInitializer.exceptionTitle,
+                         IStatus.ERROR,
+                           "An error occurred testing the accessability of the CAT Plugin default preferences file." + "\n"
+                         + "   Default Preferences File: " + commandLineOptionValue                                  + "\n"
+                         + "   Command Line Option:      " + commandLineOptionName                                   + "\n",
+                         fileException
+                      );
+            //@formatter:on
+               throw systemFileException;
+            }
+         }
+
+         DefaultPreferences defaultPreferences = null;
+         Exception defaultPreferencesException = null;
+
+         try {
+            ObjectMapper objectMapper = new ObjectMapper();
+            defaultPreferences = objectMapper.readValue(file, DefaultPreferences.class);
+         } catch (Exception e) {
+            defaultPreferencesException = null;
+         }
+
+         if (Objects.isNull(defaultPreferences)) {
+         //@formatter:off
+         CatPluginException failedToReadDefaultPreferencesException =
+            new CatPluginException
+                   (
+                      StatusManager.BLOCK | StatusManager.LOG,
+                      PreferenceInitializer.exceptionTitle,
+                      IStatus.WARNING,
+                        "Failed to read the CAT Plugin default preferences file." + "\n"
+                      + "   Default Preferences File: " + commandLineOptionValue  + "\n"
+                      + "   Command Line Option:      " + commandLineOptionName   + "\n",
+                      defaultPreferencesException // <- might be null
+                   );
+         //@formatter:on
+            throw failedToReadDefaultPreferencesException;
+         }
+
+         IPreferenceStore preferenceStore = CatPlugin.getInstancePreferenceStore();
+
+         for (Preference preference : Preference.values()) {
+            //@formatter:off
+            preference
+               .getDefault( defaultPreferences )
+               .ifPresent
+                  ( 
+                     ( defaultValue ) -> preferenceStore.setDefault
+                                            ( 
+                                               preference.getPreferenceStoreName(),
+                                               defaultValue 
+                                            )
+                  );
+            //@formatter:on
+         }
+
+      } catch (CatPluginException catPluginException) {
+         catPluginException.log();
+      } catch (Exception e) {
+         //@formatter:off
+         CatPluginException setDefaultValuesException =
+            new CatPluginException
+                   (
+                      StatusManager.BLOCK | StatusManager.LOG,
+                      PreferenceInitializer.exceptionTitle,
+                      IStatus.ERROR,
+                        "Failed to set a CAT Plugin default preference value."    + "\n"
+                      + "   Default Preferences File: " + commandLineOptionValue  + "\n"
+                      + "   Command Line Option:      " + commandLineOptionName   + "\n",
+                      e
+                   );
+         //@formatter:on
+         setDefaultValuesException.log();
+      }
+
+   }
+
+}