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 "plugin.xml" 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(); + } + + } + +}