Skip to content
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
@@ -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");
}
}
}
5 changes: 5 additions & 0 deletions bundles/org.openhab.core.model.yaml/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -35,5 +35,10 @@
<artifactId>org.openhab.core.thing</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.openhab.core.bundles</groupId>
<artifactId>org.openhab.core.automation</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
</project>
Original file line number Diff line number Diff line change
Expand Up @@ -37,11 +37,15 @@

import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.io.dto.ModularDTO;
import org.openhab.core.io.dto.SerializationException;
import org.openhab.core.model.yaml.YamlElement;
import org.openhab.core.model.yaml.YamlElementName;
import org.openhab.core.model.yaml.YamlModelListener;
import org.openhab.core.model.yaml.YamlModelRepository;
import org.openhab.core.model.yaml.internal.items.YamlItemDTO;
import org.openhab.core.model.yaml.internal.rules.YamlRuleDTO;
import org.openhab.core.model.yaml.internal.rules.YamlRuleTemplateDTO;
import org.openhab.core.model.yaml.internal.semantics.YamlSemanticTagDTO;
import org.openhab.core.model.yaml.internal.things.YamlThingDTO;
import org.openhab.core.service.WatchService;
Expand Down Expand Up @@ -87,6 +91,8 @@ public class YamlModelRepositoryImpl implements WatchService.WatchEventListener,
private static final String VERSION = "version";
private static final String READ_ONLY = "readOnly";
private static final Set<String> KNOWN_ELEMENTS = Set.of( //
getElementName(YamlRuleDTO.class), // "rules"
getElementName(YamlRuleTemplateDTO.class), // "ruleTemplates"
getElementName(YamlSemanticTagDTO.class), // "tags"
getElementName(YamlThingDTO.class), // "things"
getElementName(YamlItemDTO.class) // "items"
Expand Down Expand Up @@ -621,20 +627,22 @@ private <T extends YamlElement> List<T> parseJsonMapNode(@Nullable JsonNode mapN
T elt = null;
JsonNode node = mapNode.get(id);
if (node.isEmpty()) {
try {
elt = elementClass.getDeclaredConstructor().newInstance();
elt = createElement(elementClass, errors);
if (elt != null) {
elt.setId(id);
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException
| InvocationTargetException | NoSuchMethodException | SecurityException e) {
if (errors != null) {
errors.add("could not create new instance of %s".formatted(elementClass.getSimpleName()));
}
}
} else {
try {
elt = objectMapper.treeToValue(node, elementClass);
elt.setId(id);
} catch (JsonProcessingException e) {
if (ModularDTO.class.isAssignableFrom(elementClass)) {
elt = modularToDto(node, elementClass, errors);
if (elt != null) {
elt.setId(id);
}
} else {
elt = objectMapper.treeToValue(node, elementClass);
elt.setId(id);
}
} catch (JsonProcessingException | SerializationException e) {
if (errors != null) {
String msg = e.getMessage();
errors.add("could not parse element %s to %s: %s".formatted(node.toPrettyString(),
Expand All @@ -650,4 +658,29 @@ private <T extends YamlElement> List<T> parseJsonMapNode(@Nullable JsonNode mapN
}
return elements;
}

@SuppressWarnings("unchecked")
private <T extends YamlElement> @Nullable T modularToDto(JsonNode node, Class<T> elementClass,
@Nullable List<String> errors) throws SerializationException {
@Nullable
T result = createElement(elementClass, errors);
if (result != null) {
result = (T) ((ModularDTO<?, ObjectMapper, JsonNode>) result).toDto(node, objectMapper);
}
return result;
}

private <T extends YamlElement> @Nullable T createElement(Class<T> elementClass, @Nullable List<String> errors) {
@Nullable
T result = null;
try {
result = elementClass.getDeclaredConstructor().newInstance();
} catch (InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException
| NoSuchMethodException | SecurityException e) {
if (errors != null) {
errors.add("could not create new instance of %s".formatted(elementClass.getSimpleName()));
}
}
return result;
}
}
Loading