mirror of
https://github.com/danieldemus/openhab-core.git
synced 2026-07-29 12:34:22 +02:00
Improvements config.serial bundle: Add JavaDoc & fix concurrency bug (#5161)
* Improvements config.serial bundle: Add JavaDoc & fix concurrency bug * Improvements config.dispatch bundle: Add JavaDoc, fix NPE bug & add @NonNullByDefault * Improvements ephemeris bundle: Add comprehensive JavaDoc * Improvements id bundle: Add JavaDoc * Improvements bin2json bundle: Add JavaDoc * Improvements console bundle: Add JavaDoc * Improvements console.eclipse bundle: Add JavaDoc * Improvements console.rfc147 bundle: Add comprehensive JavaDoc Signed-off-by: Vambot07 <salihinazizizol@gmail.com>
This commit is contained in:
+61
-8
@@ -87,6 +87,7 @@ import com.google.gson.JsonSyntaxException;
|
||||
* @author Christoph Weitkamp - Added support for value containing a list of configuration options
|
||||
*/
|
||||
@Component(immediate = true, service = ConfigDispatcher.class)
|
||||
@NonNullByDefault
|
||||
public class ConfigDispatcher {
|
||||
|
||||
private final Logger logger = LoggerFactory.getLogger(ConfigDispatcher.class);
|
||||
@@ -118,17 +119,25 @@ public class ConfigDispatcher {
|
||||
private static final String DEFAULT_LIST_ENDING_CHARACTER = "]";
|
||||
private static final String DEFAULT_LIST_DELIMITER = ",";
|
||||
|
||||
private ExclusivePIDMap exclusivePIDMap;
|
||||
private @Nullable ExclusivePIDMap exclusivePIDMap;
|
||||
|
||||
private final ConfigurationAdmin configAdmin;
|
||||
|
||||
private File exclusivePIDStore;
|
||||
private @Nullable File exclusivePIDStore;
|
||||
|
||||
@Activate
|
||||
public ConfigDispatcher(final @Reference ConfigurationAdmin configAdmin) {
|
||||
this.configAdmin = configAdmin;
|
||||
}
|
||||
|
||||
/**
|
||||
* Activates the ConfigDispatcher component.
|
||||
* This method is called by the OSGi framework when the component is activated.
|
||||
* It initializes the exclusive PID store, loads any previously saved exclusive PIDs,
|
||||
* and processes the default configuration file.
|
||||
*
|
||||
* @param bundleContext the OSGi bundle context used to access bundle-specific data files
|
||||
*/
|
||||
@Activate
|
||||
public void activate(BundleContext bundleContext) {
|
||||
exclusivePIDStore = bundleContext.getDataFile(EXCLUSIVE_PID_STORE_FILE);
|
||||
@@ -136,6 +145,16 @@ public class ConfigDispatcher {
|
||||
readDefaultConfig();
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the list of exclusive PIDs from the bundle data file.
|
||||
* Exclusive PIDs are configuration PIDs that are managed by a single configuration file
|
||||
* (marked with "pid:" prefix). This method attempts to deserialize the previously stored
|
||||
* PID list from JSON format. If the file doesn't exist or cannot be parsed, a new empty
|
||||
* map is created.
|
||||
*
|
||||
* <p>
|
||||
* This method is called during component activation to restore the state from previous runs.
|
||||
*/
|
||||
private void loadExclusivePIDList() {
|
||||
try (FileReader reader = new FileReader(exclusivePIDStore)) {
|
||||
exclusivePIDMap = gson.fromJson(reader, ExclusivePIDMap.class);
|
||||
@@ -153,6 +172,16 @@ public class ConfigDispatcher {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores the current list of exclusive PIDs to the bundle data file.
|
||||
* This method serializes the exclusive PID map to JSON format and writes it to persistent storage.
|
||||
* The stored data is used to track which configuration files use exclusive PIDs and to detect
|
||||
* orphaned configurations when files are deleted.
|
||||
*
|
||||
* <p>
|
||||
* This method is called after processing configuration files to ensure the state is preserved
|
||||
* across component restarts.
|
||||
*/
|
||||
private void storeCurrentExclusivePIDList() {
|
||||
try (FileWriter writer = new FileWriter(exclusivePIDStore)) {
|
||||
exclusivePIDMap.setCurrentExclusivePIDList();
|
||||
@@ -162,7 +191,7 @@ public class ConfigDispatcher {
|
||||
}
|
||||
}
|
||||
|
||||
private Configuration getConfigurationWithContext(String pidWithContext)
|
||||
private @Nullable Configuration getConfigurationWithContext(String pidWithContext)
|
||||
throws IOException, InvalidSyntaxException {
|
||||
if (!pidWithContext.contains(OpenHAB.SERVICE_CONTEXT_MARKER)) {
|
||||
throw new IllegalArgumentException("Given PID should be followed by a context");
|
||||
@@ -223,9 +252,25 @@ public class ConfigDispatcher {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes configuration files from a directory or a single file.
|
||||
* If the given file is a directory, all .cfg files within it are processed in order of
|
||||
* their last modification time (oldest first). If the given file is a regular file,
|
||||
* it is processed directly.
|
||||
*
|
||||
* <p>
|
||||
* After processing all files, this method cleans up orphaned exclusive PIDs
|
||||
* (configurations whose files have been deleted) and saves the current state.
|
||||
*
|
||||
* @param dir the directory containing configuration files, or a single configuration file to process
|
||||
*/
|
||||
public void processConfigFile(File dir) {
|
||||
if (dir.isDirectory() && dir.exists()) {
|
||||
File[] files = dir.listFiles();
|
||||
if (files == null) {
|
||||
logger.warn("Unable to list files in directory '{}', skipping processing", dir.getAbsolutePath());
|
||||
return;
|
||||
}
|
||||
// Sort the files by modification time,
|
||||
// so that the last modified file is processed last.
|
||||
Arrays.sort(files, Comparator.comparingLong(File::lastModified));
|
||||
@@ -393,13 +438,21 @@ public class ConfigDispatcher {
|
||||
storeCurrentExclusivePIDList();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a configuration file is removed.
|
||||
* This method marks the configuration file as removed in the exclusive PID map,
|
||||
* processes any orphaned PIDs (configurations whose files no longer exist),
|
||||
* and updates the persisted state.
|
||||
*
|
||||
* @param path the absolute path of the removed configuration file
|
||||
*/
|
||||
public void fileRemoved(String path) {
|
||||
exclusivePIDMap.setFileRemoved(path);
|
||||
processOrphanExclusivePIDs();
|
||||
storeCurrentExclusivePIDList();
|
||||
}
|
||||
|
||||
private String getPIDFromLine(String line) {
|
||||
private @Nullable String getPIDFromLine(String line) {
|
||||
if (line.startsWith(PID_MARKER)) {
|
||||
return line.substring(PID_MARKER.length()).trim();
|
||||
}
|
||||
@@ -491,7 +544,7 @@ public class ConfigDispatcher {
|
||||
* service config files.
|
||||
* The map will hold a 1:1 relation mapping from an exclusive PID to its absolute path in the file system.
|
||||
*/
|
||||
private transient Map<String, String> processedPIDMapping = new HashMap<>();
|
||||
private transient Map<String, @Nullable String> processedPIDMapping = new HashMap<>();
|
||||
|
||||
/**
|
||||
* Package protected default constructor to allow reflective instantiation.
|
||||
@@ -510,8 +563,8 @@ public class ConfigDispatcher {
|
||||
}
|
||||
|
||||
public void setFileRemoved(String absolutePath) {
|
||||
for (Entry<String, String> entry : processedPIDMapping.entrySet()) {
|
||||
if (entry.getValue().equals(absolutePath)) {
|
||||
for (Entry<String, @Nullable String> entry : processedPIDMapping.entrySet()) {
|
||||
if (absolutePath.equals(entry.getValue())) {
|
||||
entry.setValue(null);
|
||||
return; // we expect a 1:1 relation between PID and path
|
||||
}
|
||||
@@ -543,7 +596,7 @@ public class ConfigDispatcher {
|
||||
.toList();
|
||||
}
|
||||
|
||||
public boolean contains(String pid) {
|
||||
public boolean contains(@Nullable String pid) {
|
||||
return processedPIDMapping.containsKey(pid);
|
||||
}
|
||||
}
|
||||
|
||||
+23
@@ -44,6 +44,15 @@ public class ConfigDispatcherFileWatcher implements WatchService.WatchEventListe
|
||||
private final ConfigDispatcher configDispatcher;
|
||||
private final WatchService watchService;
|
||||
|
||||
/**
|
||||
* Creates and activates the ConfigDispatcherFileWatcher.
|
||||
* This constructor is called by the OSGi framework during component activation.
|
||||
* It registers this component as a file system watch listener for the services configuration
|
||||
* directory and performs an initial processing of all existing configuration files.
|
||||
*
|
||||
* @param configDispatcher the ConfigDispatcher service used to process configuration files
|
||||
* @param watchService the WatchService used to monitor file system changes in the configuration directory
|
||||
*/
|
||||
@Activate
|
||||
public ConfigDispatcherFileWatcher(final @Reference ConfigDispatcher configDispatcher,
|
||||
final @Reference(target = WatchService.CONFIG_WATCHER_FILTER) WatchService watchService) {
|
||||
@@ -57,11 +66,25 @@ public class ConfigDispatcherFileWatcher implements WatchService.WatchEventListe
|
||||
configDispatcher.processConfigFile(Path.of(OpenHAB.getConfigFolder(), servicesFolder).toFile());
|
||||
}
|
||||
|
||||
/**
|
||||
* Deactivates the ConfigDispatcherFileWatcher.
|
||||
* This method is called by the OSGi framework during component deactivation.
|
||||
* It unregisters this component from the watch service to stop receiving file system events.
|
||||
*/
|
||||
@Deactivate
|
||||
public void deactivate() {
|
||||
watchService.unregisterListener(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes file system watch events for configuration files.
|
||||
* This method is called by the WatchService when a file is created, modified, or deleted
|
||||
* in the monitored services directory. It filters events to process only .cfg files that
|
||||
* are not hidden, and delegates the actual processing to the ConfigDispatcher.
|
||||
*
|
||||
* @param kind the type of file system event (CREATE, MODIFY, or DELETE)
|
||||
* @param fullPath the full path to the file that triggered the event
|
||||
*/
|
||||
@Override
|
||||
public void processWatchEvent(WatchService.Kind kind, Path fullPath) {
|
||||
try {
|
||||
|
||||
+65
-1
@@ -50,33 +50,96 @@ public class SerialConfigOptionProvider implements ConfigOptionProvider, UsbSeri
|
||||
private final Set<UsbSerialDeviceInformation> previouslyDiscovered = new CopyOnWriteArraySet<>();
|
||||
private final Set<UsbSerialDiscovery> usbSerialDiscoveries = new CopyOnWriteArraySet<>();
|
||||
|
||||
/**
|
||||
* Creates a new SerialConfigOptionProvider.
|
||||
* This constructor is called by the OSGi framework during component activation.
|
||||
*
|
||||
* @param serialPortManager the serial port manager service used to retrieve available serial ports
|
||||
*/
|
||||
@Activate
|
||||
public SerialConfigOptionProvider(final @Reference SerialPortManager serialPortManager) {
|
||||
this.serialPortManager = serialPortManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Dynamically adds a USB serial discovery service.
|
||||
* This method is called by the OSGi framework when a new {@link UsbSerialDiscovery} service becomes available.
|
||||
* The discovery service is registered as a listener to receive notifications about USB serial device
|
||||
* additions and removals.
|
||||
*
|
||||
* <p>
|
||||
* This method is synchronized to prevent race conditions with {@link #removeUsbSerialDiscovery(UsbSerialDiscovery)}
|
||||
* when services are dynamically bound and unbound.
|
||||
*
|
||||
* @param usbSerialDiscovery the USB serial discovery service to add (must not be null)
|
||||
*/
|
||||
@Reference(cardinality = ReferenceCardinality.MULTIPLE, policy = ReferencePolicy.DYNAMIC)
|
||||
protected void addUsbSerialDiscovery(UsbSerialDiscovery usbSerialDiscovery) {
|
||||
protected synchronized void addUsbSerialDiscovery(UsbSerialDiscovery usbSerialDiscovery) {
|
||||
usbSerialDiscoveries.add(usbSerialDiscovery);
|
||||
usbSerialDiscovery.registerDiscoveryListener(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dynamically removes a USB serial discovery service.
|
||||
* This method is called by the OSGi framework when a {@link UsbSerialDiscovery} service becomes unavailable.
|
||||
* The discovery service is unregistered as a listener and removed from the active discovery set.
|
||||
*
|
||||
* <p>
|
||||
* <b>Note:</b> This method clears all previously discovered USB serial devices, not just those
|
||||
* discovered by this specific service. This ensures a clean state when discovery services are
|
||||
* dynamically removed and re-added, preventing stale device information.
|
||||
*
|
||||
* <p>
|
||||
* This method is synchronized to prevent race conditions with {@link #addUsbSerialDiscovery(UsbSerialDiscovery)}
|
||||
* when services are dynamically bound and unbound.
|
||||
*
|
||||
* @param usbSerialDiscovery the USB serial discovery service to remove (must not be null)
|
||||
*/
|
||||
protected synchronized void removeUsbSerialDiscovery(UsbSerialDiscovery usbSerialDiscovery) {
|
||||
usbSerialDiscovery.unregisterDiscoveryListener(this);
|
||||
usbSerialDiscoveries.remove(usbSerialDiscovery);
|
||||
previouslyDiscovered.clear();
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a USB serial device is discovered.
|
||||
* This method is invoked by {@link UsbSerialDiscovery} services when they detect a new USB serial device.
|
||||
* The discovered device is added to the internal cache and will be included in the parameter options
|
||||
* returned by {@link #getParameterOptions(URI, String, String, Locale)}.
|
||||
*
|
||||
* @param usbSerialDeviceInformation information about the discovered USB serial device
|
||||
*/
|
||||
@Override
|
||||
public void usbSerialDeviceDiscovered(UsbSerialDeviceInformation usbSerialDeviceInformation) {
|
||||
previouslyDiscovered.add(usbSerialDeviceInformation);
|
||||
}
|
||||
|
||||
/**
|
||||
* Called when a USB serial device is removed.
|
||||
* This method is invoked by {@link UsbSerialDiscovery} services when they detect that a USB serial device
|
||||
* has been disconnected. The device is removed from the internal cache and will no longer be included
|
||||
* in the parameter options.
|
||||
*
|
||||
* @param usbSerialDeviceInformation information about the removed USB serial device
|
||||
*/
|
||||
@Override
|
||||
public void usbSerialDeviceRemoved(UsbSerialDeviceInformation usbSerialDeviceInformation) {
|
||||
previouslyDiscovered.remove(usbSerialDeviceInformation);
|
||||
}
|
||||
|
||||
/**
|
||||
* Provides serial port names as configuration parameter options.
|
||||
* This method is called by the configuration framework to populate serial port selection dropdowns
|
||||
* in the UI. It combines serial ports from both the {@link SerialPortManager} and any USB serial
|
||||
* devices discovered through {@link UsbSerialDiscovery} services.
|
||||
*
|
||||
* @param uri the URI of the configuration (not used in this implementation)
|
||||
* @param param the parameter name (not used in this implementation)
|
||||
* @param context the parameter context; returns serial port options only if context equals "serial-port"
|
||||
* @param locale the locale for internationalization (not used in this implementation)
|
||||
* @return a collection of parameter options containing available serial port names,
|
||||
* or {@code null} if the context is not "serial-port"
|
||||
*/
|
||||
@Override
|
||||
public @Nullable Collection<ParameterOption> getParameterOptions(URI uri, String param, @Nullable String context,
|
||||
@Nullable Locale locale) {
|
||||
@@ -84,6 +147,7 @@ public class SerialConfigOptionProvider implements ConfigOptionProvider, UsbSeri
|
||||
return Stream
|
||||
.concat(serialPortManager.getIdentifiers().map(SerialPortIdentifier::getName),
|
||||
previouslyDiscovered.stream().map(UsbSerialDeviceInformation::getSerialPort))
|
||||
.filter(serialPortName -> serialPortName != null && !serialPortName.isEmpty()) //
|
||||
.distinct() //
|
||||
.map(serialPortName -> new ParameterOption(serialPortName, serialPortName)) //
|
||||
.toList();
|
||||
|
||||
+96
@@ -103,6 +103,15 @@ public class EphemerisManagerImpl implements EphemerisManager, ConfigOptionProvi
|
||||
private @NonNullByDefault({}) String country;
|
||||
private @Nullable String region;
|
||||
|
||||
/**
|
||||
* Constructs and activates the EphemerisManagerImpl.
|
||||
* This constructor is called by the OSGi framework during component activation.
|
||||
* It initializes the ephemeris manager with locale support, loads country/region/city descriptions
|
||||
* from the Jollyday library resources, and sets up the default weekend dayset.
|
||||
*
|
||||
* @param localeProvider the locale provider service for internationalization support
|
||||
* @param bundleContext the OSGi bundle context used to access bundle resources
|
||||
*/
|
||||
@Activate
|
||||
public EphemerisManagerImpl(final @Reference LocaleProvider localeProvider, final BundleContext bundleContext) {
|
||||
this.localeProvider = localeProvider;
|
||||
@@ -125,15 +134,37 @@ public class EphemerisManagerImpl implements EphemerisManager, ConfigOptionProvi
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sorts a list of parameter options alphabetically by their label.
|
||||
* This ensures that country, region, and city options are presented in alphabetical order
|
||||
* in the user interface configuration dropdowns.
|
||||
*
|
||||
* @param parameterOptions the list of parameter options to sort in-place
|
||||
*/
|
||||
private void sortByLabel(List<ParameterOption> parameterOptions) {
|
||||
parameterOptions.sort(Comparator.comparing(ParameterOption::getLabel));
|
||||
}
|
||||
|
||||
/**
|
||||
* Activates the EphemerisManagerImpl component.
|
||||
* This method is called by the OSGi framework when the component is activated.
|
||||
* It delegates to the {@link #modified(Map)} method to process the initial configuration.
|
||||
*
|
||||
* @param config the initial configuration properties
|
||||
*/
|
||||
@Activate
|
||||
protected void activate(Map<String, Object> config) {
|
||||
modified(config);
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes configuration updates for the EphemerisManagerImpl.
|
||||
* This method is called by the OSGi framework when the configuration is modified.
|
||||
* It processes custom dayset definitions (e.g., custom weekend days), and updates
|
||||
* the country, region, and city parameters for holiday calculations.
|
||||
*
|
||||
* @param config the updated configuration properties
|
||||
*/
|
||||
@Modified
|
||||
protected void modified(Map<String, Object> config) {
|
||||
config.entrySet().stream().filter(e -> e.getKey().startsWith(CONFIG_DAYSET_PREFIX)).forEach(e -> {
|
||||
@@ -222,6 +253,15 @@ public class EphemerisManagerImpl implements EphemerisManager, ConfigOptionProvi
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a file path to a URL.
|
||||
* This method checks if the file exists on the local filesystem and converts it to a file:// URL.
|
||||
* Used to load custom holiday definition files from the filesystem.
|
||||
*
|
||||
* @param filename the absolute or relative path to the file
|
||||
* @return the URL representing the file
|
||||
* @throws FileNotFoundException if the file does not exist or the URL cannot be formed
|
||||
*/
|
||||
private URL getUrl(String filename) throws FileNotFoundException {
|
||||
if (Files.exists(Path.of(filename))) {
|
||||
try {
|
||||
@@ -234,6 +274,14 @@ public class EphemerisManagerImpl implements EphemerisManager, ConfigOptionProvi
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves or creates a HolidayManager for the specified key.
|
||||
* This method caches HolidayManager instances to avoid recreating them for repeated requests.
|
||||
* The manager key can be either a country code (String) or a URL to a custom holiday definition file.
|
||||
*
|
||||
* @param managerKey either a country code string or a URL to a holiday configuration file
|
||||
* @return the HolidayManager instance for the specified key
|
||||
*/
|
||||
private HolidayManager getHolidayManager(Object managerKey) {
|
||||
HolidayManager holidayManager = holidayManagers.get(managerKey);
|
||||
if (holidayManager == null) {
|
||||
@@ -253,6 +301,16 @@ public class EphemerisManagerImpl implements EphemerisManager, ConfigOptionProvi
|
||||
return holidayManager;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a list of holidays within a specified time window.
|
||||
* This method queries the HolidayManager for all holidays between the start date and
|
||||
* the end date (start date + span), considering the configured country/region/city parameters.
|
||||
*
|
||||
* @param from the start date of the time window
|
||||
* @param span the number of days to look ahead from the start date
|
||||
* @param holidayManager the HolidayManager instance to query
|
||||
* @return a sorted list of holidays within the time window
|
||||
*/
|
||||
private List<Holiday> getHolidays(ZonedDateTime from, int span, HolidayManager holidayManager) {
|
||||
LocalDate fromDate = from.toLocalDate();
|
||||
LocalDate toDate = from.plusDays(span).toLocalDate();
|
||||
@@ -276,6 +334,16 @@ public class EphemerisManagerImpl implements EphemerisManager, ConfigOptionProvi
|
||||
return getDaysUntil(from, searchedHoliday, getUrl(filename));
|
||||
}
|
||||
|
||||
/**
|
||||
* Calculates the number of days until a specified holiday.
|
||||
* This method searches for the holiday within a 1-year time window starting from the given date.
|
||||
* The search is case-insensitive and matches against the holiday's property key.
|
||||
*
|
||||
* @param from the start date to calculate from
|
||||
* @param searchedHoliday the name/key of the holiday to search for
|
||||
* @param holidayManager the HolidayManager instance to query
|
||||
* @return the number of days until the holiday, or -1 if the holiday is not found within the year
|
||||
*/
|
||||
private long getDaysUntil(ZonedDateTime from, String searchedHoliday, HolidayManager holidayManager) {
|
||||
List<Holiday> sortedHolidays = getHolidays(from, 366, holidayManager);
|
||||
Optional<Holiday> result = sortedHolidays.stream()
|
||||
@@ -283,6 +351,15 @@ public class EphemerisManagerImpl implements EphemerisManager, ConfigOptionProvi
|
||||
return result.map(holiday -> from.toLocalDate().until(holiday.getDate(), ChronoUnit.DAYS)).orElse(-1L);
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the key of the first bank holiday within a specified time window.
|
||||
* This method searches for the earliest occurring holiday starting from the given date.
|
||||
*
|
||||
* @param from the start date of the time window
|
||||
* @param span the number of days to search ahead
|
||||
* @param holidayManager the HolidayManager instance to query
|
||||
* @return the property key of the first holiday found, or null if no holiday exists in the time window
|
||||
*/
|
||||
private @Nullable String getFirstBankHolidayKey(ZonedDateTime from, int span, HolidayManager holidayManager) {
|
||||
Optional<Holiday> holiday = getHolidays(from, span, holidayManager).stream().findFirst();
|
||||
return holiday.map(Holiday::getPropertiesKey).orElse(null);
|
||||
@@ -350,6 +427,16 @@ public class EphemerisManagerImpl implements EphemerisManager, ConfigOptionProvi
|
||||
return getNextBankHoliday(from, getUrl(filename));
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds or updates a dayset definition.
|
||||
* A dayset is a collection of days of the week (e.g., weekend = Saturday + Sunday).
|
||||
* This method parses the provided values, strips non-alphabetic characters, converts to uppercase,
|
||||
* and creates a set of DayOfWeek values.
|
||||
*
|
||||
* @param setName the name of the dayset (e.g., "weekend", "workdays")
|
||||
* @param values an iterable collection of day names (e.g., "SATURDAY", "SUNDAY")
|
||||
* @throws IllegalArgumentException if a day name cannot be parsed as a valid DayOfWeek
|
||||
*/
|
||||
private void addDayset(String setName, Iterable<?> values) {
|
||||
Set<DayOfWeek> dayset = new HashSet<>();
|
||||
for (Object day : values) {
|
||||
@@ -421,6 +508,15 @@ public class EphemerisManagerImpl implements EphemerisManager, ConfigOptionProvi
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates and normalizes a property part.
|
||||
* This method trims whitespace and converts the part to lowercase.
|
||||
* Used during parsing of country/region/city property keys.
|
||||
*
|
||||
* @param part the property part to validate
|
||||
* @return the trimmed and lowercased property part
|
||||
* @throws IllegalArgumentException if the part is empty after trimming
|
||||
*/
|
||||
private static String getValidPart(String part) {
|
||||
final String subject = part.trim();
|
||||
if (!subject.isEmpty()) {
|
||||
|
||||
@@ -71,6 +71,15 @@ public class InstanceUUID {
|
||||
return uuid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a new UUID and writes it to the specified file.
|
||||
* This method creates any necessary parent directories and writes the UUID to the file
|
||||
* using UTF-8 encoding.
|
||||
*
|
||||
* @param file the file where the UUID will be stored
|
||||
* @return the newly generated UUID string
|
||||
* @throws IOException if the file cannot be written
|
||||
*/
|
||||
private static String generateToFile(File file) throws IOException {
|
||||
// create intermediary directories
|
||||
if (file.getParentFile() instanceof File parentFile) {
|
||||
@@ -81,6 +90,14 @@ public class InstanceUUID {
|
||||
return newUuid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reads the first line from the UUID file.
|
||||
* This method opens the file, reads the first line, and properly closes the reader.
|
||||
* If the file cannot be read or is empty, an empty string is returned and a warning is logged.
|
||||
*
|
||||
* @param file the file to read from
|
||||
* @return the first line of the file, or an empty string if the file cannot be read or is empty
|
||||
*/
|
||||
private static String readFirstLine(File file) {
|
||||
try (final BufferedReader reader = Files.newBufferedReader(file.toPath(), StandardCharsets.UTF_8)) {
|
||||
return reader.readLine() instanceof String line ? line : "";
|
||||
|
||||
+7
@@ -55,6 +55,13 @@ public class UUIDResource implements RESTResource {
|
||||
|
||||
public static final String PATH_UUID = "uuid";
|
||||
|
||||
/**
|
||||
* Retrieves the instance UUID via REST endpoint.
|
||||
* This method exposes the unique instance identifier through a REST API endpoint.
|
||||
* The UUID is generated once and persisted, remaining constant across restarts.
|
||||
*
|
||||
* @return a Response containing the instance UUID as plain text, or null if the UUID cannot be retrieved
|
||||
*/
|
||||
@GET
|
||||
@Produces(MediaType.TEXT_PLAIN)
|
||||
@Operation(operationId = "getUUID", summary = "A unified unique id.", responses = {
|
||||
|
||||
+29
@@ -137,6 +137,15 @@ public class Bin2Json {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a parsed JBBP field structure to a JSON object.
|
||||
* This internal method performs the actual conversion of parsed binary data to JSON format,
|
||||
* tracking the conversion time when trace logging is enabled.
|
||||
*
|
||||
* @param data the parsed JBBP field structure containing binary data
|
||||
* @return Gson {@link JsonObject} representation of the binary data
|
||||
* @throws ConversionException if an error occurs during the JSON conversion process
|
||||
*/
|
||||
private JsonObject convert(JBBPFieldStruct data) throws ConversionException {
|
||||
try {
|
||||
LocalDateTime start = LocalDateTime.now();
|
||||
@@ -151,10 +160,30 @@ public class Bin2Json {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a JBBP field to a new JSON object.
|
||||
* This is a convenience wrapper method that delegates to the main conversion method with a null
|
||||
* initial JSON object, resulting in a new JSON object being created.
|
||||
*
|
||||
* @param field the JBBP field to convert to JSON
|
||||
* @return a new Gson {@link JsonObject} containing the field data
|
||||
* @throws ConversionException if the field type is not supported or conversion fails
|
||||
*/
|
||||
private JsonObject convertToJSon(final JBBPAbstractField field) throws ConversionException {
|
||||
return convertToJSon(null, field);
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a JBBP field to JSON, optionally adding to an existing JSON object.
|
||||
* This is the main conversion method that recursively handles all JBBP field types including
|
||||
* primitives (bit, boolean, byte, int, long, short), unsigned types (ubyte, ushort),
|
||||
* arrays, and nested structures. Each field is added to the JSON object with its field name as the key.
|
||||
*
|
||||
* @param json the existing JSON object to add the field to, or null to create a new JSON object
|
||||
* @param field the JBBP field to convert (can be primitive, array, or struct)
|
||||
* @return the JSON object containing the converted field data
|
||||
* @throws ConversionException if the field type is not recognized or supported
|
||||
*/
|
||||
private JsonObject convertToJSon(@Nullable final JsonObject json, final JBBPAbstractField field)
|
||||
throws ConversionException {
|
||||
JsonObject jsn = json == null ? new JsonObject() : json;
|
||||
|
||||
+19
@@ -27,17 +27,36 @@ public class ConversionException extends Exception {
|
||||
@Serial
|
||||
private static final long serialVersionUID = 1L;
|
||||
|
||||
/**
|
||||
* Constructs a new ConversionException with no detail message.
|
||||
*/
|
||||
public ConversionException() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new ConversionException with the specified detail message.
|
||||
*
|
||||
* @param message the detail message describing the conversion error
|
||||
*/
|
||||
public ConversionException(String message) {
|
||||
super(message);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new ConversionException with the specified detail message and cause.
|
||||
*
|
||||
* @param message the detail message describing the conversion error
|
||||
* @param cause the underlying cause of the conversion error
|
||||
*/
|
||||
public ConversionException(String message, Throwable cause) {
|
||||
super(message, cause);
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructs a new ConversionException with the specified cause.
|
||||
*
|
||||
* @param cause the underlying cause of the conversion error
|
||||
*/
|
||||
public ConversionException(Throwable cause) {
|
||||
super(cause);
|
||||
}
|
||||
|
||||
+31
@@ -46,22 +46,48 @@ public class ConsoleSupportEclipse implements CommandProvider {
|
||||
private final SortedMap<String, ConsoleCommandExtension> consoleCommandExtensions = Collections
|
||||
.synchronizedSortedMap(new TreeMap<>());
|
||||
|
||||
/**
|
||||
* Constructs a new ConsoleSupportEclipse instance.
|
||||
*/
|
||||
public ConsoleSupportEclipse() {
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a console command extension to the registry.
|
||||
* This method is called dynamically by OSGi when a new console command extension is registered.
|
||||
*
|
||||
* @param consoleCommandExtension the console command extension to add
|
||||
*/
|
||||
@Reference(cardinality = ReferenceCardinality.MULTIPLE, policy = ReferencePolicy.DYNAMIC)
|
||||
public void addConsoleCommandExtension(ConsoleCommandExtension consoleCommandExtension) {
|
||||
consoleCommandExtensions.put(consoleCommandExtension.getCommand(), consoleCommandExtension);
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a console command extension from the registry.
|
||||
* This method is called dynamically by OSGi when a console command extension is unregistered.
|
||||
*
|
||||
* @param consoleCommandExtension the console command extension to remove
|
||||
*/
|
||||
public void removeConsoleCommandExtension(ConsoleCommandExtension consoleCommandExtension) {
|
||||
consoleCommandExtensions.remove(consoleCommandExtension.getCommand());
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a console command extension by command name.
|
||||
*
|
||||
* @param cmd the command name
|
||||
* @return the console command extension, or null if not found
|
||||
*/
|
||||
private ConsoleCommandExtension getConsoleCommandExtension(final String cmd) {
|
||||
return consoleCommandExtensions.get(cmd);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all registered console command extensions.
|
||||
*
|
||||
* @return a collection of all console command extensions
|
||||
*/
|
||||
private Collection<ConsoleCommandExtension> getConsoleCommandExtensions() {
|
||||
return new HashSet<>(consoleCommandExtensions.values());
|
||||
}
|
||||
@@ -105,6 +131,11 @@ public class ConsoleSupportEclipse implements CommandProvider {
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the help text for all registered openHAB console commands.
|
||||
*
|
||||
* @return the help text listing all available commands and their usage
|
||||
*/
|
||||
@Override
|
||||
public String getHelp() {
|
||||
return ConsoleInterpreter.getHelp(BASE, " ", getConsoleCommandExtensions());
|
||||
|
||||
+24
@@ -17,6 +17,8 @@ import org.eclipse.osgi.framework.console.CommandInterpreter;
|
||||
import org.openhab.core.io.console.Console;
|
||||
|
||||
/**
|
||||
* Implementation of the Console interface for Eclipse OSGi console.
|
||||
* This class wraps the Eclipse OSGi CommandInterpreter to provide a unified console interface.
|
||||
*
|
||||
* @author Kai Kreuzer - Initial contribution
|
||||
* @author Markus Rathgeb - Split to separate file
|
||||
@@ -27,21 +29,43 @@ public class OSGiConsole implements Console {
|
||||
private final String baseCommand;
|
||||
private final CommandInterpreter interpreter;
|
||||
|
||||
/**
|
||||
* Constructs a new OSGi console wrapper.
|
||||
*
|
||||
* @param baseCommand the base command name (e.g., "openhab")
|
||||
* @param interpreter the Eclipse OSGi command interpreter
|
||||
*/
|
||||
public OSGiConsole(final String baseCommand, final CommandInterpreter interpreter) {
|
||||
this.baseCommand = baseCommand;
|
||||
this.interpreter = interpreter;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints a string to the console without a newline.
|
||||
*
|
||||
* @param s the string to print
|
||||
*/
|
||||
@Override
|
||||
public void print(final String s) {
|
||||
interpreter.print(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints a string to the console with a newline.
|
||||
*
|
||||
* @param s the string to print
|
||||
*/
|
||||
@Override
|
||||
public void println(final String s) {
|
||||
interpreter.println(s);
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints the usage information for a command.
|
||||
* The output format is: "Usage: {baseCommand} {usageString}".
|
||||
*
|
||||
* @param s the usage string describing command syntax
|
||||
*/
|
||||
@Override
|
||||
public void printUsage(final String s) {
|
||||
interpreter.println(String.format("Usage: %s %s", baseCommand, s));
|
||||
|
||||
+16
-4
@@ -19,6 +19,9 @@ import org.openhab.core.io.console.ConsoleInterpreter;
|
||||
import org.openhab.core.io.console.extensions.ConsoleCommandExtension;
|
||||
|
||||
/**
|
||||
* Wrapper class that bridges console command extensions to OSGi RFC 147 command interface.
|
||||
* This class wraps a ConsoleCommandExtension and exposes it as an OSGi command that can be
|
||||
* invoked through the OSGi command shell.
|
||||
*
|
||||
* @author Markus Rathgeb - Initial contribution
|
||||
*/
|
||||
@@ -27,14 +30,23 @@ public class CommandWrapper {
|
||||
|
||||
private final ConsoleCommandExtension command;
|
||||
|
||||
/**
|
||||
* Constructs a new command wrapper.
|
||||
*
|
||||
* @param command the console command extension to wrap
|
||||
*/
|
||||
public CommandWrapper(final ConsoleCommandExtension command) {
|
||||
this.command = command;
|
||||
}
|
||||
|
||||
// Called for all commands there is no function found for.
|
||||
// The first argument is the command.
|
||||
// The CommandSession interface provides methods for executing commands and getting and setting session variables.
|
||||
// We could return an Object or void.
|
||||
/**
|
||||
* Main entry point for command execution via OSGi RFC 147 interface.
|
||||
* This method is called when no specific function is found for the command.
|
||||
* The first argument is the command name, and remaining arguments are passed to the command.
|
||||
*
|
||||
* @param args the command arguments, where args[0] is the command name
|
||||
* @throws Exception if command execution fails
|
||||
*/
|
||||
public void _main(/* CommandSession session, */String[] args) throws Exception {
|
||||
if (args.length == 0) {
|
||||
System.out.println("missing command");
|
||||
|
||||
+8
@@ -18,11 +18,19 @@ import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.io.console.extensions.ConsoleCommandExtension;
|
||||
|
||||
/**
|
||||
* Container interface for accessing registered console command extensions.
|
||||
* This interface provides access to all console commands that are currently registered
|
||||
* in the OSGi RFC 147 console support.
|
||||
*
|
||||
* @author Markus Rathgeb - Initial contribution
|
||||
*/
|
||||
@NonNullByDefault
|
||||
public interface ConsoleCommandsContainer {
|
||||
|
||||
/**
|
||||
* Gets all registered console command extensions.
|
||||
*
|
||||
* @return a collection of all console command extensions currently registered
|
||||
*/
|
||||
Collection<ConsoleCommandExtension> getConsoleCommandExtensions();
|
||||
}
|
||||
|
||||
+33
@@ -73,11 +73,21 @@ public class ConsoleSupportRfc147 implements ConsoleCommandsContainer {
|
||||
private final Map<ConsoleCommandExtension, @Nullable ServiceRegistration<?>> commands = Collections
|
||||
.synchronizedMap(new HashMap<>());
|
||||
|
||||
/**
|
||||
* Constructs a new RFC 147 console support instance.
|
||||
* Initializes the commands map and registers the built-in help command.
|
||||
*/
|
||||
public ConsoleSupportRfc147() {
|
||||
// Add our custom help console command extensions.
|
||||
commands.put(helpCommand, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* Activates this OSGi component.
|
||||
* Registers all pending console command extensions as OSGi services and activates the help command.
|
||||
*
|
||||
* @param ctx the component context provided by OSGi
|
||||
*/
|
||||
@Activate
|
||||
public void activate(ComponentContext ctx) {
|
||||
// Save bundle context to register services.
|
||||
@@ -97,6 +107,10 @@ public class ConsoleSupportRfc147 implements ConsoleCommandsContainer {
|
||||
helpCommand.setConsoleCommandsContainer(this);
|
||||
}
|
||||
|
||||
/**
|
||||
* Deactivates this OSGi component.
|
||||
* Unregisters all console command extensions and clears the help command reference.
|
||||
*/
|
||||
@Deactivate
|
||||
public void deactivate() {
|
||||
// If we get deactivated, remove from help command (so GC could do their work).
|
||||
@@ -117,6 +131,13 @@ public class ConsoleSupportRfc147 implements ConsoleCommandsContainer {
|
||||
this.bundleContext = null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a console command extension to the registry.
|
||||
* This method is called dynamically by OSGi when a new console command extension is registered.
|
||||
* The command is immediately registered as an OSGi service if the component is active.
|
||||
*
|
||||
* @param consoleCommandExtension the console command extension to add
|
||||
*/
|
||||
@Reference(cardinality = ReferenceCardinality.MULTIPLE, policy = ReferencePolicy.DYNAMIC)
|
||||
public void addConsoleCommandExtension(ConsoleCommandExtension consoleCommandExtension) {
|
||||
final ServiceRegistration<?> old;
|
||||
@@ -127,6 +148,13 @@ public class ConsoleSupportRfc147 implements ConsoleCommandsContainer {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Removes a console command extension from the registry.
|
||||
* This method is called dynamically by OSGi when a console command extension is unregistered.
|
||||
* The command's OSGi service registration is also removed.
|
||||
*
|
||||
* @param consoleCommandExtension the console command extension to remove
|
||||
*/
|
||||
public void removeConsoleCommandExtension(ConsoleCommandExtension consoleCommandExtension) {
|
||||
final ServiceRegistration<?> old;
|
||||
|
||||
@@ -136,6 +164,11 @@ public class ConsoleSupportRfc147 implements ConsoleCommandsContainer {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates an empty properties dictionary for OSGi service registration.
|
||||
*
|
||||
* @return an empty dictionary that can be used to store service properties
|
||||
*/
|
||||
@SuppressWarnings({ "unchecked", "rawtypes" })
|
||||
private Dictionary<String, Object> createProperties() {
|
||||
return (Dictionary) new Properties();
|
||||
|
||||
+13
@@ -16,6 +16,9 @@ import org.eclipse.jdt.annotation.NonNullByDefault;
|
||||
import org.openhab.core.io.console.Console;
|
||||
|
||||
/**
|
||||
* Implementation of the Console interface for OSGi RFC 147 console.
|
||||
* This console implementation outputs to System.out and uses a base command scope
|
||||
* for formatting usage messages.
|
||||
*
|
||||
* @author Markus Rathgeb - Initial contribution
|
||||
*/
|
||||
@@ -24,10 +27,20 @@ public class OSGiConsole implements Console {
|
||||
|
||||
private final String base;
|
||||
|
||||
/**
|
||||
* Constructs a new OSGi RFC 147 console.
|
||||
*
|
||||
* @param base the base command scope (e.g., "openhab")
|
||||
*/
|
||||
public OSGiConsole(final String base) {
|
||||
this.base = base;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the base command scope.
|
||||
*
|
||||
* @return the base command scope string
|
||||
*/
|
||||
public String getBase() {
|
||||
return base;
|
||||
}
|
||||
|
||||
+19
-1
@@ -23,6 +23,9 @@ import org.openhab.core.io.console.rfc147.internal.ConsoleCommandsContainer;
|
||||
import org.openhab.core.io.console.rfc147.internal.ConsoleSupportRfc147;
|
||||
|
||||
/**
|
||||
* Console command extension that provides help information for all available commands.
|
||||
* This command displays usage information for all registered console commands in the
|
||||
* OSGi RFC 147 console.
|
||||
*
|
||||
* @author Markus Rathgeb - Initial contribution
|
||||
*/
|
||||
@@ -31,15 +34,30 @@ public class HelpConsoleCommandExtension extends AbstractConsoleCommandExtension
|
||||
|
||||
private @Nullable ConsoleCommandsContainer commandsContainer;
|
||||
|
||||
/**
|
||||
* Constructs a new help console command extension.
|
||||
* Registers the "help" command with a description.
|
||||
*/
|
||||
public HelpConsoleCommandExtension() {
|
||||
super("help", "Get help for all available commands.");
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the container that provides access to all registered console commands.
|
||||
* This is used to retrieve the list of commands to display help for.
|
||||
*
|
||||
* @param commandsContainer the commands container, or null to clear the reference
|
||||
*/
|
||||
public void setConsoleCommandsContainer(final @Nullable ConsoleCommandsContainer commandsContainer) {
|
||||
this.commandsContainer = commandsContainer;
|
||||
}
|
||||
|
||||
// Add a method that name is equal to our command
|
||||
/**
|
||||
* Command entry point that matches the command name "help".
|
||||
* This method is invoked by the OSGi RFC 147 command infrastructure when the help command is called.
|
||||
*
|
||||
* @param args the command arguments
|
||||
*/
|
||||
public void help(String[] args) {
|
||||
execute(args, ConsoleSupportRfc147.CONSOLE);
|
||||
}
|
||||
|
||||
+18
@@ -26,12 +26,30 @@ import org.eclipse.jdt.annotation.Nullable;
|
||||
@NonNullByDefault
|
||||
public interface Console {
|
||||
|
||||
/**
|
||||
* Prints formatted output to the console.
|
||||
* This method formats the given string using the specified arguments and prints it to the console
|
||||
* without appending a newline.
|
||||
*
|
||||
* @param format the format string (following {@link String#format} syntax)
|
||||
* @param args the arguments referenced by the format specifiers in the format string
|
||||
*/
|
||||
default void printf(String format, Object... args) {
|
||||
print(String.format(format, args));
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints a string to the console without appending a newline.
|
||||
*
|
||||
* @param s the string to print
|
||||
*/
|
||||
void print(String s);
|
||||
|
||||
/**
|
||||
* Prints a string to the console followed by a newline.
|
||||
*
|
||||
* @param s the string to print
|
||||
*/
|
||||
void println(String s);
|
||||
|
||||
/**
|
||||
|
||||
+45
-2
@@ -30,6 +30,16 @@ import org.slf4j.LoggerFactory;
|
||||
@NonNullByDefault
|
||||
public class ConsoleInterpreter {
|
||||
|
||||
/**
|
||||
* Generates a formatted help message listing all available console commands.
|
||||
* This method creates a comprehensive help text that includes all command extensions
|
||||
* with their usage information, formatted with the specified base command and separator.
|
||||
*
|
||||
* @param base the base command string (e.g., "openhab")
|
||||
* @param separator the separator between base and command (e.g., ":")
|
||||
* @param extensions the collection of console command extensions to include in the help
|
||||
* @return a formatted string containing all command usages
|
||||
*/
|
||||
public static String getHelp(final String base, final String separator,
|
||||
Collection<ConsoleCommandExtension> extensions) {
|
||||
final List<String> usages = ConsoleInterpreter.getUsages(extensions);
|
||||
@@ -47,11 +57,30 @@ public class ConsoleInterpreter {
|
||||
return buffer.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints the formatted help message to the console.
|
||||
* This is a convenience method that generates and prints the help text for all
|
||||
* available console commands.
|
||||
*
|
||||
* @param console the console to print the help message to
|
||||
* @param base the base command string (e.g., "openhab")
|
||||
* @param separator the separator between base and command (e.g., ":")
|
||||
* @param extensions the collection of console command extensions to include in the help
|
||||
*/
|
||||
public static void printHelp(final Console console, final String base, final String separator,
|
||||
Collection<ConsoleCommandExtension> extensions) {
|
||||
console.println(getHelp(base, separator, extensions));
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes a console command extension with the given arguments.
|
||||
* This method wraps the execution with error handling, logging any exceptions that occur
|
||||
* and providing user-friendly error messages to the console.
|
||||
*
|
||||
* @param console the console for command output
|
||||
* @param extension the console command extension to execute
|
||||
* @param args the arguments to pass to the command
|
||||
*/
|
||||
public static void execute(Console console, ConsoleCommandExtension extension, String[] args) {
|
||||
try {
|
||||
extension.execute(args, console);
|
||||
@@ -62,7 +91,14 @@ public class ConsoleInterpreter {
|
||||
}
|
||||
}
|
||||
|
||||
/** returns a CR-separated list of usage texts for all available commands */
|
||||
/**
|
||||
* Returns a newline-separated list of usage texts for all available commands.
|
||||
* Each usage text is on its own line, providing a complete list of all command
|
||||
* usages from the given console command extensions.
|
||||
*
|
||||
* @param consoleCommandExtensions the collection of console command extensions
|
||||
* @return a newline-separated string containing all command usage texts
|
||||
*/
|
||||
public static String getUsage(Collection<ConsoleCommandExtension> consoleCommandExtensions) {
|
||||
StringBuilder sb = new StringBuilder();
|
||||
for (String usage : ConsoleInterpreter.getUsages(consoleCommandExtensions)) {
|
||||
@@ -71,7 +107,14 @@ public class ConsoleInterpreter {
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/** returns an array of the usage texts for all available commands */
|
||||
/**
|
||||
* Returns a list of usage texts for all available commands.
|
||||
* This method collects all usage strings from the given console command extensions
|
||||
* and returns them as a list.
|
||||
*
|
||||
* @param consoleCommandExtensions the collection of console command extensions
|
||||
* @return a list containing all command usage texts
|
||||
*/
|
||||
public static List<String> getUsages(Collection<ConsoleCommandExtension> consoleCommandExtensions) {
|
||||
List<String> usages = new ArrayList<>();
|
||||
for (ConsoleCommandExtension consoleCommandExtension : consoleCommandExtensions) {
|
||||
|
||||
+4
@@ -31,6 +31,10 @@ public class StringsCompleter implements ConsoleCommandCompleter {
|
||||
private final SortedSet<String> strings;
|
||||
private final boolean caseSensitive;
|
||||
|
||||
/**
|
||||
* Creates a case-insensitive StringsCompleter with an empty set of strings.
|
||||
* Strings can be added later by modifying the set returned from {@link #getStrings()}.
|
||||
*/
|
||||
public StringsCompleter() {
|
||||
this(List.of(), false);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user