Class ConfigPropertyEditor

java.lang.Object
org.bzdev.swing.ConfigPropertyEditor

public abstract class ConfigPropertyEditor extends Object
Property-editor class. This class supports configuration files that are represented as Java property files using the syntax described in the documentation for Properties.load(Reader). A separate class, ConfigPropUtilities, can be used to read files produced by property editors when editing is not needed.

The editor displays a window (whether a frame or dialog) containing a menubar, some buttons, and a table with two columns: one labeled Property and one labeled Value. The initial properties may have keys that cannot be edited, although their values can be edited. When this is the case, the background for this portion of the table will have a different color than the rest of the table. To insert a new row above a row, or to move or delete the row, the entire row must be selected. A table can also be configured to suppress some of the buttons located just above the table. Some keys in the table may consist of one or more dashes (minus signs). There are treated as spacers and are ignored when the properties are written or used outside of the editor.

Property values may be encrypted using GPG or a symmetric cipher. The keys for these properties start with the substring "ebase64." and the values are stored in an encrypted form. When GPG is used, GPG Agent should be configured so that decryption can be used conveniently. To use GPG Agent on Debian Linux systems, add the following lines to the .bashrc script:


     GPG_TTY=$(tty)
     export GPG_TTY
 

The file format is actually a stylized version of a standard Java properties file. The first additional constraint is that the first line, should be a comment (hence the initial '#') of the form


 #(M.T MEDIATYPE)
 
where MEDIATYPE is the media type assigned to the property file. This convention is used when ConfigPropertyEditor reads or writes a configuration file. In addition each line will be terminated with a carriage return followed by a line feed (the convention used in most RFCs for text-based formats). The first line must appear exactly as shown, with no leading or trailing white space, with a single space before the media type, and no spaces between the media type and the terminating closing parenthesis.

This format must use UTF-8 as its character set. While Java historically used ISO 8859-1 for a property file's character set, the methods Properties.load(Reader) and Properties.store(Writer,String) are used by this class, with the readers and writers configured to use the UTF-8 character set, and those methods, with UTF-8, are used by this class.

Keys are restricted to ones that consist of a sequence of tokens separated by periods, with each token starting with a letter followed by 0 or more letters, digits, and underscores. There are two special initial tokens:

  • base64. This token indicates that the value is base-64 encoded.
  • ebase64. This token indicates that the value is first encrypted using GPG or PGP, or a symmetric cipher, and then base-64 encoded. When a symmetric cipher is used, the bass-64 encoded text is prefaced with "===". One use of this field is to store passwords (e.g., for a database). To encrypt one must provide a passphrase/password and specifically with GPG, one must provide a list of recipients: when configuring a database, for instance, one can use this feature so that an administrator and another user can have access to the same password.
ConfigPropertyEditor will remove the encryption and encoding to allow editing of such fields. To decrypt, the user will have to enter a symmetric-cipher password or a GPG passphrase. GPG Agent should be configured for GPG to work properly

Values that are not encoded or encrypted allow variable substitutions. the expression


   $(KEY)
 
will be replaced with the value of the key. The order of the keys does not matter, but references must not be circular. The sequence $$ will be replaced with $. It may be more convenient to use base-64 encoding, in which case variable substitution will not occur. Leading and trailing whitespace is preserved for keys whose first token is "base64" or "ebase64", but not otherwise. With any "base64" or "ebase64" token and its following delimited removed, each key must be unique.

To create an instance of this class for editing a configuration file for a specific application, a subclass has to be defined The constructor for such a subclass is expected to call the following methods (most are optional):

  • addIcon(java.awt.Image) or addIcon(java.lang.Class<?>,java.lang.String). These methods provide an icon to display when a configuration editor's window is iconified. Normally there are multiple icons, corresponding to different sizes required by a window manager.
  • addReservedKeys(String...). There may be some number of distinguished properties that are nominally expected to be present. This method will define a group of such keys. When called multiple times, each group will be separated from the others by a series of dashes in a table's first column.
  • addAltReservedKeys(String,String...). This method adds a set of reserved properties that will appear in a single row. The property names consist of a prefix, followed by a period, followed by a suffix. A combo box will allow one to choose the appropriate property. The values can use different renderers and editors.
  • setupCompleted(). This method must be called by the constructor, and indicates that all the reserved keys, and any default values associated with these, have been provided.
  • setDefaultProperty(String,String). Some properties have default values, typically in cases where the defaults are likely to be the ones the user needs. This method should be used to define what these defaults are.
  • addRE(String,TableCellRenderer,TableCellEditor). This method associates a table-cell renderer and editor with the final components of a key (components are separated by periods). One use is for configuring specialized renderers and editors for properties that provide colors.
  • changedPropertyClears(java.lang.String,java.lang.String...) This method indicates that when one property's value is changed, or the property is removed, other properties should have their values set to null. It is useful in cases where the change of one property indicates that the value of some other properties is almost certainly wrong. Generally these will reserved properties and should be listed in close proximity to each other.
The constructor may optionally call the following methods:
  • freezeRows(). This method prevents the user from adding, moving, or deleting rows. The user may, however, change a row's value or key (unless the row is a reserved row).
  • setInitialExtraRows(int). This method sets the number of blank table entries that appear after any predefined keys.
In addition a subclass must define the following methods:
  • errorTitle(). This contains the title used in dialog boxes associated with error messages.
  • configTitle(). This contains the title used in an ConfigPropertyEditor window (whether a frame or a dialog).
  • mediaType(). This contains the application-specific media type for a properties file, and appears in the first line of files saved by this methods in this class.
  • extensionFilterTitle(). This contains the title to use in a file-chooser dialog for the extension associated with an application's configuration file.
  • extension. This contains the file-name extension for an application's configuration file.

The following statements provide some examples of frequently used operations, assuming an instance named editor has been created.

  • Loading from a file:
    
              editor.loadFile(file);
            
  • Loading using a dialog:
    
                editor.showLoadDialog(component)
            
  • Opening the editor:
    
                  editor.edit(null, ConfigPropertyEditor.Mode.MODAL, null, true);
            
  • Getting decoded/decrypted properties:
    
                Properties config = editor.getDecodedProperties();
            
Finally, ConfigPropertyEditor is not a Swing or AWT component, although it uses such components, and its public methods do not have to be called on the AWT event dispatch thread. The rationale is that one use case is for providing a dialog box for configuring a program that otherwise runs as a command-line program and exits when done.
  • Constructor Details

    • ConfigPropertyEditor

      protected ConfigPropertyEditor()
      Constructor.
  • Method Details

    • getProperties

      protected Properties getProperties()
      Get the Properties that this object uses to store key-value pairs.
      Returns:
      the properties object
    • getIconList

      public List<Image> getIconList()
      Obtain a list of images that can be used by a GUI when a window associated with this instance is closed.
      Returns:
      the images
    • setGPGHome

      public ConfigPropertyEditor setGPGHome(File gpgdir) throws IOException
      Set the GPG home directory given a file. The argument is the directory name used as the --homedir argument for gpg commands.
      Parameters:
      gpgdir - the GPG home directory; null for the default
      Returns:
      this object
      Throws:
      IOException - if an IO error occurs while constructing a cannonical path
    • setGPGDir

      public ConfigPropertyEditor setGPGDir(String gpgdir)
      Set the GPG home directory given a file name. The argument is the directory name used as the --homedir argument for gpg commands.
      Parameters:
      gpgdir - the GPG home directory; null for the default
      Returns:
      this object
    • errorTitle

      protected abstract String errorTitle()
      Get the title to use in modal dialog boxes reporting errors
      Returns:
      the title
    • configTitle

      protected abstract String configTitle()
      Get the title for the window containing this editor.
      Returns:
      the title
    • mediaType

      protected abstract String mediaType()
      Get the media type for the configuration file.
      Returns:
      the media type
    • setDefaultProperty

      protected void setDefaultProperty(String key, String value)
      Set the default value for a property. If the key starts with "base64.", this method will apply the Base-64 encoding. If the key starts with "ebase64.", the value must be first encrypted with either GPG or a symmetric cipher and then Base-64 encoded.

      The method {#useGPG(boolean)} must be called before this method is called if a symmetric cipher was used.

      Parameters:
      key - the property key
      value - the default value for the specified key
    • extensionFilterTitle

      protected abstract String extensionFilterTitle()
      Get the title for a file-chooser filter for the extension supported by this configuration property editor. This will appear as the title for a pull-down box that allows one to choose specific file extensions in an 'open' or 'save' dialog box
      Returns:
      the title
    • extension

      protected abstract String extension()
      Get the filename extension for configuration files.
      Returns:
      the filename extension
    • addIcon

      protected void addIcon(Image icon)
      Add an icon for use by a window system when this object is iconified.
      Parameters:
      icon - the icon
    • addIcon

      protected void addIcon(Class<?> clasz, String name)
      Add an icon for use by a window system when this object is iconified, given a class and resource. The name will be used to find a resource using the class loader for the specified class.

      To work well with Java modules, the resource should be in the same package as the class.

      Parameters:
      clasz - the class
      name - the name of a resource
    • useGPG

      public ConfigPropertyEditor useGPG(boolean value)
      Indicate if GPG encryption is to be used by default instead of asking for each value that is saved. The value can be overriden when a file is loaded provided that the method setUseGPGOnLoad(String) was called first.

      If called, this method should be called before a call to setUseGPGOnLoad(String).

      Parameters:
      value - true if GPG encryption should be used; false if symmetric encryption should be used
      Returns:
      this object
      See Also:
    • setUseGPGOnLoad

      public ConfigPropertyEditor setUseGPGOnLoad(String key)
      Provide a key to determine whether to use GPG or a symmetric cipher when this object is loaded from a file. If a file has not been loaded, the default set by useGPG(boolean) is used. When a fiel is loaded, the value for the key is checked to determine if its value was encrypted using GPG or not. The key must start with "ebase64.".
      Parameters:
      key - the key to check
      Returns:
      this object
      See Also:
    • useGPG

      public boolean useGPG()
      Indicate if GPG encryption is being used.
      Returns:
      true if GPG encryption is used; false for symmetric enryption
    • requestNewPassphrase

      public void requestNewPassphrase()
      Request a new passphrase. This method will not have any effect when GPG is used.
    • requestNewPassphrase

      public void requestNewPassphrase(Component owner)
      Request a new passphrase given an owner component. This method will not have any effect when GPG is used.
      Parameters:
      owner - the component used to center a dialog box.
    • setRecipients

      public void setRecipients(Component c)
      Set the list of recipients to use when values are encrypted. The list will be built interactively. A recipient is a string acceptable to the '-r' argument for GPG.
      Parameters:
      c - the component on which to center dialog boxes
    • setRecipients

      public void setRecipients(String[] list)
      Set the list of recipients to use when values are encrypted, given an array of recipients. A recipient is a string acceptable to the '-r' argument for GPG. Recipients not in the public keyring are ignored. If there are no valid recipients, symmetric encryption may be used.
      Parameters:
      list - the recipient list; null to remove the recipients list
    • setRecipients

      public void setRecipients(List<String> list)
      Set the list of recipients to use when values are encrypted, given a list of recipients. A recipient is a string acceptable to the '-r' argument for GPG. Recipients not in the public keyring are ignored. If there are no valid recipients, symmetric encryption may be used.
      Parameters:
      list - the recipient list; null to remove the recipients list
    • clearRecipients

      public void clearRecipients()
      Clear the recipients list. After this is called, and until either setRecipients(Component) or setRecipients(String[]) is called, the user will be asked for recipients each time a value is encrypted.
    • setRecipientsKey

      public void setRecipientsKey(String key)
      Set a key to use to get the recipients for a file that has already been created.
      Parameters:
      key - the key; null if none is defined.
    • setSaveQuestion

      public void setSaveQuestion(boolean mode)
      Set whether or not a warning message about needing to save the state of the table should be shown.
      Parameters:
      mode - true if the user should be warned to save a modified table; false otherwise
    • save

      public void save(File f) throws IOException
      Save the configuration in a file. If the file is not absolute and its name is "-", standard output is used instead of an actual file. This method uses Properties.store(Writer,String) with a writer that uses the UTF-8 character set with CRLF as an end-of-line delimiter. The properties file will start with a comment "#(!M.T " MEDIATYPE)" where MEDIATYPE is the media type in lower case.
      Parameters:
      f - the file
      Throws:
      IOException - if an IO error occurred
    • save

      public void save(OutputStream os) throws IOException
      Save the configuration, writing it to an output stream. This method uses Properties.store(Writer,String) with a writer that uses the UTF-8 character set with CRLF as an end-of-line delimiter. The output stream will start with a comment "#(!M.T " MEDIATYPE)" where MEDIATYPE is the media type in lower case.
      Parameters:
      os - the output stream
      Throws:
      IOException - if an IO error occurred
    • toJSON

      public String toJSON()
      Convert this object to a JSON representation.
      Returns:
      the JSON representation of this object
    • toBase64

      public String toBase64()
      Convert this object to a base-64 endcoded string. This method uses Properties.store(Writer,String) with a writer that uses the UTF-8 character set with CRLF as an end-of-line delimiter. The writer produces a byte array that is then base-64 encoded, and the corresponding string is returned, assuming a UTF-8 encoding.
      Returns:
      the base-64 encoded string
    • addReservedKeys

      protected void addReservedKeys(String... keys)
      Add a set of reserved keys.
      Parameters:
      keys - the keys
    • addAltReservedKeys

      protected void addAltReservedKeys(String prefix, String... suffixes) throws IllegalArgumentException
      Add a reserved-key entry where the key can be changed to use various suffixes. This will cause a spacer (a string of '-' characters where a key is expected) to be added after the entry, unless the prefix was already entered as a key by a call to addReservedKeys(String...) with that key given as the concatenation of the prefix, a period, and the first suffix. In this case, the call to addReservedKeys(String...) must immediately precede the call to this method or a sequence of calls to this method.
      Parameters:
      prefix - the start of a key
      suffixes - the possible suffixes following the prefix and separated from the prefix by a period.
      Throws:
      IllegalArgumentException - a key is already in use
    • setupCompleted

      protected void setupCompleted()
      Indicate that all reserved keywords have been added. If called multiple times, only the first call will have any effect.

      This should be called in a constructor.

    • showLoadDialog

      public void showLoadDialog(Component owner) throws IOException
      Load a file, chosen using a dialog, to set up this editor. This will be called before the editor's top-level window is created.
      Parameters:
      owner - the component on which any file-chooser dialog should be centered; null if there is none
      Throws:
      IOException - an IO error occurred
    • loadFile

      public void loadFile(File f) throws IOException
      Load a file to set up this editor. This will be called before the editor's top-level window is created.

      Calling this method directly will not result in the user being prompted to save changes if values are edited.

      Parameters:
      f - the file to open; null if no file should be loaded.
      Throws:
      IOException - an IO exception occurred
    • loadReader

      public void loadReader(Reader r) throws IOException
      Load a file to set up this editor. This will be called before the editor's top-level window is created.

      Calling this method directly will not result in the user being prompted to save changes if values are edited.

      Parameters:
      r - a reader
      Throws:
      IOException - an IO exception occurred
    • requestPassphrase

      public void requestPassphrase(Component owner)
      Request a GPG passphrase or a symmetric cipher password when one has not already been provided. This method will typically open a dialog box to request a GPG passphrase for decryption if the passphrase is not already known. However, if the argument is null, this method is not called from the event dispatch thread, and a system console exists, the system console will be used to obtain the passphrase.

      To use a dialog box when 'owner' is null and a console exists, use

      
       ConfigPropertyEditor cpe = ...;
       ...
       SwingUtilities.invokeAndWait(() -> {
           cpe.requestPassphrase(null);
       });
       

      NOTE: tests indicate that in Java, a system console exists only when both standard input and standard output are connected to a terminal.

      Parameters:
      owner - a component over which a dialog box should be displayed
    • requestPassphrase

      public void requestPassphrase(Component owner, boolean ignoreConsole)
      Request a passphrase when one has not already been provided, optionally suppressing any use of the system console. This method will typically open a dialog box to request a GPG or symmetric-key-encryption passphrase for decryption if the passphrase is not already known. However, if the first argument is null, this method is not called from the event dispatch thread, and a system console exists, the system console will be used to obtain the passphrase unless the second argument true.

      To use a dialog box when 'owner' is null and a console exists, use

      
       ConfigPropertyEditor cpe = ...;
       ...
       SwingUtilities.invokeAndWait(() -> {
           cpe.requestPassphrase(null);
       });
       

      NOTE: tests indicate that in Java, a system console exists only when both standard input and standard output are connected to a terminal.

      Parameters:
      owner - a component over which a dialog box should be displayed
      ignoreConsole - true if a console should always be ignored; false otherwise
    • requestPassphrase

      public void requestPassphrase(ConfigPropertyEditor cpe)
      Copy a passphrase from another editor.
      Parameters:
      cpe - an instance of ConfigPropertyEditor
    • passphraseSupplier

      public static Supplier<char[]> passphraseSupplier(Component owner, boolean useGPG, boolean ignoreConsole)
      Create a supplier that can be used to ask for a GPG passphrase. The supplier will call requestPassphrase(Component,boolean), which will typically open a dialog box to request a GPG passphrase. However, if the first argument is null, this method is not called from the event dispatch thread, and a system console exists, the system console will be used to obtain the passphrase (unless the second argument is true, in which case the current thread will block until a passphrase is provided via a dialog box or the dialog box is canceled).
      Parameters:
      owner - a component over which a dialog box should be displayed
      useGPG - true if the supplier generates a GPG passphrase; false if the supplier generates a symmetric-cipher password
      ignoreConsole - true if a console should always be ignored; false otherwise
      Returns:
      the supplier
      See Also:
    • requestPassphrase

      public static char[] requestPassphrase(Component owner, boolean useGPG, boolean ignoreConsole)
      Request a GPG passphrase. This method will typically open a dialog box to request a GPG passphrase. However, if the first argument is null, this method is not called from the event dispatch thread, and a system console exists, the system console will be used to obtain the passphrase (unless the second argument is true, in which case the current thread will block until a password is provided or the dialog box is canceled).

      To use a dialog box when 'owner' is null, the call is not from the event dispatch thread, and a console exists, use

      
       SwingUtilities.invokeAndWait(() -> {
           char[] passphrase = ConfigPropertyEditor
               .requestPassphrase(null, true, true);
       });
       
      for a GPG passphrase or
      
       SwingUtilities.invokeAndWait(() -> {
           char[] passphrase = ConfigPropertyEditor
               .requestPassphrase(null, false, true);
       });
       
      for a symmetric-cipher password

      NOTE: tests indicate that in Java, a system console exists only when both standard input and standard output are connected to a terminal. The argument useGPG only affects the text that appears in some prompts or dialog boxes.

      Parameters:
      owner - a component over which a dialog box should be displayed
      useGPG - true if the password is to be used by GPG; false if it is to be used for a symmetric cipher
      ignoreConsole - true if a console should always be ignored; false otherwise
    • hasPassphrase

      public boolean hasPassphrase()
      Determine if a passphrase is currently available. The program SBL uses this method (when not editing a table) to determine if there is no existing passphrase, in which case the passphrase will be obtained from a user and immediately cleared after use.
      Returns:
      true if a passphrase is available; false otherwise.
    • clearPassphrase

      public void clearPassphrase()
      Remove the current passphrase. As a general rule, this method should be called as soon as a passphrase is no longer needed, or will not be needed for some time.
    • freezeRows

      protected void freezeRows()
      configure the table so that new rows cannot be added and rows cannot be moved or deleted.
    • setInitialExtraRows

      protected void setInitialExtraRows(int count)
      Set the number of blank rows at the end of the table. These rows are added after any rows containing reserved keys. The default is 10. Set to zero if only the reserved rows should be in the table.
      Parameters:
      count - the number of rows
    • addRE

      public void addRE(String tail, TableCellRenderer r, TableCellEditor e)
      Provide a custom table-cell renderer and/or editor for the value in the second column of some row. The key provided in column 1 of a row will be tested against the tail argument provided by this method. If there is an exact match for a key, the renderer or editor is used. Otherwise the key is replaced by the remainder of the key after its first period and the test is repeated until there is a match or the key can no longer by shorted. If there are multiple possible matches, the longest match is used. A match is based on the first argument, not the second or third.
      Parameters:
      tail - the last components of a key.
      r - the table cell renderer to use to display the value corresponding to a key; null if the normal choice is not overridden.
      e - the table cell editor to use to modify or create a value corresponding to a key; null if the normal choice is not overridden.
    • setHelpMenuItem

      public void setHelpMenuItem(JMenuItem helpMenuItem)
      Provide a menu item for displaying 'help' documentation. One should be cautious about using an instance of HelpMenuItem as the argument to this method due to this menu item's action opening a new window, which can be problematic with modal dialogs.

      If not called with a non-null argument, a Help menu will not be included.

      Parameters:
      helpMenuItem - the menuItem; null if there is not such a menu item
    • addConfigPropertyListener

      public void addConfigPropertyListener(ConfigPropertyEditor.ConfigPropertyListener l)
      Add a ConfigPropertyEditor.ConfigPropertyListener to this ConfigPropertyEditor. The listeners will be called when a monitored property's value has changed.
      Parameters:
      l - the listener to add
      See Also:
    • removeConfigPropertyListener

      public void removeConfigPropertyListener(ConfigPropertyEditor.ConfigPropertyListener l)
      Parameters:
      l - the listener to remove
    • monitorProperty

      protected void monitorProperty(String property) throws IllegalArgumentException
      Monitor a property. Registered listeners will be called when the property changes value.
      Parameters:
      property - the property to monitor
      Throws:
      IllegalArgumentException - the property's name starts with "ebase64.", indicating an encrypted value
      See Also:
    • getMonitoredPropertyValue

      protected String getMonitoredPropertyValue(String property) throws IllegalArgumentException
      Get the value for a monitored property.
      Parameters:
      property - a property that is being monitored
      Returns:
      the value for the specified property
      Throws:
      IllegalArgumentException - the key was not monitored
    • changedPropertyClears

      public void changedPropertyClears(String p, String... others)
      Indicate that if one property's value changes, various other properties should have their values set to null.

      This is useful in cases such as one property providing a file format and a second providing a file name that is required to have a particular extension.

      Parameters:
      p - a property
      others - a list of properties whose values should be set to null if property p changes
    • hasKey

      public boolean hasKey(String key)
      Test if a key exists.
      Parameters:
      key - the key
      Returns:
      true if the key exists; false otherwise
    • set

      public boolean set(Component owner, String key, String value)
      Set a key. The first argument is used when a key starts with "ebase64." as that indicates that GPG encryption will be used, in which case dialog boxes will be used to get the names of recipients. If a key already exists, its value will be overwritten.
      Parameters:
      owner - a component over which a dialog box may appear; null if a dialog box's location is not constrained
      key - the key
      value - the value for the key
      Returns:
      true if successful; false otherwise (e.g., GPG failed to encrypt, the key was missing, or the value was null)
    • getPWOwner

      public Component getPWOwner()
      Get the component over which a password-request dialog box should appear.
      Returns:
      the component; null if there is none
    • setPWOwner

      public void setPWOwner(Component owner)
      Set the component over which a password-request dialog box should appear.
      Parameters:
      owner - the component; null if there is none
    • pushOwner

      public ConfigPropertyEditor.SavedOwner pushOwner(Component newOwner)
      Temporarily set a new password owner for the duration of a try-with-resource block. The owner may be overridden if try-with-resource blocks are nested.

      Example:

      
        Component component = ...;
        ConfigPropertyEditor cpe = ...;
        try (var saved = cpe.puahsOwner(component)) {
           ...;
        }
       
      *@param newOwner the new password owner (the component over which a dialog box will be centered)
      Returns:
      the object saving the previous password owner
    • prohibitEditing

      protected boolean prohibitEditing(int row, int col)
      Prevent editing of specific rows and columns. The default implementation returns false for any pair of arguments. If the value returned is dependent on a cell's row and column instead of its contents, the behavior of this class may be erratic unless those cells cannot be moved.

      This method can not override the prohibition on editing reserved keys or spacers.

      Parameters:
      row - the table row
      col - the table column
      Returns:
      true if editing is explicitly prohibited for the given row and column; false otherwise
    • edit

      public void edit(Component owner, ConfigPropertyEditor.Mode mode, Callable continuation, ConfigPropertyEditor.CloseMode quitCloseMode)
      Start the editor. This will cause a window to appear that will allow configuration parameters to be edited. Depending on the mode argument, the window may be a JFrame or a JDialog, and for a dialog, modal or modeless. One should call loadFile(File) if the parameters should be loaded from a known file or showLoadDialog(Component) if a dialog box should be used to select a file. Otherwise default values may be provided for some of the parameters.
      Parameters:
      owner - the component on which the editor should be centered; null if there is none
      mode - the window mode (ConfigPropertyEditor.Mode.JFRAME, ConfigPropertyEditor.Mode.MODAL, or ConfigPropertyEditor.Mode.MODELESS)
      continuation - a Callable that provides some code to run while or just after this editor's top-level window is closing.
      quitCloseMode - ConfigPropertyEditor.CloseMode.QUIT if the process should exit when the editor closes; ConfigPropertyEditor.CloseMode.CLOSE if the process should continue after the editor closes, or ConfigPropertyEditor.CloseMode.BOTH if both a Quit and a Close menu item should appear in the File menu.
    • getEncodedProperties

      public Properties getEncodedProperties()
      Get the encoded properties. Keys starting with 'base64.' will have their value Base-64 encoded and keys starting with 'ebase64.' will have their valued encrypted with GPG and then Base-64 encoded.
      Returns:
      the properties, encoded if necessary
    • getDecodedProperties

      public Properties getDecodedProperties()
      Get the decoded properties. Base-64 encoding will be removed for unencrypted properties and all string substitution will be performed before the results are returned. For keys starting with the component "base64", the first token and its following delimiter ("base64.") will be stripped from the key. Encrypted data is handled so as to allow the unencrypted data to be kept for as short a time as possible. For other keys, the value for a key will have parameter references replaced with the corresponding values.

      The Properties object returned by this method has been customized: for keys starting with "ebase64.", the method Properties.getProperty(String) will return the encrypted value, whereas the method get(Object) will return an Object that is actually an array of characters and that contains the decrypted data. For these keys, a new array will be returned each time Properties.get(Object) is called. This is somewhat atypical—normally Properties.getProperty(String) and Properties.get(Object) return the same object but with a different type. The rationale is that encrypted data is typically sensitive and should be removed as soon as it is no longer needed. You can overwrite a character array, but you cannot overwrite a string, which will persist until reclaimed by the garbage collector.

      NOTE: For encrypted values the method requestPassphrase(Component) should be called before a call to Properties.get(Object) if the dialog box is to be placed over a specific component.

      Returns:
      the properties
      See Also: