Skip to content

Rule file provider #4633

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 11 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,8 @@ public static TemplateState typeOf(@Nullable String templateState) {
case "pending":
return PENDING;
case "template-missing":
case "template missing":
case "template_missing":
return TEMPLATE_MISSING;
default:
return NO_TEMPLATE;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@
*/
package org.openhab.core.automation;

import java.util.Locale;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.automation.template.Template;
import org.openhab.core.automation.type.ModuleType;

Expand All @@ -36,6 +39,25 @@ public enum Visibility {
/**
* The UI has to show an object with such visibility only to experts.
*/
EXPERT
EXPERT;

/**
* Tries to parse the specified string value into a {@link Visibility} instance. If the parsing fails, {@code null}
* is returned.
*
* @param value the {@link String} to parse.
* @return The resulting {@link Visibility} or {@code null}.
*/
public static @Nullable Visibility typeOf(@Nullable String value) {
if (value == null || value.isBlank()) {
return null;
}
String s = value.trim().toUpperCase(Locale.ROOT);
for (Visibility element : values()) {
if (s.equals(element.name())) {
return element;
}
}
return null;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;

Expand Down Expand Up @@ -44,7 +44,7 @@ public class RuleGSONParser extends AbstractGSONParser<Rule> {
public Set<Rule> parse(InputStreamReader reader) throws ParsingException {
JsonReader jr = new JsonReader(reader);
try {
Set<Rule> rules = new HashSet<>();
Set<Rule> rules = new LinkedHashSet<>();
if (jr.hasNext()) {
JsonToken token = jr.peek();
if (JsonToken.BEGIN_ARRAY.equals(token)) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashSet;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Set;

Expand Down Expand Up @@ -46,7 +46,7 @@ public Set<Template> parse(InputStreamReader reader) throws ParsingException {
try {
if (jr.hasNext()) {
JsonToken token = jr.peek();
Set<Template> templates = new HashSet<>();
Set<Template> templates = new LinkedHashSet<>();
if (JsonToken.BEGIN_ARRAY.equals(token)) {
List<RuleTemplateDTO> templateDtos = gson.fromJson(jr, new TypeToken<List<RuleTemplateDTO>>() {
}.getType());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -225,6 +225,7 @@ public void removeParser(Parser<E> parser, Map<String, String> properties) {
* @param url a specified URL for import.
*/
protected void importFile(String parserType, URL url) {
logger.debug("Reading file \"{}\"", url);
Parser<E> parser = parsers.get(parserType);
if (parser != null) {
InputStream is = null;
Expand Down Expand Up @@ -258,7 +259,7 @@ protected void importFile(String parserType, URL url) {
List<URL> value = Objects.requireNonNull(urls.computeIfAbsent(parserType, k -> new ArrayList<>()));
value.add(url);
}
logger.debug("Parser {} not available", parserType, new Exception());
logger.debug("Couldn't parse \"{}\", no \"{}\" parser available", url, parserType);
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
/*
* Copyright (c) 2010-2025 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.core.automation.internal.provider.file;

import java.util.Collection;
import java.util.List;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.automation.Rule;
import org.openhab.core.automation.RuleProvider;

/**
* This class is a {@link RuleProvider} implementation that provides file-based rules. It extends the functionality
* of {@link AbstractFileProvider} for importing the {@link Rule}s from local files.
*
* @author Ravi Nadahar - Initial contribution
*/
@NonNullByDefault
public abstract class RuleFileProvider extends AbstractFileProvider<Rule> implements RuleProvider {

/**
* Creates a new instance.
*/
public RuleFileProvider() {
super("rules");
}

@Override
protected String getUID(Rule providedObject) {
return providedObject.getUID();
}

@Override
public Collection<Rule> getAll() {
return List.copyOf(providedObjectsHolder.values());
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,83 @@
/*
* Copyright (c) 2010-2025 Contributors to the openHAB project
*
* See the NOTICE file(s) distributed with this work for additional
* information.
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License 2.0 which is available at
* http://www.eclipse.org/legal/epl-2.0
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.core.automation.internal.provider.file;

import java.util.Map;

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.automation.Rule;
import org.openhab.core.automation.RuleProvider;
import org.openhab.core.automation.parser.Parser;
import org.openhab.core.automation.parser.ValidationException;
import org.openhab.core.automation.parser.ValidationException.ObjectType;
import org.openhab.core.service.WatchService;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.component.annotations.ReferenceCardinality;
import org.osgi.service.component.annotations.ReferencePolicy;

/**
* This class is a wrapper of {@link RuleFileProvider}s, responsible for initializing the WatchService.
*
* @author Ravi Nadahar - Initial contribution
*/
@NonNullByDefault
@Component(immediate = true, service = RuleProvider.class)
public class RuleFileProviderWatcher extends RuleFileProvider {

private final WatchService watchService;

/**
* Creates a new instance using the specified watch service.
*
* @param watchService the {@link WatchService} to use.
*/
@Activate
public RuleFileProviderWatcher(@Reference(target = WatchService.CONFIG_WATCHER_FILTER) WatchService watchService) {
this.watchService = watchService;
}

@Override
protected void initializeWatchService(String watchingDir) {
WatchServiceUtil.initializeWatchService(watchingDir, this, watchService);
}

@Override
protected void deactivateWatchService(String watchingDir) {
WatchServiceUtil.deactivateWatchService(watchingDir, this);
}

@Reference(cardinality = ReferenceCardinality.AT_LEAST_ONE, policy = ReferencePolicy.DYNAMIC, target = "(parser.type=parser.rule)")
@Override
public void addParser(Parser<Rule> parser, Map<String, String> properties) {
super.addParser(parser, properties);
}

@Override
public void removeParser(Parser<Rule> parser, Map<String, String> properties) {
super.removeParser(parser, properties);
}

@SuppressWarnings("null")
@Override
protected void validateObject(Rule rule) throws ValidationException {
String s;
if ((s = rule.getUID()) == null || s.isBlank()) {
throw new ValidationException(ObjectType.RULE, null, "UID cannot be blank");
}
if ((s = rule.getName()) == null || s.isBlank()) {
throw new ValidationException(ObjectType.RULE, rule.getUID(), "Name cannot be blank");
}
}
}
Loading
Loading