Skip to content

Commit

Permalink
Add module actions
Browse files Browse the repository at this point in the history
  • Loading branch information
seime committed Jul 16, 2024
1 parent 06df4aa commit c5ec22a
Show file tree
Hide file tree
Showing 22 changed files with 666 additions and 145 deletions.
7 changes: 7 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ developer machine - like any other regular Java project - **recommended**).
+ [JRuleItems and JRuleItemNames](#jruleitems-and-jruleitemnames)
+ [JRuleThings](#jrulethings)
+ [JRuleThingActions](#jrulethingactions)
+ [JRuleModuleActions](#jrulemoduleactions)
* [Other built-in actions](#other-built-in-actions)
- [GUI support](#gui-support)
- [Examples](#examples)
Expand Down Expand Up @@ -274,6 +275,12 @@ Logging from rule can be done in 3 different ways

See example #34

### JRuleModuleActions

* `org.openhab.automation.jrule.generated.moduleactions` package contains a class with methods for each rule module action available.
Note that these are not specific to any item or thing, but are supplied by core and addon modules such as myopenhab.


## Other built-in actions

These are method inherited from the JRule superclass.
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,137 @@
/**
* Copyright (c) 2010-2023 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.automation.jrule.actions;

import java.io.File;
import java.io.FileWriter;
import java.util.*;

import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.openhab.automation.jrule.internal.JRuleConfig;
import org.openhab.automation.jrule.internal.JRuleConstants;
import org.openhab.automation.jrule.internal.JRuleLog;
import org.openhab.automation.jrule.internal.generator.JRuleAbstractClassGenerator;
import org.openhab.core.automation.type.ActionType;
import org.openhab.core.automation.type.ModuleTypeRegistry;
import org.openhab.core.config.core.ConfigDescriptionParameter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import freemarker.template.Template;

/**
* The {@link JRuleModuleActionClassGenerator} Class Generator for Module actions
*
* @author Arne Seime - Initial contribution
*/
public class JRuleModuleActionClassGenerator extends JRuleAbstractClassGenerator {

private static final String TEMPLATE_SUFFIX = ".ftlh";

protected static final String LOG_NAME_CLASS_GENERATOR = "JRuleModuleActionClassGen";

private final Logger logger = LoggerFactory.getLogger(JRuleModuleActionClassGenerator.class);

private ModuleTypeRegistry moduleTypeRegistry;

public JRuleModuleActionClassGenerator(JRuleConfig jRuleConfig, ModuleTypeRegistry moduleTypeRegistry) {
super(jRuleConfig);
this.moduleTypeRegistry = moduleTypeRegistry;
}

public boolean generateActionSources() {
Collection<ActionType> actions = moduleTypeRegistry.getActions();
return generateActionSource(actions);
}

public boolean generateActionSource(Collection<ActionType> action) {
try {

Map<String, Object> freemarkerModel = new HashMap<>();
freemarkerModel.put("packageName", jRuleConfig.getGeneratedModuleActionPackage());

List<Object> methods = new ArrayList<>();
freemarkerModel.put("methods", methods);

action.forEach(act -> {
Map<String, Object> actionModel = createActionModel(act);
methods.add(actionModel);
});

File targetSourceFile = new File(
new StringBuilder().append(jRuleConfig.getModuleActionsDirectory()).append(File.separator)
.append("JRuleModuleActions").append(JRuleConstants.JAVA_FILE_TYPE).toString());

try (FileWriter fileWriter = new FileWriter(targetSourceFile)) {
Template template = freemarkerConfiguration.getTemplate("module/ModuleActions" + TEMPLATE_SUFFIX);
template.process(freemarkerModel, fileWriter);
}

JRuleLog.debug(logger, LOG_NAME_CLASS_GENERATOR, "Wrote Generated class: {}",
targetSourceFile.getAbsolutePath());
return true;

} catch (Exception e) {
JRuleLog.error(logger, LOG_NAME_CLASS_GENERATOR,
"Internal error when generating java source for module actions: {}",
ExceptionUtils.getStackTrace(e));

}

return false;
}

private Map<String, Object> createActionModel(ActionType actionType) {

Map<String, Object> actionModel = new HashMap<>();
actionModel.put("name", getActionFriendlyName(actionType.getUID()));
actionModel.put("uid", actionType.getUID());
actionModel.put("description", actionType.getDescription());
actionModel.put("label", actionType.getLabel());

List<Map<String, Object>> args = new ArrayList<>();
actionModel.put("args", args);

actionType.getConfigurationDescriptions().forEach(config -> {
Map<String, Object> configMap = new HashMap<>();
configMap.put("name", config.getName());
configMap.put("type", toJavaType(config.getType()));
configMap.put("default", config.getDefault());
args.add(configMap);
});

return actionModel;
}

private Object toJavaType(ConfigDescriptionParameter.Type type) {
switch (type) {
case BOOLEAN:
return "Boolean";
case DECIMAL:
return "Double";
case INTEGER:
return "Integer";
case TEXT:
return "String";

default:
return "Object";
}
}

public static String getActionFriendlyName(String moduleUID) {
String[] split = moduleUID.split("[\\.:\\-]");
return StringUtils.uncapitalize(split[0]) + StringUtils.capitalize(split[1]);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,15 +14,7 @@

import java.io.File;
import java.io.FileWriter;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.Comparator;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeSet;
import java.util.*;
import java.util.stream.Collectors;

import org.apache.commons.lang3.ClassUtils;
Expand All @@ -43,19 +35,19 @@
import freemarker.template.Template;

/**
* The {@link JRuleActionClassGenerator} Class Generator for actions
* The {@link JRuleThingActionClassGenerator} Class Generator for Thing actions
*
* @author Robert Delbrück - Initial contribution
*/
public class JRuleActionClassGenerator extends JRuleAbstractClassGenerator {
public class JRuleThingActionClassGenerator extends JRuleAbstractClassGenerator {

private static final String TEMPLATE_SUFFIX = ".ftlh";

protected static final String LOG_NAME_CLASS_GENERATOR = "JRuleActionClassGen";

private final Logger logger = LoggerFactory.getLogger(JRuleActionClassGenerator.class);
private final Logger logger = LoggerFactory.getLogger(JRuleThingActionClassGenerator.class);

public JRuleActionClassGenerator(JRuleConfig jRuleConfig) {
public JRuleThingActionClassGenerator(JRuleConfig jRuleConfig) {
super(jRuleConfig);
}

Expand All @@ -73,7 +65,7 @@ public boolean generateActionSource(Thing thing) {

try (FileWriter fileWriter = new FileWriter(targetSourceFile)) {
Template template = freemarkerConfiguration
.getTemplate("actions/" + actionModel.get("templateName") + TEMPLATE_SUFFIX);
.getTemplate("things/actions/" + actionModel.get("templateName") + TEMPLATE_SUFFIX);
template.process(processingModel, fileWriter);
}

Expand Down Expand Up @@ -104,7 +96,7 @@ public boolean generateActionsSource(Collection<Thing> things) {
.append(File.separator).append("JRuleActions.java").toString());

try (FileWriter fileWriter = new FileWriter(targetSourceFile)) {
Template template = freemarkerConfiguration.getTemplate("actions/Actions" + TEMPLATE_SUFFIX);
Template template = freemarkerConfiguration.getTemplate("things/actions/Actions" + TEMPLATE_SUFFIX);
template.process(processingModel, fileWriter);
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ public class JRuleConfig {
private static final String GENERATED_ITEM_PREFIX_PROPERTY = "org.openhab.automation.jrule.itemprefix";
private static final String GENERATED_ITEM_PACKAGE_PROPERTY = "org.openhab.automation.jrule.itempackage";
private static final String GENERATED_THING_PACKAGE_PROPERTY = "org.openhab.automation.jrule.thingpackage";
private static final String GENERATED_MODULE_ACTION_PACKAGE_PROPERTY = "org.openhab.automation.jrule.moduleactionpackage";
private static final String EXECUTORS_MIN_PROPERTY = "org.openhab.automation.jrule.engine.executors.min";
private static final String EXECUTORS_MAX_PROPERTY = "org.openhab.automation.jrule.engine.executors.max";
private static final String EXECUTORS_ENABLE_PROPERTY = "org.openhab.automation.jrule.engine.executors.enable";
Expand All @@ -65,6 +66,7 @@ public class JRuleConfig {
private static final String DEFAULT_GENERATED_ITEM_PACKAGE = "org.openhab.automation.jrule.generated.items";
private static final String DEFAULT_GENERATED_THING_PACKAGE = "org.openhab.automation.jrule.generated.things";
private static final String DEFAULT_GENERATED_ACTION_PACKAGE = "org.openhab.automation.jrule.generated.actions";
private static final String DEFAULT_GENERATED_MODULE_ACTION_PACKAGE = "org.openhab.automation.jrule.generated.moduleactions";

private static final String CLASS_DIR = "class";

Expand Down Expand Up @@ -154,6 +156,14 @@ public String getActionsDirectory() {
return sb.toString();
}

public String getModuleActionsDirectory() {
final StringBuilder sb = new StringBuilder(getWorkingDirectory());
sb.append(File.separator).append(GEN).append(File.separator);
final String p = JRuleUtil.packageNameToPath(getGeneratedModuleActionPackage());
sb.append(p);
return sb.toString();
}

public String getJarDirectory() {
return new StringBuilder().append(getWorkingDirectory()).append(File.separator).append(JAR_DIR).toString();
}
Expand Down Expand Up @@ -253,6 +263,11 @@ public String getGeneratedActionPackage() {
return getConfigPropertyOrDefaultValue(GENERATED_THING_PACKAGE_PROPERTY, DEFAULT_GENERATED_ACTION_PACKAGE);
}

public String getGeneratedModuleActionPackage() {
return getConfigPropertyOrDefaultValue(GENERATED_MODULE_ACTION_PACKAGE_PROPERTY,
DEFAULT_GENERATED_MODULE_ACTION_PACKAGE);
}

public int getRulesInitDelaySeconds() {
return getIntConfigProperty(INIT_RULES_DELAY_PROPERTY, DEFAULT_RULES_INIT_DELAY);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
package org.openhab.automation.jrule.internal;

import java.util.Map;
import java.util.Set;
import java.util.concurrent.CopyOnWriteArraySet;
import java.util.concurrent.TimeUnit;

import org.eclipse.jdt.annotation.NonNullByDefault;
Expand All @@ -23,6 +25,8 @@
import org.openhab.automation.jrule.internal.module.JRuleRuleProvider;
import org.openhab.automation.jrule.items.JRuleItemRegistry;
import org.openhab.core.audio.AudioHTTPServer;
import org.openhab.core.automation.handler.ModuleHandlerFactory;
import org.openhab.core.automation.type.ModuleTypeRegistry;
import org.openhab.core.events.EventPublisher;
import org.openhab.core.items.ItemRegistry;
import org.openhab.core.items.MetadataRegistry;
Expand All @@ -35,10 +39,7 @@
import org.openhab.core.voice.VoiceManager;
import org.osgi.framework.FrameworkUtil;
import org.osgi.service.component.ComponentContext;
import org.osgi.service.component.annotations.Activate;
import org.osgi.service.component.annotations.Component;
import org.osgi.service.component.annotations.Deactivate;
import org.osgi.service.component.annotations.Reference;
import org.osgi.service.component.annotations.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

Expand All @@ -61,6 +62,8 @@ public class JRuleFactory {

private final JRuleDelayedDebouncingExecutor delayedInit = new JRuleDelayedDebouncingExecutor(5, TimeUnit.SECONDS);

private Set<ModuleHandlerFactory> allModuleHandlerFactories = new CopyOnWriteArraySet<>();

@Activate
public JRuleFactory(Map<String, Object> properties, final @Reference JRuleEventSubscriber eventSubscriber,
final @Reference ItemRegistry itemRegistry,
Expand All @@ -71,7 +74,8 @@ public JRuleFactory(Map<String, Object> properties, final @Reference JRuleEventS
final @Reference NetworkAddressService networkAddressService, final ComponentContext componentContext,
final @Reference CronScheduler cronScheduler, final @Reference MetadataRegistry metadataRegistry,
final @Reference JRuleRuleProvider ruleProvider,
@Reference final PersistenceServiceRegistry persistenceServiceRegistry) {
@Reference final PersistenceServiceRegistry persistenceServiceRegistry,
@Reference ModuleTypeRegistry moduleTypeRegistry) {
JRuleConfig config = new JRuleConfig(properties);
config.initConfig();
jRuleEngine = JRuleEngine.get();
Expand All @@ -85,10 +89,20 @@ public JRuleFactory(Map<String, Object> properties, final @Reference JRuleEventS
JRuleItemRegistry.setMetadataRegistry(metadataRegistry);
jRuleHandler = new JRuleHandler(config, itemRegistry, itemChannelLinkRegistry, thingRegistry, thingManager,
eventPublisher, eventSubscriber, voiceManager, audioHTTPServer, networkAddressService, cronScheduler,
componentContext.getBundleContext(), metadataRegistry);
componentContext.getBundleContext(), metadataRegistry, moduleTypeRegistry, allModuleHandlerFactories);
delayedInit.call(this::init);
}

@Reference(cardinality = ReferenceCardinality.MULTIPLE, policy = ReferencePolicy.DYNAMIC)
protected void addModuleHandlerFactory(ModuleHandlerFactory moduleHandlerFactory) {
logger.debug("ModuleHandlerFactory added {}", moduleHandlerFactory.getClass().getSimpleName());
allModuleHandlerFactories.add(moduleHandlerFactory);
}

protected void removeModuleHandlerFactory(ModuleHandlerFactory moduleHandlerFactory) {
allModuleHandlerFactories.remove(moduleHandlerFactory);
}

@Nullable
private Boolean init() {
JRuleLog.info(logger, LOG_NAME_FACTORY, "Initializing Java Rules Engine v{}", getBundleVersion());
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -229,7 +229,8 @@ private boolean compileGeneratedSource(File sourceFolder) {
return compile(List.of(new File(jRuleConfig.getItemsDirectory(), "JRuleItems.java"),
new File(jRuleConfig.getItemsDirectory(), "JRuleItemNames.java"),
new File(jRuleConfig.getThingsDirectory(), "JRuleThings.java"),
new File(jRuleConfig.getActionsDirectory(), "JRuleActions.java")), genClassPath);
new File(jRuleConfig.getActionsDirectory(), "JRuleActions.java"),
new File(jRuleConfig.getModuleActionsDirectory(), "JRuleModuleActions.java")), genClassPath);
}

public boolean compile(List<File> javaSourceFiles, String classPath) {
Expand Down
Loading

0 comments on commit c5ec22a

Please sign in to comment.