/**
* 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.Collections;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.StringTokenizer;
import org.eclipse.smarthome.automation.Action;
import org.eclipse.smarthome.automation.core.internal.ReferenceResolverUtil;
import org.eclipse.smarthome.automation.handler.ActionHandler;
import org.eclipse.smarthome.automation.type.CompositeActionType;
import org.eclipse.smarthome.automation.type.Output;
/**
* This class is a handler implementation for {@link CompositeActionType}. The action of type
* {@link CompositeActionType} has to execute handlers of all child actions. The handler has to return outputs of the
* action, base on the outputs of the child actions, into rule context. The outputs of the child actions are not
* visible out of the context of the action.
*
* @author Yordan Mihaylov - Initial Contribution
*
*/
public class CompositeActionHandler extends AbstractCompositeModuleHandler<Action, CompositeActionType, ActionHandler>
implements ActionHandler {
public final static String REFERENCE = "reference";
private Map<String, Output> compositeOutputs;
/**
* Create a system handler for modules of {@link CompositeActionType} type.
*
* @param action parent action module instance. The action which has {@link CompositeActionType} type.
* @param mt {@link CompositeActionType} instance of the parent module
* @param mapModuleToHandler map of pairs child action module to its action handler
* @param ruleUID UID of rule where the parent action is part of.
*/
public CompositeActionHandler(Action action, CompositeActionType mt,
LinkedHashMap<Action, ActionHandler> mapModuleToHandler, String ruleUID) {
super(action, mt, mapModuleToHandler);
compositeOutputs = getCompositeOutputMap(moduleType.getOutputs());
}
/**
* The method calls handlers of child action, collect their outputs and sets the output of the parent action.
*
* @see org.eclipse.smarthome.automation.handler.ActionHandler#execute(java.util.Map)
*/
@Override
public Map<String, Object> execute(Map<String, Object> context) {
final Map<String, Object> result = new HashMap<String, Object>();
final List<Action> children = getChildren();
final Map<String, Object> compositeContext = getCompositeContext(context);
for (Action child : children) {
ActionHandler childHandler = moduleHandlerMap.get(child);
Map<String, Object> childContext = Collections.unmodifiableMap(getChildContext(child, compositeContext));
Map<String, Object> childResults = childHandler.execute(childContext);
if (childResults != null) {
for (Entry<String, Object> childResult : childResults.entrySet()) {
String childOuputName = child.getId() + "." + childResult.getKey();
Output output = compositeOutputs.get(childOuputName);
if (output != null) {
String childOuputRef = output.getReference();
if (childOuputRef != null && childOuputRef.length() > childOuputName.length()) {
childOuputRef = childOuputRef.substring(childOuputName.length());
result.put(output.getName(),
ReferenceResolverUtil.getValue(childResult.getValue(), childOuputRef));
} else {
result.put(output.getName(), childResult.getValue());
}
}
}
}
}
return result.size() > 0 ? result : null;
}
/**
* Create a map of links between child outputs and parent outputs. These links are base on the refecences defined in
* the outputs of parent action.
*
* @param outputs outputs of the parent action. The action of {@link CompositeActionType}
* @return map of links between child action outputs and parent output
*/
protected Map<String, Output> getCompositeOutputMap(List<Output> outputs) {
Map<String, Output> result = new HashMap<String, Output>(11);
if (outputs != null) {
for (Output output : outputs) {
String refs = output.getReference();
if (refs != null) {
String ref;
StringTokenizer st = new StringTokenizer(refs, ",");
while (st.hasMoreTokens()) {
ref = st.nextToken().trim();
int i = ref.indexOf('.');
if (i != -1) {
int j = ReferenceResolverUtil.getNextRefToken(ref, i + 1);
if (j != -1) {
ref = ref.substring(0, j);
}
}
result.put(ref, output);
}
}
}
}
return result;
}
@Override
protected List<Action> getChildren() {
return moduleType.getChildren();
}
}