Skip to content

Commit fd4cc51

Browse files
author
Ravi Nadahar
committed
Add file based rule provider and YAML rule parser
Signed-off-by: Ravi Nadahar <[email protected]>
1 parent 1a67b88 commit fd4cc51

File tree

4 files changed

+202
-1
lines changed

4 files changed

+202
-1
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
/*
2+
* Copyright (c) 2010-2025 Contributors to the openHAB project
3+
*
4+
* See the NOTICE file(s) distributed with this work for additional
5+
* information.
6+
*
7+
* This program and the accompanying materials are made available under the
8+
* terms of the Eclipse Public License 2.0 which is available at
9+
* http://www.eclipse.org/legal/epl-2.0
10+
*
11+
* SPDX-License-Identifier: EPL-2.0
12+
*/
13+
package org.openhab.core.automation.internal.parser.jackson;
14+
15+
import java.io.IOException;
16+
import java.io.InputStreamReader;
17+
import java.util.HashSet;
18+
import java.util.List;
19+
import java.util.Set;
20+
21+
import org.eclipse.jdt.annotation.NonNullByDefault;
22+
import org.openhab.core.automation.Rule;
23+
import org.openhab.core.automation.dto.RuleDTO;
24+
import org.openhab.core.automation.dto.RuleDTOMapper;
25+
import org.openhab.core.automation.parser.Parser;
26+
import org.openhab.core.automation.parser.ParsingException;
27+
import org.openhab.core.automation.parser.ParsingNestedException;
28+
import org.osgi.service.component.annotations.Component;
29+
30+
import com.fasterxml.jackson.core.type.TypeReference;
31+
import com.fasterxml.jackson.databind.JsonNode;
32+
33+
/**
34+
* This class can parse and serialize sets of {@link Rule}s.
35+
*
36+
* @author Ravi Nadahar - Initial contribution
37+
*/
38+
@NonNullByDefault
39+
@Component(immediate = true, service = Parser.class, property = { "parser.type=parser.rule", "format=yaml" })
40+
public class RuleYAMLParser extends AbstractJacksonYAMLParser<Rule> {
41+
42+
@Override
43+
public Set<Rule> parse(InputStreamReader reader) throws ParsingException {
44+
try {
45+
Set<Rule> rules = new HashSet<>();
46+
JsonNode rootNode = YAML_MAPPER.readTree(reader);
47+
if (rootNode.isArray()) {
48+
List<RuleDTO> ruleDtos = YAML_MAPPER.convertValue(rootNode, new TypeReference<List<RuleDTO>>() {
49+
});
50+
for (RuleDTO ruleDTO : ruleDtos) {
51+
rules.add(RuleDTOMapper.map(ruleDTO));
52+
}
53+
} else {
54+
RuleDTO ruleDto = YAML_MAPPER.convertValue(rootNode, new TypeReference<RuleDTO>() {
55+
});
56+
rules.add(RuleDTOMapper.map(ruleDto));
57+
}
58+
return rules;
59+
} catch (Exception e) {
60+
throw new ParsingException(new ParsingNestedException(ParsingNestedException.RULE, null, e));
61+
} finally {
62+
try {
63+
reader.close();
64+
} catch (IOException e) {
65+
}
66+
}
67+
}
68+
}

bundles/org.openhab.core.automation/src/main/java/org/openhab/core/automation/internal/provider/file/AbstractFileProvider.java

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -225,6 +225,7 @@ public void removeParser(Parser<E> parser, Map<String, String> properties) {
225225
* @param url a specified URL for import.
226226
*/
227227
protected void importFile(String parserType, URL url) {
228+
logger.debug("Reading file \"{}\"", url);
228229
Parser<E> parser = parsers.get(parserType);
229230
if (parser != null) {
230231
InputStream is = null;
@@ -258,7 +259,7 @@ protected void importFile(String parserType, URL url) {
258259
List<URL> value = Objects.requireNonNull(urls.computeIfAbsent(parserType, k -> new ArrayList<>()));
259260
value.add(url);
260261
}
261-
logger.debug("Parser {} not available", parserType, new Exception());
262+
logger.debug("Couldn't parse \"{}\", no \"{}\" parser available", url, parserType);
262263
}
263264
}
264265

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
/*
2+
* Copyright (c) 2010-2025 Contributors to the openHAB project
3+
*
4+
* See the NOTICE file(s) distributed with this work for additional
5+
* information.
6+
*
7+
* This program and the accompanying materials are made available under the
8+
* terms of the Eclipse Public License 2.0 which is available at
9+
* http://www.eclipse.org/legal/epl-2.0
10+
*
11+
* SPDX-License-Identifier: EPL-2.0
12+
*/
13+
package org.openhab.core.automation.internal.provider.file;
14+
15+
import java.util.Collection;
16+
import java.util.List;
17+
18+
import org.eclipse.jdt.annotation.NonNullByDefault;
19+
import org.openhab.core.automation.Rule;
20+
import org.openhab.core.automation.RuleProvider;
21+
22+
/**
23+
* This class is a {@link RuleProvider} implementation that provides file-based rules. It extends the functionality
24+
* of {@link AbstractFileProvider} for importing the {@link Rule}s from local files.
25+
*
26+
* @author Ravi Nadahar - Initial contribution
27+
*/
28+
@NonNullByDefault
29+
public abstract class RuleFileProvider extends AbstractFileProvider<Rule> implements RuleProvider {
30+
31+
/**
32+
* Creates a new instance.
33+
*/
34+
public RuleFileProvider() {
35+
super("rules");
36+
}
37+
38+
@Override
39+
protected String getUID(Rule providedObject) {
40+
return providedObject.getUID();
41+
}
42+
43+
@Override
44+
public Collection<Rule> getAll() {
45+
return List.copyOf(providedObjectsHolder.values());
46+
}
47+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
/*
2+
* Copyright (c) 2010-2025 Contributors to the openHAB project
3+
*
4+
* See the NOTICE file(s) distributed with this work for additional
5+
* information.
6+
*
7+
* This program and the accompanying materials are made available under the
8+
* terms of the Eclipse Public License 2.0 which is available at
9+
* http://www.eclipse.org/legal/epl-2.0
10+
*
11+
* SPDX-License-Identifier: EPL-2.0
12+
*/
13+
package org.openhab.core.automation.internal.provider.file;
14+
15+
import java.util.Map;
16+
17+
import org.eclipse.jdt.annotation.NonNullByDefault;
18+
import org.openhab.core.OpenHAB;
19+
import org.openhab.core.automation.Rule;
20+
import org.openhab.core.automation.RuleProvider;
21+
import org.openhab.core.automation.parser.Parser;
22+
import org.openhab.core.automation.parser.ValidationException;
23+
import org.openhab.core.automation.parser.ValidationException.ObjectType;
24+
import org.openhab.core.service.WatchService;
25+
import org.osgi.service.component.annotations.Activate;
26+
import org.osgi.service.component.annotations.Component;
27+
import org.osgi.service.component.annotations.Reference;
28+
import org.osgi.service.component.annotations.ReferenceCardinality;
29+
import org.osgi.service.component.annotations.ReferencePolicy;
30+
31+
/**
32+
* This class is a wrapper of {@link RuleFileProvider}s, responsible for initializing the WatchService.
33+
*
34+
* @author Ravi Nadahar - Initial contribution
35+
*/
36+
@NonNullByDefault
37+
@Component(immediate = true, service = RuleProvider.class)
38+
public class RuleFileProviderWatcher extends RuleFileProvider {
39+
40+
private final WatchService watchService;
41+
42+
/**
43+
* Creates a new instance using the specified watch service.
44+
*
45+
* @param watchService the {@link WatchService} to use.
46+
*/
47+
@Activate
48+
public RuleFileProviderWatcher(@Reference(target = WatchService.CONFIG_WATCHER_FILTER) WatchService watchService) {
49+
this.watchService = watchService;
50+
configurationRoots = new String[] { OpenHAB.getConfigFolder() };
51+
}
52+
53+
@Override
54+
protected void initializeWatchService(String watchingDir) {
55+
WatchServiceUtil.initializeWatchService(watchingDir, this, watchService);
56+
}
57+
58+
@Override
59+
protected void deactivateWatchService(String watchingDir) {
60+
WatchServiceUtil.deactivateWatchService(watchingDir, this);
61+
}
62+
63+
@Reference(cardinality = ReferenceCardinality.AT_LEAST_ONE, policy = ReferencePolicy.DYNAMIC, target = "(parser.type=parser.rule)")
64+
@Override
65+
public void addParser(Parser<Rule> parser, Map<String, String> properties) {
66+
super.addParser(parser, properties);
67+
}
68+
69+
@Override
70+
public void removeParser(Parser<Rule> parser, Map<String, String> properties) {
71+
super.removeParser(parser, properties);
72+
}
73+
74+
@SuppressWarnings("null")
75+
@Override
76+
protected void validateObject(Rule rule) throws ValidationException {
77+
String s;
78+
if ((s = rule.getUID()) == null || s.isBlank()) {
79+
throw new ValidationException(ObjectType.RULE, null, "UID cannot be blank");
80+
}
81+
if ((s = rule.getName()) == null || s.isBlank()) {
82+
throw new ValidationException(ObjectType.RULE, rule.getUID(), "Name cannot be blank");
83+
}
84+
}
85+
}

0 commit comments

Comments
 (0)