Skip to content
Snippets Groups Projects
Commit 12fa5bfe authored by PICHON's avatar PICHON
Browse files

Evolution du TangoParser pour écrire sur les atributs SPECTRUM et correction...

Evolution du TangoParser pour écrire sur les atributs SPECTRUM et correction d'un bug sur l'ordre de lecture des formules IO. Refactoring du code.
parents
Branches
Tags
1 merge request!1Evolution du TangoParser pour écrire sur les atributs SPECTRUM et correction...
Showing
with 1420 additions and 0 deletions
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.8">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="target/classes" path="src/main/java">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="src" output="target/test-classes" path="src/test/java">
<attributes>
<attribute name="optional" value="true"/>
<attribute name="maven.pomderived" value="true"/>
<attribute name="test" value="true"/>
</attributes>
</classpathentry>
<classpathentry excluding="**" kind="src" output="target/classes" path="src/main/resources">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="con" path="org.eclipse.m2e.MAVEN2_CLASSPATH_CONTAINER">
<attributes>
<attribute name="maven.pomderived" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="output" path="target/classes"/>
</classpath>
target
.svn
*/.svn/*
bin
.project 0 → 100755
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>Tangoparser</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.m2e.core.maven2Builder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.m2e.core.maven2Nature</nature>
<nature>org.eclipse.jdt.core.javanature</nature>
</natures>
</projectDescription>
eclipse.preferences.version=1
encoding//src/main/java=UTF-8
encoding//src/main/resources=UTF-8
encoding//src/test/java=UTF-8
encoding/<project>=UTF-8
eclipse.preferences.version=1
org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.8
org.eclipse.jdt.core.compiler.compliance=1.8
org.eclipse.jdt.core.compiler.problem.enablePreviewFeatures=disabled
org.eclipse.jdt.core.compiler.problem.forbiddenReference=warning
org.eclipse.jdt.core.compiler.problem.reportPreviewFeatures=ignore
org.eclipse.jdt.core.compiler.release=disabled
org.eclipse.jdt.core.compiler.source=1.8
activeProfiles=
eclipse.preferences.version=1
resolveWorkspaceProjects=true
version=1
File added
File added
@startuml TangoParser class diagram
title
<font color=red>TangoParser</font>
<b>Diagram Class</b>
Partial class diagram
01/10/2021
<u>Guillaume Pichon - Synchrotron SOLEIL</u>
end title
abstract class AJepParser [[java:fr.soleil.tango.parser.AJepParser]] {
-isVector: boolean
~logger: Logger
#{static} CONFIG_ERROR: String
#jep: JEP
#AJepParser()
#setVector(isVector: boolean): void
#parse(name: String, expression: String): Object
-logAvailableFunctions(): void
+{abstract} getExpression(): String
+{abstract} refresh(lock: boolean): void
+{abstract} getValue(lock: boolean): Object
+{abstract} getName(): String
+{abstract} initExpression(): void
+toString(): String
}
class JepParserRead [[java:fr.soleil.tango.parser.JepParserRead]] {
-logger: Logger
-name: String
-expressionsR: String
-variables: BiMap<String,String>
-variablesJep: List<AJepParser>
-variablesJepToRead: List<AJepParser>
-locker: Lock
-dataSource: TangoSource
-sourceName: String
~attributes: CaseInsensitiveMap<String>
+JepParserRead(deviceName: String, name: String, expressionsR: String, variables: BiMap<String,String>, variablesJep: List<AJepParser>, dataSource: TangoSource)
+getExpression(): String
+refresh(lock: boolean): void
+getValue(lock: boolean): Object
+initExpression(): void
+getName(): String
}
class JepParserWrite [[java:fr.soleil.tango.parser.JepParserWrite]] {
-logger: Logger
-name: String
-locker: Lock
-expression: String
-variables: BiMap<String,String>
-variablesJep: List<AJepParser>
-variablesJepToRead: List<AJepParser>
-dataSource: TangoSource
-sourceName: String
-attributeName: String
-writeSymbol: String
-resultSymbol: String
+JepParserWrite(deviceName: String, expression: String, name: String, variables: BiMap<String,String>, variablesJepToRead: List<AJepParser>, dataSource: TangoSource)
+getExpression(): String
+initExpression(): void
+setValue(value: Object): void
+getValue(lock: boolean): Object
+isAttribute(): boolean
+getName(): String
+refresh(lock: boolean): void
+getAttributeName(): String
}
class DynamicAttributeParser [[java:fr.soleil.tango.server.tangoparser.DynamicAttributeParser]] {
-logger: Logger
-config: AttributeConfiguration
-isSynchronous: boolean
-jepParserWriterGroup: WriteExpressionGroup
-value: AttributeValue
-variablesJep: List<AJepParser>
-jepParserRead: JepParserRead
-isWriteInitialized: boolean
+DynamicAttributeParser(deviceName: String, config: AttributeConfiguration, expressionsR: String, expressionsW: List<String>, variables: BiMap<String,String>, sourceGroup: TangoSource)
+DynamicAttributeParser(deviceName: String, config: AttributeConfiguration, expressionsR: String, expressionsW: List<String>, variables: BiMap<String,String>, variablesJep: List<AJepParser>, sourceGroup: TangoSource)
+getConfiguration(): AttributeConfiguration
+getExpression(): String[]
+getStateMachine(): StateMachineBehavior
+getValue(): AttributeValue
+setValue(value: AttributeValue): void
+launchRefresh(lock: boolean): void
+refreshValue(lock: boolean): void
+getJepParsers(): List<AJepParser>
}
interface IAttributeBehavior {
}
class TangoParser [[java:fr.soleil.tango.server.tangoparser.TangoParser]] {
-{static} DEFAULT_REFRESH_PERIOD: int
-{static} STOP_COMMAND_NAME: String
-{static} FR_SOLEIL_MANAGEMENT_TYPE_TANGO_PARSER_STATS: String
-logger: Logger
-xlogger: XLogger
-{static} CACHE_REFRESHER: CacheRefresher
-commandNameList: String[]
-{static} version: String
-attributeNames: String[]
-useDiagnosticFunctions: boolean
-inputNames: String[]
-iONames: String[]
-movingState: String
-outputNames: String[]
-periodRefresh: int
-priorityList: String[]
-scanMode: boolean
-stopCommandFullNameList: String[]
-dynMngt: DynamicManager
-device: DeviceManager
-initFailed: boolean
-attribMap: BiMap<String,String>
-mBeans: TangoParserStats
-oNames: String[]
-state: DeviceState
-stateResolver: StateResolver
-status: String
-variablesJep: List<AJepParser>
-{static} srcManager: SourceManager
+aroundInvoke(ctx: InvocationContext): void
-checkProperty(propertyName: String, canBeEmpty: boolean, propertyPattern: String, syntax: String, propertyValue: String[]): void
+deleteDevice(): void
+evaluateExpression(argin: String): String[]
+getLastCacheError(): String
+getExpression(argin: String): String[]
+getState(): DeviceState
+getStatus(): String
+initDevice(): void
-copyArrayAndClean(array: String[]): Set<String>
-initInputExp(): void
-initIOExp(): void
-initManagement(): void
-initOutputExp(): void
-initTangoJep(): void
-removeEmptyLineFromProperty(propertyName: String, propertyValue: String[]): String[]
+setExpression(argin: String[]): void
+setState(state: DeviceState): void
+setStatus(status: String): void
+setDynMngt(dynMngt: DynamicManager): void
+setAttributeNames(attributeNames: String[]): void
+setInputNames(inputNames: String[]): void
+setIONames(iONames: String[]): void
+setOutputNames(outputNames: String[]): void
+setUseDiagnosticFunctions(useDiagnosticFunctions: boolean): void
+setMovingState(movingState: String): void
+setPeriodRefresh(periodRefresh: int): void
+setPriorityList(priorityList: String[]): void
+setStopCommandFullNameList(stopCommandFullNameList: String[]): void
+setScanMode(scanMode: boolean): void
+setDevice(device: DeviceManager): void
+{static} getVersion(): String
+{static} setSrcManager(srcManager: SourceManager): void
+setCommandNameList(commandNameList: String[]): void
+{static} main(args: String[]): void
-{static} toType(string: String): int
}
IAttributeBehavior <|.. DynamicAttributeParser
AJepParser <|-- JepParserRead
AJepParser <|-- JepParserWrite
@enduml
pom.xml 0 → 100644
<?xml version="1.0" encoding="UTF-8"?>
<project
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"
xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance">
<modelVersion>4.0.0</modelVersion>
<parent>
<artifactId>java-updated-versions</artifactId>
<groupId>fr.soleil.maven.parent</groupId>
<version>0-SNAPSHOT</version>
</parent>
<groupId>fr.soleil.deviceservers</groupId>
<artifactId>TangoParser</artifactId>
<version>3.3.3</version>
<name>TangoParser</name>
<description>TangoParser Device</description>
<developers>
<developer>
<id>abeille</id>
<name>Gwenaelle Abeille</name>
<email>gwenaelle.abeille@synchrotron-soleil.fr</email>
<organization>Synchrotron Soleil</organization>
<organizationUrl>http://www.synchrotron-soleil.fr</organizationUrl>
<roles>
<role>Java Developer</role>
</roles>
<timezone>1</timezone>
</developer>
</developers>
<scm>
<connection>${scm.connection.svn.tango-ds}/DeviceClasses/Calculation/TangoParser/trunk/</connection>
<developerConnection>${scm.connection.svn.tango-ds}/DeviceClasses/Calculation/TangoParser/trunk/</developerConnection>
<url>${scm.connection.svn.tango-ds}/DeviceClasses/Calculation/TangoParser/trunk/</url>
</scm>
<build>
<plugins>
<plugin>
<artifactId>maven-surefire-plugin</artifactId>
<configuration>
<includes>
<include>**/Test*.java</include>
<include>**/*Test.java</include>
<include>**/*TestCase.java</include>
<include>**/*Test*.java</include>
</includes>
<systemProperties>
<property>
<name>TANGO_HOST</name>
<value>${env.TANGO_HOST}</value>
</property>
<property>
<name>org.tango.server.checkalarms</name>
<value>false</value>
</property>
</systemProperties>
</configuration>
</plugin>
</plugins>
</build>
<dependencies>
<dependency>
<groupId>org.scijava</groupId>
<artifactId>jep</artifactId>
<exclusions>
<exclusion>
<artifactId>jama</artifactId>
<groupId>jama</groupId>
</exclusion>
</exclusions>
</dependency>
<dependency>
<groupId>gov.nist.math</groupId>
<artifactId>jama</artifactId>
</dependency>
<dependency>
<groupId>org.tango-controls</groupId>
<artifactId>JTangoClientLang</artifactId>
</dependency>
<dependency>
<groupId>org.tango-controls</groupId>
<artifactId>JTangoServer</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-math3</artifactId>
</dependency>
<dependency>
<groupId>com.google.guava</groupId>
<artifactId>guava</artifactId>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.mockito</groupId>
<artifactId>mockito-all</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
</project>
<?xml version="1.0" encoding="UTF-8"?>
<assembly>
<id>netbeans</id>
<includeBaseDirectory>false</includeBaseDirectory>
<fileSets>
<fileSet>
<directory>target</directory>
<outputDirectory></outputDirectory>
<includes>
<include>*.jar</include>
</includes>
</fileSet>
</fileSets>
<dependencySets>
<dependencySet>
<outputDirectory>lib</outputDirectory>
<unpack>false</unpack>
<scope>runtime</scope>
</dependencySet>
</dependencySets>
</assembly>
<assembly>
<id>with-dep</id>
<formats>
<format>jar</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<dependencySets>
<dependencySet>
<!-- unpack les dépendances avant de les inclures dans le jar final de l'application -->
<unpack>true</unpack>
<scope>runtime</scope>
<useProjectArtifact>false</useProjectArtifact>
</dependencySet>
</dependencySets>
<fileSets>
<fileSet>
<directory>${project.build.outputDirectory}</directory>
<outputDirectory></outputDirectory>
</fileSet>
</fileSets>
</assembly>
\ No newline at end of file
package fr.soleil.management;
import javax.management.AttributeChangeNotification;
import javax.management.ListenerNotFoundException;
import javax.management.MBeanNotificationInfo;
import javax.management.Notification;
import javax.management.NotificationBroadcasterSupport;
import javax.management.NotificationEmitter;
import javax.management.NotificationFilter;
import javax.management.NotificationListener;
/**
* Class TangoParserStats
*
* @author HARDION
*/
public final class TangoParserStats implements NotificationEmitter {
private static final double TO_SECS = 1000.0;
private final NotificationBroadcasterSupport broadcaster = new NotificationBroadcasterSupport();
private long seqNumber;
/**
* Attribute : MeanResponseTime
*/
private double meanResponseTime;
/**
* Attribute : MinResponseTime
*/
private double minResponseTime;
/**
* Attribute : MaxResponseTime
*/
private double maxResponseTime;
/**
* Attribute : LastResponseTime
*/
private double lastResponseTime;
/**
* Attribute : numberOfReading
*/
private long numberOfReading;
public TangoParserStats() {
}
/**
* Get Response time of the last read_attributes
*/
public double getLastResponseTime() {
return lastResponseTime;
}
/**
* Get Mean response of read attributes
*/
public double getMeanResponseTime() {
double result = 0.0D;
if (numberOfReading != 0) {
result = meanResponseTime / numberOfReading;
}
return result;
}
/**
* Get Min response of read attributes
*/
public double getMinResponseTime() {
return minResponseTime;
}
/**
* Get Max response of read attributes
*/
public double getMaxResponseTime() {
return maxResponseTime;
}
/**
* Reset Statistic
*/
public void resetAll() {
meanResponseTime = 0;
minResponseTime = 0;
maxResponseTime = 0;
lastResponseTime = 0;
numberOfReading = 0;
}
@Override
public void addNotificationListener(final NotificationListener listener, final NotificationFilter filter,
final Object handback) {
broadcaster.addNotificationListener(listener, filter, handback);
}
@Override
public MBeanNotificationInfo[] getNotificationInfo() {
return new MBeanNotificationInfo[] { new MBeanNotificationInfo(
new String[] { AttributeChangeNotification.ATTRIBUTE_CHANGE },
javax.management.AttributeChangeNotification.class.getName(), "Attributes has been reading") };
}
@Override
public void removeNotificationListener(final NotificationListener listener) throws ListenerNotFoundException {
broadcaster.removeNotificationListener(listener);
}
@Override
public void removeNotificationListener(final NotificationListener listener, final NotificationFilter filter,
final Object handback) throws ListenerNotFoundException {
broadcaster.removeNotificationListener(listener, filter, handback);
}
public synchronized long getNextSeqNumber() {
return seqNumber++;
}
/*
* Methods exposed to Anagrams application to feed management with data.
*/
// Stores the time at which a new anagram is proposed to the user.
private long startTime;
/**
* A new Anagram is proposed to the user: store current time.
*/
public void startReading() {
startTime = System.currentTimeMillis();
}
/**
* An Anagram has been resolved.
*/
public void stopReading() {
// Update the number of resolved anagrams
numberOfReading++;
// Compute last, min and max thinking times
lastResponseTime = (System.currentTimeMillis() - startTime) / TO_SECS;
minResponseTime = lastResponseTime < minResponseTime || minResponseTime == 0 ? lastResponseTime
: minResponseTime;
maxResponseTime = lastResponseTime > maxResponseTime ? lastResponseTime : maxResponseTime;
meanResponseTime += lastResponseTime;
// Create a JMX Notification
final Notification notification = new Notification(AttributeChangeNotification.ATTRIBUTE_CHANGE, this,
getNextSeqNumber(), "" + "" + "Attributes read: " + numberOfReading);
// Send a JMX notification.
broadcaster.sendNotification(notification);
}
}
package fr.soleil.management;
/**
* Interface TangoParserStatsMBean
*
* @author HARDION
*/
public interface TangoParserStatsMBean {
/**
* Get Response time of the last read_attributes
*/
double getLastResponseTime();
/**
* Get Max response of read attributes
*/
double getMaxResponseTime();
/**
* Get Mean response of read attributes
*/
double getMeanResponseTime();
/**
* Get Min response of read attributes
*/
double getMinResponseTime();
/**
* Reset Statistic
*/
void resetAll();
}
package fr.soleil.tango.parser;
import java.lang.reflect.Array;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import org.lsmp.djep.vectorJep.VectorJep;
import org.lsmp.djep.vectorJep.values.MVector;
import org.lsmp.djep.xjep.function.FromBase;
import org.lsmp.djep.xjep.function.ToBase;
import org.nfunk.jep.FunctionTable;
import org.nfunk.jep.JEP;
import org.nfunk.jep.Node;
import org.nfunk.jep.Operator;
import org.nfunk.jep.ParseException;
import org.nfunk.jep.SymbolTable;
import org.nfunk.jep.Variable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.tango.utils.CaseInsensitiveMap;
import org.tango.utils.DevFailedUtils;
import com.google.common.collect.BiMap;
import com.google.common.collect.HashBiMap;
import fr.esrf.Tango.DevFailed;
import fr.soleil.tango.parser.datasource.AttributeResult;
import fr.soleil.tango.parser.datasource.TangoSource;
import fr.soleil.tango.parser.function.BooleanExtractor;
import fr.soleil.tango.parser.function.Left;
import fr.soleil.tango.parser.function.Max;
import fr.soleil.tango.parser.function.Mean;
import fr.soleil.tango.parser.function.Min;
import fr.soleil.tango.parser.function.Right;
import fr.soleil.tango.parser.function.Std;
import fr.soleil.tango.parser.function.StringLength;
import fr.soleil.tango.parser.function.SubString;
import fr.soleil.tango.parser.function.spectrum.Add;
import fr.soleil.tango.parser.function.spectrum.Div;
import fr.soleil.tango.parser.function.spectrum.FFT;
import fr.soleil.tango.parser.function.spectrum.Mul;
import fr.soleil.tango.parser.function.spectrum.Sub;
import fr.soleil.tango.parser.function.spectrum.VCos;
import fr.soleil.tango.parser.function.spectrum.VLog;
import fr.soleil.tango.parser.function.spectrum.VSinus;
/**
*
* @author fourneau
*
*/
public abstract class AJepParser {
private Logger logger = LoggerFactory.getLogger(AJepParser.class);
/**
* Use in throw DevFailed
*/
protected static final String CONFIG_ERROR = "CONFIG_ERROR";
// private boolean isVector;
protected final JEP jep;
private boolean isVector;
protected final String name;
/**
* key = attribute name, value = variable name
*/
protected BiMap<String, String> variables = HashBiMap.create();
protected final List<AJepParser> variablesJep;
protected final List<AJepParser> variablesJepToRead = new ArrayList<AJepParser>();
protected final Lock locker = new ReentrantLock();
protected final TangoSource dataSource;
protected final String sourceName;
protected String expressions;
protected final CaseInsensitiveMap<String> attributes = new CaseInsensitiveMap<String>();
protected AJepParser(final String deviceName, final String name, final String expressions,
final BiMap<String, String> variables, final List<AJepParser> variablesJep, final TangoSource dataSource) {
sourceName = deviceName;
this.name = name;
this.expressions = expressions;
this.variables = variables;
this.variablesJep = variablesJep;
this.dataSource = dataSource;
jep = new VectorJep();
jep.addStandardFunctions();
jep.addStandardConstants();
jep.addComplex();
jep.setAllowUndeclared(true);
jep.setAllowAssignment(true);
jep.setTraverse(true);
jep.setImplicitMul(true);
jep.addFunction("fft", new FFT());
jep.addFunction("vsin", new VSinus());
jep.addFunction("vcos", new VCos());
jep.addFunction("vlog", new VLog());
jep.addFunction("add", new Add());
jep.addFunction("sub", new Sub());
jep.addFunction("div", new Div());
jep.addFunction("mul", new Mul());
jep.addFunction("mean", new Mean());
jep.addFunction("std", new Std());
jep.addFunction("max", new Max());
jep.addFunction("min", new Min());
jep.addFunction("boolextract", new BooleanExtractor());
jep.addFunction("toBase", new ToBase());
jep.addFunction("toDec", new ToBase(10));
jep.addFunction("toHex", new ToBase(16, "0x"));
jep.addFunction("fromDec", new FromBase(10));
jep.addFunction("fromHex", new FromBase(16, "0x"));
jep.addFunction("fromBase", new FromBase());
jep.addFunction("substring", new SubString());
jep.addFunction("stringlen", new StringLength());
jep.addFunction("left", new Left());
jep.addFunction("right", new Right());
if (logger.isInfoEnabled()) {
logAvailableFunctions();
}
}
protected final void setVector(final boolean isVector) {
this.isVector = isVector;
// When set the multiplication of vectors and matrices will be element by
// element.
// * Otherwise multiplication will be matrix multiplication
((VectorJep) jep).setElementMultiply(isVector);
}
protected final Object parse(final String name, final String expression) throws DevFailed {
Object result = null;
logger.debug("parsing expression {} = {}", name, expression);
try {
final Node node = jep.parse(expression);
logger.debug("using parser of type vector = {}", isVector);
result = jep.evaluate(node);
} catch (final ParseException e) {
if (!isVector) {
// if parsing is not OK, try with vector options
try {
setVector(true);
final Node node = jep.parse(expression);
result = jep.evaluate(node);
} catch (final ParseException e1) {
setVector(false);
DevFailedUtils.throwDevFailed(e1);
}
} else {
DevFailedUtils.throwDevFailed(e);
}
}
logger.debug("result is {} = {}", expression, result);
return result;
}
private void logAvailableFunctions() {
final FunctionTable fc = jep.getFunctionTable();
StringBuilder sb = new StringBuilder();
for (final Object object : fc.keySet()) {
sb.append(object).append(" ");
}
logger.info("available functions are: {}", sb);
// for (final Object object : fc.entrySet()) {
// logger.info("{}", object);
// }
sb = new StringBuilder();
final Operator[] operators = jep.getOperatorSet().getOperators();
for (int i = 0; i < operators.length; i++) {
sb.append(operators[i].getSymbol()).append(" ");
}
logger.info("available operators are: {}", sb);
}
/**
* Getter on expression(s) (read or/and write)
*
* @return
*/
public abstract String getExpression();
/**
* Update variables of the expression (ie reading tango attributes asynchrously)
*
* @param lock true to use synchronisation. For using Parser in multi-threaded
* environment.
* @throws DevFailed
*/
public void refresh(boolean lock) throws DevFailed {
if (lock) {
locker.lock();
}
try {
// refresh tango attributes
dataSource.refresh();
// refresh other variables
for (final AJepParser variable : variablesJepToRead) {
variable.refresh(lock);
}
} finally {
if (lock) {
locker.unlock();
}
}
}
/**
* Evaluate the expression with lastest values refreshed by
* {@link #refresh(boolean)}
*
* @param lock true to use synchronisation. For using Parser in multi-threaded
* environment.
* @return the result of evaluation
* @throws DevFailed
*/
public Object getValue(boolean lock) throws DevFailed {
if (lock) {
locker.lock();
}
try {
// get results for tango attributes
for (final String variableName : variables.values()) {
final AttributeResult r = dataSource.getResult(sourceName, variableName);
if (r != null) {
final Object value = r.getValue();
final DevFailed e = r.getError();
if (e != null && attributes.containsValue(variableName)) {
throw e;
} else if (value != null) {
jep.addVariable(variableName, fromStandardToJepType(value));
logger.debug("add tango result : {}={}", variableName, value);
}
}
}
// get results for variables
for (final AJepParser variable : variablesJepToRead) {
final Object r = variable.getValue(lock);
logger.debug("get input variable {} = {}", variable, r);
jep.addVariable(variable.getName(), r);
}
Object lastWriteResult = parse(name, expressions);
lastWriteResult = fromJepToStandardType(lastWriteResult);
return lastWriteResult;
} finally {
if (lock) {
locker.unlock();
}
}
}
public abstract String getName();
@Override
public String toString() {
final ToStringBuilder toStringBuilder = new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE);
toStringBuilder.append("name", getName());
toStringBuilder.append("expression", getExpression());
return toStringBuilder.toString();
}
public abstract void initExpression() throws DevFailed;
protected final void initExpression(String expression) throws ParseException, DevFailed {
List<String> missingSymbols = new ArrayList<>();
jep.parse(expression);
final SymbolTable symbols = jep.getSymbolTable();
for (final Object entry : symbols.entrySet()) {
@SuppressWarnings("rawtypes")
final Variable symbol = (Variable) ((Map.Entry) entry).getValue();
final String symbolName = symbol.getName();
logger.debug("symbol {}", symbolName);
if (variables.containsValue(symbolName)) {
// attribute to read before parsing write expression
final String attrName = variables.inverse().get(symbolName);
logger.debug("read attribute {} ({}) for {} ", new Object[] { attrName, symbolName, expression });
attributes.put(attrName, symbolName);
} else { // not an attribute, may be the write input
if (!symbol.isConstant() && !name.equals(symbolName)) {
boolean founded = false;
for (final AJepParser jepReader : variablesJep) {
if (jepReader.getName().equals(symbolName)) {
logger.debug("add existing variable {}", jepReader.getName());
variablesJepToRead.add(jepReader);
founded = true;
}
}
if (!founded) {
// The symbol is unknown. It's not a
missingSymbols.add(symbolName);
}
}
}
}
if (!missingSymbols.isEmpty()) {
// At least 1 symbol is missing, an error is thrown
StringBuilder symbolsStrBldr = new StringBuilder();
for (String missingSymbol : missingSymbols) {
if (symbolsStrBldr.length() > 0) {
symbolsStrBldr.append(", ");
}
symbolsStrBldr.append(missingSymbol);
}
logger.warn("Some symbols in the expression are unknown: " + symbolsStrBldr.toString(),
"In the expression '" + expression + "' the following symbols are missing:\n"
+ symbolsStrBldr.toString());
// throw DevFailedUtils.newDevFailed("Some symbols in the equation are unknown.",
// "In the equation '" + expression + "' the following symbols are missing:\n" + strBldr.toString());
}
if (!attributes.isEmpty()) {
dataSource.addSource(sourceName, attributes);
}
}
public List<AJepParser> getDependantJepParserList() {
return variablesJepToRead;
}
/**
* This method transform a Jep vector into a standard array.
*
* @param value The input value which may be an array.
* @return An array if the input value was a Jep vector.
*/
public static final Object fromJepToStandardType(Object value) {
Object result = value;
if (value instanceof MVector) {
final MVector vect = (MVector) value;
result = new Object[vect.getNumEles()];
for (int j = 0; j < vect.getNumEles(); j++) {
Array.set(result, j, vect.getEle(j));
}
}
return result;
}
/**
* This method transform a standard array into a Jep vector.
*
* @param value The input value
* @return A value which can be used in Jep.
*/
public static final Object fromStandardToJepType(Object value) {
Object result = value;
if (value.getClass().isArray()) {
final MVector vect = new MVector(Array.getLength(value));
for (int j = 0; j < Array.getLength(value); j++) {
vect.setEle(j, Array.get(value, j));
}
result = vect;
}
return result;
}
}
package fr.soleil.tango.parser;
import java.util.List;
import org.nfunk.jep.JEP;
import org.nfunk.jep.ParseException;
import org.tango.utils.DevFailedUtils;
import com.google.common.collect.BiMap;
import fr.esrf.Tango.DevFailed;
import fr.soleil.tango.parser.datasource.TangoSource;
/**
* Manage a read expression that is able to read Tango Attributes. Base on JEP
* library. NB: If this class is used in multi-threaded environment: set lock to
* true for {@link #refresh(boolean)} and {@link #getValue(boolean)}
*
* @author fourneau
* @see JEP
*/
public final class JepParserRead extends AJepParser {
private final String expressionsR;
/**
* Build a read expression
*
* @param name The name of the result
* @param expressionsR The read expression
* @param variables The map of variables {key = variable name, value =
* attribute name}
* @param variablesJep The already build expressions. Allow interlinked
* expression
* @throws DevFailed
*/
public JepParserRead(final String deviceName, final String name, final String expressionsR,
final BiMap<String, String> variables, final List<AJepParser> variablesJep, final TangoSource dataSource)
throws DevFailed {
super(deviceName, name, expressionsR, variables, variablesJep, dataSource);
this.expressionsR = expressionsR;
}
@Override
public String getExpression() {
return expressionsR;
}
/**
* Init the JEP parser
*
* @throws ParseException
* @throws DevFailed
*/
@Override
public void initExpression() throws DevFailed {
try {
initExpression(expressionsR);
} catch (final ParseException e) {
throw DevFailedUtils.newDevFailed(e);
}
}
@Override
public String getName() {
return name;
}
}
package fr.soleil.tango.parser;
import java.util.List;
import java.util.Map;
import org.nfunk.jep.JEP;
import org.nfunk.jep.ParseException;
import org.nfunk.jep.SymbolTable;
import org.nfunk.jep.Variable;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.tango.utils.DevFailedUtils;
import com.google.common.collect.BiMap;
import fr.esrf.Tango.DevFailed;
import fr.soleil.tango.parser.datasource.TangoSource;
/**
* Manage a JEP expression to write on Tango attributes. NB: If this class is
* used in multi-threaded environment: set lock to true for
* {@link #refresh(boolean)} and {@link #getValue(boolean)}
*
* @see JEP
* @author fourneau
*
*/
public final class JepParserWrite extends AJepParser {
private final Logger logger = LoggerFactory.getLogger(JepParserWrite.class);
private String attributeName = "";
private String writeSymbol = "";
private String resultSymbol = "";
private final String expression;
/**
*
* @param expression The expression with pattern *=*
* @param name The name of expression
* @param variables The map of variables {key = variable name, value =
* attribute name}
* @throws DevFailed
*/
public JepParserWrite(final String deviceName, final String expression, final String name,
final BiMap<String, String> variables, final List<AJepParser> variablesJepToRead,
final TangoSource dataSource) throws DevFailed {
super(deviceName, name, expression, variables, variablesJepToRead, dataSource);
this.expression = expression.trim();
this.variables = variables;
}
@Override
public String getExpression() {
return expression;
}
/**
* Init JEP
*
* @throws ParseException
* @throws DevFailed
*/
@Override
public void initExpression() throws DevFailed {
logger.debug("***building write expression - {} with variables {}", expression, variables);
// retrieve the result name result=expression
int equalIndex = expression.indexOf('=');
if (equalIndex < 1) {
// The equal symbol cannot be absent or the first character.
throw DevFailedUtils.newDevFailed("The equal symbol cannot be absent or the first character.",
"The symbol '=' is absent or is the first character.\nThe expression should be like x = f(y).");
}
resultSymbol = expression.substring(0, equalIndex).trim();
if (resultSymbol.isEmpty()) {
// The result symbol is the name of the writer, it's mandatory.
throw DevFailedUtils.newDevFailed("The result symbol is missing.",
"A result symbol is required before the '='.");
}
logger.debug("resultSymbol is {} for {} ", resultSymbol, expression);
if (variables.containsValue(resultSymbol)) {
// result attribute, will write on it
attributeName = variables.inverse().get(resultSymbol);
logger.debug("result will be written on attribute {} for {} ", attributeName, expression);
}
final String exp = expression.substring(equalIndex + 1).trim();
try {
initExpression(exp);
} catch (final ParseException e) {
throw DevFailedUtils.newDevFailed(e);
}
final SymbolTable symbols = jep.getSymbolTable();
for (final Object entry : symbols.entrySet()) {
@SuppressWarnings("rawtypes")
final Variable symbol = (Variable) ((Map.Entry) entry).getValue();
final String symbolName = symbol.getName();
if (name.equals(symbolName)) {
writeSymbol = symbolName;
logger.debug("write input is {} for {} ", writeSymbol, expression);
}
}
}
/**
* set a variable in expression
*
* @param value
* @throws DevFailed
*/
public void setValue(final Object value) throws DevFailed {
// set write value to parser
logger.debug("set write value \"{}\" = {} for {}", new Object[] { writeSymbol, value, expression });
jep.addVariable(writeSymbol, fromStandardToJepType(value));
}
/**
* Evaluate the expression with latest values refreshed by
* {@link #refresh(boolean)} and last set value by {@link #setValue(Object)}
*
* @param lock true to use synchronization. For using Parser in multi-threaded
* environment.
* @return the result of evaluation
* @throws DevFailed
*/
@Override
public Object getValue(final boolean lock) throws DevFailed {
Object lastWriteResult = super.getValue(lock);
if (!attributeName.isEmpty()) {
logger.debug("{} ({}) = {}", new Object[] { resultSymbol, attributeName, lastWriteResult });
} else {
logger.debug("result variable {} = {}", resultSymbol, lastWriteResult);
}
return lastWriteResult;
}
public boolean isAttribute() {
return !attributeName.isEmpty();
}
@Override
public String getName() {
return resultSymbol;
}
public String getAttributeName() {
return attributeName;
}
}
package fr.soleil.tango.parser.datasource;
import fr.esrf.Tango.AttrDataFormat;
import fr.esrf.Tango.DevFailed;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
public class AttributeResult {
private final String name;
private final String sourceName;
private final String variable;
private final AttrDataFormat format;
private Object value;
private DevFailed error;
public AttributeResult(final String sourceName, final String name, final AttrDataFormat format,
final String variable) {
super();
this.sourceName = sourceName;
this.name = name;
this.format = format;
this.variable = variable;
}
public String getName() {
return name;
}
public AttrDataFormat getFormat() {
return format;
}
public Object getValue() {
return value;
}
public String getVariable() {
return variable;
}
public void setValue(final Object value) {
this.value = value;
}
public DevFailed getError() {
return error;
}
public void setError(final DevFailed error) {
this.error = error;
}
@Override
public String toString() {
return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE);
}
public String getSourceName() {
return sourceName;
}
}
package fr.soleil.tango.parser.datasource;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.collect.HashBasedTable;
import com.google.common.collect.Table;
import fr.esrf.Tango.AttrDataFormat;
import fr.esrf.Tango.DevFailed;
public class AttributeResults {
private final Logger logger = LoggerFactory.getLogger(TangoSource.class);
private final Table<String, String, AttributeResult> table = HashBasedTable.create();
private final Map<String, AttrDataFormat> formats = new TreeMap<String, AttrDataFormat>();
void addAttributeResult(final AttributeResult attributeResult) {
logger.debug("adding source {} = {}", attributeResult.getSourceName(), attributeResult);
table.put(attributeResult.getSourceName(), attributeResult.getVariable(), attributeResult);
formats.put(attributeResult.getName(), attributeResult.getFormat());
}
boolean contains(final String attributeName) {
return formats.containsKey(attributeName);
}
String[] getAllAttributes() {
final Set<String> attributeList = formats.keySet();
return attributeList.toArray(new String[attributeList.size()]);
}
AttrDataFormat getFormat(final String attributeName) {
return formats.get(attributeName);
}
AttributeResult getAttributeResult(final String sourceName, final String variableName) {
return table.get(sourceName, variableName);
}
void setAttributeResult(final String attributeName, final Object value) {
final Map<String, Map<String, AttributeResult>> columnMap = table.columnMap();
for (final Map<String, AttributeResult> line : columnMap.values()) {
for (final Map.Entry<String, AttributeResult> entry : line.entrySet()) {
final AttributeResult result = entry.getValue();
if (attributeName.equalsIgnoreCase(result.getName())) {
result.setValue(value);
logger.debug("set value of {}", attributeName);
}
}
}
}
void resetAttributeResultError(final String attributeName) {
final Map<String, Map<String, AttributeResult>> columnMap = table.columnMap();
for (final Map<String, AttributeResult> line : columnMap.values()) {
for (final Map.Entry<String, AttributeResult> entry : line.entrySet()) {
final AttributeResult result = entry.getValue();
if (attributeName.equalsIgnoreCase(result.getName())) {
result.setError(null);
}
}
}
}
void setAttributeResultError(final String attributeName, final DevFailed error) {
final Map<String, Map<String, AttributeResult>> columnMap = table.columnMap();
for (final Map<String, AttributeResult> line : columnMap.values()) {
for (final Map.Entry<String, AttributeResult> entry : line.entrySet()) {
final AttributeResult result = entry.getValue();
if (attributeName.equalsIgnoreCase(result.getName())) {
result.setError(error);
logger.debug("set error of {}", attributeName);
}
}
}
}
@Override
public String toString() {
return ToStringBuilder.reflectionToString(this, ToStringStyle.MULTI_LINE_STYLE);
}
public void clear() {
table.clear();
formats.clear();
}
}
package fr.soleil.tango.parser.datasource;
import java.util.Date;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledFuture;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.TimeUnit;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.tango.utils.DevFailedUtils;
import fr.esrf.Tango.DevFailed;
/**
* Update tango attributes values' cache
*
* @author ABEILLE
*
*/
public class CacheRefresher {
private final int refreshRate;
private final Logger logger = LoggerFactory.getLogger(CacheRefresher.class);
private final RefreshRunner refreshRunner;
/**
* A runnable to get tango attributes values
*
* @author ABEILLE
*
*/
private class RefreshRunner implements Runnable {
private final TangoSource source;
private volatile String lastError = "";
public RefreshRunner(final TangoSource source) {
this.source = source;
}
public String getLastError() {
return lastError;
}
@Override
public void run() {
// read tango attributes
try {
source.refresh();
lastError = "";
} catch (final DevFailed e) {
lastError = new Date(System.currentTimeMillis()) + " - " + DevFailedUtils.toString(e);
logger.error("error when launchRefresh {}", DevFailedUtils.toString(e));
} catch (final Throwable e) {
lastError = new Date(System.currentTimeMillis()) + " - " + e.getMessage();
logger.error("error when launchRefresh {}", e);
}
}
}
private static class CacheRefresherFactory implements ThreadFactory {
@Override
public Thread newThread(final Runnable r) {
return new Thread(r, "TangoParserRefresher");
}
}
private final ScheduledExecutorService executor = Executors.newScheduledThreadPool(1, new CacheRefresherFactory());
private ScheduledFuture<?> future;
public CacheRefresher(final TangoSource source, final int refreshRate) {
refreshRunner = new RefreshRunner(source);
this.refreshRate = refreshRate;
}
/**
* Start refreshing
*/
public synchronized void start() {
if (!isStarted()) {
logger.debug("start refresher at a {} ms rate", refreshRate);
future = executor.scheduleAtFixedRate(refreshRunner, 0L, refreshRate, TimeUnit.MILLISECONDS);
}
}
public synchronized boolean isStarted() {
return future != null;
}
public synchronized void stop() {
if (future != null) {
future.cancel(true);
}
future = null;
}
public String getLastError() {
return refreshRunner.getLastError();
}
}
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Please register or to comment