aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/org/traccar/handler/ComputedAttributesHandler.java
diff options
context:
space:
mode:
Diffstat (limited to 'src/main/java/org/traccar/handler/ComputedAttributesHandler.java')
-rw-r--r--src/main/java/org/traccar/handler/ComputedAttributesHandler.java114
1 files changed, 82 insertions, 32 deletions
diff --git a/src/main/java/org/traccar/handler/ComputedAttributesHandler.java b/src/main/java/org/traccar/handler/ComputedAttributesHandler.java
index 153da29b9..042747359 100644
--- a/src/main/java/org/traccar/handler/ComputedAttributesHandler.java
+++ b/src/main/java/org/traccar/handler/ComputedAttributesHandler.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017 - 2019 Anton Tananaev (anton@traccar.org)
+ * Copyright 2017 - 2023 Anton Tananaev (anton@traccar.org)
* Copyright 2017 Andrey Kunitsyn (andrey@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -24,56 +24,77 @@ import java.util.Collections;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
+import java.util.List;
import io.netty.channel.ChannelHandler;
-import org.apache.commons.jexl2.JexlEngine;
-import org.apache.commons.jexl2.JexlException;
-import org.apache.commons.jexl2.MapContext;
+import org.apache.commons.jexl3.JexlFeatures;
+import org.apache.commons.jexl3.JexlEngine;
+import org.apache.commons.jexl3.JexlBuilder;
+import org.apache.commons.jexl3.introspection.JexlSandbox;
+import org.apache.commons.jexl3.JexlException;
+import org.apache.commons.jexl3.MapContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.traccar.BaseDataHandler;
import org.traccar.config.Config;
import org.traccar.config.Keys;
-import org.traccar.database.AttributesManager;
-import org.traccar.database.IdentityManager;
import org.traccar.model.Attribute;
import org.traccar.model.Device;
import org.traccar.model.Position;
+import org.traccar.session.cache.CacheManager;
+import jakarta.inject.Inject;
+import jakarta.inject.Singleton;
+
+@Singleton
@ChannelHandler.Sharable
public class ComputedAttributesHandler extends BaseDataHandler {
private static final Logger LOGGER = LoggerFactory.getLogger(ComputedAttributesHandler.class);
- private final IdentityManager identityManager;
- private final AttributesManager attributesManager;
+ private final CacheManager cacheManager;
private final JexlEngine engine;
+ private final JexlFeatures features;
+
private final boolean includeDeviceAttributes;
- public ComputedAttributesHandler(
- Config config, IdentityManager identityManager, AttributesManager attributesManager) {
- this.identityManager = identityManager;
- this.attributesManager = attributesManager;
- engine = new JexlEngine();
- engine.setStrict(true);
- engine.setFunctions(Collections.singletonMap("math", Math.class));
+ @Inject
+ public ComputedAttributesHandler(Config config, CacheManager cacheManager) {
+ this.cacheManager = cacheManager;
+ JexlSandbox sandbox = new JexlSandbox(false);
+ sandbox.allow("com.safe.Functions");
+ sandbox.allow(Math.class.getName());
+ List.of(
+ Double.class, Float.class, Integer.class, Long.class, Short.class,
+ Character.class, Boolean.class, String.class, Byte.class)
+ .forEach((type) -> sandbox.allow(type.getName()));
+ features = new JexlFeatures()
+ .localVar(config.getBoolean(Keys.PROCESSING_COMPUTED_ATTRIBUTES_LOCAL_VARIABLES))
+ .loops(config.getBoolean(Keys.PROCESSING_COMPUTED_ATTRIBUTES_LOOPS))
+ .newInstance(config.getBoolean(Keys.PROCESSING_COMPUTED_ATTRIBUTES_NEW_INSTANCE_CREATION))
+ .structuredLiteral(true);
+ engine = new JexlBuilder()
+ .strict(true)
+ .namespaces(Collections.singletonMap("math", Math.class))
+ .sandbox(sandbox)
+ .create();
includeDeviceAttributes = config.getBoolean(Keys.PROCESSING_COMPUTED_ATTRIBUTES_DEVICE_ATTRIBUTES);
}
private MapContext prepareContext(Position position) {
MapContext result = new MapContext();
if (includeDeviceAttributes) {
- Device device = identityManager.getById(position.getDeviceId());
+ Device device = cacheManager.getObject(Device.class, position.getDeviceId());
if (device != null) {
- for (Object key : device.getAttributes().keySet()) {
- result.set((String) key, device.getAttributes().get(key));
+ for (String key : device.getAttributes().keySet()) {
+ result.set(key, device.getAttributes().get(key));
}
}
}
Set<Method> methods = new HashSet<>(Arrays.asList(position.getClass().getMethods()));
- methods.removeAll(Arrays.asList(Object.class.getMethods()));
+ Arrays.asList(Object.class.getMethods()).forEach(methods::remove);
for (Method method : methods) {
if (method.getName().startsWith("get") && method.getParameterTypes().length == 0) {
String name = Character.toLowerCase(method.getName().charAt(3)) + method.getName().substring(4);
@@ -82,8 +103,8 @@ public class ComputedAttributesHandler extends BaseDataHandler {
if (!method.getReturnType().equals(Map.class)) {
result.set(name, method.invoke(position));
} else {
- for (Object key : ((Map) method.invoke(position)).keySet()) {
- result.set((String) key, ((Map) method.invoke(position)).get(key));
+ for (Object key : ((Map<?, ?>) method.invoke(position)).keySet()) {
+ result.set((String) key, ((Map<?, ?>) method.invoke(position)).get(key));
}
}
} catch (IllegalAccessException | InvocationTargetException error) {
@@ -99,13 +120,14 @@ public class ComputedAttributesHandler extends BaseDataHandler {
*/
@Deprecated
public Object computeAttribute(Attribute attribute, Position position) throws JexlException {
- return engine.createExpression(attribute.getExpression()).evaluate(prepareContext(position));
+ return engine
+ .createScript(features, engine.createInfo(), attribute.getExpression())
+ .execute(prepareContext(position));
}
@Override
protected Position handlePosition(Position position) {
- Collection<Attribute> attributes = attributesManager.getItems(
- attributesManager.getAllDeviceItems(position.getDeviceId()));
+ Collection<Attribute> attributes = cacheManager.getDeviceObjects(position.getDeviceId(), Attribute.class);
for (Attribute attribute : attributes) {
if (attribute.getAttribute() != null) {
Object result = null;
@@ -116,17 +138,45 @@ public class ComputedAttributesHandler extends BaseDataHandler {
}
if (result != null) {
try {
- switch (attribute.getType()) {
- case "number":
- Number numberValue = (Number) result;
- position.getAttributes().put(attribute.getAttribute(), numberValue);
+ switch (attribute.getAttribute()) {
+ case "valid":
+ position.setValid((Boolean) result);
+ break;
+ case "latitude":
+ position.setLatitude(((Number) result).doubleValue());
+ break;
+ case "longitude":
+ position.setLongitude(((Number) result).doubleValue());
+ break;
+ case "altitude":
+ position.setAltitude(((Number) result).doubleValue());
break;
- case "boolean":
- Boolean booleanValue = (Boolean) result;
- position.getAttributes().put(attribute.getAttribute(), booleanValue);
+ case "speed":
+ position.setSpeed(((Number) result).doubleValue());
+ break;
+ case "course":
+ position.setCourse(((Number) result).doubleValue());
+ break;
+ case "address":
+ position.setAddress((String) result);
+ break;
+ case "accuracy":
+ position.setAccuracy(((Number) result).doubleValue());
break;
default:
- position.getAttributes().put(attribute.getAttribute(), result.toString());
+ switch (attribute.getType()) {
+ case "number":
+ Number numberValue = (Number) result;
+ position.getAttributes().put(attribute.getAttribute(), numberValue);
+ break;
+ case "boolean":
+ Boolean booleanValue = (Boolean) result;
+ position.getAttributes().put(attribute.getAttribute(), booleanValue);
+ break;
+ default:
+ position.getAttributes().put(attribute.getAttribute(), result.toString());
+ }
+ break;
}
} catch (ClassCastException error) {
LOGGER.warn("Attribute cast error", error);