Registry.java
/*
** Module : Registry.java
** Abstract : Progress 4GL compatible Winodws registry related methods
**
** Copyright (c) 2013-2024, Golden Code Development Corporation.
**
** -#- -I- --Date-- ---------------------------------Description----------------------------------
** 001 EVL 20130604 Created initial version.
** 002 EVL 20140117 The native library call is performing now in dedicated place and only once.
** See the ClientCore class.
** 003 EVL 20140327 The default constructor needs the session parameter to get properties from
** server side.
** 004 CA 20140702 Added getEnvironmentName API.
** 005 MAG 20140908 Added getEnvironmentType API. Added return value to load() method.
** 006 CA 20180523 Registry env name is case insensitive.
** 007 GBB 20240826 Removing ServerPropertiesInspector.
*/
/*
** This program is free software: you can redistribute it and/or modify
** it under the terms of the GNU Affero General Public License as
** published by the Free Software Foundation, either version 3 of the
** License, or (at your option) any later version.
**
** This program is distributed in the hope that it will be useful,
** but WITHOUT ANY WARRANTY; without even the implied warranty of
** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
** GNU Affero General Public License for more details.
**
** You may find a copy of the GNU Affero GPL version 3 at the following
** location: https://www.gnu.org/licenses/agpl-3.0.en.html
**
** Additional terms under GNU Affero GPL version 3 section 7:
**
** Under Section 7 of the GNU Affero GPL version 3, the following additional
** terms apply to the works covered under the License. These additional terms
** are non-permissive additional terms allowed under Section 7 of the GNU
** Affero GPL version 3 and may not be removed by you.
**
** 0. Attribution Requirement.
**
** You must preserve all legal notices or author attributions in the covered
** work or Appropriate Legal Notices displayed by works containing the covered
** work. You may not remove from the covered work any author or developer
** credit already included within the covered work.
**
** 1. No License To Use Trademarks.
**
** This license does not grant any license or rights to use the trademarks
** Golden Code, FWD, any Golden Code or FWD logo, or any other trademarks
** of Golden Code Development Corporation. You are not authorized to use the
** name Golden Code, FWD, or the names of any author or contributor, for
** publicity purposes without written authorization.
**
** 2. No Misrepresentation of Affiliation.
**
** You may not represent yourself as Golden Code Development Corporation or FWD.
**
** You may not represent yourself for publicity purposes as associated with
** Golden Code Development Corporation, FWD, or any author or contributor to
** the covered work, without written authorization.
**
** 3. No Misrepresentation of Source or Origin.
**
** You may not represent the covered work as solely your work. All modified
** versions of the covered work must be marked in a reasonable way to make it
** clear that the modified work is not originating from Golden Code Development
** Corporation or FWD. All modified versions must contain the notices of
** attribution required in this license.
*/
package com.goldencode.p2j.util;
import com.goldencode.p2j.net.*;
/**
* A class implementing the Windows registry based environment methods. Key values are stored in
* registry under appropriate keys in registry subsection. This is the default approach if none
* new environment is not loaded and used by LOAD and USE Progress statements.
* <p>
* Some terms need to be clarified. Unlike handling the INI file the 4GL sections are stored as
* registry subkeys, while the keys are stored as registry value names. Current investigation
* show the 4GL base option has no effect in registry handling, everything is happening under
* HKEY_CURRENT_USER registry base. Also the documented behavior for getting the subkeys in
* format 'section1@key1,section2@key2,..,sectionN@keyN' does not work. Another format for
* getting the list of the keys is implemented: 'section1,section2,..,sectionN'.
*
* @author EVL
*/
public class Registry
implements EnvironmentReader
{
/** Windows registry key-subkey names separator. */
public static final String NAME_SEPARATOR = "\\";
/** Windows default hive name. */
public static final String HKEY_DEFAULT_BASE = "HKEY_CURRENT_USER";
/** Windows default key name. */
public static final String KEY_DEFAULT = "";
/**
* Native entry point to get key value from registry.
*
* @param base
* The name of the root for the environment location. It is currently ignored because
* the only root is working is HKEY_CURRENT_USER.
* @param section
* The name of the section in the current environment registry entry to look the key.
* @param key
* The name of the key(or value name in a terms of the windows registry) whose value
* is requested.
*
* @return The string representing the value of the given environment key.
*/
private native static String getKeyVal(String base, String section, String key);
/**
* Getting the comma separated list of subkeys for the given environment name.
*
* @param base
* The name of the root for the environment location. It is currently ignored because
* the only root is working is HKEY_CURRENT_USER.
* @param name
* The name of the current environment registry entry to get the section list.
*
* @return The string representing the comma separated list of the sections for a given
* environment entry.
*/
private native static String getSubKeys(String base, String name);
/**
* Getting the comma separated list of keys(value name sin a terms of the windows registry)
* for given subkey section.
*
* @param base
* The name of the root for the environment location. It is currently ignored because
* the only root is working is HKEY_CURRENT_USER.
* @param section
* The name of the section in the current environment registry entry to get the value
* names list.
*
* @return The string representing the comma separated list of the keys in a given section.
*/
private native static String getValueNames(String base, String section);
/**
* Native entry point to store new key value to registry.
*
* @param base
* The name of the root for the environment location. It is currently ignored because
* the only root is working is HKEY_CURRENT_USER.
* @param section
* The name of the section in the current environment registry entry to change the key.
* @param key
* The name of the key(or value name in a terms of the windows registry) to modify.
* @param value
* The new value to be stored for the key.
*
* @return <code>true</code> in case of success, <code>false</code> otherwise.
*/
private native static boolean setKeyVal(String base, String section, String key, String value);
/**
* Deletes name and it's value from subkey 'section'.
*
* @param base
* The name of the root for the environment location. It is currently ignored because
* the only root is working is HKEY_CURRENT_USER.
* @param section
* The name of the section in the current environment registry entry to remove the key.
* @param key
* The name of the key(or value name in a terms of the windows registry) to remove.
*
* @return <code>true</code> in case of success, <code>false</code> otherwise.
*/
private native static boolean removeValueName(String base, String section, String key);
/**
* Deletes subkey section and all content.
*
* @param base
* The name of the root for the environment location. It is currently ignored because
* the only root is working is HKEY_CURRENT_USER.
* @param section
* The name of the section to remove from the current environment registry entry.
*
* @return <code>true</code> in case of success, <code>false</code> otherwise.
*/
private native static boolean removeSubKey(String base, String section);
/** The complete key path with subkeys to store the key values without base key name. */
private String registryKeyName = null;
/** The name of the registry base to store the keys. */
private String baseKeyName = null;
/** The flag indicating whether we need to create new registry sections replacing existed. */
private boolean isNew;
/**
* Default constructor creating the internals based on the expected registry keys for currently
* installed Progress simulation.
*
* @param envVersion
* The current version string of the Progress compatible environment.
*/
public Registry(String envVersion)
{
registryKeyName = "SOFTWARE"+NAME_SEPARATOR+"PSC"+NAME_SEPARATOR+"PROGRESS"+NAME_SEPARATOR+envVersion;
isNew = false;
baseKeyName = HKEY_DEFAULT_BASE;
}
/**
* Construct an instance of the environment with Windows registry as backend.
*
* @param env
* The environment to create or load. Can be the registry key.
* @param flagNew
* If <code>true</code> - the new file will be created overwriting the possibly
* existed one.
* @param baseKey
* When the parameter is specified the serching is performed under the particular base
* key value.
*/
public Registry(String env, boolean flagNew, String baseKey)
{
registryKeyName = env;
isNew = flagNew;
if (baseKey != null)
{
baseKeyName = baseKey;
}
else
{
baseKeyName = HKEY_DEFAULT_BASE;
}
}
/**
* Creates application defaults implementing Progress LOAD statement.
*
* @return <code>true</code> if loaded false otherwise
*/
public boolean load()
{
return true;
}
/**
* Adds, modifies and deletes keys or sections in current environment. The real work it
* performs is controlled by the input parameters. In a simplest case when all three inputs
* have the real not null and not empty string the method change the registry key for the
* current environment.
* <p>
* The other possible cases are("" means the parameter is null or empty string if the
* difference is not important):
* section == "", key != "", value != "" causes adding directly under current environment
* value name 'key' with given 'value'.
* section == "", key != "", value == "" removing value name 'key' directly under current
* environment with its 'value'
* section != "", key != "", value == "" deletes name and it's value from subkey 'section'.
* section != "", key == "", value == "" deletes subkey 'section' with all content.
* section != "", key == null, value != "" sets new value for DEFAULT value name for subkey
* 'section'.
* section != "", key == null, value == "" removes DEFAULT value name setting 'value' as unset
* for subkey 'section'
*
* @param section
* The name of the section containing the key to modify.
* @param key
* The name of the key to modify or default key if not specified.
* @param value
* The new value of the key under modification.
*/
public void setKeyValue(String section, String key, String value)
{
// Prepare initial parameters for JNI call
String sectionInitial = null;
String keyInitial = null;
String valueInitial = null;
if (section == null || section.isEmpty()) // Section is empty or null
{
if (key != null && !key.isEmpty()) // Key is not empty
{
if (value != null && !value.isEmpty()) // Value is not empty
{
// Adding name-value directly under current environment
sectionInitial = registryKeyName;
keyInitial = key;
valueInitial = value;
// Call C native code here
setKeyVal(baseKeyName, sectionInitial, keyInitial, valueInitial);
}
else // Value is empty or null
{
// Deletes name and it's value from current environment (no subsections)
sectionInitial = registryKeyName;
keyInitial = key;
// Call C native code here
removeValueName(baseKeyName, sectionInitial, keyInitial);
}
}
else // Key is empty or null
{
// Other 2 invalid cases - probably we have to generate error here
}
}
else
{
if (key == null) // Key is null, working with DEFAULT key for given section
{
if (value == null || value.isEmpty()) // Value is empty or null
{
// Deletes subkey section and all content
sectionInitial = registryKeyName + NAME_SEPARATOR + section;
keyInitial = KEY_DEFAULT;
// Call C native code here
removeValueName(baseKeyName, sectionInitial, keyInitial);
}
else // Value is not empty
{
// Sets the DEFAULT value name for subkey section
sectionInitial = registryKeyName + NAME_SEPARATOR + section;
keyInitial = KEY_DEFAULT;
valueInitial = value;
// Call C native code here
setKeyVal(baseKeyName, sectionInitial, keyInitial, valueInitial);
}
}
else if (key.isEmpty()) // Key is empty
{
if (value == null || value.isEmpty()) // Value is empty or null
{
// Deletes subkey section and all content
sectionInitial = registryKeyName + NAME_SEPARATOR + section;
// Call C native code here
removeSubKey(baseKeyName, sectionInitial);
}
}
else // Key is not empty
{
if (value == null || value.isEmpty()) // Value is empty
{
// Deletes name and it's value from subkey 'section'
sectionInitial = registryKeyName + NAME_SEPARATOR + section;
keyInitial = key;
// Call C native code here
removeValueName(baseKeyName, sectionInitial, keyInitial);
}
else // Value is not empty
{
// Usual work, just set the new value
sectionInitial = registryKeyName + NAME_SEPARATOR + section;
keyInitial = key;
valueInitial = value;
// Call C native code here
setKeyVal(baseKeyName, sectionInitial, keyInitial, valueInitial);
}
}
}
}
/**
* Getting the key value or key or section lists from the current environment. The real work
* it performs is controlled by the input parameters. In a simplest case when all two inputs
* have the real not null and not empty string the method gets the value of the given key.
* <p>
* The other possible cases are("" means the parameter is null or empty string if the
* difference is not important):
* section == "", key != "" gets the value for given value name 'key' under current
* environment. There is no 'section' for this key.
* section == "", key == "" gets the comma separated list of all subkeys for the current
* environment.
* section != "", key == empty gets the comma separated list of value names for subkey
* 'section'. Empty here means not null string with 0 length.
* section != "", key == null gets the DEFAULT value for the given subkey 'section'.
*
* @param section
* The name of the section containing the key to get.
* @param key
* The name of the key to get or default key if not specified.
*
* @return The value of the key.
*/
public String getKeyValue(String section, String key)
{
// Prepare initial parameters for JNI call
String sectionInitial = null;
String keyInitial = null;
@SuppressWarnings("unused")
String valueInitial = null;
// What we return from C native code
String result = null;
if (section == null || section.isEmpty()) // Section is empty or null
{
if (key == null || key.isEmpty()) // Key is empty or null
{
// Getting the comma separated list of subkey@value_name pair
sectionInitial = registryKeyName;
result = getSubKeys(baseKeyName, sectionInitial);
}
else // Key is not empty
{
// Getting the value of the key under current environment
sectionInitial = registryKeyName;
keyInitial = key;
// Call C native code here
result = getKeyVal(baseKeyName, sectionInitial, keyInitial);
}
}
else // Section is not empty
{
if (key == null) // Key is null
{
// Getting the default value name for given subkey section
sectionInitial = registryKeyName + NAME_SEPARATOR + section;
keyInitial = KEY_DEFAULT;
// Call C native code here
result = getKeyVal(baseKeyName, sectionInitial, keyInitial);
}
else if (key.isEmpty()) // Key is empty but not null, special case
{
// Getting the comma separated list of value_names for given subkey section
sectionInitial = registryKeyName + NAME_SEPARATOR + section;
result = getValueNames(baseKeyName, sectionInitial);
}
else // Section and key are not empty
{
// Usual provessing, get the key value
sectionInitial = registryKeyName + NAME_SEPARATOR + section;
keyInitial = key;
// Call C native code here
result = getKeyVal(baseKeyName, sectionInitial, keyInitial);
}
}
return result;
}
/**
* Unloads specifies environment from the current one.
*/
public void unload()
{
return;
}
/**
* Get the environment's name.
*
* @return See above.
*/
@Override
public String getEnvironmentName()
{
return registryKeyName.toLowerCase();
}
/**
* Get the environment's type.
*
* @return See above.
*/
@Override
public String getEnvironmentType()
{
return TYPE_REG;
}
}