Refactor ScriptExecution to plain Java ScriptExtension (#3155)

* Refactor ScriptExecution to plain Java ScriptExtension
* keep callScript backward compatible

Signed-off-by: Jan N. Klug <github@klug.nrw>
This commit is contained in:
J-N-K 2022-11-19 20:29:58 +01:00 committed by GitHub
parent 06c0e90535
commit c340e8db6c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
10 changed files with 305 additions and 70 deletions

View File

@ -0,0 +1,69 @@
/**
* Copyright (c) 2010-2022 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.module.script.action;
import java.time.ZonedDateTime;
import java.util.function.Consumer;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
/**
* The {@link ScriptExecution} allows creating timers for asynchronous script execution
*
* @author Jan N. Klug - Initial contribution
*/
@NonNullByDefault
public interface ScriptExecution {
/**
* Schedules a block of code for later execution.
*
* @param zonedDateTime the point in time when the code should be executed
* @param closure the code block to execute
* @return a handle to the created timer, so that it can be canceled or rescheduled
*/
Timer createTimer(ZonedDateTime zonedDateTime, Runnable closure);
/**
* Schedules a block of code for later execution.
*
* @param identifier an optional identifier
* @param zonedDateTime the point in time when the code should be executed
* @param closure the code block to execute
* @return a handle to the created timer, so that it can be canceled or rescheduled
*/
Timer createTimer(@Nullable String identifier, ZonedDateTime zonedDateTime, Runnable closure);
/**
* Schedules a block of code (with argument) for later execution
*
* @param zonedDateTime the point in time when the code should be executed
* @param arg1 the argument to pass to the code block
* @param closure the code block to execute
* @return a handle to the created timer, so that it can be canceled or rescheduled
*/
Timer createTimerWithArgument(ZonedDateTime zonedDateTime, Object arg1, Consumer<Object> closure);
/**
* Schedules a block of code (with argument) for later execution
*
* @param identifier an optional identifier
* @param zonedDateTime the point in time when the code should be executed
* @param arg1 the argument to pass to the code block
* @param closure the code block to execute
* @return a handle to the created timer, so that it can be canceled or rescheduled
*/
Timer createTimerWithArgument(@Nullable String identifier, ZonedDateTime zonedDateTime, Object arg1,
Consumer<Object> closure);
}

View File

@ -10,7 +10,7 @@
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.core.model.script.actions;
package org.openhab.core.automation.module.script.action;
import java.time.ZonedDateTime;

View File

@ -0,0 +1,77 @@
/**
* Copyright (c) 2010-2022 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.module.script.internal.action;
import java.util.Collection;
import java.util.Map;
import java.util.Set;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.automation.module.script.ScriptExtensionProvider;
import org.openhab.core.automation.module.script.action.ScriptExecution;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
/**
* This is a scope provider for script actions that were available in openHAB 1 DSL rules
*
* @author Jan N. Klug - Initial contribution
*/
@Component(immediate = true)
@NonNullByDefault
public class ScriptActionScriptScopeProvider implements ScriptExtensionProvider {
private static final String PRESET_ACTIONS = "ScriptAction";
private final Map<String, Object> elements;
@Activate
public ScriptActionScriptScopeProvider(final @Reference ScriptExecution scriptExecution) {
elements = Map.of("scriptExecution", scriptExecution);
}
@Override
public Collection<String> getDefaultPresets() {
return Set.of();
}
@Override
public Collection<String> getPresets() {
return Set.of(PRESET_ACTIONS);
}
@Override
public Collection<String> getTypes() {
return elements.keySet();
}
@Override
public @Nullable Object get(String scriptIdentifier, String type) {
return elements.get(type);
}
@Override
public Map<String, Object> importPreset(String scriptIdentifier, String preset) {
if (PRESET_ACTIONS.equals(preset)) {
return elements;
}
return Map.of();
}
@Override
public void unload(String scriptIdentifier) {
// nothing todo
}
}

View File

@ -0,0 +1,71 @@
/**
* Copyright (c) 2010-2022 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.module.script.internal.action;
import java.time.ZonedDateTime;
import java.util.function.Consumer;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.automation.RuleManager;
import org.openhab.core.automation.RuleRegistry;
import org.openhab.core.automation.module.script.action.ScriptExecution;
import org.openhab.core.automation.module.script.action.Timer;
import org.openhab.core.scheduler.Scheduler;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
/**
* The static methods of this class are made available as functions in the scripts.
* This allows a script to call another script, which is available as a file.
*
* @author Kai Kreuzer - Initial contribution
*/
@Component(immediate = true, service = ScriptExecution.class)
@NonNullByDefault
public class ScriptExecutionImpl implements ScriptExecution {
private final Scheduler scheduler;
private final RuleManager ruleManager;
private final RuleRegistry ruleRegistry;
@Activate
public ScriptExecutionImpl(@Reference RuleRegistry ruleRegistry, @Reference RuleManager ruleManager,
@Reference Scheduler scheduler) {
this.ruleRegistry = ruleRegistry;
this.scheduler = scheduler;
this.ruleManager = ruleManager;
}
@Override
public Timer createTimer(ZonedDateTime zonedDateTime, Runnable runnable) {
return createTimer(null, zonedDateTime, runnable);
}
@Override
public Timer createTimer(@Nullable String identifier, ZonedDateTime zonedDateTime, Runnable runnable) {
return new TimerImpl(scheduler, zonedDateTime, runnable::run, identifier);
}
@Override
public Timer createTimerWithArgument(ZonedDateTime zonedDateTime, Object arg1, Consumer<Object> consumer) {
return createTimerWithArgument(null, zonedDateTime, arg1, consumer);
}
@Override
public Timer createTimerWithArgument(@Nullable String identifier, ZonedDateTime zonedDateTime, Object arg1,
Consumer<Object> consumer) {
return new TimerImpl(scheduler, zonedDateTime, () -> consumer.accept(arg1), identifier);
}
}

View File

@ -10,14 +10,14 @@
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.core.model.script.internal.actions;
package org.openhab.core.automation.module.script.internal.action;
import java.time.ZonedDateTime;
import java.util.concurrent.TimeUnit;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.model.script.actions.Timer;
import org.openhab.core.automation.module.script.action.Timer;
import org.openhab.core.scheduler.ScheduledCompletableFuture;
import org.openhab.core.scheduler.Scheduler;
import org.openhab.core.scheduler.SchedulerRunnable;

View File

@ -10,7 +10,7 @@
*
* SPDX-License-Identifier: EPL-2.0
*/
package org.openhab.core.model.script.internal.actions;
package org.openhab.core.automation.module.script;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
@ -21,8 +21,9 @@ import java.util.concurrent.TimeUnit;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.openhab.core.automation.module.script.action.Timer;
import org.openhab.core.automation.module.script.internal.action.TimerImpl;
import org.openhab.core.internal.scheduler.SchedulerImpl;
import org.openhab.core.model.script.actions.Timer;
import org.openhab.core.scheduler.SchedulerRunnable;
/**

View File

@ -20,6 +20,7 @@ Export-Package: org.openhab.core.model.script,\
Import-Package: \
org.openhab.core.audio,\
org.openhab.core.common.registry,\
org.openhab.core.automation.module.script.action,\
org.openhab.core.ephemeris,\
org.openhab.core.events,\
org.openhab.core.items,\

View File

@ -50,6 +50,11 @@
<artifactId>org.openhab.core.io.net</artifactId>
<version>${project.version}</version>
</dependency>
<dependency>
<groupId>org.openhab.core.bundles</groupId>
<artifactId>org.openhab.core.automation.module.script</artifactId>
<version>${project.version}</version>
</dependency>
</dependencies>
<build>

View File

@ -12,28 +12,33 @@
*/
package org.openhab.core.model.script.actions;
import java.time.ZonedDateTime;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.eclipse.xtext.xbase.XExpression;
import org.eclipse.xtext.xbase.lib.Procedures.Procedure0;
import org.eclipse.xtext.xbase.lib.Procedures.Procedure1;
import org.eclipse.xtext.xbase.lib.Procedures;
import org.openhab.core.automation.module.script.action.Timer;
import org.openhab.core.model.core.ModelRepository;
import org.openhab.core.model.script.ScriptServiceUtil;
import org.openhab.core.model.script.engine.Script;
import org.openhab.core.model.script.engine.ScriptEngine;
import org.openhab.core.model.script.engine.ScriptExecutionException;
import org.openhab.core.model.script.internal.actions.TimerImpl;
import org.openhab.core.scheduler.Scheduler;
import org.openhab.core.model.script.engine.action.ActionDoc;
import org.openhab.core.model.script.internal.engine.action.ScriptExecutionActionService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.time.ZonedDateTime;
/**
* The static methods of this class are made available as functions in the scripts.
* This allows a script to call another script, which is available as a file.
* The {@link ScriptExecution} is a wrapper for the ScriptExecution actions
*
* @author Kai Kreuzer - Initial contribution
* @author Jan N. Klug - Initial contribution
*/
@NonNullByDefault
public class ScriptExecution {
private static final Logger logger = LoggerFactory.getLogger(ScriptExecution.class);
/**
* Calls a script which must be located in the configurations/scripts folder.
*
@ -43,6 +48,7 @@ public class ScriptExecution {
* @return the return value of the script
* @throws ScriptExecutionException if an error occurs during the execution
*/
@ActionDoc(text = "call a script file")
public static Object callScript(String scriptName) throws ScriptExecutionException {
ModelRepository repo = ScriptServiceUtil.getModelRepository();
if (repo != null) {
@ -67,67 +73,23 @@ public class ScriptExecution {
}
}
/**
* Schedules a block of code for later execution.
*
* @param instant the point in time when the code should be executed
* @param closure the code block to execute
*
* @return a handle to the created timer, so that it can be canceled or rescheduled
* @throws ScriptExecutionException if an error occurs during the execution
*/
public static Timer createTimer(ZonedDateTime instant, Procedure0 closure) {
return createTimer(null, instant, closure);
@ActionDoc(text = "create a timer")
public static Timer createTimer(ZonedDateTime zonedDateTime, Procedures.Procedure0 closure) {
return ScriptExecutionActionService.getScriptExecution().createTimer(zonedDateTime, closure::apply);
}
/**
* Schedules a block of code for later execution.
*
* @param identifier an optional identifier
* @param instant the point in time when the code should be executed
* @param closure the code block to execute
*
* @return a handle to the created timer, so that it can be canceled or rescheduled
* @throws ScriptExecutionException if an error occurs during the execution
*/
public static Timer createTimer(@Nullable String identifier, ZonedDateTime instant, Procedure0 closure) {
Scheduler scheduler = ScriptServiceUtil.getScheduler();
return new TimerImpl(scheduler, instant, () -> {
closure.apply();
}, identifier);
@ActionDoc(text = "create an identifiable timer ")
public static Timer createTimer(@Nullable String identifier, ZonedDateTime zonedDateTime, Procedures.Procedure0 closure) {
return ScriptExecutionActionService.getScriptExecution().createTimer(identifier, zonedDateTime, closure::apply);
}
/**
* Schedules a block of code (with argument) for later execution
*
* @param instant the point in time when the code should be executed
* @param arg1 the argument to pass to the code block
* @param closure the code block to execute
*
* @return a handle to the created timer, so that it can be canceled or rescheduled
* @throws ScriptExecutionException if an error occurs during the execution
*/
public static Timer createTimerWithArgument(ZonedDateTime instant, Object arg1, Procedure1<Object> closure) {
return createTimerWithArgument(null, instant, arg1, closure);
@ActionDoc(text = "create a timer with argument")
public static Timer createTimerWithArgument(ZonedDateTime zonedDateTime, Object arg1, Procedures.Procedure1 closure) {
return ScriptExecutionActionService.getScriptExecution().createTimerWithArgument(zonedDateTime, arg1, closure::apply);
}
/**
* Schedules a block of code (with argument) for later execution
*
* @param identifier an optional identifier
* @param instant the point in time when the code should be executed
* @param arg1 the argument to pass to the code block
* @param closure the code block to execute
*
* @return a handle to the created timer, so that it can be canceled or rescheduled
* @throws ScriptExecutionException if an error occurs during the execution
*/
public static Timer createTimerWithArgument(@Nullable String identifier, ZonedDateTime instant, Object arg1, Procedure1<Object> closure) {
Scheduler scheduler = ScriptServiceUtil.getScheduler();
return new TimerImpl(scheduler, instant, () -> {
closure.apply(arg1);
}, identifier);
@ActionDoc(text = "create an identifiable timer with argument")
public static Timer createTimerWithArgument(@Nullable String identifier, ZonedDateTime zonedDateTime, Object arg1, Procedures.Procedure1 closure) {
return ScriptExecutionActionService.getScriptExecution().createTimerWithArgument(identifier, zonedDateTime, arg1, closure::apply);
}
}

View File

@ -0,0 +1,49 @@
/**
* Copyright (c) 2010-2022 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.model.script.internal.engine.action;
import org.eclipse.jdt.annotation.NonNullByDefault;
import org.eclipse.jdt.annotation.Nullable;
import org.openhab.core.automation.module.script.action.ScriptExecution;
import org.openhab.core.model.script.engine.action.ActionService;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Reference;
import java.util.Objects;
/**
* This class registers an OSGi service for the ScriptExecution action.
*
* @author Jan N. Klug - Initial contribution
*/
@Component(immediate = true)
@NonNullByDefault
public class ScriptExecutionActionService implements ActionService {
private static @Nullable ScriptExecution scriptExecution;
@Activate
public ScriptExecutionActionService(final @Reference ScriptExecution scriptExecution) {
ScriptExecutionActionService.scriptExecution = scriptExecution;
}
@Override
public Class<?> getActionClass() {
return ScriptExecution.class;
}
public static ScriptExecution getScriptExecution() {
return Objects.requireNonNull(scriptExecution);
}
}