Skip to content

Commit

Permalink
Add file based rule provider and YAML rule parser
Browse files Browse the repository at this point in the history
Signed-off-by: Ravi Nadahar <nadahar@rediffmail.com>
  • Loading branch information
Ravi Nadahar committed Feb 13, 2025
1 parent 07fbfd1 commit ba2b127
Show file tree
Hide file tree
Showing 4 changed files with 202 additions and 1 deletion.
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
/*
* 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.parser.jackson;

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

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.openhab.core.automation.Rule;
import org.openhab.core.automation.dto.RuleDTO;
import org.openhab.core.automation.dto.RuleDTOMapper;
import org.openhab.core.automation.parser.Parser;
import org.openhab.core.automation.parser.ParsingException;
import org.openhab.core.automation.parser.ParsingNestedException;
import org.osgi.service.component.annotations.Component;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;

/**
* This class can parse and serialize sets of {@link Rule}s.
*
* @author Ravi Nadahar - Initial contribution
*/
@NonNullByDefault
@Component(immediate = true, service = Parser.class, property = { "parser.type=parser.rule", "format=yaml" })
public class RuleYAMLParser extends AbstractJacksonYAMLParser<Rule> {

@Override
public Set<Rule> parse(InputStreamReader reader) throws ParsingException {
try {
Set<Rule> rules = new HashSet<>();
JsonNode rootNode = yamlMapper.readTree(reader);
if (rootNode.isArray()) {
List<RuleDTO> ruleDtos = yamlMapper.convertValue(rootNode, new TypeReference<List<RuleDTO>>() {
});
for (RuleDTO ruleDTO : ruleDtos) {
rules.add(RuleDTOMapper.map(ruleDTO));
}
} else {
RuleDTO ruleDto = yamlMapper.convertValue(rootNode, new TypeReference<RuleDTO>() {
});
rules.add(RuleDTOMapper.map(ruleDto));
}
return rules;
} catch (Exception e) {
throw new ParsingException(new ParsingNestedException(ParsingNestedException.RULE, null, e));
} finally {
try {
reader.close();
} catch (IOException e) {
}
}
}
}
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,85 @@
/*
* 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.OpenHAB;
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;
configurationRoots = new String[] { OpenHAB.getConfigFolder() };
}

@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");
}
}
}

0 comments on commit ba2b127

Please sign in to comment.