/** * Copyright (C) 2010-14 diirt developers. See COPYRIGHT.TXT * All rights reserved. Use is subject to license terms. See LICENSE.TXT */ package org.diirt.datasource.extra; import java.util.ArrayList; import java.util.List; import org.diirt.datasource.ReadRecipe; import org.diirt.datasource.DataSource; import org.diirt.datasource.expression.DesiredRateExpression; import org.diirt.datasource.expression.DesiredRateExpressionImpl; import org.diirt.datasource.ExceptionHandler; import org.diirt.datasource.PVManager; import org.diirt.datasource.expression.DesiredRateExpressionListImpl; /** * A expression that returns the result of a dynamically managed group. * Once the group is created, any {@link DesiredRateExpression} can be * added dynamically. The exceptions eventually generated by those * expressions can be obtained through {@link #lastExceptions() }. * * @author carcassi */ public class DynamicGroup extends DesiredRateExpressionImpl<List<Object>> { private final DataSource dataSource = PVManager.getDefaultDataSource(); private final List<ReadRecipe> recipes = new ArrayList<ReadRecipe>(); /** * Creates a new group. */ public DynamicGroup() { super(new DesiredRateExpressionListImpl<Object>(), new DynamicGroupFunction(), "dynamic group"); } DynamicGroupFunction getGroup() { return (DynamicGroupFunction) getFunction(); } /** * Returns the last exception for each expression in the group (if present). * * @return a list of exceptions (never null) */ public List<Exception> lastExceptions() { synchronized (getGroup()) { return new ArrayList<Exception>(getGroup().getExceptions()); } } /** * Removes all the expressions currently in the group. * * @return this */ public synchronized DynamicGroup clear() { for (int index = recipes.size() - 1; index >= 0; index--) { ReadRecipe recipe = recipes.remove(index); dataSource.disconnectRead(recipe); synchronized (getGroup()) { getGroup().getArguments().remove(index); getGroup().getExceptions().remove(index); getGroup().getPreviousValues().remove(index); } } return this; } /** * Returns the number of expressions in the group. * * @return number of expressions in the group */ public synchronized int size() { return recipes.size(); } /** * Adds the expression at the end. * * @param expression the expression to be added * @return this */ public synchronized DynamicGroup add(DesiredRateExpression<?> expression) { // DataRecipe recipe = expression.getDataRecipe(); // recipe = recipe.withExceptionHandler(handlerFor(recipes.size())); synchronized (getGroup()) { getGroup().getArguments().add(expression.getFunction()); getGroup().getExceptions().add(null); getGroup().getPreviousValues().add(null); } // dataSource.connect(recipe); // recipes.add(recipe); return this; } /** * Removes the expression at the given location. * * @param index the position to remove * @return this */ public synchronized DynamicGroup remove(int index) { ReadRecipe recipe = recipes.remove(index); dataSource.disconnectRead(recipe); synchronized (getGroup()) { getGroup().getArguments().remove(index); getGroup().getExceptions().remove(index); getGroup().getPreviousValues().remove(index); } return this; } /** * Changes the expression to the given location. * * @param index the position to remove * @param expression the new expression * @return this */ public synchronized DynamicGroup set(int index, DesiredRateExpression<?> expression) { // DataRecipe recipe = expression.getDataRecipe(); // recipe = recipe.withExceptionHandler(handlerFor(index)); ReadRecipe oldRecipe = recipes.get(index); dataSource.disconnectRead(oldRecipe); synchronized (getGroup()) { getGroup().getArguments().set(index, expression.getFunction()); getGroup().getExceptions().set(index, null); getGroup().getPreviousValues().set(index, null); } // dataSource.connect(recipe); // recipes.set(index, recipe); return this; } private ExceptionHandler handlerFor(final int index) { return new ExceptionHandler() { @Override public void handleException(Exception ex) { synchronized (getGroup()) { getGroup().getExceptions().set(index, ex); } } }; } }