/** * Copyright (c) 1997, 2015 by ProSyst Software GmbH and others. * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html */ package org.eclipse.smarthome.automation.core.internal.composite; import java.util.Collection; import java.util.LinkedHashMap; import java.util.List; import java.util.Map; import java.util.Set; import org.eclipse.smarthome.automation.Action; import org.eclipse.smarthome.automation.Condition; import org.eclipse.smarthome.automation.Module; import org.eclipse.smarthome.automation.Trigger; import org.eclipse.smarthome.automation.core.internal.ReferenceResolverUtil; import org.eclipse.smarthome.automation.core.internal.RuleEngine; import org.eclipse.smarthome.automation.handler.ActionHandler; import org.eclipse.smarthome.automation.handler.BaseModuleHandlerFactory; import org.eclipse.smarthome.automation.handler.ConditionHandler; import org.eclipse.smarthome.automation.handler.ModuleHandler; import org.eclipse.smarthome.automation.handler.ModuleHandlerFactory; import org.eclipse.smarthome.automation.handler.TriggerHandler; import org.eclipse.smarthome.automation.type.CompositeActionType; import org.eclipse.smarthome.automation.type.CompositeConditionType; import org.eclipse.smarthome.automation.type.CompositeTriggerType; import org.eclipse.smarthome.automation.type.ModuleType; import org.eclipse.smarthome.automation.type.ModuleTypeRegistry; import org.eclipse.smarthome.config.core.Configuration; import org.osgi.framework.BundleContext; import org.slf4j.Logger; import org.slf4j.LoggerFactory; /** * This class is a factory for system module handler for modules of composite module types: {@link CompositeTriggerType} * , {@link CompositeConditionType} and {@link CompositeActionType}. The composite module type is a type which contains * one or more internal (child) modules and these modules have access to configuration properties and inputs of * composite module. The outputs of module of composite type (if they exists) are set these handlers and they are base * on the values of child module outputs. * The {@link CompositeModuleHandlerFactory} is a system handler factory and it is not registered as service in OSGi * framework, but it will be used by the rule engine to serve composite module types without any action of the user. * * * @author Yordan Mihaylov - Initial Contribution */ public class CompositeModuleHandlerFactory extends BaseModuleHandlerFactory implements ModuleHandlerFactory { private ModuleTypeRegistry mtRegistry; private RuleEngine ruleEngine; private Logger logger = LoggerFactory.getLogger(getClass()); /** * The constructor of system handler factory for composite module types * * @param bc is a bundle context * @param mtManager is a module type manager * @param re is a rule engine */ public CompositeModuleHandlerFactory(BundleContext bc, ModuleTypeRegistry mtRegistry, RuleEngine re) { this.mtRegistry = mtRegistry; this.ruleEngine = re; activate(bc); } /** * It is system factory and must not be registered as service. This method is not used. * * @see org.eclipse.smarthome.automation.handler.ModuleHandlerFactory#getTypes() */ @Override public Collection<String> getTypes() { return null; } @SuppressWarnings({ "unchecked" }) @Override public void ungetHandler(Module module, String childModulePrefix, ModuleHandler handler) { ModuleHandler handlerOfModule = getHandlers().get(childModulePrefix + module.getId()); if (handlerOfModule instanceof AbstractCompositeModuleHandler) { AbstractCompositeModuleHandler<Module, ?, ?> h = (AbstractCompositeModuleHandler<Module, ?, ?>) handlerOfModule; Set<Module> modules = h.moduleHandlerMap.keySet(); if (modules != null) { for (Module child : modules) { ModuleHandler childHandler = h.moduleHandlerMap.get(child); ModuleHandlerFactory mhf = ruleEngine.getModuleHandlerFactory(child.getTypeUID()); mhf.ungetHandler(child, childModulePrefix + ":" + module.getId(), childHandler); } } } String ruleId = getRuleId(childModulePrefix); super.ungetHandler(module, ruleId, handler); } private String getRuleId(String childModulePrefix) { int i = childModulePrefix.indexOf(':'); String ruleId = i != -1 ? childModulePrefix.substring(0, i) : childModulePrefix; return ruleId; } @Override public ModuleHandler internalCreate(Module module, String ruleUID) { ModuleHandler handler = null; if (module != null) { String moduleType = module.getTypeUID(); ModuleType mt = mtRegistry.get(moduleType); if (mt instanceof CompositeTriggerType) { List<Trigger> childModules = ((CompositeTriggerType) mt).getChildren(); LinkedHashMap<Trigger, TriggerHandler> mapModuleToHandler = getChildHandlers(module.getId(), module.getConfiguration(), childModules, ruleUID); if (mapModuleToHandler != null) { handler = new CompositeTriggerHandler((Trigger) module, (CompositeTriggerType) mt, mapModuleToHandler, ruleUID); } } else if (mt instanceof CompositeConditionType) { List<Condition> childModules = ((CompositeConditionType) mt).getChildren(); LinkedHashMap<Condition, ConditionHandler> mapModuleToHandler = getChildHandlers(module.getId(), module.getConfiguration(), childModules, ruleUID); if (mapModuleToHandler != null) { handler = new CompositeConditionHandler((Condition) module, (CompositeConditionType) mt, mapModuleToHandler, ruleUID); } } else if (mt instanceof CompositeActionType) { List<Action> childModules = ((CompositeActionType) mt).getChildren(); LinkedHashMap<Action, ActionHandler> mapModuleToHandler = getChildHandlers(module.getId(), module.getConfiguration(), childModules, ruleUID); if (mapModuleToHandler != null) { handler = new CompositeActionHandler((Action) module, (CompositeActionType) mt, mapModuleToHandler, ruleUID); } } if (handler != null) { logger.debug("Set module handler: {} -> {} of rule {}.", module.getId(), handler.getClass().getSimpleName() + "(" + moduleType + ")", ruleUID); } else { logger.debug("Not found module handler {} for moduleType {} of rule {}.", module.getId(), moduleType, ruleUID); } } return handler; } /** * This method associates module handlers to the child modules of composite module types. It links module types of * child modules to the rule which contains this composite module. It also resolve links between child configuration * properties and configuration of composite module see: * {@link #ReferenceResolverUtil.updateModuleConfiguration(Module, Map)}. * * @param compositeConfig configuration values of composite module. * @param childModules list of child modules * @param childModulePrefix defines UID of child module. The rule id is not enough for prefix when a composite type * is used more then one time in one and the same rule. For example the prefix can be: * ruleId:compositeModuleId:compositeModileId2. * @return map of pairs of module and its handler. Return null when some of the child modules can not find its * handler. */ @SuppressWarnings("unchecked") private <T extends Module, MT extends ModuleHandler> LinkedHashMap<T, MT> getChildHandlers(String compositeModuleId, Configuration compositeConfig, List<T> childModules, String childModulePrefix) { LinkedHashMap<T, MT> mapModuleToHandler = new LinkedHashMap<T, MT>(); for (T child : childModules) { String ruleId = getRuleId(childModulePrefix); ruleEngine.updateMapModuleTypeToRule(ruleId, child.getTypeUID()); ModuleHandlerFactory childMhf = ruleEngine.getModuleHandlerFactory(child.getTypeUID()); if (childMhf == null) { mapModuleToHandler.clear(); mapModuleToHandler = null; return null; } ReferenceResolverUtil.updateModuleConfiguration(child, compositeConfig.getProperties()); MT childHandler = (MT) childMhf.getHandler(child, childModulePrefix + ":" + compositeModuleId); if (childHandler == null) { mapModuleToHandler.clear(); mapModuleToHandler = null; return null; } mapModuleToHandler.put(child, childHandler); } return mapModuleToHandler; } @Override public void dispose() { super.dispose(); mtRegistry = null; ruleEngine = null; } }