From 0738af216e7b31926e05d3de64e14e5b7f0b214c Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Fri, 4 Feb 2022 23:55:53 -0800 Subject: Fix buffer search --- src/main/java/org/traccar/helper/BufferUtil.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'src/main/java/org/traccar/helper') diff --git a/src/main/java/org/traccar/helper/BufferUtil.java b/src/main/java/org/traccar/helper/BufferUtil.java index bbf12d738..9485c17c6 100644 --- a/src/main/java/org/traccar/helper/BufferUtil.java +++ b/src/main/java/org/traccar/helper/BufferUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2018 - 2021 Anton Tananaev (anton@traccar.org) + * Copyright 2018 - 2022 Anton Tananaev (anton@traccar.org) * Copyright 2018 Andrey Kunitsyn (andrey@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -50,7 +50,7 @@ public final class BufferUtil { wrappedHaystack.writerIndex(endIndex - haystack.readerIndex()); } int result = ByteBufUtil.indexOf(needle, wrappedHaystack); - return result < 0 ? result : haystack.readerIndex() + startIndex + result; + return result < 0 ? result : startIndex + result; } } -- cgit v1.2.3 From 17d8ffe18170c422ac2c6dccef8361e1ca684548 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Mon, 14 Feb 2022 21:30:25 -0800 Subject: Extract package scanning --- src/main/java/org/traccar/ServerManager.java | 48 ++----------- src/main/java/org/traccar/helper/ClassScanner.java | 80 ++++++++++++++++++++++ 2 files changed, 84 insertions(+), 44 deletions(-) create mode 100644 src/main/java/org/traccar/helper/ClassScanner.java (limited to 'src/main/java/org/traccar/helper') diff --git a/src/main/java/org/traccar/ServerManager.java b/src/main/java/org/traccar/ServerManager.java index 0db786bdb..2e2cf7cff 100644 --- a/src/main/java/org/traccar/ServerManager.java +++ b/src/main/java/org/traccar/ServerManager.java @@ -18,23 +18,16 @@ package org.traccar; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.traccar.config.Keys; +import org.traccar.helper.ClassScanner; -import java.io.File; import java.io.IOException; import java.net.BindException; import java.net.ConnectException; -import java.net.URI; import java.net.URISyntaxException; -import java.net.URL; -import java.net.URLDecoder; -import java.nio.charset.StandardCharsets; -import java.util.Enumeration; import java.util.LinkedList; import java.util.List; import java.util.Map; import java.util.concurrent.ConcurrentHashMap; -import java.util.jar.JarEntry; -import java.util.jar.JarFile; public class ServerManager { @@ -43,38 +36,9 @@ public class ServerManager { private final List connectorList = new LinkedList<>(); private final Map protocolList = new ConcurrentHashMap<>(); - private void loadPackage(String packageName) throws IOException, URISyntaxException, ReflectiveOperationException { - - List names = new LinkedList<>(); - String packagePath = packageName.replace('.', '/'); - URL packageUrl = getClass().getClassLoader().getResource(packagePath); - - if (packageUrl.getProtocol().equals("jar")) { - String jarFileName = URLDecoder.decode(packageUrl.getFile(), StandardCharsets.UTF_8.name()); - try (JarFile jf = new JarFile(jarFileName.substring(5, jarFileName.indexOf("!")))) { - Enumeration jarEntries = jf.entries(); - while (jarEntries.hasMoreElements()) { - String entryName = jarEntries.nextElement().getName(); - if (entryName.startsWith(packagePath) && entryName.length() > packagePath.length() + 5) { - names.add(entryName.substring(packagePath.length() + 1, entryName.lastIndexOf('.'))); - } - } - } - } else { - File folder = new File(new URI(packageUrl.toString())); - File[] files = folder.listFiles(); - if (files != null) { - for (File actual: files) { - String entryName = actual.getName(); - names.add(entryName.substring(0, entryName.lastIndexOf('.'))); - } - } - } - - for (String name : names) { - Class protocolClass = Class.forName(packageName + '.' + name); - if (BaseProtocol.class.isAssignableFrom(protocolClass) && Context.getConfig().hasKey( - Keys.PROTOCOL_PORT.withPrefix(BaseProtocol.nameFromClass(protocolClass)))) { + public ServerManager() throws IOException, URISyntaxException, ReflectiveOperationException { + for (Class protocolClass : ClassScanner.findSubclasses(BaseProtocol.class, "org.traccar.protocol")) { + if (Context.getConfig().hasKey(Keys.PROTOCOL_PORT.withPrefix(BaseProtocol.nameFromClass(protocolClass)))) { BaseProtocol protocol = (BaseProtocol) protocolClass.getDeclaredConstructor().newInstance(); connectorList.addAll(protocol.getConnectorList()); protocolList.put(protocol.getName(), protocol); @@ -82,10 +46,6 @@ public class ServerManager { } } - public ServerManager() throws IOException, URISyntaxException, ReflectiveOperationException { - loadPackage("org.traccar.protocol"); - } - public BaseProtocol getProtocol(String name) { return protocolList.get(name); } diff --git a/src/main/java/org/traccar/helper/ClassScanner.java b/src/main/java/org/traccar/helper/ClassScanner.java new file mode 100644 index 000000000..c928f6a12 --- /dev/null +++ b/src/main/java/org/traccar/helper/ClassScanner.java @@ -0,0 +1,80 @@ +/* + * Copyright 2022 Anton Tananaev (anton@traccar.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.traccar.helper; + +import java.io.File; +import java.io.IOException; +import java.net.URI; +import java.net.URISyntaxException; +import java.net.URL; +import java.net.URLDecoder; +import java.nio.charset.StandardCharsets; +import java.util.Enumeration; +import java.util.LinkedList; +import java.util.List; +import java.util.jar.JarEntry; +import java.util.jar.JarFile; + +public final class ClassScanner { + + private ClassScanner() { + } + + public static List> findSubclasses( + Class baseClass) throws IOException, URISyntaxException, ReflectiveOperationException { + return findSubclasses(baseClass, baseClass.getPackageName()); + } + + public static List> findSubclasses(Class baseClass, String packageName) + throws IOException, URISyntaxException, ReflectiveOperationException { + + List names = new LinkedList<>(); + String packagePath = packageName.replace('.', '/'); + URL packageUrl = baseClass.getClassLoader().getResource(packagePath); + + if (packageUrl.getProtocol().equals("jar")) { + String jarFileName = URLDecoder.decode(packageUrl.getFile(), StandardCharsets.UTF_8.name()); + try (JarFile jf = new JarFile(jarFileName.substring(5, jarFileName.indexOf("!")))) { + Enumeration jarEntries = jf.entries(); + while (jarEntries.hasMoreElements()) { + String entryName = jarEntries.nextElement().getName(); + if (entryName.startsWith(packagePath) && entryName.length() > packagePath.length() + 5) { + names.add(entryName.substring(packagePath.length() + 1, entryName.lastIndexOf('.'))); + } + } + } + } else { + File folder = new File(new URI(packageUrl.toString())); + File[] files = folder.listFiles(); + if (files != null) { + for (File actual: files) { + String entryName = actual.getName(); + names.add(entryName.substring(0, entryName.lastIndexOf('.'))); + } + } + } + + var classes = new LinkedList>(); + for (String name : names) { + var clazz = Class.forName(packageName + '.' + name); + if (baseClass.isAssignableFrom(clazz)) { + classes.add(clazz); + } + } + return classes; + } + +} -- cgit v1.2.3 From 94fa65d6961fc369923b11a60758b83ac7c3ecae Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 30 Apr 2022 09:30:43 -0700 Subject: Fix Envotech location --- src/main/java/org/traccar/helper/Parser.java | 5 +++++ .../traccar/protocol/EnvotechProtocolDecoder.java | 21 ++++++++++++++++----- .../protocol/EnvotechProtocolDecoderTest.java | 3 ++- 3 files changed, 23 insertions(+), 6 deletions(-) (limited to 'src/main/java/org/traccar/helper') diff --git a/src/main/java/org/traccar/helper/Parser.java b/src/main/java/org/traccar/helper/Parser.java index 75106e2ba..22e98ded1 100644 --- a/src/main/java/org/traccar/helper/Parser.java +++ b/src/main/java/org/traccar/helper/Parser.java @@ -155,6 +155,7 @@ public class Parser { public enum CoordinateFormat { DEG_DEG, + DEG_DEG_HEM, DEG_HEM, DEG_MIN_MIN, DEG_MIN_HEM, @@ -173,6 +174,10 @@ public class Parser { case DEG_DEG: coordinate = Double.parseDouble(next() + '.' + next()); break; + case DEG_DEG_HEM: + coordinate = Double.parseDouble(next() + '.' + next()); + hemisphere = next(); + break; case DEG_HEM: coordinate = nextDouble(0); hemisphere = next(); diff --git a/src/main/java/org/traccar/protocol/EnvotechProtocolDecoder.java b/src/main/java/org/traccar/protocol/EnvotechProtocolDecoder.java index 083d8a921..51391d4cc 100644 --- a/src/main/java/org/traccar/protocol/EnvotechProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/EnvotechProtocolDecoder.java @@ -54,8 +54,8 @@ public class EnvotechProtocolDecoder extends BaseProtocolDecoder { .number("(dd)(dd)(dd)") // date (ddmmyy) .number("(dd)(dd)(dd)") // time (hhmmss) .number("(d)") // fix - .number("(dd)(dd)(d+)([NS])") // latitude - .number("(ddd)(dd)(d+)([EW])") // longitude + .number("(d+)(d{5})([NS])") // latitude + .number("(d+)(d{5})([EW])") // longitude .number("(ddd)") // speed .number("(ddd)") // course .any() @@ -72,7 +72,18 @@ public class EnvotechProtocolDecoder extends BaseProtocolDecoder { Position position = new Position(getProtocolName()); - position.set(Position.KEY_EVENT, parser.nextHexInt()); + int event = parser.nextHexInt(); + switch (event) { + case 0x60: + position.set(Position.KEY_ALARM, Position.ALARM_LOCK); + break; + case 0x61: + position.set(Position.KEY_ALARM, Position.ALARM_UNLOCK); + break; + default: + break; + } + position.set(Position.KEY_EVENT, event); DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); if (deviceSession == null) { @@ -92,8 +103,8 @@ public class EnvotechProtocolDecoder extends BaseProtocolDecoder { position.setFixTime(parser.nextDateTime(Parser.DateTimeFormat.DMY_HMS)); position.setValid(parser.nextInt() > 0); - position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_MIN_MIN_HEM)); - position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_MIN_MIN_HEM)); + position.setLatitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_DEG_HEM)); + position.setLongitude(parser.nextCoordinate(Parser.CoordinateFormat.DEG_DEG_HEM)); position.setSpeed(parser.nextInt()); position.setCourse(parser.nextInt()); diff --git a/src/test/java/org/traccar/protocol/EnvotechProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/EnvotechProtocolDecoderTest.java index 6a455975d..60c592e1e 100644 --- a/src/test/java/org/traccar/protocol/EnvotechProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/EnvotechProtocolDecoderTest.java @@ -11,7 +11,8 @@ public class EnvotechProtocolDecoderTest extends ProtocolTest { var decoder = new EnvotechProtocolDecoder(null); verifyPosition(decoder, text( - "$80SLM,02,F,AB0010,130410155921,431750216,000040,0000,,00000000,'13041015592110476673N10111459E001281*2A")); + "$80SLM,02,F,AB0010,130410155921,431750216,000040,0000,,00000000,'13041015592110476673N10111459E001281*2A"), + position("2010-04-13 15:59:21.000", true, 4.76673, 101.11459)); verifyPosition(decoder, text( "$80SLM,82,F,AB0010,130410155921,431750216,000040,0000,,00000000,'13041015592110476673N10111459E001281@B0,F,C456,038,00,M234567,,,1A2A3A4A5A6A*4E")); -- cgit v1.2.3 From 9633eccdead886ed0b580707ad76cdf06df9a603 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Mon, 2 May 2022 08:22:53 -0700 Subject: Log transport layer protocol --- src/main/java/org/traccar/BaseProtocolEncoder.java | 3 ++- src/main/java/org/traccar/MainEventHandler.java | 17 +++++------- .../traccar/handler/StandardLoggingHandler.java | 8 +++--- src/main/java/org/traccar/helper/NetworkUtil.java | 31 ++++++++++++++++++++++ 4 files changed, 44 insertions(+), 15 deletions(-) create mode 100644 src/main/java/org/traccar/helper/NetworkUtil.java (limited to 'src/main/java/org/traccar/helper') diff --git a/src/main/java/org/traccar/BaseProtocolEncoder.java b/src/main/java/org/traccar/BaseProtocolEncoder.java index b6df07b98..71fa61e4e 100644 --- a/src/main/java/org/traccar/BaseProtocolEncoder.java +++ b/src/main/java/org/traccar/BaseProtocolEncoder.java @@ -21,6 +21,7 @@ import io.netty.channel.ChannelOutboundHandlerAdapter; import io.netty.channel.ChannelPromise; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.traccar.helper.NetworkUtil; import org.traccar.model.Command; public abstract class BaseProtocolEncoder extends ChannelOutboundHandlerAdapter { @@ -62,7 +63,7 @@ public abstract class BaseProtocolEncoder extends ChannelOutboundHandlerAdapter Object encodedCommand = encodeCommand(ctx.channel(), command); StringBuilder s = new StringBuilder(); - s.append("[").append(ctx.channel().id().asShortText()).append("] "); + s.append("[").append(NetworkUtil.session(ctx.channel())).append("] "); s.append("id: ").append(getUniqueId(command.getDeviceId())).append(", "); s.append("command type: ").append(command.getType()).append(" "); if (encodedCommand != null) { diff --git a/src/main/java/org/traccar/MainEventHandler.java b/src/main/java/org/traccar/MainEventHandler.java index a3f6f4105..f1f2527bc 100644 --- a/src/main/java/org/traccar/MainEventHandler.java +++ b/src/main/java/org/traccar/MainEventHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2012 - 2020 Anton Tananaev (anton@traccar.org) + * Copyright 2012 - 2022 Anton Tananaev (anton@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -26,6 +26,7 @@ import org.slf4j.LoggerFactory; import org.traccar.config.Keys; import org.traccar.database.StatisticsManager; import org.traccar.helper.DateUtil; +import org.traccar.helper.NetworkUtil; import org.traccar.model.Position; import org.traccar.storage.StorageException; @@ -64,7 +65,7 @@ public class MainEventHandler extends ChannelInboundHandlerAdapter { String uniqueId = Context.getIdentityManager().getById(position.getDeviceId()).getUniqueId(); StringBuilder builder = new StringBuilder(); - builder.append(formatChannel(ctx.channel())).append(" "); + builder.append("[").append(NetworkUtil.session(ctx.channel())).append("] "); builder.append("id: ").append(uniqueId); for (String attribute : logAttributes) { switch (attribute) { @@ -113,20 +114,16 @@ public class MainEventHandler extends ChannelInboundHandlerAdapter { } } - private static String formatChannel(Channel channel) { - return String.format("[%s]", channel.id().asShortText()); - } - @Override public void channelActive(ChannelHandlerContext ctx) { if (!(ctx.channel() instanceof DatagramChannel)) { - LOGGER.info(formatChannel(ctx.channel()) + " connected"); + LOGGER.info("[{}] connected", NetworkUtil.session(ctx.channel())); } } @Override public void channelInactive(ChannelHandlerContext ctx) { - LOGGER.info(formatChannel(ctx.channel()) + " disconnected"); + LOGGER.info("[{}] disconnected", NetworkUtil.session(ctx.channel())); closeChannel(ctx.channel()); if (BasePipelineFactory.getHandler(ctx.pipeline(), HttpRequestDecoder.class) == null @@ -140,14 +137,14 @@ public class MainEventHandler extends ChannelInboundHandlerAdapter { while (cause.getCause() != null && cause.getCause() != cause) { cause = cause.getCause(); } - LOGGER.warn(formatChannel(ctx.channel()) + " error", cause); + LOGGER.info("[{}] error", NetworkUtil.session(ctx.channel()), cause); closeChannel(ctx.channel()); } @Override public void userEventTriggered(ChannelHandlerContext ctx, Object evt) { if (evt instanceof IdleStateEvent) { - LOGGER.info(formatChannel(ctx.channel()) + " timed out"); + LOGGER.info("[{}] timed out", NetworkUtil.session(ctx.channel())); closeChannel(ctx.channel()); } } diff --git a/src/main/java/org/traccar/handler/StandardLoggingHandler.java b/src/main/java/org/traccar/handler/StandardLoggingHandler.java index 13c5f8281..84492e2a5 100644 --- a/src/main/java/org/traccar/handler/StandardLoggingHandler.java +++ b/src/main/java/org/traccar/handler/StandardLoggingHandler.java @@ -1,5 +1,5 @@ /* - * Copyright 2019 Anton Tananaev (anton@traccar.org) + * Copyright 2019 - 2022 Anton Tananaev (anton@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,6 +23,7 @@ import io.netty.channel.ChannelPromise; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.traccar.NetworkMessage; +import org.traccar.helper.NetworkUtil; import java.net.InetSocketAddress; import java.net.SocketAddress; @@ -63,7 +64,7 @@ public class StandardLoggingHandler extends ChannelDuplexHandler { public void log(ChannelHandlerContext ctx, boolean downstream, SocketAddress remoteAddress, ByteBuf buf) { StringBuilder message = new StringBuilder(); - message.append("[").append(ctx.channel().id().asShortText()).append(": "); + message.append("[").append(NetworkUtil.session(ctx.channel())).append(": "); message.append(protocol); if (downstream) { message.append(" > "); @@ -76,9 +77,8 @@ public class StandardLoggingHandler extends ChannelDuplexHandler { } else { message.append("unknown"); } - message.append("]"); + message.append("] "); - message.append(" HEX: "); message.append(ByteBufUtil.hexDump(buf)); LOGGER.info(message.toString()); diff --git a/src/main/java/org/traccar/helper/NetworkUtil.java b/src/main/java/org/traccar/helper/NetworkUtil.java new file mode 100644 index 000000000..2fe3487da --- /dev/null +++ b/src/main/java/org/traccar/helper/NetworkUtil.java @@ -0,0 +1,31 @@ +/* + * Copyright 2022 Anton Tananaev (anton@traccar.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.traccar.helper; + +import io.netty.channel.Channel; +import io.netty.channel.socket.DatagramChannel; + +public final class NetworkUtil { + + private NetworkUtil() { + } + + public static String session(Channel channel) { + char transport = channel instanceof DatagramChannel ? 'U' : 'T'; + return transport + channel.id().asShortText(); + } + +} -- cgit v1.2.3 From fed6597faa141ba3ee8b11bff2c987ac981fd91b Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Tue, 24 May 2022 08:59:27 -0700 Subject: Include address in login logs --- .../java/org/traccar/api/resource/SessionResource.java | 5 ++--- src/main/java/org/traccar/helper/LogAction.java | 17 ++++++++++------- 2 files changed, 12 insertions(+), 10 deletions(-) (limited to 'src/main/java/org/traccar/helper') diff --git a/src/main/java/org/traccar/api/resource/SessionResource.java b/src/main/java/org/traccar/api/resource/SessionResource.java index 8422e0b49..136aab0eb 100644 --- a/src/main/java/org/traccar/api/resource/SessionResource.java +++ b/src/main/java/org/traccar/api/resource/SessionResource.java @@ -110,8 +110,7 @@ public class SessionResource extends BaseResource { @FormParam("email") String email, @FormParam("password") String password) throws StorageException { User user = Context.getPermissionsManager().login(email, password); if (user != null) { - request.getSession().setAttribute(USER_ID_KEY, user.getId()); - LogAction.login(user.getId()); + LogAction.login(user.getId(), ServletHelper.retrieveRemoteAddress(request)); return user; } else { LogAction.failedLogin(ServletHelper.retrieveRemoteAddress(request)); @@ -121,7 +120,7 @@ public class SessionResource extends BaseResource { @DELETE public Response remove() { - LogAction.logout(getUserId()); + LogAction.logout(getUserId(), ServletHelper.retrieveRemoteAddress(request)); request.getSession().removeAttribute(USER_ID_KEY); return Response.noContent().build(); } diff --git a/src/main/java/org/traccar/helper/LogAction.java b/src/main/java/org/traccar/helper/LogAction.java index d16b25483..b255b9206 100644 --- a/src/main/java/org/traccar/helper/LogAction.java +++ b/src/main/java/org/traccar/helper/LogAction.java @@ -47,7 +47,7 @@ public final class LogAction { private static final String PATTERN_OBJECT = "user: %d, action: %s, object: %s, id: %d"; private static final String PATTERN_LINK = "user: %d, action: %s, owner: %s, id: %d, property: %s, id: %d"; - private static final String PATTERN_LOGIN = "user: %d, action: %s"; + private static final String PATTERN_LOGIN = "user: %d, action: %s, from: %s"; private static final String PATTERN_LOGIN_FAILED = "login failed from: %s"; private static final String PATTERN_DEVICE_ACCUMULATORS = "user: %d, action: %s, deviceId: %d"; private static final String PATTERN_REPORT = "user: %d, report: %s, from: %s, to: %s, devices: %s, groups: %s"; @@ -72,12 +72,12 @@ public final class LogAction { logLinkAction(ACTION_UNLINK, userId, owner, ownerId, property, propertyId); } - public static void login(long userId) { - logLoginAction(ACTION_LOGIN, userId); + public static void login(long userId, String remoteAddress) { + logLoginAction(ACTION_LOGIN, userId, remoteAddress); } - public static void logout(long userId) { - logLoginAction(ACTION_LOGOUT, userId); + public static void logout(long userId, String remoteAddress) { + logLoginAction(ACTION_LOGOUT, userId, remoteAddress); } public static void failedLogin(String remoteAddress) { @@ -105,8 +105,11 @@ public final class LogAction { Introspector.decapitalize(property.getSimpleName()), propertyId)); } - private static void logLoginAction(String action, long userId) { - LOGGER.info(String.format(PATTERN_LOGIN, userId, action)); + private static void logLoginAction(String action, long userId, String remoteAddress) { + if (remoteAddress == null || remoteAddress.isEmpty()) { + remoteAddress = "unknown"; + } + LOGGER.info(String.format(PATTERN_LOGIN, userId, action, remoteAddress)); } public static void logReport( -- cgit v1.2.3 From 56af285413c2337079332f303f7d091d65f09c4e Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 28 May 2022 06:31:55 -0700 Subject: Decode G6W audio format --- src/main/java/org/traccar/helper/BufferUtil.java | 12 +++++++ .../org/traccar/protocol/WatchProtocolDecoder.java | 39 +++++++++++++++++----- .../traccar/protocol/WatchProtocolDecoderTest.java | 3 ++ 3 files changed, 46 insertions(+), 8 deletions(-) (limited to 'src/main/java/org/traccar/helper') diff --git a/src/main/java/org/traccar/helper/BufferUtil.java b/src/main/java/org/traccar/helper/BufferUtil.java index 9485c17c6..1e1a687fa 100644 --- a/src/main/java/org/traccar/helper/BufferUtil.java +++ b/src/main/java/org/traccar/helper/BufferUtil.java @@ -27,6 +27,18 @@ public final class BufferUtil { private BufferUtil() { } + public static int indexOf(ByteBuf buffer, int fromIndex, int toIndex, byte value, int count) { + int startIndex = fromIndex; + for (int i = 0; i < count; i++) { + int result = buffer.indexOf(startIndex, toIndex, value); + if (result < 0 || i == count - 1) { + return result; + } + startIndex = result + 1; + } + return -1; + } + public static int indexOf(String needle, ByteBuf haystack) { return indexOf(needle, haystack, haystack.readerIndex(), haystack.writerIndex()); } diff --git a/src/main/java/org/traccar/protocol/WatchProtocolDecoder.java b/src/main/java/org/traccar/protocol/WatchProtocolDecoder.java index b25a15f93..420866578 100644 --- a/src/main/java/org/traccar/protocol/WatchProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/WatchProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 - 2021 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 2022 Anton Tananaev (anton@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -18,14 +18,13 @@ package org.traccar.protocol; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.Channel; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.traccar.BaseProtocolDecoder; import org.traccar.Context; import org.traccar.DeviceSession; import org.traccar.NetworkMessage; import org.traccar.Protocol; import org.traccar.helper.BitUtil; +import org.traccar.helper.BufferUtil; import org.traccar.helper.Parser; import org.traccar.helper.PatternBuilder; import org.traccar.helper.UnitsConverter; @@ -41,7 +40,7 @@ import java.util.regex.Pattern; public class WatchProtocolDecoder extends BaseProtocolDecoder { - private static final Logger LOGGER = LoggerFactory.getLogger(WatchProtocolDecoder.class); + private ByteBuf audio; public WatchProtocolDecoder(Protocol protocol) { super(protocol); @@ -318,13 +317,37 @@ public class WatchProtocolDecoder extends BaseProtocolDecoder { return position; + } else if (type.equals("JXTK")) { + + int dataIndex = BufferUtil.indexOf(buf, buf.readerIndex(), buf.writerIndex(), (byte) ',', 4) + 1; + String[] values = buf.readCharSequence( + dataIndex - buf.readerIndex(), StandardCharsets.US_ASCII).toString().split(","); + + int current = Integer.parseInt(values[2]); + int total = Integer.parseInt(values[3]); + + if (audio == null) { + audio = Unpooled.buffer(); + } + audio.writeBytes(buf); + + sendResponse(channel, id, index, "JXTKR,1"); + + if (current < total) { + return null; + } else { + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + getLastLocation(position, null); + position.set(Position.KEY_AUDIO, Context.getMediaManager().writeFile(id, audio, "amr")); + audio.release(); + audio = null; + return position; + } + } else if (type.equals("TK")) { if (buf.readableBytes() == 1) { - byte result = buf.readByte(); - if (result != '1') { - LOGGER.warn(type + "," + result); - } return null; } diff --git a/src/test/java/org/traccar/protocol/WatchProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/WatchProtocolDecoderTest.java index 34ef7839b..ef6c33da9 100644 --- a/src/test/java/org/traccar/protocol/WatchProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/WatchProtocolDecoderTest.java @@ -15,6 +15,9 @@ public class WatchProtocolDecoderTest extends ProtocolTest { var decoder = new WatchProtocolDecoder(null); + verifyNull(decoder, binary( + "5b5a4a2a3738393436383035303034323639322a303033342a303433392a4a58544b2c302c77617463685f375f32303232303532363039333935342c312c362c2321414d520a0c0a3c3f96d98367e9468ea245320c0a3c3f96d98367e9468ea245320c0a3c3f96d98367e9468ea245320c389814ffcd762fe49d50ae7a2e0cb528aefbf76911df05c2fbe17d050c2200cff77ef0df4d9b4ab9a4340c449814dbe7c63fa82bc3750d800cc48abbffddb0df8e8fda95e5980c49982ff6cf65f9377d02a39c3aaa0c389805f2ff42c1b80e0a0eb1dc0c2998e9defe15cfa3bdbe80d3540c7298c2f6d9239e3eae3c4a81660c490034dbfd513fedad0c2fc3900cc40039b7f71bb0657ba75558c40cd7813b97ff7219777ec7f401260c7d040003bff6f75fdb898a6ba1140cecd127f7f83357cb73a68a5f680cb081d4f6e749e6af8ed367bc480cec1815dfffd2dbed358112af320ccc21179fffbd17a3a61c133b380c920047defc72a784770ec0fe400c383c42f6faebe76fa736e9d1be0c4918e7decddc67ec9afd87ff220cc418e6bffe6cf6c9ac1f83c3900ca6cad1ffe3da24e1be3b547d03c00c6b00b8fee77f60a76d3e7d0292e20c2918b7bfff76387b793d3a36300c7d0400b7fff7f63ae513ac6f74de0c980016fbff7d01f9b30fca67c7220caa982ff6dbd7bf3d8dfed143ec0c44982fdfcb7b517e26f6ea52420c0ed19cfedb438f179d3fc50ec40c008ad2ffff635fe28dc1ec1f860c76cb7d05bffda53eaebe4d201ae20ccccaffbbfd3db4abb6ddf39d0e0c6b00acfeff406fe4a12661caf80c76982fbffffeb17b2f65472f300c7d04c24bf6ef1b10e47f73fc10b40c76036cfecd4e7837145a6a8e900ccccaf2beeba36fbaa36feb60640c7d0400dfffff73bfa3b87d0256a1700c7d04e4efd6efc23b651eb73e77780ccc1813ffffb39f6baa6f3195080c00007afffee0b9df6346ca08d00c6bca7d04feff4d64a7b56f9855da0c769819fbfd954ea5bd7d040ba6420c4c4c09bfffd5f6c57d01930e7d01220cc48a22dffe30bfcbaf08a795140c7d040433b7ff3cba5f3e336a40060cecbd2bfaf775bea7bde7e095ee0cc4caaef7fb623feeaab69eabc20c8c0021bffd1ea4a1b090175a920c7d046445fbdfc1abe910b0ca56160c7d0440cbd7ef03893c7f7d02e1a8c20c85e42dff5fdaa145759d326b5a0ccc4084f75f8eeb7b15e4eb4ff80c6bc22ef7d7eaf8df3b8ff678cc0cca4026f3cf7518fd731ceca3560cec041ffbe7655eaf822f04c4fe0c7d0478e3fbfcb5dfc8a81fdbb9e20cc418e6d7ff777f26affe37cc020cd7977cbff7d0aecb9727be6a0c0c00bde1f2d797fc8754ed09d4ae0cc498279f7e729fcb9eff70c1a60c7d0478e5bfffc67eef953fda69aa0c7200f1bbf7e891ef5a287cb5b80c983629fee5555f739f8a29279a0c76d103bef73f55a6bf89ba8ce40cc46424f6ded9a194167a067d05880cc4780efeffc37fae944d89bfb40c4464bffffb6dd54e8344394a5c0c49781ffffc653feaa31af59ac00cc464cebfd76ae4e8a55d5b5a4a2a3738393436383035303034323639322a303033352a303434332a4a58544b2c302c77617463685f375f32303232303532363039333935342c322c362c5f24fbbc0c7d04983effcfe35fbd8fff7ce6f60c448a1dfbd715bec3b42448e58a0c0e0421bf5f17ebc31a43301bc40c768ababf4f66cf629ee31fe9900c6b6426bf5f4eb7669dacc439140c945733bff9351e7d04ab6be54ef60ccc98bfbffbf67f63b78d8f42880c7d0400c6f7fffab5cbae8e8275da0c0097ffdefff5dfafb0c4727d04980ccc78d1f6ff1a6b7e37631059fa0c760045f3fd853fea877d03aa87440cc40022f7ffa8b5c58f6e80c58e0ccc4c1f9ffff32fa7af87de04560cb09801f6fdd32efcbdad9495b60c6b987d05bff72d61eb687d05a9f9e20cca57c7ffff6cb1fe3387ea596e0c629823dedfbfc50b97965e44ea0c4918ccbfd7cc75e59fff92e9ee0c8c78e7faff707ffda60ec3ada60c30c217befffcb8f3290f06d75e0c0e8a7bb7dff3eec7b7928ef6680c38ca1cdeff272ba012597d051a520c0018dfffeff27d01e369b3bcd7d80c98146eb2fc7f45c38e1ce53e120c3d5700ff7fd44bee28aa089d900c007157bffffe30302d7d0583585c0ccc5747bfe7f73cff7d02de1098240c7d047865f6feca71d70bdfaab6a20cecb946bfd966be74b61a06c6660c441612ffe7eb966a8c2886cf760ccc7827bffd653ff7980a62e9320c00ca98f7fc1b311a3986700cc20c490017bfff70cfe7bb455637320c6228afbf7e6da4c59763b693740cccc2b5fee1951975760e4a9dca0c0000faffdb255f6f86af4be6fc0cccc2ffdfff7d0225efbc847c42760cb48a8fdffbe23ff1a78782cbe60c7d04980cffff6e6dfc75a6c65a500ce62808bfff24f853748a9537400cb4004ebfeb6e70aa4314903e8c0cb46408ff72d62f44945f64897d040cccca7abfff2db5c6bfcc345e700c7d04c24dd6fd5f95638f78974a800cc4caffffffb17d01c36bdd7d047c2e0c7d0436d1f7f8917f83af7fc5c2180c070449f6fe570f128577c8c97d040c7d047813f6df3fd17d026b6790d1b80cc400c9d6d92dc56497843ed10a0c44986effffe13fef8eef7c717a0c7d049872bbfdad3abe2be0d60b240c4900adbf7d02dfa4ef960fdf23580c629845fefc5a650fbf8b0d4cda0c7d040076b7ef273fe78fce983ae40c4a00ded7ff629f7fab4531501c0c6200b7ffedf13fe6a68f01fb6c0cc49809f77fdb91517fb39e8ba00c760009bf7fd6afe7b46921f27a0cecbd1df6faf99120776e807d03fe0c98ca23fbff3749fb5ed3909c160cc44cbbbfffbd70e77d0367bc2e740c499816f77fe2ffe08edd7d048c9e0c940021beff1df0f1338c2f1a3a0c7d040083feebba1c756e5760c2200c94981dfffdf921b92b99909ba40c7d04984ebbdf7ff0c77d025a1fbfc00c7657b3ff77f4befcae2bf625640c62ca53f7fdb35f2e92af3bd5c60c7d049878bbdfc0dfc1bdaa1918000cc404bbbfefb41ee6b50a39bf180c767874f7fb8ee156320ee600020c69981cffffe0fff6bb2764acaa0cec781bfbff7d0324eb9b4b4d5d5b5a4a2a3738393436383035303034323639322a303033362a303433302a4a58544b2c302c77617463685f375f32303232303532363039333935342c332c362c73580c07ca4fbbfff5bec5abcfac465c0c0042a8beff316aed38fe4603dc0c7d04577d04fefdc929f7294ce7520c0c76984dfaff402fe68ebe113b000c7d0436a6fed465ff4f8d8e3306300c44e434f7f79e84abb8fa081be80c983636bef7e128bf7d03d34c71c80cd7982dffd54cac94536beab1320c058bd6bfff701fe69d1a39d1e80c76caedb77ffea0e47febb469440c0098b2bef5e55eed981672b1c40cd800d1bef4bda58daf7d01d309180c08cadffbfc31799f5613fab2da0c7d049828beffa5eea0bd09a14c2e0c0000e59feb5f9dff7f4945e98e0cc40046ffcfe57fb58f7d053dd9e20c7d040047d7ffd38f67aa9db8d38c0c7698d2df5fe2efc6bb0f5a18220c980367bbfd95dae73e3bf2b59a0c49813796fdf5efab9d3ed7d3d80c9800ebd7fdb831ae8f91811e920c7d04ca74bbff5cdcf45605c25f140c013e029fbfe7ffc299376b409a0c7510009e7d02010f68824cccead60cb13b00f7d5821e6c8d594a06880c75ec00f6e782e8f06b0c610d1a0cc09843dfef117fa5b3aef236f40cdcc208ffff4831f83703ca20c00cc09800bf7fd71eec9ba34e3c200c650f6bffd5bc4dbe7ec5b0f1d80c0d1c1f92ef917fa0b96023eac00c8efb1db6bfa42eed9f69051d4e0c8eff23b2fe4486d56ef44f702e0c8ebc1b9657d46eeea852ac337e0c8efb1f96d9877fc9b34c38f1540c121c2796df13577c727f8cedec0ca9107d05afdd6a9d957ab76c02560c121c2dd6bfd33fa5b844f27d02340cb11037b6e3962e6eaf52d6e7460c2b1c3db2dfe61eef9aad3dcc0a0c542e42d763e709fe723a83ae7c0c7cfa56bf7fedb8763c3f8ab2c00ca40022efff2411604d22a485e00c228adcbfdfcd748293c66b0bf20cb10f0097ff806dcf7a0a640d6e0c5a0400b7e3030ef4ae0a6046f80cb82812fe7b04d77e4bab11894a0c541c24b2dd53fea5891e3824420ca9fb26b2d7156fa485049cac420ca91c2d9edb2487526c2e2260fa0ca9bc25b65ff28e41a34232c0f00c8efb25b649e51ec39c0ae6703a0c70f425a6c820dfaf2f8124c8960c80f42794b323aed9ca9b6924be0cb93b278e3e8d929c36bb70b6360c587b27524f85857d056d214841660cda2f278b4c876eb3186e5acc540ce6832f6e3f0d82f81226e6dc3a0c0b922feff50a03d03c98ae28360c03d62befb54ab611de0c8addee0c84d626b7fdb4461556dc0153040c0b0f27ff5781c5c2b32f6762140c49bf2dfaf521969b702ecb11d80c7d050f27cfed75bfab95dc4af3180c011c3d8e7451df80a5cd0948080c7c2e35f2c7b0becca22e50769e0c7c1c3d965e628f46a9a58ae6100c7c2e3b965f4a6b5ebd1436b0b00c7c863eaedf18c7816cdeeed7e20c2b3e3df6b73952b2b1abc048a00c7cfb3db6cd67ae68cda18af9d60c2bff3e96df12ff61b39627cd580c7c863fd6cd810ee595d85ee6645d5b5a4a2a3738393436383035303034323639322a303033372a303433372a4a58544b2c302c77617463685f375f32303232303532363039333935342c342c362c0c7cff3fb65f812fe196dc62d8360c7c2e3db2de738fae9ca7c7236c0c2b2e3d96df6c1d775a3df5a47e0c7c3e3f96fe943dc07e81e170700c75503fb7d6a6197f1b08df85440c5a133ab6d6a0e68f3acb04b7b00cfa293fd6cfc20c390d5265d3c80c581347b278077d03dc22d9e49c680ce64d47924e8dcdffe9be19dc100cb90f4f9e612d2201961c2e111c0c003b4febb58a96c809ab5a71040ce6d759fbddba54b2aa9d9d983e0cc029576ecf1f703099d84994520c4029579e7d0281577073f5629dd80c5a2952b6fed177177d01e57d0175c20cd8647d044f7e3c58aba523ddb0720cb56753d3e9c6799f95938401f60c756414ff5f00fb57bc4d7e111c0c7c085573ef743ee19ca30057e00c752e5ab77e34eec69f3cbe53940c542e4d96d6e7ff03854a9506620c7cff55b6efca197610a86606180c7cfb55b67eb25f4b999c002bf20c7c107d03beeb451fad8d042492740cb8f05eb5ff664f679c1cc991c60ce1671bffd33d9445b57d0584c7d60c07781dfef5e3ee81b45ff8a8c80cc40072b7dfe6fe6e978257253a0cb1131fe6783035868e439b00d80c583b27b17ecb53dd165c3422180c703b2fbeb18d023e14d90304700c3cce2b93cdc2e6b3550a5546160cb13b3b72fe24273859059b52040c224d34edc742f6bb7c877d02b5940cb84d37cdcfcbc3f03a041cf4ac0ca4923a9f3b74e805b235cce8660c759000fbfd90565072aa7d03bb520cb592017f411dcbe80a0cc420360c09d6528fcf2e25b382ee46d75a0ce2e853d3cfb617fd7d023f05e0780c07cc3bbabfa9f6cec5aa48ac600c404208fb678a4cf16a9c09098c0cf14244fbdfc2afe7932fe57d02900c011c369e7d0264a8570a54f9a2e80cb1103daed6249fe59dc888c2ac0cb1103573c5f697be759923ecc80c705f7d059effaaa4b09b976f375a0c804223bbed89767d041693edab180cb49819d7eb5a8573bb10c951540c3c643af74f021f25b6dd3b7d02040c07982bd73fb31fe38f09a227a40c037610ff7d03c6058098fef936a80c03b808debbe055a1a71319128c0c6b8f2e9e3bb52d71c226d3141a0cdab82d7fa9d416167a1cb950020c03c32bb23ee9e3743f3b6853060cc02937adb5157d05f4a6960c1b680c4076365e6b754bda9394a7aa720c06293ef23313fb1b94bcc2c09a0ce676006bbd8e0417941b90d23c0cb9294f7d01fd3d65748cf6d1cc220c03767d035e3a65e6f2514ab1db060ce6d965bf4035f65c79a9e4446a0ce62921dbf46457b56cd65f6c500c584d6bba7ea8166edd6cf7693a0cb939227bfca25f82a7c4202f2e0c06ce2b9a4f0d95f39eb43c22840c06901eef6fd15fe48f452000e00c62023afbffb269beba0ee0ac540ce6ec00f37b8139f2026e80f1440c22501dfe7d017d03ed8c3ff6803f240cc48ae3b7fd725e63a347cd64100c0094f8efdeb0a9f35c83eb06b00c005d5b5a4a2a3738393436383035303034323639322a303033382a303433332a4a58544b2c302c77617463685f375f32303232303532363039333935342c352c362c6647deef2df57fb68fd76b660c44e43cbfefc0beec867d025c3f920cb4507d01ff6f42ee6c1f58a0db0e0c7d045701ff7f19f9f90fdff037c20c4404259efcd47d02a52b7ef6df0e0c7d04d128f3578db14779993109560ce1e41ecffd2851af49256b1ecc0c7d049837ffff707168db3dd1ac240cc09419f7f39a7d013d6ec1b4e55c0cc4881cff5f49f55fadc52285a40c06ce9ad7dbb8349b97031ac3b00c407d049d9bed74dfadad950eab560c06799ffac7a924b18bdf11c3d40c8054a2f777522e65be921a77240c8042a19bff706fe5b7e3e7d0360cd82840bff3f4fe429bea0081560c0064419fd9157f8b9c797e92c20cc47fe2b7d5e6ee45bf0524010e0c0894299e7d037e4553bcbbc0989e0c40501bbbdc926f8daf53885e0a0c80971ffee559f5bf98ed54cf140c00581abbffac75b88b14d5e3780c5a046dd66fd7bfe5b7ca749df40c403672bbcfe47ee797860ded5e0cb5502efb7ee2ffc7bbdc27d0880c44ca08fbf7031ecd9321d21ef40cdc9806fefde36f0699ad1569420c22cb1bfbdc974fcb900ab601440c00cb1cfbdfd2f7d2730b0b46680c0b4203dfef309fe0adc121e2080c225829feeb901f25b926343bae0c624204dfff4875b69ceda4df4c0c499886ffe7301e8e8bf9ef0a260cdce408dbef829fe45337e98d860c010800ef76088d8015f3b2c84e0c755c3ecfc898f50fbcdb9344220c7c7d03459349337d01e4949da1b4ec0c7cf046ae6e4a90df3552070a5e0c7cf045d23fbba0951147986eca0c7536426e6ef2ef0b7d01c22fd2960cb8284e9db92d40552988334f200cb8024acdbfea90d13b545fe35e0cb8f04d5e48659d48b97c1096140c7c084f79df4402702126bf358a0cb8a74d4def66535e145638d12e0c543e4d8edfa2531b15a340eb800cb83e4eafbd9031291a8563e4780c54a74ef1c7300da79aa94bb67d050cb8f04eba6fb0325813871511b80ce20ff6fffd404ed58ecf264c8e0c7c0f1cb3fe1a36fb7187c379d00c7c3e52f6727d0261ca8bdd1361b80cb8d64d9a4fb1cfe0aadaaa7d05c40c2b2e44b2bfb9b4dcad9d7d0200280c7c3b47d5db803fc2aee71a77f00c7c1343b2bfa06ee6ad3228f10a0c7c3b4a76477fe7650b0c809ca80c54d74b92dbc327134514d6126e0c7c5f4a8f4f74efaaa5cd0a43bc0c7c104bb64ff5ce604fa2028b680c7cff4aaec7f7a9394cc4c599e60cb8ce52eeb553d215a6a466b4120c750f4fae5f9816c04a0a3f751e0c75e04f73c58e96bb4b925a4c680cb80f4b6e3fe1635614bbdeccbc0c7c3b4faf7e825e42d473ee76800ce298578ffcb61f0af936387bbe0cb800e39bf62410681583e0d2b20cb4987d05ff7f297bf69eaf4cd8b40cb57815bf7f300fcffe9fae966a0cb497acd75fd37f648d00d141a00cc48af9fffe1a3b979b8f8573e80c29bff1bf4b94c6fd7c3eec075e0c7cce1f5d5b5a4a2a3738393436383035303034323639322a303033392a303065352a4a58544b2c302c77617463685f375f32303232303532363039333935342c362c362c8f5cf9f34fa6edceb18c0ca4ce436e7d02d329de94b63eb11a0cb894438f44cf753dbc1a83b4560cb8e44391eff729d4155a231bf40cb59443f373b4288492cd6e38160c5a42049bfec8678ad42bce0c560cb12e39fec3d1fe24b5572ee0be0cb1ce35fe33688455aa74e3ffa40cb1d635df4b704160ae864a7d03440cb10f3267dbf4a21d540ca1051c0cb11337724f8747f5547d054e91660cb1a73692df964f3bbb0758d41a0cfe05b60c314460297eae4185f20cad673ceb6dfa05ddbe0278d5de5d")); + verifyPosition(decoder, buffer( "[3G*9031853319*004E*UD2,220322,055105,A,22.761162,N,114.360192,E,0,0,47,14,100,64,0,0,00000008,0,0]")); -- cgit v1.2.3 From 104281f161f622df8fca0c65a5b9969ceb03c46f Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Tue, 7 Jun 2022 18:04:24 -0700 Subject: Extract user utils from reports --- build.gradle | 2 +- src/main/java/org/traccar/Main.java | 3 +- .../org/traccar/api/resource/PasswordResource.java | 3 +- .../traccar/api/security/PermissionsService.java | 2 + .../org/traccar/database/PermissionsManager.java | 12 ----- src/main/java/org/traccar/helper/UserUtil.java | 57 ++++++++++++++++++++++ .../notification/NotificationFormatter.java | 12 +++-- .../notification/TextTemplateFormatter.java | 9 ++-- .../org/traccar/reports/EventsReportProvider.java | 8 ++- .../org/traccar/reports/RouteReportProvider.java | 13 ++++- .../org/traccar/reports/StopsReportProvider.java | 8 ++- .../org/traccar/reports/SummaryReportProvider.java | 19 ++++++-- .../org/traccar/reports/TripsReportProvider.java | 8 ++- .../org/traccar/reports/common/ReportUtils.java | 30 +++--------- .../org/traccar/session/cache/CacheManager.java | 36 +++++++++++--- src/main/java/org/traccar/web/WebServer.java | 3 ++ 16 files changed, 162 insertions(+), 63 deletions(-) create mode 100644 src/main/java/org/traccar/helper/UserUtil.java (limited to 'src/main/java/org/traccar/helper') diff --git a/build.gradle b/build.gradle index de8c86712..8c196043a 100644 --- a/build.gradle +++ b/build.gradle @@ -49,7 +49,7 @@ dependencies { implementation "io.netty:netty-all:4.1.66.Final" implementation "org.slf4j:slf4j-jdk14:2.0.0-alpha6" implementation "com.google.inject:guice:$guiceVersion" - implementation "com.google.inject.extensions:guice-assistedinject:$guiceVersion" + implementation "com.google.inject.extensions:guice-servlet:$guiceVersion" implementation "org.owasp.encoder:encoder:1.2.3" implementation "org.glassfish:javax.json:1.1.4" implementation "org.eclipse.jetty:jetty-server:$jettyVersion" diff --git a/src/main/java/org/traccar/Main.java b/src/main/java/org/traccar/Main.java index db9892bb9..b14f22a00 100644 --- a/src/main/java/org/traccar/Main.java +++ b/src/main/java/org/traccar/Main.java @@ -17,6 +17,7 @@ package org.traccar; import com.google.inject.Guice; import com.google.inject.Injector; +import com.google.inject.servlet.ServletModule; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.traccar.schedule.ScheduleManager; @@ -111,7 +112,7 @@ public final class Main { public static void run(String configFile) { try { - injector = Guice.createInjector(new MainModule()); + injector = Guice.createInjector(new MainModule(), new ServletModule()); Context.init(configFile); logSystemInfo(); LOGGER.info("Version: " + Main.class.getPackage().getImplementationVersion()); diff --git a/src/main/java/org/traccar/api/resource/PasswordResource.java b/src/main/java/org/traccar/api/resource/PasswordResource.java index ed7131718..91d994153 100644 --- a/src/main/java/org/traccar/api/resource/PasswordResource.java +++ b/src/main/java/org/traccar/api/resource/PasswordResource.java @@ -51,7 +51,8 @@ public class PasswordResource extends BaseResource { String token = UUID.randomUUID().toString().replaceAll("-", ""); user.set(PASSWORD_RESET_TOKEN, token); Context.getUsersManager().updateItem(user); - VelocityContext velocityContext = TextTemplateFormatter.prepareContext(null); + VelocityContext velocityContext = TextTemplateFormatter.prepareContext( + permissionsService.getServer(), user); velocityContext.put("token", token); NotificationMessage fullMessage = TextTemplateFormatter.formatMessage(velocityContext, "passwordReset", "full"); diff --git a/src/main/java/org/traccar/api/security/PermissionsService.java b/src/main/java/org/traccar/api/security/PermissionsService.java index 9ec3b43c1..c70414b2a 100644 --- a/src/main/java/org/traccar/api/security/PermissionsService.java +++ b/src/main/java/org/traccar/api/security/PermissionsService.java @@ -15,6 +15,7 @@ */ package org.traccar.api.security; +import com.google.inject.servlet.RequestScoped; import org.traccar.model.BaseModel; import org.traccar.model.Calendar; import org.traccar.model.Command; @@ -34,6 +35,7 @@ import org.traccar.storage.query.Request; import javax.inject.Inject; +@RequestScoped public class PermissionsService { private final Storage storage; diff --git a/src/main/java/org/traccar/database/PermissionsManager.java b/src/main/java/org/traccar/database/PermissionsManager.java index 47941d681..e8f2380a2 100644 --- a/src/main/java/org/traccar/database/PermissionsManager.java +++ b/src/main/java/org/traccar/database/PermissionsManager.java @@ -412,16 +412,4 @@ public class PermissionsManager { return null; } - public Object lookupAttribute(long userId, String key, Object defaultValue) { - Object preference; - Object serverPreference = server.getAttributes().get(key); - Object userPreference = getUser(userId).getAttributes().get(key); - if (server.getForceSettings()) { - preference = serverPreference != null ? serverPreference : userPreference; - } else { - preference = userPreference != null ? userPreference : serverPreference; - } - return preference != null ? preference : defaultValue; - } - } diff --git a/src/main/java/org/traccar/helper/UserUtil.java b/src/main/java/org/traccar/helper/UserUtil.java new file mode 100644 index 000000000..6050ad349 --- /dev/null +++ b/src/main/java/org/traccar/helper/UserUtil.java @@ -0,0 +1,57 @@ +/* + * Copyright 2022 Anton Tananaev (anton@traccar.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.traccar.helper; + +import org.traccar.model.Server; +import org.traccar.model.User; + +import java.util.TimeZone; + +public final class UserUtil { + + private UserUtil() { + } + + public static String getDistanceUnit(Server server, User user) { + return lookupStringAttribute(server, user, "distanceUnit", "km"); + } + + public static String getSpeedUnit(Server server, User user) { + return lookupStringAttribute(server, user, "speedUnit", "kn"); + } + + public static String getVolumeUnit(Server server, User user) { + return lookupStringAttribute(server, user, "volumeUnit", "ltr"); + } + + public static TimeZone getTimezone(Server server, User user) { + String timezone = lookupStringAttribute(server, user, "timezone", null); + return timezone != null ? TimeZone.getTimeZone(timezone) : TimeZone.getDefault(); + } + + private static String lookupStringAttribute(Server server, User user, String key, String defaultValue) { + String preference; + String serverPreference = server.getString(key); + String userPreference = user.getString(key); + if (server.getForceSettings()) { + preference = serverPreference != null ? serverPreference : userPreference; + } else { + preference = userPreference != null ? userPreference : serverPreference; + } + return preference != null ? preference : defaultValue; + } + +} diff --git a/src/main/java/org/traccar/notification/NotificationFormatter.java b/src/main/java/org/traccar/notification/NotificationFormatter.java index be90761b1..13f42a8b2 100644 --- a/src/main/java/org/traccar/notification/NotificationFormatter.java +++ b/src/main/java/org/traccar/notification/NotificationFormatter.java @@ -17,13 +17,14 @@ package org.traccar.notification; import org.apache.velocity.VelocityContext; +import org.traccar.helper.UserUtil; import org.traccar.model.Device; import org.traccar.model.Event; import org.traccar.model.Geofence; import org.traccar.model.Maintenance; import org.traccar.model.Position; +import org.traccar.model.Server; import org.traccar.model.User; -import org.traccar.reports.common.ReportUtils; import org.traccar.session.cache.CacheManager; public final class NotificationFormatter { @@ -34,17 +35,18 @@ public final class NotificationFormatter { public static NotificationMessage formatMessage( CacheManager cacheManager, User user, Event event, Position position, String templatePath) { + Server server = cacheManager.getServer(); Device device = cacheManager.getObject(Device.class, event.getDeviceId()); - VelocityContext velocityContext = TextTemplateFormatter.prepareContext(user); + VelocityContext velocityContext = TextTemplateFormatter.prepareContext(server, user); velocityContext.put("device", device); velocityContext.put("event", event); if (position != null) { velocityContext.put("position", position); - velocityContext.put("speedUnit", ReportUtils.getSpeedUnit(user.getId())); - velocityContext.put("distanceUnit", ReportUtils.getDistanceUnit(user.getId())); - velocityContext.put("volumeUnit", ReportUtils.getVolumeUnit(user.getId())); + velocityContext.put("speedUnit", UserUtil.getSpeedUnit(server, user)); + velocityContext.put("distanceUnit", UserUtil.getDistanceUnit(server, user)); + velocityContext.put("volumeUnit", UserUtil.getVolumeUnit(server, user)); } if (event.getGeofenceId() != 0) { velocityContext.put("geofence", cacheManager.getObject(Geofence.class, event.getGeofenceId())); diff --git a/src/main/java/org/traccar/notification/TextTemplateFormatter.java b/src/main/java/org/traccar/notification/TextTemplateFormatter.java index 469de2d4a..06375afac 100644 --- a/src/main/java/org/traccar/notification/TextTemplateFormatter.java +++ b/src/main/java/org/traccar/notification/TextTemplateFormatter.java @@ -1,5 +1,5 @@ /* - * Copyright 2021 Anton Tananaev (anton@traccar.org) + * Copyright 2021 - 2022 Anton Tananaev (anton@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -23,8 +23,9 @@ import org.apache.velocity.tools.generic.NumberTool; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.traccar.Context; +import org.traccar.helper.UserUtil; +import org.traccar.model.Server; import org.traccar.model.User; -import org.traccar.reports.common.ReportUtils; import java.io.StringWriter; import java.nio.charset.StandardCharsets; @@ -38,13 +39,13 @@ public final class TextTemplateFormatter { private TextTemplateFormatter() { } - public static VelocityContext prepareContext(User user) { + public static VelocityContext prepareContext(Server server, User user) { VelocityContext velocityContext = new VelocityContext(); if (user != null) { velocityContext.put("user", user); - velocityContext.put("timezone", ReportUtils.getTimezone(user.getId())); + velocityContext.put("timezone", UserUtil.getTimezone(server, user)); } velocityContext.put("webUrl", Context.getVelocityEngine().getProperty("web.url")); diff --git a/src/main/java/org/traccar/reports/EventsReportProvider.java b/src/main/java/org/traccar/reports/EventsReportProvider.java index 9b4a7df2b..f0c8c31b6 100644 --- a/src/main/java/org/traccar/reports/EventsReportProvider.java +++ b/src/main/java/org/traccar/reports/EventsReportProvider.java @@ -28,6 +28,7 @@ import java.util.Iterator; import org.apache.poi.ss.util.WorkbookUtil; import org.traccar.Context; +import org.traccar.api.security.PermissionsService; import org.traccar.model.Device; import org.traccar.model.Event; import org.traccar.model.Geofence; @@ -42,10 +43,12 @@ import javax.inject.Inject; public class EventsReportProvider { + private final PermissionsService permissionsService; private final Storage storage; @Inject - public EventsReportProvider(Storage storage) { + public EventsReportProvider(PermissionsService permissionsService, Storage storage) { + this.permissionsService = permissionsService; this.storage = storage; } @@ -127,7 +130,8 @@ public class EventsReportProvider { String templatePath = Context.getConfig().getString("report.templatesPath", "templates/export/"); try (InputStream inputStream = new FileInputStream(templatePath + "/events.xlsx")) { - org.jxls.common.Context jxlsContext = ReportUtils.initializeContext(userId); + var jxlsContext = ReportUtils.initializeContext( + permissionsService.getServer(), permissionsService.getUser(userId)); jxlsContext.putVar("devices", devicesEvents); jxlsContext.putVar("sheetNames", sheetNames); jxlsContext.putVar("geofenceNames", geofenceNames); diff --git a/src/main/java/org/traccar/reports/RouteReportProvider.java b/src/main/java/org/traccar/reports/RouteReportProvider.java index 4c4a41405..e20ba6885 100644 --- a/src/main/java/org/traccar/reports/RouteReportProvider.java +++ b/src/main/java/org/traccar/reports/RouteReportProvider.java @@ -26,6 +26,7 @@ import java.util.Date; import org.apache.poi.ss.util.WorkbookUtil; import org.traccar.Context; +import org.traccar.api.security.PermissionsService; import org.traccar.model.Device; import org.traccar.model.Group; import org.traccar.model.Position; @@ -33,8 +34,17 @@ import org.traccar.reports.common.ReportUtils; import org.traccar.reports.model.DeviceReportSection; import org.traccar.storage.StorageException; +import javax.inject.Inject; + public class RouteReportProvider { + private final PermissionsService permissionsService; + + @Inject + public RouteReportProvider(PermissionsService permissionsService) { + this.permissionsService = permissionsService; + } + public Collection getObjects(long userId, Collection deviceIds, Collection groupIds, Date from, Date to) throws StorageException { ReportUtils.checkPeriodLimit(from, to); @@ -72,7 +82,8 @@ public class RouteReportProvider { String templatePath = Context.getConfig().getString("report.templatesPath", "templates/export/"); try (InputStream inputStream = new FileInputStream(templatePath + "/route.xlsx")) { - org.jxls.common.Context jxlsContext = ReportUtils.initializeContext(userId); + var jxlsContext = ReportUtils.initializeContext( + permissionsService.getServer(), permissionsService.getUser(userId)); jxlsContext.putVar("devices", devicesRoutes); jxlsContext.putVar("sheetNames", sheetNames); jxlsContext.putVar("from", from); diff --git a/src/main/java/org/traccar/reports/StopsReportProvider.java b/src/main/java/org/traccar/reports/StopsReportProvider.java index 58dc71d2d..8899dc42f 100644 --- a/src/main/java/org/traccar/reports/StopsReportProvider.java +++ b/src/main/java/org/traccar/reports/StopsReportProvider.java @@ -28,6 +28,7 @@ import java.util.Date; import org.apache.poi.ss.util.WorkbookUtil; import org.traccar.Context; import org.traccar.Main; +import org.traccar.api.security.PermissionsService; import org.traccar.database.DeviceManager; import org.traccar.database.IdentityManager; import org.traccar.model.Device; @@ -42,10 +43,12 @@ import javax.inject.Inject; public class StopsReportProvider { + private final PermissionsService permissionsService; private final Storage storage; @Inject - public StopsReportProvider(Storage storage) { + public StopsReportProvider(PermissionsService permissionsService, Storage storage) { + this.permissionsService = permissionsService; this.storage = storage; } @@ -98,7 +101,8 @@ public class StopsReportProvider { String templatePath = Context.getConfig().getString("report.templatesPath", "templates/export/"); try (InputStream inputStream = new FileInputStream(templatePath + "/stops.xlsx")) { - org.jxls.common.Context jxlsContext = ReportUtils.initializeContext(userId); + var jxlsContext = ReportUtils.initializeContext( + permissionsService.getServer(), permissionsService.getUser(userId)); jxlsContext.putVar("devices", devicesStops); jxlsContext.putVar("sheetNames", sheetNames); jxlsContext.putVar("from", from); diff --git a/src/main/java/org/traccar/reports/SummaryReportProvider.java b/src/main/java/org/traccar/reports/SummaryReportProvider.java index a2306f3d1..c9fac4309 100644 --- a/src/main/java/org/traccar/reports/SummaryReportProvider.java +++ b/src/main/java/org/traccar/reports/SummaryReportProvider.java @@ -27,14 +27,25 @@ import java.util.Date; import org.jxls.util.JxlsHelper; import org.traccar.Context; +import org.traccar.api.security.PermissionsService; import org.traccar.helper.UnitsConverter; +import org.traccar.helper.UserUtil; import org.traccar.model.Position; import org.traccar.reports.common.ReportUtils; import org.traccar.reports.model.SummaryReportItem; import org.traccar.storage.StorageException; +import javax.inject.Inject; + public class SummaryReportProvider { + private final PermissionsService permissionsService; + + @Inject + public SummaryReportProvider(PermissionsService permissionsService) { + this.permissionsService = permissionsService; + } + private SummaryReportItem calculateSummaryResult(long deviceId, Collection positions) { SummaryReportItem result = new SummaryReportItem(); result.setDeviceId(deviceId); @@ -88,8 +99,9 @@ public class SummaryReportProvider { return result; } - private int getDay(long userId, Date date) { - Calendar calendar = Calendar.getInstance(ReportUtils.getTimezone(userId)); + private int getDay(long userId, Date date) throws StorageException { + Calendar calendar = Calendar.getInstance(UserUtil.getTimezone( + permissionsService.getServer(), permissionsService.getUser(userId))); calendar.setTime(date); return calendar.get(Calendar.DAY_OF_MONTH); } @@ -144,7 +156,8 @@ public class SummaryReportProvider { String templatePath = Context.getConfig().getString("report.templatesPath", "templates/export/"); try (InputStream inputStream = new FileInputStream(templatePath + "/summary.xlsx")) { - org.jxls.common.Context jxlsContext = ReportUtils.initializeContext(userId); + var jxlsContext = ReportUtils.initializeContext( + permissionsService.getServer(), permissionsService.getUser(userId)); jxlsContext.putVar("summaries", summaries); jxlsContext.putVar("from", from); jxlsContext.putVar("to", to); diff --git a/src/main/java/org/traccar/reports/TripsReportProvider.java b/src/main/java/org/traccar/reports/TripsReportProvider.java index 5ff31dbe2..bcd79ab25 100644 --- a/src/main/java/org/traccar/reports/TripsReportProvider.java +++ b/src/main/java/org/traccar/reports/TripsReportProvider.java @@ -27,6 +27,7 @@ import java.util.Date; import org.apache.poi.ss.util.WorkbookUtil; import org.traccar.Context; import org.traccar.Main; +import org.traccar.api.security.PermissionsService; import org.traccar.database.DeviceManager; import org.traccar.database.IdentityManager; import org.traccar.model.Device; @@ -41,10 +42,12 @@ import javax.inject.Inject; public class TripsReportProvider { + private final PermissionsService permissionsService; private final Storage storage; @Inject - public TripsReportProvider(Storage storage) { + public TripsReportProvider(PermissionsService permissionsService, Storage storage) { + this.permissionsService = permissionsService; this.storage = storage; } @@ -96,7 +99,8 @@ public class TripsReportProvider { String templatePath = Context.getConfig().getString("report.templatesPath", "templates/export/"); try (InputStream inputStream = new FileInputStream(templatePath + "/trips.xlsx")) { - org.jxls.common.Context jxlsContext = ReportUtils.initializeContext(userId); + var jxlsContext = ReportUtils.initializeContext( + permissionsService.getServer(), permissionsService.getUser(userId)); jxlsContext.putVar("devices", devicesTrips); jxlsContext.putVar("sheetNames", sheetNames); jxlsContext.putVar("from", from); diff --git a/src/main/java/org/traccar/reports/common/ReportUtils.java b/src/main/java/org/traccar/reports/common/ReportUtils.java index 4bcb54899..71c49f65b 100644 --- a/src/main/java/org/traccar/reports/common/ReportUtils.java +++ b/src/main/java/org/traccar/reports/common/ReportUtils.java @@ -31,7 +31,9 @@ import org.traccar.database.DeviceManager; import org.traccar.database.IdentityManager; import org.traccar.handler.events.MotionEventHandler; import org.traccar.helper.UnitsConverter; +import org.traccar.helper.UserUtil; import org.traccar.model.BaseModel; +import org.traccar.model.Server; import org.traccar.model.User; import org.traccar.session.DeviceState; import org.traccar.model.Driver; @@ -58,7 +60,6 @@ import java.util.LinkedHashSet; import java.util.List; import java.util.Locale; import java.util.Map; -import java.util.TimeZone; public final class ReportUtils { @@ -81,23 +82,6 @@ public final class ReportUtils { } } - public static String getDistanceUnit(long userId) { - return (String) Context.getPermissionsManager().lookupAttribute(userId, "distanceUnit", "km"); - } - - public static String getSpeedUnit(long userId) { - return (String) Context.getPermissionsManager().lookupAttribute(userId, "speedUnit", "kn"); - } - - public static String getVolumeUnit(long userId) { - return (String) Context.getPermissionsManager().lookupAttribute(userId, "volumeUnit", "ltr"); - } - - public static TimeZone getTimezone(long userId) { - String timezone = (String) Context.getPermissionsManager().lookupAttribute(userId, "timezone", null); - return timezone != null ? TimeZone.getTimeZone(timezone) : TimeZone.getDefault(); - } - public static Collection getDeviceList(Collection deviceIds, Collection groupIds) { Collection result = new LinkedHashSet<>(deviceIds); for (long groupId : groupIds) { @@ -158,15 +142,15 @@ public final class ReportUtils { return null; } - public static org.jxls.common.Context initializeContext(long userId) { + public static org.jxls.common.Context initializeContext(Server server, User user) { org.jxls.common.Context jxlsContext = PoiTransformer.createInitialContext(); - jxlsContext.putVar("distanceUnit", getDistanceUnit(userId)); - jxlsContext.putVar("speedUnit", getSpeedUnit(userId)); - jxlsContext.putVar("volumeUnit", getVolumeUnit(userId)); + jxlsContext.putVar("distanceUnit", UserUtil.getDistanceUnit(server, user)); + jxlsContext.putVar("speedUnit", UserUtil.getSpeedUnit(server, user)); + jxlsContext.putVar("volumeUnit", UserUtil.getVolumeUnit(server, user)); jxlsContext.putVar("webUrl", Context.getVelocityEngine().getProperty("web.url")); jxlsContext.putVar("dateTool", new DateTool()); jxlsContext.putVar("numberTool", new NumberTool()); - jxlsContext.putVar("timezone", getTimezone(userId)); + jxlsContext.putVar("timezone", UserUtil.getTimezone(server, user)); jxlsContext.putVar("locale", Locale.getDefault()); jxlsContext.putVar("bracketsRegex", "[\\{\\}\"]"); return jxlsContext; diff --git a/src/main/java/org/traccar/session/cache/CacheManager.java b/src/main/java/org/traccar/session/cache/CacheManager.java index 6ea0f252d..586237655 100644 --- a/src/main/java/org/traccar/session/cache/CacheManager.java +++ b/src/main/java/org/traccar/session/cache/CacheManager.java @@ -23,6 +23,7 @@ import org.traccar.model.Geofence; import org.traccar.model.Maintenance; import org.traccar.model.Notification; import org.traccar.model.Position; +import org.traccar.model.Server; import org.traccar.model.User; import org.traccar.storage.Storage; import org.traccar.storage.StorageException; @@ -57,12 +58,14 @@ public class CacheManager { private final Map deviceCache = new HashMap<>(); private final Map, List>> deviceLinks = new HashMap<>(); + private Server server; private final Map devicePositions = new HashMap<>(); private final Map> notificationUsers = new HashMap<>(); @Inject public CacheManager(Storage storage) throws StorageException { this.storage = storage; + invalidateServer(); invalidateUsers(); } @@ -96,6 +99,15 @@ public class CacheManager { } } + public Server getServer() { + try { + lock.readLock().lock(); + return server; + } finally { + lock.readLock().unlock(); + } + } + public List getNotificationUsers(long notificationId) { try { lock.readLock().lock(); @@ -154,6 +166,10 @@ public class CacheManager { invalidate(new CacheKey(clazz1, id1), new CacheKey(clazz2, id2)); } + private void invalidateServer() throws StorageException { + server = storage.getObject(Server.class, new Request(new Columns.All())); + } + private void invalidateUsers() throws StorageException { Map users = new HashMap<>(); storage.getObjects(User.class, new Request(new Columns.All())) @@ -220,21 +236,29 @@ public class CacheManager { } private void unsafeInvalidate(CacheKey[] keys) throws StorageException { + boolean invalidateServer = false; boolean invalidateUsers = false; Set linkedDevices = new HashSet<>(); for (var key : keys) { - if (key.classIs(User.class) || key.classIs(Notification.class)) { - invalidateUsers = true; + if (key.classIs(Server.class)) { + invalidateServer = true; + } else { + if (key.classIs(User.class) || key.classIs(Notification.class)) { + invalidateUsers = true; + } + deviceCache.computeIfPresent(key, (k, value) -> { + linkedDevices.addAll(value.getReferences()); + return value; + }); } - deviceCache.computeIfPresent(key, (k, value) -> { - linkedDevices.addAll(value.getReferences()); - return value; - }); } for (long deviceId : linkedDevices) { unsafeRemoveDevice(deviceId); unsafeAddDevice(deviceId); } + if (invalidateServer) { + invalidateServer(); + } if (invalidateUsers) { invalidateUsers(); } diff --git a/src/main/java/org/traccar/web/WebServer.java b/src/main/java/org/traccar/web/WebServer.java index 06676fb41..f1ee8fcb2 100644 --- a/src/main/java/org/traccar/web/WebServer.java +++ b/src/main/java/org/traccar/web/WebServer.java @@ -15,6 +15,7 @@ */ package org.traccar.web; +import com.google.inject.servlet.GuiceFilter; import org.eclipse.jetty.http.HttpCookie; import org.eclipse.jetty.http.HttpMethod; import org.eclipse.jetty.http.HttpStatus; @@ -164,6 +165,8 @@ public class WebServer implements LifecycleObject { } private void initApi(Config config, ServletContextHandler servletHandler) { + servletHandler.addFilter(GuiceFilter.class, "/api/*", EnumSet.allOf(DispatcherType.class)); + servletHandler.addServlet(new ServletHolder(new AsyncSocketServlet()), "/api/socket"); JettyWebSocketServletContainerInitializer.configure(servletHandler, null); -- cgit v1.2.3 From 12fe28bebbdbc61214363a9c7b51bd300ed62c15 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Thu, 9 Jun 2022 07:00:20 -0700 Subject: Remove geofence manager --- src/main/java/org/traccar/Context.java | 11 ---- src/main/java/org/traccar/MainModule.java | 6 -- .../java/org/traccar/api/BaseObjectResource.java | 1 - .../java/org/traccar/database/DeviceManager.java | 6 -- .../java/org/traccar/database/GeofenceManager.java | 66 ---------------------- .../org/traccar/database/PermissionsManager.java | 13 +---- .../handler/events/GeofenceEventHandler.java | 34 +++++------ .../handler/events/OverspeedEventHandler.java | 12 ++-- src/main/java/org/traccar/helper/UserUtil.java | 57 ------------------- .../org/traccar/helper/model/GeofenceUtil.java | 40 +++++++++++++ .../org/traccar/helper/model/PositionUtil.java | 31 ++++++++++ .../java/org/traccar/helper/model/UserUtil.java | 57 +++++++++++++++++++ .../notification/NotificationFormatter.java | 2 +- .../notification/TextTemplateFormatter.java | 2 +- .../org/traccar/reports/SummaryReportProvider.java | 2 +- .../org/traccar/reports/common/ReportUtils.java | 2 +- .../org/traccar/session/cache/CacheManager.java | 15 ++++- 17 files changed, 167 insertions(+), 190 deletions(-) delete mode 100644 src/main/java/org/traccar/database/GeofenceManager.java delete mode 100644 src/main/java/org/traccar/helper/UserUtil.java create mode 100644 src/main/java/org/traccar/helper/model/GeofenceUtil.java create mode 100644 src/main/java/org/traccar/helper/model/PositionUtil.java create mode 100644 src/main/java/org/traccar/helper/model/UserUtil.java (limited to 'src/main/java/org/traccar/helper') diff --git a/src/main/java/org/traccar/Context.java b/src/main/java/org/traccar/Context.java index 899f8ea54..dcbe6c811 100644 --- a/src/main/java/org/traccar/Context.java +++ b/src/main/java/org/traccar/Context.java @@ -26,7 +26,6 @@ import org.traccar.config.Keys; import org.traccar.database.BaseObjectManager; import org.traccar.database.DataManager; import org.traccar.database.DeviceManager; -import org.traccar.database.GeofenceManager; import org.traccar.database.GroupsManager; import org.traccar.database.IdentityManager; import org.traccar.database.MailManager; @@ -38,7 +37,6 @@ import org.traccar.helper.Log; import org.traccar.helper.SanitizerModule; import org.traccar.model.BaseModel; import org.traccar.model.Device; -import org.traccar.model.Geofence; import org.traccar.model.Group; import org.traccar.model.Notification; import org.traccar.model.User; @@ -140,12 +138,6 @@ public final class Context { return broadcastService; } - private static GeofenceManager geofenceManager; - - public static GeofenceManager getGeofenceManager() { - return geofenceManager; - } - private static NotificationManager notificationManager; public static NotificationManager getNotificationManager() { @@ -273,7 +265,6 @@ public final class Context { private static void initEventsModule() { - geofenceManager = new GeofenceManager(dataManager); notificationManager = new NotificationManager(dataManager, Main.getInjector().getInstance(CacheManager.class)); notificatorManager = new NotificatorManager(); Properties velocityProperties = new Properties(); @@ -312,8 +303,6 @@ public final class Context { return (BaseObjectManager) groupsManager; } else if (clazz.equals(User.class)) { return (BaseObjectManager) usersManager; - } else if (clazz.equals(Geofence.class)) { - return (BaseObjectManager) geofenceManager; } else if (clazz.equals(Notification.class)) { return (BaseObjectManager) notificationManager; } diff --git a/src/main/java/org/traccar/MainModule.java b/src/main/java/org/traccar/MainModule.java index b757b99a7..bb264cff3 100644 --- a/src/main/java/org/traccar/MainModule.java +++ b/src/main/java/org/traccar/MainModule.java @@ -27,7 +27,6 @@ import org.traccar.database.LdapProvider; import org.traccar.session.ConnectionManager; import org.traccar.database.DataManager; import org.traccar.database.DeviceManager; -import org.traccar.database.GeofenceManager; import org.traccar.database.IdentityManager; import org.traccar.database.StatisticsManager; import org.traccar.geocoder.AddressFormat; @@ -119,11 +118,6 @@ public class MainModule extends AbstractModule { return Context.getDeviceManager(); } - @Provides - public static GeofenceManager provideGeofenceManager() { - return Context.getGeofenceManager(); - } - @Provides public static SmsManager provideSmsManager() { return Context.getSmsManager(); diff --git a/src/main/java/org/traccar/api/BaseObjectResource.java b/src/main/java/org/traccar/api/BaseObjectResource.java index eb1db5e89..cc930c591 100644 --- a/src/main/java/org/traccar/api/BaseObjectResource.java +++ b/src/main/java/org/traccar/api/BaseObjectResource.java @@ -151,7 +151,6 @@ public abstract class BaseObjectResource extends BaseResour Context.getPermissionsManager().refreshAllExtendedPermissions(); } } else if (baseClass.equals(Calendar.class)) { - Context.getGeofenceManager().refreshItems(); Context.getNotificationManager().refreshItems(); } return Response.noContent().build(); diff --git a/src/main/java/org/traccar/database/DeviceManager.java b/src/main/java/org/traccar/database/DeviceManager.java index 0bac8f642..20f179f2e 100644 --- a/src/main/java/org/traccar/database/DeviceManager.java +++ b/src/main/java/org/traccar/database/DeviceManager.java @@ -218,12 +218,6 @@ public class DeviceManager extends BaseObjectManager implements Identity protected void addNewItem(Device device) { super.addNewItem(device); addByUniqueId(device); - if (Context.getGeofenceManager() != null) { - Position lastPosition = getLastPosition(device.getId()); - if (lastPosition != null) { - device.setGeofenceIds(Context.getGeofenceManager().getCurrentDeviceGeofences(lastPosition)); - } - } } @Override diff --git a/src/main/java/org/traccar/database/GeofenceManager.java b/src/main/java/org/traccar/database/GeofenceManager.java deleted file mode 100644 index a32847cf9..000000000 --- a/src/main/java/org/traccar/database/GeofenceManager.java +++ /dev/null @@ -1,66 +0,0 @@ -/* - * Copyright 2016 - 2017 Anton Tananaev (anton@traccar.org) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.traccar.database; - -import java.util.ArrayList; -import java.util.List; - -import org.traccar.Context; -import org.traccar.model.Device; -import org.traccar.model.Geofence; -import org.traccar.model.Position; - -public class GeofenceManager extends ExtendedObjectManager { - - public GeofenceManager(DataManager dataManager) { - super(dataManager, Geofence.class); - } - - @Override - public final void refreshExtendedPermissions() { - super.refreshExtendedPermissions(); - recalculateDevicesGeofences(); - } - - public List getCurrentDeviceGeofences(Position position) { - List result = new ArrayList<>(); - for (long geofenceId : getAllDeviceItems(position.getDeviceId())) { - Geofence geofence = getById(geofenceId); - if (geofence != null && geofence.getGeometry() - .containsPoint(position.getLatitude(), position.getLongitude())) { - result.add(geofenceId); - } - } - return result; - } - - public void recalculateDevicesGeofences() { - for (Device device : Context.getDeviceManager().getAllDevices()) { - List deviceGeofenceIds = device.getGeofenceIds(); - if (deviceGeofenceIds == null) { - deviceGeofenceIds = new ArrayList<>(); - } else { - deviceGeofenceIds.clear(); - } - Position lastPosition = Context.getIdentityManager().getLastPosition(device.getId()); - if (lastPosition != null && getAllDeviceItems(device.getId()) != null) { - deviceGeofenceIds.addAll(getCurrentDeviceGeofences(lastPosition)); - } - device.setGeofenceIds(deviceGeofenceIds); - } - } - -} diff --git a/src/main/java/org/traccar/database/PermissionsManager.java b/src/main/java/org/traccar/database/PermissionsManager.java index e8f2380a2..3c74c0049 100644 --- a/src/main/java/org/traccar/database/PermissionsManager.java +++ b/src/main/java/org/traccar/database/PermissionsManager.java @@ -20,7 +20,6 @@ import org.slf4j.LoggerFactory; import org.traccar.Context; import org.traccar.model.BaseModel; import org.traccar.model.Device; -import org.traccar.model.Geofence; import org.traccar.model.Group; import org.traccar.model.ManagedUser; import org.traccar.model.Notification; @@ -356,18 +355,12 @@ public class PermissionsManager { } public void refreshAllUsersPermissions() { - if (Context.getGeofenceManager() != null) { - Context.getGeofenceManager().refreshUserItems(); - } if (Context.getNotificationManager() != null) { Context.getNotificationManager().refreshUserItems(); } } public void refreshAllExtendedPermissions() { - if (Context.getGeofenceManager() != null) { - Context.getGeofenceManager().refreshExtendedPermissions(); - } } public void refreshPermissions(Permission permission) { @@ -378,16 +371,12 @@ public class PermissionsManager { refreshAllExtendedPermissions(); } else if (permission.getPropertyClass().equals(ManagedUser.class)) { usersManager.refreshUserItems(); - } else if (permission.getPropertyClass().equals(Geofence.class) && Context.getGeofenceManager() != null) { - Context.getGeofenceManager().refreshUserItems(); } else if (permission.getPropertyClass().equals(Notification.class) && Context.getNotificationManager() != null) { Context.getNotificationManager().refreshUserItems(); } } else if (permission.getOwnerClass().equals(Device.class) || permission.getOwnerClass().equals(Group.class)) { - if (permission.getPropertyClass().equals(Geofence.class) && Context.getGeofenceManager() != null) { - Context.getGeofenceManager().refreshExtendedPermissions(); - } else if (permission.getPropertyClass().equals(Notification.class) + if (permission.getPropertyClass().equals(Notification.class) && Context.getNotificationManager() != null) { Context.getNotificationManager().refreshExtendedPermissions(); } diff --git a/src/main/java/org/traccar/handler/events/GeofenceEventHandler.java b/src/main/java/org/traccar/handler/events/GeofenceEventHandler.java index 17e240f68..724f8f0d0 100644 --- a/src/main/java/org/traccar/handler/events/GeofenceEventHandler.java +++ b/src/main/java/org/traccar/handler/events/GeofenceEventHandler.java @@ -15,52 +15,46 @@ */ package org.traccar.handler.events; -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - import io.netty.channel.ChannelHandler; -import org.traccar.session.ConnectionManager; -import org.traccar.database.GeofenceManager; -import org.traccar.database.IdentityManager; +import org.traccar.helper.model.GeofenceUtil; +import org.traccar.helper.model.PositionUtil; import org.traccar.model.Calendar; import org.traccar.model.Device; import org.traccar.model.Event; +import org.traccar.model.Geofence; import org.traccar.model.Position; +import org.traccar.session.ConnectionManager; import org.traccar.session.cache.CacheManager; import javax.inject.Inject; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; @ChannelHandler.Sharable public class GeofenceEventHandler extends BaseEventHandler { private final CacheManager cacheManager; - private final IdentityManager identityManager; - private final GeofenceManager geofenceManager; private final ConnectionManager connectionManager; @Inject - public GeofenceEventHandler( - CacheManager cacheManager, IdentityManager identityManager, GeofenceManager geofenceManager, - ConnectionManager connectionManager) { + public GeofenceEventHandler(CacheManager cacheManager, ConnectionManager connectionManager) { this.cacheManager = cacheManager; - this.identityManager = identityManager; - this.geofenceManager = geofenceManager; this.connectionManager = connectionManager; } @Override protected Map analyzePosition(Position position) { - Device device = identityManager.getById(position.getDeviceId()); + Device device = cacheManager.getObject(Device.class, position.getDeviceId()); if (device == null) { return null; } - if (!identityManager.isLatestPosition(position) || !position.getValid()) { + if (!PositionUtil.isLatest(cacheManager, position) || !position.getValid()) { return null; } - List currentGeofences = geofenceManager.getCurrentDeviceGeofences(position); + List currentGeofences = GeofenceUtil.getCurrentGeofences(cacheManager, position); List oldGeofences = new ArrayList<>(); if (device.getGeofenceIds() != null) { oldGeofences.addAll(device.getGeofenceIds()); @@ -76,7 +70,7 @@ public class GeofenceEventHandler extends BaseEventHandler { Map events = new HashMap<>(); for (long geofenceId : oldGeofences) { - long calendarId = geofenceManager.getById(geofenceId).getCalendarId(); + long calendarId = cacheManager.getObject(Geofence.class, geofenceId).getCalendarId(); Calendar calendar = calendarId != 0 ? cacheManager.getObject(Calendar.class, calendarId) : null; if (calendar == null || calendar.checkMoment(position.getFixTime())) { Event event = new Event(Event.TYPE_GEOFENCE_EXIT, position); @@ -85,7 +79,7 @@ public class GeofenceEventHandler extends BaseEventHandler { } } for (long geofenceId : newGeofences) { - long calendarId = geofenceManager.getById(geofenceId).getCalendarId(); + long calendarId = cacheManager.getObject(Geofence.class, geofenceId).getCalendarId(); Calendar calendar = calendarId != 0 ? cacheManager.getObject(Calendar.class, calendarId) : null; if (calendar == null || calendar.checkMoment(position.getFixTime())) { Event event = new Event(Event.TYPE_GEOFENCE_ENTER, position); diff --git a/src/main/java/org/traccar/handler/events/OverspeedEventHandler.java b/src/main/java/org/traccar/handler/events/OverspeedEventHandler.java index 84d80e55f..45bb13be5 100644 --- a/src/main/java/org/traccar/handler/events/OverspeedEventHandler.java +++ b/src/main/java/org/traccar/handler/events/OverspeedEventHandler.java @@ -23,12 +23,12 @@ import io.netty.channel.ChannelHandler; import org.traccar.config.Config; import org.traccar.config.Keys; import org.traccar.database.DeviceManager; -import org.traccar.database.GeofenceManager; import org.traccar.model.Device; import org.traccar.session.DeviceState; import org.traccar.model.Event; import org.traccar.model.Geofence; import org.traccar.model.Position; +import org.traccar.session.cache.CacheManager; import javax.inject.Inject; @@ -39,16 +39,16 @@ public class OverspeedEventHandler extends BaseEventHandler { public static final String ATTRIBUTE_SPEED_LIMIT = "speedLimit"; private final DeviceManager deviceManager; - private final GeofenceManager geofenceManager; + private final CacheManager cacheManager; private final boolean notRepeat; private final long minimalDuration; private final boolean preferLowest; @Inject - public OverspeedEventHandler(Config config, DeviceManager deviceManager, GeofenceManager geofenceManager) { + public OverspeedEventHandler(Config config, DeviceManager deviceManager, CacheManager cacheManager) { this.deviceManager = deviceManager; - this.geofenceManager = geofenceManager; + this.cacheManager = cacheManager; notRepeat = config.getBoolean(Keys.EVENT_OVERSPEED_NOT_REPEAT); minimalDuration = config.getLong(Keys.EVENT_OVERSPEED_MINIMAL_DURATION) * 1000; preferLowest = config.getBoolean(Keys.EVENT_OVERSPEED_PREFER_LOWEST); @@ -133,9 +133,9 @@ public class OverspeedEventHandler extends BaseEventHandler { double geofenceSpeedLimit = 0; long overspeedGeofenceId = 0; - if (geofenceManager != null && device.getGeofenceIds() != null) { + if (device.getGeofenceIds() != null) { for (long geofenceId : device.getGeofenceIds()) { - Geofence geofence = geofenceManager.getById(geofenceId); + Geofence geofence = cacheManager.getObject(Geofence.class, geofenceId); if (geofence != null) { double currentSpeedLimit = geofence.getDouble(ATTRIBUTE_SPEED_LIMIT); if (currentSpeedLimit > 0 && geofenceSpeedLimit == 0 diff --git a/src/main/java/org/traccar/helper/UserUtil.java b/src/main/java/org/traccar/helper/UserUtil.java deleted file mode 100644 index 6050ad349..000000000 --- a/src/main/java/org/traccar/helper/UserUtil.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * Copyright 2022 Anton Tananaev (anton@traccar.org) - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ -package org.traccar.helper; - -import org.traccar.model.Server; -import org.traccar.model.User; - -import java.util.TimeZone; - -public final class UserUtil { - - private UserUtil() { - } - - public static String getDistanceUnit(Server server, User user) { - return lookupStringAttribute(server, user, "distanceUnit", "km"); - } - - public static String getSpeedUnit(Server server, User user) { - return lookupStringAttribute(server, user, "speedUnit", "kn"); - } - - public static String getVolumeUnit(Server server, User user) { - return lookupStringAttribute(server, user, "volumeUnit", "ltr"); - } - - public static TimeZone getTimezone(Server server, User user) { - String timezone = lookupStringAttribute(server, user, "timezone", null); - return timezone != null ? TimeZone.getTimeZone(timezone) : TimeZone.getDefault(); - } - - private static String lookupStringAttribute(Server server, User user, String key, String defaultValue) { - String preference; - String serverPreference = server.getString(key); - String userPreference = user.getString(key); - if (server.getForceSettings()) { - preference = serverPreference != null ? serverPreference : userPreference; - } else { - preference = userPreference != null ? userPreference : serverPreference; - } - return preference != null ? preference : defaultValue; - } - -} diff --git a/src/main/java/org/traccar/helper/model/GeofenceUtil.java b/src/main/java/org/traccar/helper/model/GeofenceUtil.java new file mode 100644 index 000000000..f56bf4224 --- /dev/null +++ b/src/main/java/org/traccar/helper/model/GeofenceUtil.java @@ -0,0 +1,40 @@ +/* + * Copyright 2022 Anton Tananaev (anton@traccar.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.traccar.helper.model; + +import org.traccar.model.Geofence; +import org.traccar.model.Position; +import org.traccar.session.cache.CacheManager; + +import java.util.ArrayList; +import java.util.List; + +public final class GeofenceUtil { + + private GeofenceUtil() { + } + + public static List getCurrentGeofences(CacheManager cacheManager, Position position) { + List result = new ArrayList<>(); + for (Geofence geofence : cacheManager.getDeviceObjects(position.getDeviceId(), Geofence.class)) { + if (geofence.getGeometry().containsPoint(position.getLatitude(), position.getLongitude())) { + result.add(geofence.getId()); + } + } + return result; + } + +} diff --git a/src/main/java/org/traccar/helper/model/PositionUtil.java b/src/main/java/org/traccar/helper/model/PositionUtil.java new file mode 100644 index 000000000..64216a937 --- /dev/null +++ b/src/main/java/org/traccar/helper/model/PositionUtil.java @@ -0,0 +1,31 @@ +/* + * Copyright 2022 Anton Tananaev (anton@traccar.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.traccar.helper.model; + +import org.traccar.model.Position; +import org.traccar.session.cache.CacheManager; + +public final class PositionUtil { + + private PositionUtil() { + } + + public static boolean isLatest(CacheManager cacheManager, Position position) { + Position lastPosition = cacheManager.getPosition(position.getDeviceId()); + return lastPosition == null || position.getFixTime().compareTo(lastPosition.getFixTime()) >= 0; + } + +} diff --git a/src/main/java/org/traccar/helper/model/UserUtil.java b/src/main/java/org/traccar/helper/model/UserUtil.java new file mode 100644 index 000000000..9919e1d95 --- /dev/null +++ b/src/main/java/org/traccar/helper/model/UserUtil.java @@ -0,0 +1,57 @@ +/* + * Copyright 2022 Anton Tananaev (anton@traccar.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.traccar.helper.model; + +import org.traccar.model.Server; +import org.traccar.model.User; + +import java.util.TimeZone; + +public final class UserUtil { + + private UserUtil() { + } + + public static String getDistanceUnit(Server server, User user) { + return lookupStringAttribute(server, user, "distanceUnit", "km"); + } + + public static String getSpeedUnit(Server server, User user) { + return lookupStringAttribute(server, user, "speedUnit", "kn"); + } + + public static String getVolumeUnit(Server server, User user) { + return lookupStringAttribute(server, user, "volumeUnit", "ltr"); + } + + public static TimeZone getTimezone(Server server, User user) { + String timezone = lookupStringAttribute(server, user, "timezone", null); + return timezone != null ? TimeZone.getTimeZone(timezone) : TimeZone.getDefault(); + } + + private static String lookupStringAttribute(Server server, User user, String key, String defaultValue) { + String preference; + String serverPreference = server.getString(key); + String userPreference = user.getString(key); + if (server.getForceSettings()) { + preference = serverPreference != null ? serverPreference : userPreference; + } else { + preference = userPreference != null ? userPreference : serverPreference; + } + return preference != null ? preference : defaultValue; + } + +} diff --git a/src/main/java/org/traccar/notification/NotificationFormatter.java b/src/main/java/org/traccar/notification/NotificationFormatter.java index 13f42a8b2..2d3b90412 100644 --- a/src/main/java/org/traccar/notification/NotificationFormatter.java +++ b/src/main/java/org/traccar/notification/NotificationFormatter.java @@ -17,7 +17,7 @@ package org.traccar.notification; import org.apache.velocity.VelocityContext; -import org.traccar.helper.UserUtil; +import org.traccar.helper.model.UserUtil; import org.traccar.model.Device; import org.traccar.model.Event; import org.traccar.model.Geofence; diff --git a/src/main/java/org/traccar/notification/TextTemplateFormatter.java b/src/main/java/org/traccar/notification/TextTemplateFormatter.java index 06375afac..9072ec89e 100644 --- a/src/main/java/org/traccar/notification/TextTemplateFormatter.java +++ b/src/main/java/org/traccar/notification/TextTemplateFormatter.java @@ -23,7 +23,7 @@ import org.apache.velocity.tools.generic.NumberTool; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.traccar.Context; -import org.traccar.helper.UserUtil; +import org.traccar.helper.model.UserUtil; import org.traccar.model.Server; import org.traccar.model.User; diff --git a/src/main/java/org/traccar/reports/SummaryReportProvider.java b/src/main/java/org/traccar/reports/SummaryReportProvider.java index c9fac4309..27dc5819d 100644 --- a/src/main/java/org/traccar/reports/SummaryReportProvider.java +++ b/src/main/java/org/traccar/reports/SummaryReportProvider.java @@ -29,7 +29,7 @@ import org.jxls.util.JxlsHelper; import org.traccar.Context; import org.traccar.api.security.PermissionsService; import org.traccar.helper.UnitsConverter; -import org.traccar.helper.UserUtil; +import org.traccar.helper.model.UserUtil; import org.traccar.model.Position; import org.traccar.reports.common.ReportUtils; import org.traccar.reports.model.SummaryReportItem; diff --git a/src/main/java/org/traccar/reports/common/ReportUtils.java b/src/main/java/org/traccar/reports/common/ReportUtils.java index 71c49f65b..36d5c0fb1 100644 --- a/src/main/java/org/traccar/reports/common/ReportUtils.java +++ b/src/main/java/org/traccar/reports/common/ReportUtils.java @@ -31,7 +31,7 @@ import org.traccar.database.DeviceManager; import org.traccar.database.IdentityManager; import org.traccar.handler.events.MotionEventHandler; import org.traccar.helper.UnitsConverter; -import org.traccar.helper.UserUtil; +import org.traccar.helper.model.UserUtil; import org.traccar.model.BaseModel; import org.traccar.model.Server; import org.traccar.model.User; diff --git a/src/main/java/org/traccar/session/cache/CacheManager.java b/src/main/java/org/traccar/session/cache/CacheManager.java index 4b42ea4e5..18daeae15 100644 --- a/src/main/java/org/traccar/session/cache/CacheManager.java +++ b/src/main/java/org/traccar/session/cache/CacheManager.java @@ -15,6 +15,7 @@ */ package org.traccar.session.cache; +import org.traccar.helper.model.GeofenceUtil; import org.traccar.model.Attribute; import org.traccar.model.BaseModel; import org.traccar.model.Device; @@ -181,13 +182,16 @@ public class CacheManager { if (invalidate) { invalidate(object.getClass(), object.getId()); } else { - // TODO if device, also need to update geofences try { lock.writeLock().lock(); deviceCache.get(new CacheKey(object.getClass(), object.getId())).setValue(object); } finally { lock.writeLock().unlock(); } + + if (object instanceof Device) { + invalidateDeviceGeofences((Device) object); + } } } @@ -254,6 +258,8 @@ public class CacheManager { devicePositions.put(deviceId, storage.getObject(Position.class, new Request( new Columns.All(), new Condition.Equals("id", "id", device.getPositionId())))); } + + invalidateDeviceGeofences(device); } private void unsafeRemoveDevice(long deviceId) { @@ -306,4 +312,11 @@ public class CacheManager { } } + private void invalidateDeviceGeofences(Device device) { + Position position = getPosition(device.getId()); + if (position != null) { + device.setGeofenceIds(GeofenceUtil.getCurrentGeofences(this, position)); + } + } + } -- cgit v1.2.3 From bbe84d6a751fdc840e4201ef9027a96527006049 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Fri, 10 Jun 2022 07:56:49 -0700 Subject: Inject report utils --- src/main/java/org/traccar/Context.java | 7 +- .../org/traccar/api/resource/ServerResource.java | 10 +- .../org/traccar/database/NotificationManager.java | 14 +- .../traccar/handler/events/MotionEventHandler.java | 11 +- .../org/traccar/helper/model/PositionUtil.java | 13 ++ .../org/traccar/reports/EventsReportProvider.java | 64 ++++---- .../org/traccar/reports/RouteReportProvider.java | 43 +++--- .../org/traccar/reports/StopsReportProvider.java | 62 +++----- .../org/traccar/reports/SummaryReportProvider.java | 43 +++--- .../org/traccar/reports/TripsReportProvider.java | 54 +++---- .../org/traccar/reports/common/ReportUtils.java | 165 +++++++++++---------- .../java/org/traccar/reports/ReportUtilsTest.java | 78 ++++++---- 12 files changed, 282 insertions(+), 282 deletions(-) (limited to 'src/main/java/org/traccar/helper') diff --git a/src/main/java/org/traccar/Context.java b/src/main/java/org/traccar/Context.java index cba4c0a58..471416926 100644 --- a/src/main/java/org/traccar/Context.java +++ b/src/main/java/org/traccar/Context.java @@ -109,10 +109,6 @@ public final class Context { return permissionsManager; } - public static Geocoder getGeocoder() { - return Main.getInjector() != null ? Main.getInjector().getInstance(Geocoder.class) : null; - } - private static NotificationManager notificationManager; public static NotificationManager getNotificationManager() { @@ -196,7 +192,8 @@ public final class Context { notificationManager = new NotificationManager( dataManager, Main.getInjector().getInstance(CacheManager.class), - Main.getInjector().getInstance(NotificatorManager.class)); + Main.getInjector().getInstance(NotificatorManager.class), + Main.getInjector().getInstance(Geocoder.class)); Properties velocityProperties = new Properties(); velocityProperties.setProperty("file.resource.loader.path", Context.getConfig().getString("templates.rootPath", "templates") + "/"); diff --git a/src/main/java/org/traccar/api/resource/ServerResource.java b/src/main/java/org/traccar/api/resource/ServerResource.java index 51a26825b..18230a2b3 100644 --- a/src/main/java/org/traccar/api/resource/ServerResource.java +++ b/src/main/java/org/traccar/api/resource/ServerResource.java @@ -18,6 +18,7 @@ package org.traccar.api.resource; import org.traccar.Context; import org.traccar.api.BaseResource; import org.traccar.database.MailManager; +import org.traccar.geocoder.Geocoder; import org.traccar.helper.LogAction; import org.traccar.model.Server; import org.traccar.storage.Storage; @@ -25,6 +26,7 @@ import org.traccar.storage.StorageException; import org.traccar.storage.query.Columns; import org.traccar.storage.query.Request; +import javax.annotation.Nullable; import javax.annotation.security.PermitAll; import javax.inject.Inject; import javax.ws.rs.Consumes; @@ -50,6 +52,10 @@ public class ServerResource extends BaseResource { @Inject private MailManager mailManager; + @Inject + @Nullable + private Geocoder geocoder; + @PermitAll @GET public Server get() throws StorageException { @@ -69,8 +75,8 @@ public class ServerResource extends BaseResource { @Path("geocode") @GET public String geocode(@QueryParam("latitude") double latitude, @QueryParam("longitude") double longitude) { - if (Context.getGeocoder() != null) { - return Context.getGeocoder().getAddress(latitude, longitude, null); + if (geocoder != null) { + return geocoder.getAddress(latitude, longitude, null); } else { throw new RuntimeException("Reverse geocoding is not enabled"); } diff --git a/src/main/java/org/traccar/database/NotificationManager.java b/src/main/java/org/traccar/database/NotificationManager.java index eddd7e2b4..1f4a48ac0 100644 --- a/src/main/java/org/traccar/database/NotificationManager.java +++ b/src/main/java/org/traccar/database/NotificationManager.java @@ -30,6 +30,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.traccar.Context; import org.traccar.config.Keys; +import org.traccar.geocoder.Geocoder; import org.traccar.model.Calendar; import org.traccar.model.Event; import org.traccar.model.Notification; @@ -41,20 +42,25 @@ import org.traccar.notification.NotificatorManager; import org.traccar.session.cache.CacheManager; import org.traccar.storage.StorageException; +import javax.annotation.Nullable; + public class NotificationManager extends ExtendedObjectManager { private static final Logger LOGGER = LoggerFactory.getLogger(NotificationManager.class); private final CacheManager cacheManager; private final NotificatorManager notificatorManager; + private final Geocoder geocoder; private final boolean geocodeOnRequest; public NotificationManager( - DataManager dataManager, CacheManager cacheManager, NotificatorManager notificatorManager) { + DataManager dataManager, CacheManager cacheManager, + NotificatorManager notificatorManager, @Nullable Geocoder geocoder) { super(dataManager, Notification.class); this.cacheManager = cacheManager; this.notificatorManager = notificatorManager; + this.geocoder = geocoder; geocodeOnRequest = Context.getConfig().getBoolean(Keys.GEOCODER_ON_REQUEST); } @@ -110,10 +116,8 @@ public class NotificationManager extends ExtendedObjectManager { } } - if (position != null && position.getAddress() == null - && geocodeOnRequest && Context.getGeocoder() != null) { - position.setAddress(Context.getGeocoder() - .getAddress(position.getLatitude(), position.getLongitude(), null)); + if (position != null && position.getAddress() == null && geocodeOnRequest && geocoder != null) { + position.setAddress(geocoder.getAddress(position.getLatitude(), position.getLongitude(), null)); } User user = Context.getUsersManager().getById(userId); diff --git a/src/main/java/org/traccar/handler/events/MotionEventHandler.java b/src/main/java/org/traccar/handler/events/MotionEventHandler.java index 57d2bc1c5..2c381e530 100644 --- a/src/main/java/org/traccar/handler/events/MotionEventHandler.java +++ b/src/main/java/org/traccar/handler/events/MotionEventHandler.java @@ -16,20 +16,19 @@ */ package org.traccar.handler.events; -import java.util.Collections; -import java.util.Map; - import io.netty.channel.ChannelHandler; import org.traccar.database.DeviceManager; import org.traccar.database.IdentityManager; +import org.traccar.helper.model.PositionUtil; import org.traccar.model.Device; -import org.traccar.session.DeviceState; import org.traccar.model.Event; import org.traccar.model.Position; -import org.traccar.reports.common.ReportUtils; import org.traccar.reports.common.TripsConfig; +import org.traccar.session.DeviceState; import javax.inject.Inject; +import java.util.Collections; +import java.util.Map; @ChannelHandler.Sharable public class MotionEventHandler extends BaseEventHandler { @@ -89,7 +88,7 @@ public class MotionEventHandler extends BaseEventHandler { Position motionPosition = deviceState.getMotionPosition(); if (motionPosition != null) { long motionTime = motionPosition.getFixTime().getTime(); - double distance = ReportUtils.calculateDistance(motionPosition, position, false); + double distance = PositionUtil.calculateDistance(motionPosition, position, false); Boolean ignition = null; if (tripsConfig.getUseIgnition() && position.getAttributes().containsKey(Position.KEY_IGNITION)) { diff --git a/src/main/java/org/traccar/helper/model/PositionUtil.java b/src/main/java/org/traccar/helper/model/PositionUtil.java index 64216a937..644517dac 100644 --- a/src/main/java/org/traccar/helper/model/PositionUtil.java +++ b/src/main/java/org/traccar/helper/model/PositionUtil.java @@ -28,4 +28,17 @@ public final class PositionUtil { return lastPosition == null || position.getFixTime().compareTo(lastPosition.getFixTime()) >= 0; } + public static double calculateDistance(Position first, Position last, boolean useOdometer) { + double distance; + double firstOdometer = first.getDouble(Position.KEY_ODOMETER); + double lastOdometer = last.getDouble(Position.KEY_ODOMETER); + + if (useOdometer && firstOdometer != 0.0 && lastOdometer != 0.0) { + distance = lastOdometer - firstOdometer; + } else { + distance = last.getDouble(Position.KEY_TOTAL_DISTANCE) - first.getDouble(Position.KEY_TOTAL_DISTANCE); + } + return distance; + } + } diff --git a/src/main/java/org/traccar/reports/EventsReportProvider.java b/src/main/java/org/traccar/reports/EventsReportProvider.java index f0c8c31b6..6de313a13 100644 --- a/src/main/java/org/traccar/reports/EventsReportProvider.java +++ b/src/main/java/org/traccar/reports/EventsReportProvider.java @@ -16,19 +16,8 @@ */ package org.traccar.reports; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Date; -import java.util.HashMap; -import java.util.Iterator; - import org.apache.poi.ss.util.WorkbookUtil; import org.traccar.Context; -import org.traccar.api.security.PermissionsService; import org.traccar.model.Device; import org.traccar.model.Event; import org.traccar.model.Geofence; @@ -36,28 +25,34 @@ import org.traccar.model.Group; import org.traccar.model.Maintenance; import org.traccar.reports.common.ReportUtils; import org.traccar.reports.model.DeviceReportSection; -import org.traccar.storage.Storage; import org.traccar.storage.StorageException; import javax.inject.Inject; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Date; +import java.util.HashMap; +import java.util.Iterator; public class EventsReportProvider { - private final PermissionsService permissionsService; - private final Storage storage; + private final ReportUtils reportUtils; @Inject - public EventsReportProvider(PermissionsService permissionsService, Storage storage) { - this.permissionsService = permissionsService; - this.storage = storage; + public EventsReportProvider(ReportUtils reportUtils) { + this.reportUtils = reportUtils; } public Collection getObjects( long userId, Collection deviceIds, Collection groupIds, Collection types, Date from, Date to) throws StorageException { - ReportUtils.checkPeriodLimit(from, to); + reportUtils.checkPeriodLimit(from, to); ArrayList result = new ArrayList<>(); - for (long deviceId: ReportUtils.getDeviceList(deviceIds, groupIds)) { + for (long deviceId: reportUtils.getDeviceList(deviceIds, groupIds)) { Context.getPermissionsManager().checkDevice(userId, deviceId); Collection events = Context.getDataManager().getEvents(deviceId, from, to); boolean all = types.isEmpty() || types.contains(Event.ALL_EVENTS); @@ -65,9 +60,9 @@ public class EventsReportProvider { if (all || types.contains(event.getType())) { long geofenceId = event.getGeofenceId(); long maintenanceId = event.getMaintenanceId(); - if ((geofenceId == 0 || ReportUtils.getObject(storage, userId, Geofence.class, geofenceId) != null) + if ((geofenceId == 0 || reportUtils.getObject(userId, Geofence.class, geofenceId) != null) && (maintenanceId == 0 - || ReportUtils.getObject(storage, userId, Maintenance.class, maintenanceId) != null)) { + || reportUtils.getObject(userId, Maintenance.class, maintenanceId) != null)) { result.add(event); } } @@ -79,12 +74,12 @@ public class EventsReportProvider { public void getExcel( OutputStream outputStream, long userId, Collection deviceIds, Collection groupIds, Collection types, Date from, Date to) throws StorageException, IOException { - ReportUtils.checkPeriodLimit(from, to); + reportUtils.checkPeriodLimit(from, to); ArrayList devicesEvents = new ArrayList<>(); ArrayList sheetNames = new ArrayList<>(); HashMap geofenceNames = new HashMap<>(); HashMap maintenanceNames = new HashMap<>(); - for (long deviceId: ReportUtils.getDeviceList(deviceIds, groupIds)) { + for (long deviceId: reportUtils.getDeviceList(deviceIds, groupIds)) { Context.getPermissionsManager().checkDevice(userId, deviceId); Collection events = Context.getDataManager().getEvents(deviceId, from, to); boolean all = types.isEmpty() || types.contains(Event.ALL_EVENTS); @@ -94,16 +89,14 @@ public class EventsReportProvider { long geofenceId = event.getGeofenceId(); long maintenanceId = event.getMaintenanceId(); if (geofenceId != 0) { - Geofence geofence = ReportUtils.getObject( - storage, userId, Geofence.class, geofenceId); + Geofence geofence = reportUtils.getObject(userId, Geofence.class, geofenceId); if (geofence != null) { geofenceNames.put(geofenceId, geofence.getName()); } else { iterator.remove(); } } else if (maintenanceId != 0) { - Maintenance maintenance = ReportUtils.getObject( - storage, userId, Maintenance.class, maintenanceId); + Maintenance maintenance = reportUtils.getObject(userId, Maintenance.class, maintenanceId); if (maintenance != null) { maintenanceNames.put(maintenanceId, maintenance.getName()); } else { @@ -130,15 +123,14 @@ public class EventsReportProvider { String templatePath = Context.getConfig().getString("report.templatesPath", "templates/export/"); try (InputStream inputStream = new FileInputStream(templatePath + "/events.xlsx")) { - var jxlsContext = ReportUtils.initializeContext( - permissionsService.getServer(), permissionsService.getUser(userId)); - jxlsContext.putVar("devices", devicesEvents); - jxlsContext.putVar("sheetNames", sheetNames); - jxlsContext.putVar("geofenceNames", geofenceNames); - jxlsContext.putVar("maintenanceNames", maintenanceNames); - jxlsContext.putVar("from", from); - jxlsContext.putVar("to", to); - ReportUtils.processTemplateWithSheets(inputStream, outputStream, jxlsContext); + var context = reportUtils.initializeContext(userId); + context.putVar("devices", devicesEvents); + context.putVar("sheetNames", sheetNames); + context.putVar("geofenceNames", geofenceNames); + context.putVar("maintenanceNames", maintenanceNames); + context.putVar("from", from); + context.putVar("to", to); + reportUtils.processTemplateWithSheets(inputStream, outputStream, context); } } } diff --git a/src/main/java/org/traccar/reports/RouteReportProvider.java b/src/main/java/org/traccar/reports/RouteReportProvider.java index e20ba6885..136a154aa 100644 --- a/src/main/java/org/traccar/reports/RouteReportProvider.java +++ b/src/main/java/org/traccar/reports/RouteReportProvider.java @@ -16,17 +16,8 @@ */ package org.traccar.reports; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Date; - import org.apache.poi.ss.util.WorkbookUtil; import org.traccar.Context; -import org.traccar.api.security.PermissionsService; import org.traccar.model.Device; import org.traccar.model.Group; import org.traccar.model.Position; @@ -35,21 +26,28 @@ import org.traccar.reports.model.DeviceReportSection; import org.traccar.storage.StorageException; import javax.inject.Inject; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Date; public class RouteReportProvider { - private final PermissionsService permissionsService; + private final ReportUtils reportUtils; @Inject - public RouteReportProvider(PermissionsService permissionsService) { - this.permissionsService = permissionsService; + public RouteReportProvider(ReportUtils reportUtils) { + this.reportUtils = reportUtils; } public Collection getObjects(long userId, Collection deviceIds, Collection groupIds, Date from, Date to) throws StorageException { - ReportUtils.checkPeriodLimit(from, to); + reportUtils.checkPeriodLimit(from, to); ArrayList result = new ArrayList<>(); - for (long deviceId: ReportUtils.getDeviceList(deviceIds, groupIds)) { + for (long deviceId: reportUtils.getDeviceList(deviceIds, groupIds)) { Context.getPermissionsManager().checkDevice(userId, deviceId); result.addAll(Context.getDataManager().getPositions(deviceId, from, to)); } @@ -59,10 +57,10 @@ public class RouteReportProvider { public void getExcel(OutputStream outputStream, long userId, Collection deviceIds, Collection groupIds, Date from, Date to) throws StorageException, IOException { - ReportUtils.checkPeriodLimit(from, to); + reportUtils.checkPeriodLimit(from, to); ArrayList devicesRoutes = new ArrayList<>(); ArrayList sheetNames = new ArrayList<>(); - for (long deviceId: ReportUtils.getDeviceList(deviceIds, groupIds)) { + for (long deviceId: reportUtils.getDeviceList(deviceIds, groupIds)) { Context.getPermissionsManager().checkDevice(userId, deviceId); Collection positions = Context.getDataManager() .getPositions(deviceId, from, to); @@ -82,13 +80,12 @@ public class RouteReportProvider { String templatePath = Context.getConfig().getString("report.templatesPath", "templates/export/"); try (InputStream inputStream = new FileInputStream(templatePath + "/route.xlsx")) { - var jxlsContext = ReportUtils.initializeContext( - permissionsService.getServer(), permissionsService.getUser(userId)); - jxlsContext.putVar("devices", devicesRoutes); - jxlsContext.putVar("sheetNames", sheetNames); - jxlsContext.putVar("from", from); - jxlsContext.putVar("to", to); - ReportUtils.processTemplateWithSheets(inputStream, outputStream, jxlsContext); + var context = reportUtils.initializeContext(userId); + context.putVar("devices", devicesRoutes); + context.putVar("sheetNames", sheetNames); + context.putVar("from", from); + context.putVar("to", to); + reportUtils.processTemplateWithSheets(inputStream, outputStream, context); } } } diff --git a/src/main/java/org/traccar/reports/StopsReportProvider.java b/src/main/java/org/traccar/reports/StopsReportProvider.java index b7896c423..807a6133b 100644 --- a/src/main/java/org/traccar/reports/StopsReportProvider.java +++ b/src/main/java/org/traccar/reports/StopsReportProvider.java @@ -14,65 +14,48 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package org.traccar.reports; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Date; - import org.apache.poi.ss.util.WorkbookUtil; import org.traccar.Context; -import org.traccar.Main; -import org.traccar.api.security.PermissionsService; -import org.traccar.database.DeviceManager; -import org.traccar.database.IdentityManager; import org.traccar.model.Device; import org.traccar.model.Group; import org.traccar.reports.common.ReportUtils; -import org.traccar.reports.common.TripsConfig; import org.traccar.reports.model.DeviceReportSection; import org.traccar.reports.model.StopReportItem; -import org.traccar.storage.Storage; import org.traccar.storage.StorageException; import javax.inject.Inject; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Date; public class StopsReportProvider { - private final PermissionsService permissionsService; - private final Storage storage; - private final TripsConfig tripsConfig; + private final ReportUtils reportUtils; @Inject - public StopsReportProvider(PermissionsService permissionsService, Storage storage, TripsConfig tripsConfig) { - this.permissionsService = permissionsService; - this.storage = storage; - this.tripsConfig = tripsConfig; + public StopsReportProvider(ReportUtils reportUtils) { + this.reportUtils = reportUtils; } private Collection detectStops(long deviceId, Date from, Date to) throws StorageException { boolean ignoreOdometer = Context.getDeviceManager() .lookupAttributeBoolean(deviceId, "report.ignoreOdometer", false, false, true); - - IdentityManager identityManager = Main.getInjector().getInstance(IdentityManager.class); - DeviceManager deviceManager = Main.getInjector().getInstance(DeviceManager.class); - - return ReportUtils.detectTripsAndStops( - storage, identityManager, deviceManager, Context.getDataManager().getPositions(deviceId, from, to), - tripsConfig, ignoreOdometer, StopReportItem.class); + return reportUtils.detectTripsAndStops( + Context.getDataManager().getPositions(deviceId, from, to), ignoreOdometer, StopReportItem.class); } public Collection getObjects( long userId, Collection deviceIds, Collection groupIds, Date from, Date to) throws StorageException { - ReportUtils.checkPeriodLimit(from, to); + reportUtils.checkPeriodLimit(from, to); ArrayList result = new ArrayList<>(); - for (long deviceId: ReportUtils.getDeviceList(deviceIds, groupIds)) { + for (long deviceId: reportUtils.getDeviceList(deviceIds, groupIds)) { Context.getPermissionsManager().checkDevice(userId, deviceId); result.addAll(detectStops(deviceId, from, to)); } @@ -82,10 +65,10 @@ public class StopsReportProvider { public void getExcel( OutputStream outputStream, long userId, Collection deviceIds, Collection groupIds, Date from, Date to) throws StorageException, IOException { - ReportUtils.checkPeriodLimit(from, to); + reportUtils.checkPeriodLimit(from, to); ArrayList devicesStops = new ArrayList<>(); ArrayList sheetNames = new ArrayList<>(); - for (long deviceId: ReportUtils.getDeviceList(deviceIds, groupIds)) { + for (long deviceId: reportUtils.getDeviceList(deviceIds, groupIds)) { Context.getPermissionsManager().checkDevice(userId, deviceId); Collection stops = detectStops(deviceId, from, to); DeviceReportSection deviceStops = new DeviceReportSection(); @@ -104,13 +87,12 @@ public class StopsReportProvider { String templatePath = Context.getConfig().getString("report.templatesPath", "templates/export/"); try (InputStream inputStream = new FileInputStream(templatePath + "/stops.xlsx")) { - var jxlsContext = ReportUtils.initializeContext( - permissionsService.getServer(), permissionsService.getUser(userId)); - jxlsContext.putVar("devices", devicesStops); - jxlsContext.putVar("sheetNames", sheetNames); - jxlsContext.putVar("from", from); - jxlsContext.putVar("to", to); - ReportUtils.processTemplateWithSheets(inputStream, outputStream, jxlsContext); + var context = reportUtils.initializeContext(userId); + context.putVar("devices", devicesStops); + context.putVar("sheetNames", sheetNames); + context.putVar("from", from); + context.putVar("to", to); + reportUtils.processTemplateWithSheets(inputStream, outputStream, context); } } diff --git a/src/main/java/org/traccar/reports/SummaryReportProvider.java b/src/main/java/org/traccar/reports/SummaryReportProvider.java index 27dc5819d..28abe790b 100644 --- a/src/main/java/org/traccar/reports/SummaryReportProvider.java +++ b/src/main/java/org/traccar/reports/SummaryReportProvider.java @@ -16,19 +16,11 @@ */ package org.traccar.reports; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.Calendar; -import java.util.Collection; -import java.util.Date; - import org.jxls.util.JxlsHelper; import org.traccar.Context; import org.traccar.api.security.PermissionsService; import org.traccar.helper.UnitsConverter; +import org.traccar.helper.model.PositionUtil; import org.traccar.helper.model.UserUtil; import org.traccar.model.Position; import org.traccar.reports.common.ReportUtils; @@ -36,13 +28,23 @@ import org.traccar.reports.model.SummaryReportItem; import org.traccar.storage.StorageException; import javax.inject.Inject; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.Calendar; +import java.util.Collection; +import java.util.Date; public class SummaryReportProvider { + private final ReportUtils reportUtils; private final PermissionsService permissionsService; @Inject - public SummaryReportProvider(PermissionsService permissionsService) { + public SummaryReportProvider(ReportUtils reportUtils, PermissionsService permissionsService) { + this.reportUtils = reportUtils; this.permissionsService = permissionsService; } @@ -64,8 +66,8 @@ public class SummaryReportProvider { } boolean ignoreOdometer = Context.getDeviceManager() .lookupAttributeBoolean(deviceId, "report.ignoreOdometer", false, false, true); - result.setDistance(ReportUtils.calculateDistance(firstPosition, previousPosition, !ignoreOdometer)); - result.setSpentFuel(ReportUtils.calculateFuel(firstPosition, previousPosition)); + result.setDistance(PositionUtil.calculateDistance(firstPosition, previousPosition, !ignoreOdometer)); + result.setSpentFuel(reportUtils.calculateFuel(firstPosition, previousPosition)); long durationMilliseconds; if (firstPosition.getAttributes().containsKey(Position.KEY_HOURS) @@ -134,9 +136,9 @@ public class SummaryReportProvider { public Collection getObjects( long userId, Collection deviceIds, Collection groupIds, Date from, Date to, boolean daily) throws StorageException { - ReportUtils.checkPeriodLimit(from, to); + reportUtils.checkPeriodLimit(from, to); ArrayList result = new ArrayList<>(); - for (long deviceId: ReportUtils.getDeviceList(deviceIds, groupIds)) { + for (long deviceId: reportUtils.getDeviceList(deviceIds, groupIds)) { Context.getPermissionsManager().checkDevice(userId, deviceId); Collection deviceResults = calculateSummaryResults(userId, deviceId, from, to, daily); for (SummaryReportItem summaryReport : deviceResults) { @@ -151,18 +153,17 @@ public class SummaryReportProvider { public void getExcel(OutputStream outputStream, long userId, Collection deviceIds, Collection groupIds, Date from, Date to, boolean daily) throws StorageException, IOException { - ReportUtils.checkPeriodLimit(from, to); + reportUtils.checkPeriodLimit(from, to); Collection summaries = getObjects(userId, deviceIds, groupIds, from, to, daily); String templatePath = Context.getConfig().getString("report.templatesPath", "templates/export/"); try (InputStream inputStream = new FileInputStream(templatePath + "/summary.xlsx")) { - var jxlsContext = ReportUtils.initializeContext( - permissionsService.getServer(), permissionsService.getUser(userId)); - jxlsContext.putVar("summaries", summaries); - jxlsContext.putVar("from", from); - jxlsContext.putVar("to", to); + var context = reportUtils.initializeContext(userId); + context.putVar("summaries", summaries); + context.putVar("from", from); + context.putVar("to", to); JxlsHelper.getInstance().setUseFastFormulaProcessor(false) - .processTemplate(inputStream, outputStream, jxlsContext); + .processTemplate(inputStream, outputStream, context); } } } diff --git a/src/main/java/org/traccar/reports/TripsReportProvider.java b/src/main/java/org/traccar/reports/TripsReportProvider.java index 0505baaa1..5e598cb50 100644 --- a/src/main/java/org/traccar/reports/TripsReportProvider.java +++ b/src/main/java/org/traccar/reports/TripsReportProvider.java @@ -16,42 +16,34 @@ */ package org.traccar.reports; -import java.io.FileInputStream; -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; -import java.util.ArrayList; -import java.util.Collection; -import java.util.Date; - import org.apache.poi.ss.util.WorkbookUtil; import org.traccar.Context; import org.traccar.Main; -import org.traccar.api.security.PermissionsService; import org.traccar.database.DeviceManager; import org.traccar.database.IdentityManager; import org.traccar.model.Device; import org.traccar.model.Group; import org.traccar.reports.common.ReportUtils; -import org.traccar.reports.common.TripsConfig; import org.traccar.reports.model.DeviceReportSection; import org.traccar.reports.model.TripReportItem; -import org.traccar.storage.Storage; import org.traccar.storage.StorageException; import javax.inject.Inject; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.io.OutputStream; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Date; public class TripsReportProvider { - private final PermissionsService permissionsService; - private final Storage storage; - private final TripsConfig tripsConfig; + private final ReportUtils reportUtils; @Inject - public TripsReportProvider(PermissionsService permissionsService, Storage storage, TripsConfig tripsConfig) { - this.permissionsService = permissionsService; - this.storage = storage; - this.tripsConfig = tripsConfig; + public TripsReportProvider(ReportUtils reportUtils) { + this.reportUtils = reportUtils; } private Collection detectTrips(long deviceId, Date from, Date to) throws StorageException { @@ -61,16 +53,15 @@ public class TripsReportProvider { IdentityManager identityManager = Main.getInjector().getInstance(IdentityManager.class); DeviceManager deviceManager = Main.getInjector().getInstance(DeviceManager.class); - return ReportUtils.detectTripsAndStops( - storage, identityManager, deviceManager, Context.getDataManager().getPositions(deviceId, from, to), - tripsConfig, ignoreOdometer, TripReportItem.class); + return reportUtils.detectTripsAndStops( + Context.getDataManager().getPositions(deviceId, from, to), ignoreOdometer, TripReportItem.class); } public Collection getObjects(long userId, Collection deviceIds, Collection groupIds, Date from, Date to) throws StorageException { - ReportUtils.checkPeriodLimit(from, to); + reportUtils.checkPeriodLimit(from, to); ArrayList result = new ArrayList<>(); - for (long deviceId: ReportUtils.getDeviceList(deviceIds, groupIds)) { + for (long deviceId: reportUtils.getDeviceList(deviceIds, groupIds)) { Context.getPermissionsManager().checkDevice(userId, deviceId); result.addAll(detectTrips(deviceId, from, to)); } @@ -80,10 +71,10 @@ public class TripsReportProvider { public void getExcel(OutputStream outputStream, long userId, Collection deviceIds, Collection groupIds, Date from, Date to) throws StorageException, IOException { - ReportUtils.checkPeriodLimit(from, to); + reportUtils.checkPeriodLimit(from, to); ArrayList devicesTrips = new ArrayList<>(); ArrayList sheetNames = new ArrayList<>(); - for (long deviceId: ReportUtils.getDeviceList(deviceIds, groupIds)) { + for (long deviceId: reportUtils.getDeviceList(deviceIds, groupIds)) { Context.getPermissionsManager().checkDevice(userId, deviceId); Collection trips = detectTrips(deviceId, from, to); DeviceReportSection deviceTrips = new DeviceReportSection(); @@ -102,13 +93,12 @@ public class TripsReportProvider { String templatePath = Context.getConfig().getString("report.templatesPath", "templates/export/"); try (InputStream inputStream = new FileInputStream(templatePath + "/trips.xlsx")) { - var jxlsContext = ReportUtils.initializeContext( - permissionsService.getServer(), permissionsService.getUser(userId)); - jxlsContext.putVar("devices", devicesTrips); - jxlsContext.putVar("sheetNames", sheetNames); - jxlsContext.putVar("from", from); - jxlsContext.putVar("to", to); - ReportUtils.processTemplateWithSheets(inputStream, outputStream, jxlsContext); + var context = reportUtils.initializeContext(userId); + context.putVar("devices", devicesTrips); + context.putVar("sheetNames", sheetNames); + context.putVar("from", from); + context.putVar("to", to); + reportUtils.processTemplateWithSheets(inputStream, outputStream, context); } } diff --git a/src/main/java/org/traccar/reports/common/ReportUtils.java b/src/main/java/org/traccar/reports/common/ReportUtils.java index 36d5c0fb1..706475241 100644 --- a/src/main/java/org/traccar/reports/common/ReportUtils.java +++ b/src/main/java/org/traccar/reports/common/ReportUtils.java @@ -26,28 +26,33 @@ import org.jxls.transform.Transformer; import org.jxls.transform.poi.PoiTransformer; import org.jxls.util.TransformerFactory; import org.traccar.Context; +import org.traccar.api.security.PermissionsService; +import org.traccar.config.Config; import org.traccar.config.Keys; import org.traccar.database.DeviceManager; import org.traccar.database.IdentityManager; +import org.traccar.geocoder.Geocoder; import org.traccar.handler.events.MotionEventHandler; import org.traccar.helper.UnitsConverter; +import org.traccar.helper.model.PositionUtil; import org.traccar.helper.model.UserUtil; import org.traccar.model.BaseModel; -import org.traccar.model.Server; -import org.traccar.model.User; -import org.traccar.session.DeviceState; import org.traccar.model.Driver; import org.traccar.model.Event; import org.traccar.model.Position; +import org.traccar.model.User; import org.traccar.reports.model.BaseReportItem; import org.traccar.reports.model.StopReportItem; import org.traccar.reports.model.TripReportItem; +import org.traccar.session.DeviceState; import org.traccar.storage.Storage; import org.traccar.storage.StorageException; import org.traccar.storage.query.Columns; import org.traccar.storage.query.Condition; import org.traccar.storage.query.Request; +import javax.annotation.Nullable; +import javax.inject.Inject; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; @@ -61,13 +66,31 @@ import java.util.List; import java.util.Locale; import java.util.Map; -public final class ReportUtils { - - private ReportUtils() { +public class ReportUtils { + + private final Config config; + private final Storage storage; + private final PermissionsService permissionsService; + private final IdentityManager identityManager; + private final DeviceManager deviceManager; + private final TripsConfig tripsConfig; + private final Geocoder geocoder; + + @Inject + public ReportUtils( + Config config, Storage storage, PermissionsService permissionsService, IdentityManager identityManager, + DeviceManager deviceManager, TripsConfig tripsConfig, @Nullable Geocoder geocoder) { + this.config = config; + this.storage = storage; + this.permissionsService = permissionsService; + this.identityManager = identityManager; + this.deviceManager = deviceManager; + this.tripsConfig = tripsConfig; + this.geocoder = geocoder; } - public static T getObject( - Storage storage, long userId, Class clazz, long objectId) throws StorageException, SecurityException { + public T getObject( + long userId, Class clazz, long objectId) throws StorageException, SecurityException { return storage.getObject(clazz, new Request( new Columns.Include("id"), new Condition.And( @@ -75,14 +98,14 @@ public final class ReportUtils { new Condition.Permission(User.class, userId, clazz)))); } - public static void checkPeriodLimit(Date from, Date to) { - long limit = Context.getConfig().getLong(Keys.REPORT_PERIOD_LIMIT) * 1000; + public void checkPeriodLimit(Date from, Date to) { + long limit = config.getLong(Keys.REPORT_PERIOD_LIMIT) * 1000; if (limit > 0 && to.getTime() - from.getTime() > limit) { throw new IllegalArgumentException("Time period exceeds the limit"); } } - public static Collection getDeviceList(Collection deviceIds, Collection groupIds) { + public Collection getDeviceList(Collection deviceIds, Collection groupIds) { Collection result = new LinkedHashSet<>(deviceIds); for (long groupId : groupIds) { result.addAll(Context.getPermissionsManager().getGroupDevices(groupId)); @@ -90,26 +113,7 @@ public final class ReportUtils { return result; } - public static double calculateDistance(Position firstPosition, Position lastPosition) { - return calculateDistance(firstPosition, lastPosition, true); - } - - public static double calculateDistance(Position firstPosition, Position lastPosition, boolean useOdometer) { - double distance = 0.0; - double firstOdometer = firstPosition.getDouble(Position.KEY_ODOMETER); - double lastOdometer = lastPosition.getDouble(Position.KEY_ODOMETER); - - if (useOdometer && firstOdometer != 0.0 && lastOdometer != 0.0) { - distance = lastOdometer - firstOdometer; - } else if (firstPosition.getAttributes().containsKey(Position.KEY_TOTAL_DISTANCE) - && lastPosition.getAttributes().containsKey(Position.KEY_TOTAL_DISTANCE)) { - distance = lastPosition.getDouble(Position.KEY_TOTAL_DISTANCE) - - firstPosition.getDouble(Position.KEY_TOTAL_DISTANCE); - } - return distance; - } - - public static double calculateFuel(Position firstPosition, Position lastPosition) { + public double calculateFuel(Position firstPosition, Position lastPosition) { if (firstPosition.getAttributes().get(Position.KEY_FUEL_LEVEL) != null && lastPosition.getAttributes().get(Position.KEY_FUEL_LEVEL) != null) { @@ -121,7 +125,7 @@ public final class ReportUtils { return 0; } - public static String findDriver(Position firstPosition, Position lastPosition) { + public String findDriver(Position firstPosition, Position lastPosition) { if (firstPosition.getAttributes().containsKey(Position.KEY_DRIVER_UNIQUE_ID)) { return firstPosition.getString(Position.KEY_DRIVER_UNIQUE_ID); } else if (lastPosition.getAttributes().containsKey(Position.KEY_DRIVER_UNIQUE_ID)) { @@ -130,7 +134,7 @@ public final class ReportUtils { return null; } - public static String findDriverName(Storage storage, String driverUniqueId) throws StorageException { + public String findDriverName(String driverUniqueId) throws StorageException { if (driverUniqueId != null) { Driver driver = storage.getObject(Driver.class, new Request( new Columns.All(), @@ -142,28 +146,29 @@ public final class ReportUtils { return null; } - public static org.jxls.common.Context initializeContext(Server server, User user) { - org.jxls.common.Context jxlsContext = PoiTransformer.createInitialContext(); - jxlsContext.putVar("distanceUnit", UserUtil.getDistanceUnit(server, user)); - jxlsContext.putVar("speedUnit", UserUtil.getSpeedUnit(server, user)); - jxlsContext.putVar("volumeUnit", UserUtil.getVolumeUnit(server, user)); - jxlsContext.putVar("webUrl", Context.getVelocityEngine().getProperty("web.url")); - jxlsContext.putVar("dateTool", new DateTool()); - jxlsContext.putVar("numberTool", new NumberTool()); - jxlsContext.putVar("timezone", UserUtil.getTimezone(server, user)); - jxlsContext.putVar("locale", Locale.getDefault()); - jxlsContext.putVar("bracketsRegex", "[\\{\\}\"]"); - return jxlsContext; + public org.jxls.common.Context initializeContext(long userId) throws StorageException { + var server = permissionsService.getServer(); + var user = permissionsService.getUser(userId); + var context = PoiTransformer.createInitialContext(); + context.putVar("distanceUnit", UserUtil.getDistanceUnit(server, user)); + context.putVar("speedUnit", UserUtil.getSpeedUnit(server, user)); + context.putVar("volumeUnit", UserUtil.getVolumeUnit(server, user)); + context.putVar("webUrl", Context.getVelocityEngine().getProperty("web.url")); + context.putVar("dateTool", new DateTool()); + context.putVar("numberTool", new NumberTool()); + context.putVar("timezone", UserUtil.getTimezone(server, user)); + context.putVar("locale", Locale.getDefault()); + context.putVar("bracketsRegex", "[\\{\\}\"]"); + return context; } - public static void processTemplateWithSheets( - InputStream templateStream, OutputStream targetStream, - org.jxls.common.Context jxlsContext) throws IOException { + public void processTemplateWithSheets( + InputStream templateStream, OutputStream targetStream, org.jxls.common.Context context) throws IOException { Transformer transformer = TransformerFactory.createTransformer(templateStream, targetStream); List xlsAreas = new XlsCommentAreaBuilder(transformer).build(); for (Area xlsArea : xlsAreas) { - xlsArea.applyAt(new CellRef(xlsArea.getStartCellRef().getCellName()), jxlsContext); + xlsArea.applyAt(new CellRef(xlsArea.getStartCellRef().getCellName()), context); xlsArea.setFormulaProcessor(new StandardFormulaProcessor()); xlsArea.processFormulas(); } @@ -171,9 +176,9 @@ public final class ReportUtils { transformer.write(); } - private static TripReportItem calculateTrip( - Storage storage, IdentityManager identityManager, ArrayList positions, - int startIndex, int endIndex, boolean ignoreOdometer) throws StorageException { + private TripReportItem calculateTrip( + ArrayList positions, int startIndex, int endIndex, + boolean ignoreOdometer) throws StorageException { Position startTrip = positions.get(startIndex); Position endTrip = positions.get(endIndex); @@ -198,9 +203,8 @@ public final class ReportUtils { trip.setStartLon(startTrip.getLongitude()); trip.setStartTime(startTrip.getFixTime()); String startAddress = startTrip.getAddress(); - if (startAddress == null && Context.getGeocoder() != null - && Context.getConfig().getBoolean(Keys.GEOCODER_ON_REQUEST)) { - startAddress = Context.getGeocoder().getAddress(startTrip.getLatitude(), startTrip.getLongitude(), null); + if (startAddress == null && geocoder != null && config.getBoolean(Keys.GEOCODER_ON_REQUEST)) { + startAddress = geocoder.getAddress(startTrip.getLatitude(), startTrip.getLongitude(), null); } trip.setStartAddress(startAddress); @@ -209,13 +213,12 @@ public final class ReportUtils { trip.setEndLon(endTrip.getLongitude()); trip.setEndTime(endTrip.getFixTime()); String endAddress = endTrip.getAddress(); - if (endAddress == null && Context.getGeocoder() != null - && Context.getConfig().getBoolean(Keys.GEOCODER_ON_REQUEST)) { - endAddress = Context.getGeocoder().getAddress(endTrip.getLatitude(), endTrip.getLongitude(), null); + if (endAddress == null && geocoder != null && config.getBoolean(Keys.GEOCODER_ON_REQUEST)) { + endAddress = geocoder.getAddress(endTrip.getLatitude(), endTrip.getLongitude(), null); } trip.setEndAddress(endAddress); - trip.setDistance(calculateDistance(startTrip, endTrip, !ignoreOdometer)); + trip.setDistance(PositionUtil.calculateDistance(startTrip, endTrip, !ignoreOdometer)); trip.setDuration(tripDuration); if (tripDuration > 0) { trip.setAverageSpeed(UnitsConverter.knotsFromMps(trip.getDistance() * 1000 / tripDuration)); @@ -224,7 +227,7 @@ public final class ReportUtils { trip.setSpentFuel(calculateFuel(startTrip, endTrip)); trip.setDriverUniqueId(findDriver(startTrip, endTrip)); - trip.setDriverName(findDriverName(storage, trip.getDriverUniqueId())); + trip.setDriverName(findDriverName(trip.getDriverUniqueId())); if (!ignoreOdometer && startTrip.getDouble(Position.KEY_ODOMETER) != 0 @@ -239,9 +242,8 @@ public final class ReportUtils { return trip; } - private static StopReportItem calculateStop( - IdentityManager identityManager, ArrayList positions, - int startIndex, int endIndex, boolean ignoreOdometer) { + private StopReportItem calculateStop( + ArrayList positions, int startIndex, int endIndex, boolean ignoreOdometer) { Position startStop = positions.get(startIndex); Position endStop = positions.get(endIndex); @@ -257,9 +259,8 @@ public final class ReportUtils { stop.setLongitude(startStop.getLongitude()); stop.setStartTime(startStop.getFixTime()); String address = startStop.getAddress(); - if (address == null && Context.getGeocoder() != null - && Context.getConfig().getBoolean(Keys.GEOCODER_ON_REQUEST)) { - address = Context.getGeocoder().getAddress(stop.getLatitude(), stop.getLongitude(), null); + if (address == null && geocoder != null && config.getBoolean(Keys.GEOCODER_ON_REQUEST)) { + address = geocoder.getAddress(stop.getLatitude(), stop.getLongitude(), null); } stop.setAddress(address); @@ -288,18 +289,19 @@ public final class ReportUtils { } - private static T calculateTripOrStop( - Storage storage, IdentityManager identityManager, ArrayList positions, - int startIndex, int endIndex, boolean ignoreOdometer, Class reportClass) throws StorageException { + @SuppressWarnings("unchecked") + private T calculateTripOrStop( + ArrayList positions, int startIndex, int endIndex, + boolean ignoreOdometer, Class reportClass) throws StorageException { if (reportClass.equals(TripReportItem.class)) { - return (T) calculateTrip(storage, identityManager, positions, startIndex, endIndex, ignoreOdometer); + return (T) calculateTrip(positions, startIndex, endIndex, ignoreOdometer); } else { - return (T) calculateStop(identityManager, positions, startIndex, endIndex, ignoreOdometer); + return (T) calculateStop(positions, startIndex, endIndex, ignoreOdometer); } } - private static boolean isMoving(ArrayList positions, int index, TripsConfig tripsConfig) { + private boolean isMoving(ArrayList positions, int index, TripsConfig tripsConfig) { if (tripsConfig.getMinimalNoDataDuration() > 0) { boolean beforeGap = index < positions.size() - 1 && positions.get(index + 1).getFixTime().getTime() - positions.get(index).getFixTime().getTime() @@ -319,17 +321,16 @@ public final class ReportUtils { } } - public static Collection detectTripsAndStops( - Storage storage, IdentityManager identityManager, DeviceManager deviceManager, - Collection positionCollection, - TripsConfig tripsConfig, boolean ignoreOdometer, Class reportClass) throws StorageException { + public Collection detectTripsAndStops( + Collection positionCollection, boolean ignoreOdometer, + Class reportClass) throws StorageException { Collection result = new ArrayList<>(); ArrayList positions = new ArrayList<>(positionCollection); if (!positions.isEmpty()) { boolean trips = reportClass.equals(TripReportItem.class); - MotionEventHandler motionHandler = new MotionEventHandler(identityManager, deviceManager, tripsConfig); + MotionEventHandler motionHandler = new MotionEventHandler(identityManager, deviceManager, tripsConfig); DeviceState deviceState = new DeviceState(); deviceState.setMotionState(isMoving(positions, 0, tripsConfig)); int startEventIndex = trips == deviceState.getMotionState() ? 0 : -1; @@ -355,15 +356,15 @@ public final class ReportUtils { } if (startEventIndex != -1 && startNoEventIndex != -1 && event != null && trips != deviceState.getMotionState()) { - result.add(calculateTripOrStop(storage, identityManager, positions, - startEventIndex, startNoEventIndex, ignoreOdometer, reportClass)); + result.add(calculateTripOrStop( + positions, startEventIndex, startNoEventIndex, ignoreOdometer, reportClass)); startEventIndex = -1; } } if (startEventIndex != -1 && (startNoEventIndex != -1 || !trips)) { - result.add(calculateTripOrStop(storage, identityManager, positions, - startEventIndex, startNoEventIndex != -1 ? startNoEventIndex : positions.size() - 1, - ignoreOdometer, reportClass)); + int endIndex = startNoEventIndex != -1 ? startNoEventIndex : positions.size() - 1; + result.add(calculateTripOrStop( + positions, startEventIndex, endIndex, ignoreOdometer, reportClass)); } } diff --git a/src/test/java/org/traccar/reports/ReportUtilsTest.java b/src/test/java/org/traccar/reports/ReportUtilsTest.java index 9b287a0fd..92bfdae1c 100644 --- a/src/test/java/org/traccar/reports/ReportUtilsTest.java +++ b/src/test/java/org/traccar/reports/ReportUtilsTest.java @@ -2,7 +2,11 @@ package org.traccar.reports; import org.junit.Test; import org.traccar.BaseTest; +import org.traccar.api.security.PermissionsService; +import org.traccar.config.Config; +import org.traccar.database.DeviceManager; import org.traccar.database.IdentityManager; +import org.traccar.helper.model.PositionUtil; import org.traccar.model.Device; import org.traccar.model.Position; import org.traccar.reports.common.ReportUtils; @@ -63,20 +67,23 @@ public class ReportUtilsTest extends BaseTest { startPosition.set(Position.KEY_TOTAL_DISTANCE, 500.0); Position endPosition = new Position(); endPosition.set(Position.KEY_TOTAL_DISTANCE, 700.0); - assertEquals(ReportUtils.calculateDistance(startPosition, endPosition), 200.0, 10); + assertEquals(PositionUtil.calculateDistance(startPosition, endPosition, true), 200.0, 10); startPosition.set(Position.KEY_ODOMETER, 50000); endPosition.set(Position.KEY_ODOMETER, 51000); - assertEquals(ReportUtils.calculateDistance(startPosition, endPosition), 1000.0, 10); + assertEquals(PositionUtil.calculateDistance(startPosition, endPosition, true), 1000.0, 10); } @Test public void testCalculateSpentFuel() { + ReportUtils reportUtils = new ReportUtils( + mock(Config.class), mock(Storage.class), mock(PermissionsService.class), + mockIdentityManager(), mock(DeviceManager.class), mock(TripsConfig.class), null); Position startPosition = new Position(); Position endPosition = new Position(); - assertEquals(ReportUtils.calculateFuel(startPosition, endPosition), 0.0, 0.01); + assertEquals(reportUtils.calculateFuel(startPosition, endPosition), 0.0, 0.01); startPosition.set(Position.KEY_FUEL_LEVEL, 0.7); endPosition.set(Position.KEY_FUEL_LEVEL, 0.5); - assertEquals(ReportUtils.calculateFuel(startPosition, endPosition), 0.2, 0.01); + assertEquals(reportUtils.calculateFuel(startPosition, endPosition), 0.2, 0.01); } @Test @@ -93,9 +100,11 @@ public class ReportUtilsTest extends BaseTest { position("2016-01-01 00:07:00.000", 0, 3000)); TripsConfig tripsConfig = new TripsConfig(500, 300000, 180000, 900000, false, false, 0.01); + ReportUtils reportUtils = new ReportUtils( + mock(Config.class), mock(Storage.class), mock(PermissionsService.class), + mockIdentityManager(), mock(DeviceManager.class), tripsConfig, null); - Collection trips = ReportUtils.detectTripsAndStops( - mock(Storage.class), mockIdentityManager(), null, data, tripsConfig, false, TripReportItem.class); + Collection trips = reportUtils.detectTripsAndStops(data, false, TripReportItem.class); assertNotNull(trips); assertFalse(trips.isEmpty()); @@ -109,8 +118,7 @@ public class ReportUtilsTest extends BaseTest { assertEquals(10, itemTrip.getMaxSpeed(), 0.01); assertEquals(3000, itemTrip.getDistance(), 0.01); - Collection stops = ReportUtils.detectTripsAndStops( - mock(Storage.class), mockIdentityManager(), null, data, tripsConfig, false, StopReportItem.class); + Collection stops = reportUtils.detectTripsAndStops(data, false, StopReportItem.class); assertNotNull(stops); assertFalse(stops.isEmpty()); @@ -147,9 +155,11 @@ public class ReportUtilsTest extends BaseTest { data.get(5).set(Position.KEY_IGNITION, false); TripsConfig tripsConfig = new TripsConfig(500, 300000, 180000, 900000, true, false, 0.01); + ReportUtils reportUtils = new ReportUtils( + mock(Config.class), mock(Storage.class), mock(PermissionsService.class), + mockIdentityManager(), mock(DeviceManager.class), tripsConfig, null); - Collection trips = ReportUtils.detectTripsAndStops( - mock(Storage.class), mockIdentityManager(), null, data, tripsConfig, false, TripReportItem.class); + Collection trips = reportUtils.detectTripsAndStops(data, false, TripReportItem.class); assertNotNull(trips); assertFalse(trips.isEmpty()); @@ -163,8 +173,7 @@ public class ReportUtilsTest extends BaseTest { assertEquals(10, itemTrip.getMaxSpeed(), 0.01); assertEquals(3000, itemTrip.getDistance(), 0.01); - trips = ReportUtils.detectTripsAndStops( - mock(Storage.class), mockIdentityManager(), null, data, tripsConfig, false, TripReportItem.class); + trips = reportUtils.detectTripsAndStops(data, false, TripReportItem.class); assertNotNull(trips); assertFalse(trips.isEmpty()); @@ -178,8 +187,7 @@ public class ReportUtilsTest extends BaseTest { assertEquals(10, itemTrip.getMaxSpeed(), 0.01); assertEquals(3000, itemTrip.getDistance(), 0.01); - Collection stops = ReportUtils.detectTripsAndStops( - mock(Storage.class), mockIdentityManager(), null, data, tripsConfig, false, StopReportItem.class); + Collection stops = reportUtils.detectTripsAndStops(data, false, StopReportItem.class); assertNotNull(stops); assertFalse(stops.isEmpty()); @@ -218,9 +226,11 @@ public class ReportUtilsTest extends BaseTest { position("2016-01-01 00:11:00.000", 0, 7000)); TripsConfig tripsConfig = new TripsConfig(500, 300000, 180000, 900000, false, false, 0.01); + ReportUtils reportUtils = new ReportUtils( + mock(Config.class), mock(Storage.class), mock(PermissionsService.class), + mockIdentityManager(), mock(DeviceManager.class), tripsConfig, null); - Collection trips = ReportUtils.detectTripsAndStops( - mock(Storage.class), mockIdentityManager(), null, data, tripsConfig, false, TripReportItem.class); + Collection trips = reportUtils.detectTripsAndStops(data, false, TripReportItem.class); assertNotNull(trips); assertFalse(trips.isEmpty()); @@ -234,8 +244,7 @@ public class ReportUtilsTest extends BaseTest { assertEquals(10, itemTrip.getMaxSpeed(), 0.01); assertEquals(7000, itemTrip.getDistance(), 0.01); - Collection stops = ReportUtils.detectTripsAndStops( - mock(Storage.class), mockIdentityManager(), null, data, tripsConfig, false, StopReportItem.class); + Collection stops = reportUtils.detectTripsAndStops(data, false, StopReportItem.class); assertNotNull(stops); assertFalse(stops.isEmpty()); @@ -268,9 +277,11 @@ public class ReportUtilsTest extends BaseTest { position("2016-01-01 00:05:00.000", 0, 0)); TripsConfig tripsConfig = new TripsConfig(500, 300000, 200000, 900000, false, false, 0.01); + ReportUtils reportUtils = new ReportUtils( + mock(Config.class), mock(Storage.class), mock(PermissionsService.class), + mockIdentityManager(), mock(DeviceManager.class), tripsConfig, null); - Collection result = ReportUtils.detectTripsAndStops( - mock(Storage.class), mockIdentityManager(), null, data, tripsConfig, false, StopReportItem.class); + Collection result = reportUtils.detectTripsAndStops(data, false, StopReportItem.class); assertNotNull(result); assertFalse(result.isEmpty()); @@ -295,9 +306,11 @@ public class ReportUtilsTest extends BaseTest { position("2016-01-01 00:05:00.000", 2, 0)); TripsConfig tripsConfig = new TripsConfig(500, 300000, 200000, 900000, false, false, 0.01); + ReportUtils reportUtils = new ReportUtils( + mock(Config.class), mock(Storage.class), mock(PermissionsService.class), + mockIdentityManager(), mock(DeviceManager.class), tripsConfig, null); - Collection result = ReportUtils.detectTripsAndStops( - mock(Storage.class), mockIdentityManager(), null, data, tripsConfig, false, StopReportItem.class); + Collection result = reportUtils.detectTripsAndStops(data, false, StopReportItem.class); assertNotNull(result); assertFalse(result.isEmpty()); @@ -322,9 +335,11 @@ public class ReportUtilsTest extends BaseTest { position("2016-01-01 00:05:00.000", 0, 0)); TripsConfig tripsConfig = new TripsConfig(500, 300000, 200000, 900000, false, false, 0.01); + ReportUtils reportUtils = new ReportUtils( + mock(Config.class), mock(Storage.class), mock(PermissionsService.class), + mockIdentityManager(), mock(DeviceManager.class), tripsConfig, null); - Collection result = ReportUtils.detectTripsAndStops( - mock(Storage.class), mockIdentityManager(), null, data, tripsConfig, false, StopReportItem.class); + Collection result = reportUtils.detectTripsAndStops(data, false, StopReportItem.class); assertNotNull(result); assertFalse(result.isEmpty()); @@ -349,9 +364,11 @@ public class ReportUtilsTest extends BaseTest { position("2016-01-01 00:05:00.000", 5, 0)); TripsConfig tripsConfig = new TripsConfig(500, 300000, 200000, 900000, false, false, 0.01); + ReportUtils reportUtils = new ReportUtils( + mock(Config.class), mock(Storage.class), mock(PermissionsService.class), + mockIdentityManager(), mock(DeviceManager.class), tripsConfig, null); - Collection result = ReportUtils.detectTripsAndStops( - mock(Storage.class), mockIdentityManager(), null, data, tripsConfig, false, StopReportItem.class); + Collection result = reportUtils.detectTripsAndStops(data, false, StopReportItem.class); assertNotNull(result); assertTrue(result.isEmpty()); @@ -372,9 +389,11 @@ public class ReportUtilsTest extends BaseTest { position("2016-01-01 00:25:00.000", 5, 900)); TripsConfig tripsConfig = new TripsConfig(500, 200000, 200000, 900000, false, false, 0.01); + ReportUtils reportUtils = new ReportUtils( + mock(Config.class), mock(Storage.class), mock(PermissionsService.class), + mockIdentityManager(), mock(DeviceManager.class), tripsConfig, null); - Collection trips = ReportUtils.detectTripsAndStops( - mock(Storage.class), mockIdentityManager(), null, data, tripsConfig, false, TripReportItem.class); + Collection trips = reportUtils.detectTripsAndStops(data, false, TripReportItem.class); assertNotNull(trips); assertFalse(trips.isEmpty()); @@ -388,8 +407,7 @@ public class ReportUtilsTest extends BaseTest { assertEquals(7, itemTrip.getMaxSpeed(), 0.01); assertEquals(600, itemTrip.getDistance(), 0.01); - Collection stops = ReportUtils.detectTripsAndStops( - mock(Storage.class), mockIdentityManager(), null, data, tripsConfig, false, StopReportItem.class); + Collection stops = reportUtils.detectTripsAndStops(data, false, StopReportItem.class); assertNotNull(stops); assertFalse(stops.isEmpty()); -- cgit v1.2.3 From e894c17cf14addb729a6c51712ef672cc2cd160b Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Mon, 13 Jun 2022 17:19:15 -0700 Subject: Refactor getPositions method --- .../org/traccar/api/resource/PositionResource.java | 10 +++++++--- src/main/java/org/traccar/database/DataManager.java | 9 --------- .../java/org/traccar/helper/model/PositionUtil.java | 19 +++++++++++++++++++ .../java/org/traccar/reports/RouteReportProvider.java | 11 +++++++---- .../java/org/traccar/reports/StopsReportProvider.java | 8 ++++++-- .../org/traccar/reports/SummaryReportProvider.java | 10 ++++++---- .../java/org/traccar/reports/TripsReportProvider.java | 14 ++++++-------- 7 files changed, 51 insertions(+), 30 deletions(-) (limited to 'src/main/java/org/traccar/helper') diff --git a/src/main/java/org/traccar/api/resource/PositionResource.java b/src/main/java/org/traccar/api/resource/PositionResource.java index 2618a04cb..ae948ee14 100644 --- a/src/main/java/org/traccar/api/resource/PositionResource.java +++ b/src/main/java/org/traccar/api/resource/PositionResource.java @@ -17,9 +17,13 @@ package org.traccar.api.resource; import org.traccar.Context; import org.traccar.api.BaseResource; +import org.traccar.helper.model.PositionUtil; import org.traccar.model.Position; import org.traccar.model.UserRestrictions; import org.traccar.storage.StorageException; +import org.traccar.storage.query.Columns; +import org.traccar.storage.query.Condition; +import org.traccar.storage.query.Request; import javax.ws.rs.Consumes; import javax.ws.rs.GET; @@ -29,7 +33,6 @@ import javax.ws.rs.QueryParam; import javax.ws.rs.core.MediaType; import java.util.ArrayList; import java.util.Collection; -import java.util.Collections; import java.util.Date; import java.util.List; @@ -57,9 +60,10 @@ public class PositionResource extends BaseResource { Context.getPermissionsManager().checkDevice(getUserId(), deviceId); if (from != null && to != null) { permissionsService.checkRestriction(getUserId(), UserRestrictions::getDisableReports); - return Context.getDataManager().getPositions(deviceId, from, to); + return PositionUtil.getPositions(storage, deviceId, from, to); } else { - return Collections.singleton(Context.getDeviceManager().getLastPosition(deviceId)); + return storage.getObjects(Position.class, new Request( + new Columns.All(), new Condition.LatestPositions(deviceId))); } } } diff --git a/src/main/java/org/traccar/database/DataManager.java b/src/main/java/org/traccar/database/DataManager.java index 556f1e348..93c6861e6 100644 --- a/src/main/java/org/traccar/database/DataManager.java +++ b/src/main/java/org/traccar/database/DataManager.java @@ -176,15 +176,6 @@ public class DataManager { new Condition.Equals("id", "id"))); } - public Collection getPositions(long deviceId, Date from, Date to) throws StorageException { - return storage.getObjects(Position.class, new Request( - new Columns.All(), - new Condition.And( - new Condition.Equals("deviceId", "deviceId", deviceId), - new Condition.Between("fixTime", "from", from, "to", to)), - new Order("fixTime"))); - } - public Position getPrecedingPosition(long deviceId, Date date) throws StorageException { return storage.getObject(Position.class, new Request( new Columns.All(), diff --git a/src/main/java/org/traccar/helper/model/PositionUtil.java b/src/main/java/org/traccar/helper/model/PositionUtil.java index 644517dac..566e31bc5 100644 --- a/src/main/java/org/traccar/helper/model/PositionUtil.java +++ b/src/main/java/org/traccar/helper/model/PositionUtil.java @@ -17,6 +17,15 @@ package org.traccar.helper.model; import org.traccar.model.Position; import org.traccar.session.cache.CacheManager; +import org.traccar.storage.Storage; +import org.traccar.storage.StorageException; +import org.traccar.storage.query.Columns; +import org.traccar.storage.query.Condition; +import org.traccar.storage.query.Order; +import org.traccar.storage.query.Request; + +import java.util.Date; +import java.util.List; public final class PositionUtil { @@ -41,4 +50,14 @@ public final class PositionUtil { return distance; } + public static List getPositions( + Storage storage, long deviceId, Date from, Date to) throws StorageException { + return storage.getObjects(Position.class, new Request( + new Columns.All(), + new Condition.And( + new Condition.Equals("deviceId", "deviceId", deviceId), + new Condition.Between("fixTime", "from", from, "to", to)), + new Order("fixTime"))); + } + } diff --git a/src/main/java/org/traccar/reports/RouteReportProvider.java b/src/main/java/org/traccar/reports/RouteReportProvider.java index 136a154aa..dbbf0906d 100644 --- a/src/main/java/org/traccar/reports/RouteReportProvider.java +++ b/src/main/java/org/traccar/reports/RouteReportProvider.java @@ -18,11 +18,13 @@ package org.traccar.reports; import org.apache.poi.ss.util.WorkbookUtil; import org.traccar.Context; +import org.traccar.helper.model.PositionUtil; import org.traccar.model.Device; import org.traccar.model.Group; import org.traccar.model.Position; import org.traccar.reports.common.ReportUtils; import org.traccar.reports.model.DeviceReportSection; +import org.traccar.storage.Storage; import org.traccar.storage.StorageException; import javax.inject.Inject; @@ -37,10 +39,12 @@ import java.util.Date; public class RouteReportProvider { private final ReportUtils reportUtils; + private final Storage storage; @Inject - public RouteReportProvider(ReportUtils reportUtils) { + public RouteReportProvider(ReportUtils reportUtils, Storage storage) { this.reportUtils = reportUtils; + this.storage = storage; } public Collection getObjects(long userId, Collection deviceIds, Collection groupIds, @@ -49,7 +53,7 @@ public class RouteReportProvider { ArrayList result = new ArrayList<>(); for (long deviceId: reportUtils.getDeviceList(deviceIds, groupIds)) { Context.getPermissionsManager().checkDevice(userId, deviceId); - result.addAll(Context.getDataManager().getPositions(deviceId, from, to)); + result.addAll(PositionUtil.getPositions(storage, deviceId, from, to)); } return result; } @@ -62,8 +66,7 @@ public class RouteReportProvider { ArrayList sheetNames = new ArrayList<>(); for (long deviceId: reportUtils.getDeviceList(deviceIds, groupIds)) { Context.getPermissionsManager().checkDevice(userId, deviceId); - Collection positions = Context.getDataManager() - .getPositions(deviceId, from, to); + var positions = PositionUtil.getPositions(storage, deviceId, from, to); DeviceReportSection deviceRoutes = new DeviceReportSection(); Device device = Context.getIdentityManager().getById(deviceId); deviceRoutes.setDeviceName(device.getName()); diff --git a/src/main/java/org/traccar/reports/StopsReportProvider.java b/src/main/java/org/traccar/reports/StopsReportProvider.java index 807a6133b..534ab7742 100644 --- a/src/main/java/org/traccar/reports/StopsReportProvider.java +++ b/src/main/java/org/traccar/reports/StopsReportProvider.java @@ -18,11 +18,13 @@ package org.traccar.reports; import org.apache.poi.ss.util.WorkbookUtil; import org.traccar.Context; +import org.traccar.helper.model.PositionUtil; import org.traccar.model.Device; import org.traccar.model.Group; import org.traccar.reports.common.ReportUtils; import org.traccar.reports.model.DeviceReportSection; import org.traccar.reports.model.StopReportItem; +import org.traccar.storage.Storage; import org.traccar.storage.StorageException; import javax.inject.Inject; @@ -37,17 +39,19 @@ import java.util.Date; public class StopsReportProvider { private final ReportUtils reportUtils; + private final Storage storage; @Inject - public StopsReportProvider(ReportUtils reportUtils) { + public StopsReportProvider(ReportUtils reportUtils, Storage storage) { this.reportUtils = reportUtils; + this.storage = storage; } private Collection detectStops(long deviceId, Date from, Date to) throws StorageException { boolean ignoreOdometer = Context.getDeviceManager() .lookupAttributeBoolean(deviceId, "report.ignoreOdometer", false, false, true); return reportUtils.detectTripsAndStops( - Context.getDataManager().getPositions(deviceId, from, to), ignoreOdometer, StopReportItem.class); + PositionUtil.getPositions(storage, deviceId, from, to), ignoreOdometer, StopReportItem.class); } public Collection getObjects( diff --git a/src/main/java/org/traccar/reports/SummaryReportProvider.java b/src/main/java/org/traccar/reports/SummaryReportProvider.java index 28abe790b..25d558480 100644 --- a/src/main/java/org/traccar/reports/SummaryReportProvider.java +++ b/src/main/java/org/traccar/reports/SummaryReportProvider.java @@ -25,6 +25,7 @@ import org.traccar.helper.model.UserUtil; import org.traccar.model.Position; import org.traccar.reports.common.ReportUtils; import org.traccar.reports.model.SummaryReportItem; +import org.traccar.storage.Storage; import org.traccar.storage.StorageException; import javax.inject.Inject; @@ -41,11 +42,13 @@ public class SummaryReportProvider { private final ReportUtils reportUtils; private final PermissionsService permissionsService; + private final Storage storage; @Inject - public SummaryReportProvider(ReportUtils reportUtils, PermissionsService permissionsService) { + public SummaryReportProvider(ReportUtils reportUtils, PermissionsService permissionsService, Storage storage) { this.reportUtils = reportUtils; this.permissionsService = permissionsService; + this.storage = storage; } private SummaryReportItem calculateSummaryResult(long deviceId, Collection positions) { @@ -111,9 +114,8 @@ public class SummaryReportProvider { private Collection calculateSummaryResults( long userId, long deviceId, Date from, Date to, boolean daily) throws StorageException { - ArrayList positions = new ArrayList<>(Context.getDataManager().getPositions(deviceId, from, to)); - - ArrayList results = new ArrayList<>(); + var positions = PositionUtil.getPositions(storage, deviceId, from, to); + var results = new ArrayList(); if (daily && !positions.isEmpty()) { int startIndex = 0; int startDay = getDay(userId, positions.iterator().next().getFixTime()); diff --git a/src/main/java/org/traccar/reports/TripsReportProvider.java b/src/main/java/org/traccar/reports/TripsReportProvider.java index 5e598cb50..a8e0e3dde 100644 --- a/src/main/java/org/traccar/reports/TripsReportProvider.java +++ b/src/main/java/org/traccar/reports/TripsReportProvider.java @@ -18,14 +18,13 @@ package org.traccar.reports; import org.apache.poi.ss.util.WorkbookUtil; import org.traccar.Context; -import org.traccar.Main; -import org.traccar.database.DeviceManager; -import org.traccar.database.IdentityManager; +import org.traccar.helper.model.PositionUtil; import org.traccar.model.Device; import org.traccar.model.Group; import org.traccar.reports.common.ReportUtils; import org.traccar.reports.model.DeviceReportSection; import org.traccar.reports.model.TripReportItem; +import org.traccar.storage.Storage; import org.traccar.storage.StorageException; import javax.inject.Inject; @@ -40,21 +39,20 @@ import java.util.Date; public class TripsReportProvider { private final ReportUtils reportUtils; + private final Storage storage; @Inject - public TripsReportProvider(ReportUtils reportUtils) { + public TripsReportProvider(ReportUtils reportUtils, Storage storage) { this.reportUtils = reportUtils; + this.storage = storage; } private Collection detectTrips(long deviceId, Date from, Date to) throws StorageException { boolean ignoreOdometer = Context.getDeviceManager() .lookupAttributeBoolean(deviceId, "report.ignoreOdometer", false, false, true); - IdentityManager identityManager = Main.getInjector().getInstance(IdentityManager.class); - DeviceManager deviceManager = Main.getInjector().getInstance(DeviceManager.class); - return reportUtils.detectTripsAndStops( - Context.getDataManager().getPositions(deviceId, from, to), ignoreOdometer, TripReportItem.class); + PositionUtil.getPositions(storage, deviceId, from, to), ignoreOdometer, TripReportItem.class); } public Collection getObjects(long userId, Collection deviceIds, Collection groupIds, -- cgit v1.2.3 From 15c4b6b21a31c63bc0f7e624e26d032d531c459d Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Thu, 16 Jun 2022 18:48:08 -0700 Subject: Refactor geofence classes --- src/main/java/org/traccar/MainModule.java | 1 - .../java/org/traccar/geofence/GeofenceCircle.java | 4 +- .../org/traccar/geofence/GeofenceGeometry.java | 5 ++- .../java/org/traccar/geofence/GeofencePolygon.java | 4 +- .../org/traccar/geofence/GeofencePolyline.java | 23 +++++------ .../handler/events/GeofenceEventHandler.java | 7 +++- .../org/traccar/helper/model/GeofenceUtil.java | 6 ++- src/main/java/org/traccar/model/Geofence.java | 22 ++++------- .../org/traccar/session/cache/CacheManager.java | 7 +++- .../org/traccar/geofence/GeofenceCircleTest.java | 13 +++--- .../org/traccar/geofence/GeofencePolygonTest.java | 37 +++++++---------- .../org/traccar/geofence/GeofencePolylineTest.java | 46 ++++++++++++++-------- 12 files changed, 93 insertions(+), 82 deletions(-) (limited to 'src/main/java/org/traccar/helper') diff --git a/src/main/java/org/traccar/MainModule.java b/src/main/java/org/traccar/MainModule.java index a29c2c910..a9337a3a2 100644 --- a/src/main/java/org/traccar/MainModule.java +++ b/src/main/java/org/traccar/MainModule.java @@ -75,7 +75,6 @@ import org.traccar.web.WebServer; import javax.annotation.Nullable; import javax.inject.Singleton; -import javax.sql.DataSource; import javax.ws.rs.client.Client; import javax.ws.rs.client.ClientBuilder; import javax.ws.rs.ext.ContextResolver; diff --git a/src/main/java/org/traccar/geofence/GeofenceCircle.java b/src/main/java/org/traccar/geofence/GeofenceCircle.java index 5d566f84e..59feb1730 100644 --- a/src/main/java/org/traccar/geofence/GeofenceCircle.java +++ b/src/main/java/org/traccar/geofence/GeofenceCircle.java @@ -18,7 +18,9 @@ package org.traccar.geofence; import java.text.DecimalFormat; import java.text.ParseException; +import org.traccar.config.Config; import org.traccar.helper.DistanceCalculator; +import org.traccar.model.Geofence; public class GeofenceCircle extends GeofenceGeometry { @@ -44,7 +46,7 @@ public class GeofenceCircle extends GeofenceGeometry { } @Override - public boolean containsPoint(double latitude, double longitude) { + public boolean containsPoint(Config config, Geofence geofence, double latitude, double longitude) { return distanceFromCenter(latitude, longitude) <= radius; } diff --git a/src/main/java/org/traccar/geofence/GeofenceGeometry.java b/src/main/java/org/traccar/geofence/GeofenceGeometry.java index 2c45c22af..fadabab1c 100644 --- a/src/main/java/org/traccar/geofence/GeofenceGeometry.java +++ b/src/main/java/org/traccar/geofence/GeofenceGeometry.java @@ -15,11 +15,14 @@ */ package org.traccar.geofence; +import org.traccar.config.Config; +import org.traccar.model.Geofence; + import java.text.ParseException; public abstract class GeofenceGeometry { - public abstract boolean containsPoint(double latitude, double longitude); + public abstract boolean containsPoint(Config config, Geofence geofence, double latitude, double longitude); public abstract double calculateArea(); diff --git a/src/main/java/org/traccar/geofence/GeofencePolygon.java b/src/main/java/org/traccar/geofence/GeofencePolygon.java index cd2cbf16a..13f6658ef 100644 --- a/src/main/java/org/traccar/geofence/GeofencePolygon.java +++ b/src/main/java/org/traccar/geofence/GeofencePolygon.java @@ -19,6 +19,8 @@ import org.locationtech.spatial4j.context.SpatialContext; import org.locationtech.spatial4j.context.jts.JtsSpatialContextFactory; import org.locationtech.spatial4j.shape.ShapeFactory; import org.locationtech.spatial4j.shape.jts.JtsShapeFactory; +import org.traccar.config.Config; +import org.traccar.model.Geofence; import java.text.ParseException; import java.util.ArrayList; @@ -95,7 +97,7 @@ public class GeofencePolygon extends GeofenceGeometry { } @Override - public boolean containsPoint(double latitude, double longitude) { + public boolean containsPoint(Config config, Geofence geofence, double latitude, double longitude) { int polyCorners = coordinates.size(); int i; diff --git a/src/main/java/org/traccar/geofence/GeofencePolyline.java b/src/main/java/org/traccar/geofence/GeofencePolyline.java index 370bf99bb..d9c280ae4 100644 --- a/src/main/java/org/traccar/geofence/GeofencePolyline.java +++ b/src/main/java/org/traccar/geofence/GeofencePolyline.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 - 2020 Anton Tananaev (anton@traccar.org) + * Copyright 2016 - 2022 Anton Tananaev (anton@traccar.org) * Copyright 2016 Andrey Kunitsyn (andrey@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -19,23 +19,28 @@ package org.traccar.geofence; import java.text.ParseException; import java.util.ArrayList; +import org.traccar.config.Config; +import org.traccar.config.Keys; import org.traccar.helper.DistanceCalculator; +import org.traccar.model.Geofence; public class GeofencePolyline extends GeofenceGeometry { private ArrayList coordinates; - private double distance; public GeofencePolyline() { } - public GeofencePolyline(String wkt, double distance) throws ParseException { + public GeofencePolyline(String wkt) throws ParseException { fromWkt(wkt); - this.distance = distance; } @Override - public boolean containsPoint(double latitude, double longitude) { + public boolean containsPoint(Config config, Geofence geofence, double latitude, double longitude) { + double distance = geofence.getDouble("polylineDistance"); + if (distance == 0) { + distance = config.getDouble(Keys.GEOFENCE_POLYLINE_DISTANCE); + } for (int i = 1; i < coordinates.size(); i++) { if (DistanceCalculator.distanceToLine( latitude, longitude, coordinates.get(i - 1).getLat(), coordinates.get(i - 1).getLon(), @@ -56,9 +61,9 @@ public class GeofencePolyline extends GeofenceGeometry { StringBuilder buf = new StringBuilder(); buf.append("LINESTRING ("); for (Coordinate coordinate : coordinates) { - buf.append(String.valueOf(coordinate.getLat())); + buf.append(coordinate.getLat()); buf.append(" "); - buf.append(String.valueOf(coordinate.getLon())); + buf.append(coordinate.getLon()); buf.append(", "); } return buf.substring(0, buf.length() - 2) + ")"; @@ -105,8 +110,4 @@ public class GeofencePolyline extends GeofenceGeometry { } - public void setDistance(double distance) { - this.distance = distance; - } - } diff --git a/src/main/java/org/traccar/handler/events/GeofenceEventHandler.java b/src/main/java/org/traccar/handler/events/GeofenceEventHandler.java index 724f8f0d0..0a924cfc3 100644 --- a/src/main/java/org/traccar/handler/events/GeofenceEventHandler.java +++ b/src/main/java/org/traccar/handler/events/GeofenceEventHandler.java @@ -16,6 +16,7 @@ package org.traccar.handler.events; import io.netty.channel.ChannelHandler; +import org.traccar.config.Config; import org.traccar.helper.model.GeofenceUtil; import org.traccar.helper.model.PositionUtil; import org.traccar.model.Calendar; @@ -35,11 +36,13 @@ import java.util.Map; @ChannelHandler.Sharable public class GeofenceEventHandler extends BaseEventHandler { + private final Config config; private final CacheManager cacheManager; private final ConnectionManager connectionManager; @Inject - public GeofenceEventHandler(CacheManager cacheManager, ConnectionManager connectionManager) { + public GeofenceEventHandler(Config config, CacheManager cacheManager, ConnectionManager connectionManager) { + this.config = config; this.cacheManager = cacheManager; this.connectionManager = connectionManager; } @@ -54,7 +57,7 @@ public class GeofenceEventHandler extends BaseEventHandler { return null; } - List currentGeofences = GeofenceUtil.getCurrentGeofences(cacheManager, position); + List currentGeofences = GeofenceUtil.getCurrentGeofences(config, cacheManager, position); List oldGeofences = new ArrayList<>(); if (device.getGeofenceIds() != null) { oldGeofences.addAll(device.getGeofenceIds()); diff --git a/src/main/java/org/traccar/helper/model/GeofenceUtil.java b/src/main/java/org/traccar/helper/model/GeofenceUtil.java index f56bf4224..9f063a8b4 100644 --- a/src/main/java/org/traccar/helper/model/GeofenceUtil.java +++ b/src/main/java/org/traccar/helper/model/GeofenceUtil.java @@ -15,6 +15,7 @@ */ package org.traccar.helper.model; +import org.traccar.config.Config; import org.traccar.model.Geofence; import org.traccar.model.Position; import org.traccar.session.cache.CacheManager; @@ -27,10 +28,11 @@ public final class GeofenceUtil { private GeofenceUtil() { } - public static List getCurrentGeofences(CacheManager cacheManager, Position position) { + public static List getCurrentGeofences(Config config, CacheManager cacheManager, Position position) { List result = new ArrayList<>(); for (Geofence geofence : cacheManager.getDeviceObjects(position.getDeviceId(), Geofence.class)) { - if (geofence.getGeometry().containsPoint(position.getLatitude(), position.getLongitude())) { + if (geofence.getGeometry().containsPoint( + config, geofence, position.getLatitude(), position.getLongitude())) { result.add(geofence.getId()); } } diff --git a/src/main/java/org/traccar/model/Geofence.java b/src/main/java/org/traccar/model/Geofence.java index 5b857580d..9259028fb 100644 --- a/src/main/java/org/traccar/model/Geofence.java +++ b/src/main/java/org/traccar/model/Geofence.java @@ -1,5 +1,5 @@ /* - * Copyright 2016 Anton Tananaev (anton@traccar.org) + * Copyright 2016 - 2022 Anton Tananaev (anton@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,26 +15,19 @@ */ package org.traccar.model; -import java.text.ParseException; - -import org.traccar.Context; -import org.traccar.config.Keys; -import org.traccar.storage.QueryIgnore; +import com.fasterxml.jackson.annotation.JsonIgnore; import org.traccar.geofence.GeofenceCircle; import org.traccar.geofence.GeofenceGeometry; import org.traccar.geofence.GeofencePolygon; import org.traccar.geofence.GeofencePolyline; - -import com.fasterxml.jackson.annotation.JsonIgnore; +import org.traccar.storage.QueryIgnore; import org.traccar.storage.StorageName; +import java.text.ParseException; + @StorageName("tc_geofences") public class Geofence extends ScheduledModel { - public static final String TYPE_GEOFENCE_CILCLE = "geofenceCircle"; - public static final String TYPE_GEOFENCE_POLYGON = "geofencePolygon"; - public static final String TYPE_GEOFENCE_POLYLINE = "geofencePolyline"; - private String name; public String getName() { @@ -68,9 +61,7 @@ public class Geofence extends ScheduledModel { } else if (area.startsWith("POLYGON")) { geometry = new GeofencePolygon(area); } else if (area.startsWith("LINESTRING")) { - final double distance = getDouble("polylineDistance"); - geometry = new GeofencePolyline(area, distance > 0 ? distance - : Context.getConfig().getDouble(Keys.GEOFENCE_POLYLINE_DISTANCE)); + geometry = new GeofencePolyline(area); } else { throw new ParseException("Unknown geometry type", 0); } @@ -92,4 +83,5 @@ public class Geofence extends ScheduledModel { area = geometry.toWkt(); this.geometry = geometry; } + } diff --git a/src/main/java/org/traccar/session/cache/CacheManager.java b/src/main/java/org/traccar/session/cache/CacheManager.java index 18daeae15..14034f3d6 100644 --- a/src/main/java/org/traccar/session/cache/CacheManager.java +++ b/src/main/java/org/traccar/session/cache/CacheManager.java @@ -15,6 +15,7 @@ */ package org.traccar.session.cache; +import org.traccar.config.Config; import org.traccar.helper.model.GeofenceUtil; import org.traccar.model.Attribute; import org.traccar.model.BaseModel; @@ -53,6 +54,7 @@ public class CacheManager { private static final Collection> CLASSES = Arrays.asList( Attribute.class, Driver.class, Geofence.class, Maintenance.class, Notification.class); + private final Config config; private final Storage storage; private final ReadWriteLock lock = new ReentrantReadWriteLock(); @@ -65,7 +67,8 @@ public class CacheManager { private final Map> notificationUsers = new HashMap<>(); @Inject - public CacheManager(Storage storage) throws StorageException { + public CacheManager(Config config, Storage storage) throws StorageException { + this.config = config; this.storage = storage; invalidateServer(); invalidateUsers(); @@ -315,7 +318,7 @@ public class CacheManager { private void invalidateDeviceGeofences(Device device) { Position position = getPosition(device.getId()); if (position != null) { - device.setGeofenceIds(GeofenceUtil.getCurrentGeofences(this, position)); + device.setGeofenceIds(GeofenceUtil.getCurrentGeofences(config, this, position)); } } diff --git a/src/test/java/org/traccar/geofence/GeofenceCircleTest.java b/src/test/java/org/traccar/geofence/GeofenceCircleTest.java index 038e4b6d6..9a02cec76 100644 --- a/src/test/java/org/traccar/geofence/GeofenceCircleTest.java +++ b/src/test/java/org/traccar/geofence/GeofenceCircleTest.java @@ -5,6 +5,7 @@ import org.junit.Test; import java.text.ParseException; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; public class GeofenceCircleTest { @@ -12,17 +13,15 @@ public class GeofenceCircleTest { @Test public void testCircleWkt() throws ParseException { String test = "CIRCLE (55.75414 37.6204, 100)"; - GeofenceGeometry geofenceGeometry = new GeofenceCircle(); - geofenceGeometry.fromWkt(test); + GeofenceGeometry geofenceGeometry = new GeofenceCircle(test); assertEquals(geofenceGeometry.toWkt(), test); } @Test public void testContainsCircle() throws ParseException { - String test = "CIRCLE (55.75414 37.6204, 100)"; - GeofenceGeometry geofenceGeometry = new GeofenceCircle(); - geofenceGeometry.fromWkt(test); - assertTrue(geofenceGeometry.containsPoint(55.75477, 37.62025)); - assertTrue(!geofenceGeometry.containsPoint(55.75545, 37.61921)); + GeofenceGeometry geofenceGeometry = new GeofenceCircle("CIRCLE (55.75414 37.6204, 100)"); + assertTrue(geofenceGeometry.containsPoint(null, null, 55.75477, 37.62025)); + assertFalse(geofenceGeometry.containsPoint(null, null, 55.75545, 37.61921)); } + } diff --git a/src/test/java/org/traccar/geofence/GeofencePolygonTest.java b/src/test/java/org/traccar/geofence/GeofencePolygonTest.java index 1b8de68ad..5baecd771 100644 --- a/src/test/java/org/traccar/geofence/GeofencePolygonTest.java +++ b/src/test/java/org/traccar/geofence/GeofencePolygonTest.java @@ -19,41 +19,34 @@ public class GeofencePolygonTest { @Test public void testPolygonWkt() throws ParseException { String test = "POLYGON ((55.75474 37.61823, 55.75513 37.61888, 55.7535 37.6222, 55.75315 37.62165))"; - GeofenceGeometry geofenceGeometry = new GeofencePolygon(); - geofenceGeometry.fromWkt(test); + GeofenceGeometry geofenceGeometry = new GeofencePolygon(test); assertEquals(geofenceGeometry.toWkt(), test); } @Test public void testContainsPolygon() throws ParseException { - String test = "POLYGON ((55.75474 37.61823, 55.75513 37.61888, 55.7535 37.6222, 55.75315 37.62165))"; - GeofenceGeometry geofenceGeometry = new GeofencePolygon(); - geofenceGeometry.fromWkt(test); - assertTrue(geofenceGeometry.containsPoint(55.75476, 37.61915)); - assertFalse(geofenceGeometry.containsPoint(55.75545, 37.61921)); - + GeofenceGeometry geofenceGeometry = new GeofencePolygon( + "POLYGON ((55.75474 37.61823, 55.75513 37.61888, 55.7535 37.6222, 55.75315 37.62165))"); + assertTrue(geofenceGeometry.containsPoint(null, null, 55.75476, 37.61915)); + assertFalse(geofenceGeometry.containsPoint(null, null, 55.75545, 37.61921)); } @Test public void testContainsPolygon180() throws ParseException { - String test = "POLYGON ((66.9494 179.838, 66.9508 -179.8496, 66.8406 -180.0014))"; - GeofenceGeometry geofenceGeometry = new GeofencePolygon(); - geofenceGeometry.fromWkt(test); - assertTrue(geofenceGeometry.containsPoint(66.9015, -180.0096)); - assertTrue(geofenceGeometry.containsPoint(66.9015, 179.991)); - assertFalse(geofenceGeometry.containsPoint(66.8368, -179.8792)); - + GeofenceGeometry geofenceGeometry = new GeofencePolygon( + "POLYGON ((66.9494 179.838, 66.9508 -179.8496, 66.8406 -180.0014))"); + assertTrue(geofenceGeometry.containsPoint(null, null, 66.9015, -180.0096)); + assertTrue(geofenceGeometry.containsPoint(null, null, 66.9015, 179.991)); + assertFalse(geofenceGeometry.containsPoint(null, null, 66.8368, -179.8792)); } @Test public void testContainsPolygon0() throws ParseException { - String test = "POLYGON ((51.1966 -0.6207, 51.1897 0.4147, 50.9377 0.5136, 50.8675 -0.6082))"; - GeofenceGeometry geofenceGeometry = new GeofencePolygon(); - geofenceGeometry.fromWkt(test); - assertTrue(geofenceGeometry.containsPoint(51.0466, -0.0165)); - assertTrue(geofenceGeometry.containsPoint(51.0466, 0.018)); - assertFalse(geofenceGeometry.containsPoint(50.9477, 0.5836)); - + GeofenceGeometry geofenceGeometry = new GeofencePolygon( + "POLYGON ((51.1966 -0.6207, 51.1897 0.4147, 50.9377 0.5136, 50.8675 -0.6082))"); + assertTrue(geofenceGeometry.containsPoint(null, null, 51.0466, -0.0165)); + assertTrue(geofenceGeometry.containsPoint(null, null, 51.0466, 0.018)); + assertFalse(geofenceGeometry.containsPoint(null, null, 50.9477, 0.5836)); } } diff --git a/src/test/java/org/traccar/geofence/GeofencePolylineTest.java b/src/test/java/org/traccar/geofence/GeofencePolylineTest.java index 0e8905319..b7ee14510 100644 --- a/src/test/java/org/traccar/geofence/GeofencePolylineTest.java +++ b/src/test/java/org/traccar/geofence/GeofencePolylineTest.java @@ -1,47 +1,59 @@ package org.traccar.geofence; import org.junit.Test; +import org.traccar.config.Config; +import org.traccar.config.Keys; +import org.traccar.model.Geofence; import java.text.ParseException; import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertFalse; import static org.junit.Assert.assertTrue; +import static org.mockito.Mockito.mock; +import static org.mockito.Mockito.when; public class GeofencePolylineTest { @Test public void testPolylineWkt() throws ParseException { String test = "LINESTRING (55.75474 37.61823, 55.75513 37.61888, 55.7535 37.6222, 55.75315 37.62165)"; - GeofenceGeometry geofenceGeometry = new GeofencePolyline(); - geofenceGeometry.fromWkt(test); + GeofenceGeometry geofenceGeometry = new GeofencePolyline(test); assertEquals(geofenceGeometry.toWkt(), test); } @Test public void testContainsPolyline1Interval() throws ParseException { - String test = "LINESTRING (56.83777 60.59833, 56.83766 60.5968)"; - GeofenceGeometry geofenceGeometry = new GeofencePolyline(test, 35); - assertTrue(geofenceGeometry.containsPoint(56.83801, 60.59748)); - ((GeofencePolyline) geofenceGeometry).setDistance(15); - assertTrue(!geofenceGeometry.containsPoint(56.83801, 60.59748)); + GeofenceGeometry geofenceGeometry = new GeofencePolyline( + "LINESTRING (56.83777 60.59833, 56.83766 60.5968)"); + Config config = mock(Config.class); + when(config.getDouble(Keys.GEOFENCE_POLYLINE_DISTANCE)).thenReturn(35.0); + assertTrue(geofenceGeometry.containsPoint(config, mock(Geofence.class), 56.83801, 60.59748)); + when(config.getDouble(Keys.GEOFENCE_POLYLINE_DISTANCE)).thenReturn(15.0); + assertFalse(geofenceGeometry.containsPoint(config, mock(Geofence.class), 56.83801, 60.59748)); } @Test public void testContainsPolyline3Intervals() throws ParseException { - String test = "LINESTRING (56.836 60.6126, 56.8393 60.6114, 56.83887 60.60811, 56.83782 60.5988)"; - GeofenceGeometry geofenceGeometry = new GeofencePolyline(test, 15); - assertTrue(geofenceGeometry.containsPoint(56.83847, 60.60458)); - assertTrue(!geofenceGeometry.containsPoint(56.83764, 60.59725)); - assertTrue(!geofenceGeometry.containsPoint(56.83861, 60.60822)); + GeofenceGeometry geofenceGeometry = new GeofencePolyline( + "LINESTRING (56.836 60.6126, 56.8393 60.6114, 56.83887 60.60811, 56.83782 60.5988)"); + Config config = mock(Config.class); + when(config.getDouble(Keys.GEOFENCE_POLYLINE_DISTANCE)).thenReturn(15.0); + assertTrue(geofenceGeometry.containsPoint(config, mock(Geofence.class), 56.83847, 60.60458)); + assertFalse(geofenceGeometry.containsPoint(config, mock(Geofence.class), 56.83764, 60.59725)); + assertFalse(geofenceGeometry.containsPoint(config, mock(Geofence.class), 56.83861, 60.60822)); } @Test public void testContainsPolylineNear180() throws ParseException { - String test = "LINESTRING (66.9494 179.838, 66.9508 -179.8496)"; - GeofenceGeometry geofenceGeometry = new GeofencePolyline(test, 25); - assertTrue(geofenceGeometry.containsPoint(66.95, 180.0)); - assertTrue(!geofenceGeometry.containsPoint(66.96, 180.0)); - assertTrue(!geofenceGeometry.containsPoint(66.9509, -179.83)); + GeofenceGeometry geofenceGeometry = new GeofencePolyline( + "LINESTRING (66.9494 179.838, 66.9508 -179.8496)"); + Config config = mock(Config.class); + when(config.getDouble(Keys.GEOFENCE_POLYLINE_DISTANCE)).thenReturn(25.0); + assertTrue(geofenceGeometry.containsPoint(config, mock(Geofence.class), 66.95, 180.0)); + assertFalse(geofenceGeometry.containsPoint(config, mock(Geofence.class), 66.96, 180.0)); + assertFalse(geofenceGeometry.containsPoint(config, mock(Geofence.class), 66.9509, -179.83)); } + } -- cgit v1.2.3 From c248ed30047a0525bf792730a0fbd4de0c89ad8e Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 18 Jun 2022 10:00:52 -0700 Subject: Refactor attribute lookup --- src/main/java/org/traccar/BaseProtocolDecoder.java | 14 +- src/main/java/org/traccar/config/ConfigKey.java | 73 +- src/main/java/org/traccar/config/ConfigSuffix.java | 81 ++- src/main/java/org/traccar/config/Keys.java | 779 ++++++++++++--------- .../java/org/traccar/database/DeviceManager.java | 57 -- .../java/org/traccar/database/IdentityManager.java | 11 - .../java/org/traccar/handler/FilterHandler.java | 48 +- .../org/traccar/handler/HemisphereHandler.java | 2 +- .../handler/events/FuelDropEventHandler.java | 25 +- .../handler/events/OverspeedEventHandler.java | 13 +- .../org/traccar/helper/model/AttributeUtil.java | 72 ++ src/main/java/org/traccar/model/CellTower.java | 2 +- .../traccar/protocol/StarLinkProtocolDecoder.java | 14 +- .../traccar/protocol/SuntechProtocolDecoder.java | 25 +- .../org/traccar/session/ConnectionManager.java | 5 +- .../org/traccar/session/cache/CacheManager.java | 4 + src/test/java/org/traccar/BaseTest.java | 15 +- .../org/traccar/handler/FilterHandlerTest.java | 21 +- .../handler/events/OverspeedEventHandlerTest.java | 2 +- 19 files changed, 748 insertions(+), 515 deletions(-) create mode 100644 src/main/java/org/traccar/helper/model/AttributeUtil.java (limited to 'src/main/java/org/traccar/helper') diff --git a/src/main/java/org/traccar/BaseProtocolDecoder.java b/src/main/java/org/traccar/BaseProtocolDecoder.java index cbcb429b3..076b52e96 100644 --- a/src/main/java/org/traccar/BaseProtocolDecoder.java +++ b/src/main/java/org/traccar/BaseProtocolDecoder.java @@ -23,11 +23,13 @@ import org.traccar.database.IdentityManager; import org.traccar.database.MediaManager; import org.traccar.database.StatisticsManager; import org.traccar.helper.UnitsConverter; +import org.traccar.helper.model.AttributeUtil; import org.traccar.model.Command; import org.traccar.model.Device; import org.traccar.model.Position; import org.traccar.session.ConnectionManager; import org.traccar.session.DeviceSession; +import org.traccar.session.cache.CacheManager; import org.traccar.storage.StorageException; import javax.inject.Inject; @@ -46,6 +48,7 @@ public abstract class BaseProtocolDecoder extends ExtendedObjectDecoder { private final Protocol protocol; private IdentityManager identityManager; + private CacheManager cacheManager; private ConnectionManager connectionManager; private StatisticsManager statisticsManager; private MediaManager mediaManager; @@ -64,6 +67,15 @@ public abstract class BaseProtocolDecoder extends ExtendedObjectDecoder { this.identityManager = identityManager; } + public CacheManager getCacheManager() { + return cacheManager; + } + + @Inject + public void setCacheManager(CacheManager cacheManager) { + this.cacheManager = cacheManager; + } + @Inject public void setConnectionManager(ConnectionManager connectionManager) { this.connectionManager = connectionManager; @@ -125,7 +137,7 @@ public abstract class BaseProtocolDecoder extends ExtendedObjectDecoder { protected TimeZone getTimeZone(long deviceId, String defaultTimeZone) { TimeZone result = TimeZone.getTimeZone(defaultTimeZone); - String timeZoneName = identityManager.lookupAttributeString(deviceId, "decoder.timezone", null, false, true); + String timeZoneName = AttributeUtil.lookup(cacheManager, Keys.DECODER_TIMEZONE, deviceId); if (timeZoneName != null) { result = TimeZone.getTimeZone(timeZoneName); } diff --git a/src/main/java/org/traccar/config/ConfigKey.java b/src/main/java/org/traccar/config/ConfigKey.java index c046a46a5..b8151392c 100644 --- a/src/main/java/org/traccar/config/ConfigKey.java +++ b/src/main/java/org/traccar/config/ConfigKey.java @@ -1,5 +1,5 @@ /* - * Copyright 2019 - 2020 Anton Tananaev (anton@traccar.org) + * Copyright 2019 - 2022 Anton Tananaev (anton@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -15,30 +15,34 @@ */ package org.traccar.config; +import java.util.HashSet; import java.util.List; +import java.util.Set; -public class ConfigKey { +public abstract class ConfigKey { private final String key; - private final List types; + private final Set types = new HashSet<>(); + private final Class valueClass; private final T defaultValue; - ConfigKey(String key, List types) { - this(key, types, null); - } - - ConfigKey(String key, List types, T defaultValue) { + ConfigKey(String key, List types, Class valueClass, T defaultValue) { this.key = key; - this.types = types; + this.types.addAll(types); + this.valueClass = valueClass; this.defaultValue = defaultValue; } - String getKey() { + public String getKey() { return key; } - public List getTypes() { - return types; + public boolean hasType(KeyType type) { + return types.contains(type); + } + + public Class getValueClass() { + return valueClass; } public T getDefaultValue() { @@ -46,3 +50,48 @@ public class ConfigKey { } } + +class StringConfigKey extends ConfigKey { + StringConfigKey(String key, List types) { + super(key, types, String.class, null); + } + StringConfigKey(String key, List types, String defaultValue) { + super(key, types, String.class, defaultValue); + } +} + +class BooleanConfigKey extends ConfigKey { + BooleanConfigKey(String key, List types) { + super(key, types, Boolean.class, null); + } + BooleanConfigKey(String key, List types, Boolean defaultValue) { + super(key, types, Boolean.class, defaultValue); + } +} + +class IntegerConfigKey extends ConfigKey { + IntegerConfigKey(String key, List types) { + super(key, types, Integer.class, null); + } + IntegerConfigKey(String key, List types, Integer defaultValue) { + super(key, types, Integer.class, defaultValue); + } +} + +class LongConfigKey extends ConfigKey { + LongConfigKey(String key, List types) { + super(key, types, Long.class, null); + } + LongConfigKey(String key, List types, Long defaultValue) { + super(key, types, Long.class, defaultValue); + } +} + +class DoubleConfigKey extends ConfigKey { + DoubleConfigKey(String key, List types) { + super(key, types, Double.class, null); + } + DoubleConfigKey(String key, List types, Double defaultValue) { + super(key, types, Double.class, defaultValue); + } +} diff --git a/src/main/java/org/traccar/config/ConfigSuffix.java b/src/main/java/org/traccar/config/ConfigSuffix.java index ede4c107d..aac3219c6 100644 --- a/src/main/java/org/traccar/config/ConfigSuffix.java +++ b/src/main/java/org/traccar/config/ConfigSuffix.java @@ -1,5 +1,5 @@ /* - * Copyright 2019 - 2020 Anton Tananaev (anton@traccar.org) + * Copyright 2019 - 2022 Anton Tananaev (anton@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,15 +17,11 @@ package org.traccar.config; import java.util.List; -public class ConfigSuffix { +public abstract class ConfigSuffix { - private final String keySuffix; - private final List types; - private final T defaultValue; - - ConfigSuffix(String keySuffix, List types) { - this(keySuffix, types, null); - } + protected final String keySuffix; + protected final List types; + protected final T defaultValue; ConfigSuffix(String keySuffix, List types, T defaultValue) { this.keySuffix = keySuffix; @@ -33,8 +29,71 @@ public class ConfigSuffix { this.defaultValue = defaultValue; } - public ConfigKey withPrefix(String prefix) { - return new ConfigKey<>(prefix + keySuffix, types, defaultValue); + public abstract ConfigKey withPrefix(String prefix); + +} + +class StringConfigSuffix extends ConfigSuffix { + StringConfigSuffix(String key, List types) { + super(key, types, null); + } + StringConfigSuffix(String key, List types, String defaultValue) { + super(key, types, defaultValue); + } + @Override + public ConfigKey withPrefix(String prefix) { + return new StringConfigKey(prefix + keySuffix, types, defaultValue); + } +} + +class BooleanConfigSuffix extends ConfigSuffix { + BooleanConfigSuffix(String key, List types) { + super(key, types, null); + } + BooleanConfigSuffix(String key, List types, Boolean defaultValue) { + super(key, types, defaultValue); + } + @Override + public ConfigKey withPrefix(String prefix) { + return new BooleanConfigKey(prefix + keySuffix, types, defaultValue); + } +} + +class IntegerConfigSuffix extends ConfigSuffix { + IntegerConfigSuffix(String key, List types) { + super(key, types, null); + } + IntegerConfigSuffix(String key, List types, Integer defaultValue) { + super(key, types, defaultValue); + } + @Override + public ConfigKey withPrefix(String prefix) { + return new IntegerConfigKey(prefix + keySuffix, types, defaultValue); } +} +class LongConfigSuffix extends ConfigSuffix { + LongConfigSuffix(String key, List types) { + super(key, types, null); + } + LongConfigSuffix(String key, List types, Long defaultValue) { + super(key, types, defaultValue); + } + @Override + public ConfigKey withPrefix(String prefix) { + return new LongConfigKey(prefix + keySuffix, types, defaultValue); + } +} + +class DoubleConfigSuffix extends ConfigSuffix { + DoubleConfigSuffix(String key, List types) { + super(key, types, null); + } + DoubleConfigSuffix(String key, List types, Double defaultValue) { + super(key, types, defaultValue); + } + @Override + public ConfigKey withPrefix(String prefix) { + return new DoubleConfigKey(prefix + keySuffix, types, defaultValue); + } } diff --git a/src/main/java/org/traccar/config/Keys.java b/src/main/java/org/traccar/config/Keys.java index 292202de0..465751d38 100644 --- a/src/main/java/org/traccar/config/Keys.java +++ b/src/main/java/org/traccar/config/Keys.java @@ -15,7 +15,7 @@ */ package org.traccar.config; -import java.util.Collections; +import java.util.List; public final class Keys { @@ -25,39 +25,39 @@ public final class Keys { /** * Network interface for a the protocol. If not specified, server will bind all interfaces. */ - public static final ConfigSuffix PROTOCOL_ADDRESS = new ConfigSuffix<>( + public static final ConfigSuffix PROTOCOL_ADDRESS = new StringConfigSuffix( ".address", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Port number for the protocol. Most protocols use TCP on the transport layer. Some protocols use UDP. Some * support both TCP and UDP. */ - public static final ConfigSuffix PROTOCOL_PORT = new ConfigSuffix<>( + public static final ConfigSuffix PROTOCOL_PORT = new IntegerConfigSuffix( ".port", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * List of devices for polling protocols. List should contain unique ids separated by commas. Used only for polling * protocols. */ - public static final ConfigSuffix PROTOCOL_DEVICES = new ConfigSuffix<>( + public static final ConfigSuffix PROTOCOL_DEVICES = new StringConfigSuffix( ".devices", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Polling interval in seconds. Used only for polling protocols. */ - public static final ConfigSuffix PROTOCOL_INTERVAL = new ConfigSuffix<>( + public static final ConfigSuffix PROTOCOL_INTERVAL = new LongConfigSuffix( ".interval", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Enable SSL support for the protocol. Not all protocols support this. */ - public static final ConfigSuffix PROTOCOL_SSL = new ConfigSuffix<>( + public static final ConfigSuffix PROTOCOL_SSL = new BooleanConfigSuffix( ".ssl", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Connection timeout value in seconds. Because sometimes there is no way to detect lost TCP connection old @@ -65,568 +65,640 @@ public final class Keys { * problems with establishing new connections when number of devices is high or devices data connections are * unstable. */ - public static final ConfigSuffix PROTOCOL_TIMEOUT = new ConfigSuffix<>( + public static final ConfigSuffix PROTOCOL_TIMEOUT = new IntegerConfigSuffix( ".timeout", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Device password. Commonly used in some protocol for sending commands. */ - public static final ConfigSuffix PROTOCOL_DEVICE_PASSWORD = new ConfigSuffix<>( + public static final ConfigSuffix PROTOCOL_DEVICE_PASSWORD = new StringConfigSuffix( ".devicePassword", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Default protocol mask to use. Currently used only by Skypatrol protocol. */ - public static final ConfigSuffix PROTOCOL_MASK = new ConfigSuffix<>( + public static final ConfigSuffix PROTOCOL_MASK = new IntegerConfigSuffix( ".mask", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Custom message length. Currently used only by H2 protocol for specifying binary message length. */ - public static final ConfigSuffix PROTOCOL_MESSAGE_LENGTH = new ConfigSuffix<>( + public static final ConfigSuffix PROTOCOL_MESSAGE_LENGTH = new IntegerConfigSuffix( ".messageLength", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Enable extended functionality for the protocol. The reason it's disabled by default is that not all devices * support it. */ - public static final ConfigSuffix PROTOCOL_EXTENDED = new ConfigSuffix<>( + public static final ConfigSuffix PROTOCOL_EXTENDED = new BooleanConfigSuffix( ".extended", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Decode string as UTF8 instead of ASCII. Only applicable for some protocols. */ - public static final ConfigSuffix PROTOCOL_UTF8 = new ConfigSuffix<>( + public static final ConfigSuffix PROTOCOL_UTF8 = new BooleanConfigSuffix( ".utf8", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Enable CAN decoding for the protocol. Similar to 'extended' configuration, it's not supported for some devices. */ - public static final ConfigSuffix PROTOCOL_CAN = new ConfigSuffix<>( + public static final ConfigSuffix PROTOCOL_CAN = new BooleanConfigSuffix( ".can", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Indicates whether server acknowledgement is required. Only applicable for some protocols. */ - public static final ConfigSuffix PROTOCOL_ACK = new ConfigSuffix<>( + public static final ConfigSuffix PROTOCOL_ACK = new BooleanConfigSuffix( ".ack", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Ignore device reported fix time. Useful in case some devices report invalid time. Currently only available for * GL200 protocol. */ - public static final ConfigSuffix PROTOCOL_IGNORE_FIX_TIME = new ConfigSuffix<>( + public static final ConfigSuffix PROTOCOL_IGNORE_FIX_TIME = new BooleanConfigSuffix( ".ignoreFixTime", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Decode additional TK103 attributes. Not supported for some devices. */ - public static final ConfigSuffix PROTOCOL_DECODE_LOW = new ConfigSuffix<>( + public static final ConfigSuffix PROTOCOL_DECODE_LOW = new BooleanConfigSuffix( ".decodeLow", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Use long date format for Atrack protocol. */ - public static final ConfigSuffix PROTOCOL_LONG_DATE = new ConfigSuffix<>( + public static final ConfigSuffix PROTOCOL_LONG_DATE = new BooleanConfigSuffix( ".longDate", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Use decimal fuel value format for Atrack protocol. */ - public static final ConfigSuffix PROTOCOL_DECIMAL_FUEL = new ConfigSuffix<>( + public static final ConfigSuffix PROTOCOL_DECIMAL_FUEL = new BooleanConfigSuffix( ".decimalFuel", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Indicates additional custom attributes for Atrack protocol. */ - public static final ConfigSuffix PROTOCOL_CUSTOM = new ConfigSuffix<>( + public static final ConfigSuffix PROTOCOL_CUSTOM = new BooleanConfigSuffix( ".custom", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Custom format string for Atrack protocol. */ - public static final ConfigSuffix PROTOCOL_FORM = new ConfigSuffix<>( + public static final ConfigSuffix PROTOCOL_FORM = new StringConfigSuffix( ".form", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Protocol configuration. Required for some devices for decoding incoming data. */ - public static final ConfigSuffix PROTOCOL_CONFIG = new ConfigSuffix<>( + public static final ConfigSuffix PROTOCOL_CONFIG = new StringConfigSuffix( ".config", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Alarm mapping for Atrack protocol. */ - public static final ConfigSuffix PROTOCOL_ALARM_MAP = new ConfigSuffix<>( + public static final ConfigSuffix PROTOCOL_ALARM_MAP = new StringConfigSuffix( ".alarmMap", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Indicates whether TAIP protocol should have prefixes for messages. */ - public static final ConfigSuffix PROTOCOL_PREFIX = new ConfigSuffix<>( + public static final ConfigSuffix PROTOCOL_PREFIX = new BooleanConfigSuffix( ".prefix", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Some devices require server address confirmation. Use this parameter to configure correct public address. */ - public static final ConfigSuffix PROTOCOL_SERVER = new ConfigSuffix<>( + public static final ConfigSuffix PROTOCOL_SERVER = new StringConfigSuffix( ".server", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); + + /** + * Protocol type for Suntech. + */ + public static final ConfigKey PROTOCOL_TYPE = new IntegerConfigKey( + "suntech.protocolType", + List.of(KeyType.CONFIG, KeyType.DEVICE)); + + /** + * Suntech HBM configuration value. + */ + public static final ConfigKey PROTOCOL_HBM = new BooleanConfigKey( + "suntech.hbm", + List.of(KeyType.CONFIG, KeyType.DEVICE)); + + /** + * Format includes ADC value. + */ + public static final ConfigSuffix PROTOCOL_INCLUDE_ADC = new BooleanConfigSuffix( + ".includeAdc", + List.of(KeyType.CONFIG, KeyType.DEVICE)); + + /** + * Format includes RPM value. + */ + public static final ConfigSuffix PROTOCOL_INCLUDE_RPM = new BooleanConfigSuffix( + ".includeRpm", + List.of(KeyType.CONFIG, KeyType.DEVICE)); + + /** + * Format includes temperature values. + */ + public static final ConfigSuffix PROTOCOL_INCLUDE_TEMPERATURE = new BooleanConfigSuffix( + ".includeTemp", + List.of(KeyType.CONFIG, KeyType.DEVICE)); + + /** + * Protocol format. Used by protocols that have configurable message format. + */ + public static final ConfigSuffix PROTOCOL_FORMAT = new StringConfigSuffix( + ".format", + List.of(KeyType.DEVICE)); + + /** + * Protocol date format. Used by protocols that have configurable date format. + */ + public static final ConfigSuffix PROTOCOL_DATE_FORMAT = new StringConfigSuffix( + ".dateFormat", + List.of(KeyType.DEVICE)); + + /** + * Device time zone. Most devices report UTC time, but in some cases devices report local time, so this parameter + * needs to be configured for the server to be able to decode the time correctly. + */ + public static final ConfigKey DECODER_TIMEZONE = new StringConfigKey( + "decoder.timezone", + List.of(KeyType.CONFIG, KeyType.DEVICE)); /** * ORBCOMM API access id. */ - public static final ConfigKey ORBCOMM_ACCESS_ID = new ConfigKey<>( + public static final ConfigKey ORBCOMM_ACCESS_ID = new StringConfigKey( "orbcomm.accessId", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * ORBCOMM API password. */ - public static final ConfigKey ORBCOMM_PASSWORD = new ConfigKey<>( + public static final ConfigKey ORBCOMM_PASSWORD = new StringConfigKey( "orbcomm.password", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Server wide connection timeout value in seconds. See protocol timeout for more information. */ - public static final ConfigKey SERVER_TIMEOUT = new ConfigKey<>( + public static final ConfigKey SERVER_TIMEOUT = new IntegerConfigKey( "server.timeout", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Address for uploading aggregated anonymous usage statistics. Uploaded information is the same you can see on the * statistics screen in the web app. It does not include any sensitive (e.g. locations). */ - public static final ConfigKey SERVER_STATISTICS = new ConfigKey<>( + public static final ConfigKey SERVER_STATISTICS = new StringConfigKey( "server.statistics", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); + + /** + * Fuel drop threshold value. When fuel level drops from one position to another for more the value, an event is + * generated. + */ + public static final ConfigKey EVENT_FUEL_DROP_THRESHOLD = new DoubleConfigKey( + "fuelDropThreshold", + List.of(KeyType.SERVER, KeyType.DEVICE)); + + /** + * Speed limit value in knots. + */ + public static final ConfigKey EVENT_OVERSPEED_LIMIT = new DoubleConfigKey( + "speedLimit", + List.of(KeyType.SERVER, KeyType.DEVICE)); /** * If true, the event is generated once at the beginning of overspeeding period. */ - public static final ConfigKey EVENT_OVERSPEED_NOT_REPEAT = new ConfigKey<>( + public static final ConfigKey EVENT_OVERSPEED_NOT_REPEAT = new BooleanConfigKey( "event.overspeed.notRepeat", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Minimal over speed duration to trigger the event. Value in seconds. */ - public static final ConfigKey EVENT_OVERSPEED_MINIMAL_DURATION = new ConfigKey<>( + public static final ConfigKey EVENT_OVERSPEED_MINIMAL_DURATION = new LongConfigKey( "event.overspeed.minimalDuration", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Relevant only for geofence speed limits. Use the lowest speed limit from all geofences. */ - public static final ConfigKey EVENT_OVERSPEED_PREFER_LOWEST = new ConfigKey<>( + public static final ConfigKey EVENT_OVERSPEED_PREFER_LOWEST = new BooleanConfigKey( "event.overspeed.preferLowest", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Driver behavior acceleration threshold. Value is in meter per second squared. */ - public static final ConfigKey EVENT_BEHAVIOR_ACCELERATION_THRESHOLD = new ConfigKey<>( + public static final ConfigKey EVENT_BEHAVIOR_ACCELERATION_THRESHOLD = new DoubleConfigKey( "event.behavior.accelerationThreshold", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Driver behavior braking threshold. Value is in meter per second squared. */ - public static final ConfigKey EVENT_BEHAVIOR_BRAKING_THRESHOLD = new ConfigKey<>( + public static final ConfigKey EVENT_BEHAVIOR_BRAKING_THRESHOLD = new DoubleConfigKey( "event.behavior.brakingThreshold", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Do not generate alert event if same alert was present in last known location. */ - public static final ConfigKey EVENT_IGNORE_DUPLICATE_ALERTS = new ConfigKey<>( + public static final ConfigKey EVENT_IGNORE_DUPLICATE_ALERTS = new BooleanConfigKey( "event.ignoreDuplicateAlerts", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * If set to true, invalid positions will be considered for motion logic. */ - public static final ConfigKey EVENT_MOTION_PROCESS_INVALID_POSITIONS = new ConfigKey<>( + public static final ConfigKey EVENT_MOTION_PROCESS_INVALID_POSITIONS = new BooleanConfigKey( "event.motion.processInvalidPositions", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * If the speed is above specified value, the object is considered to be in motion. Default value is 0.01 knots. */ - public static final ConfigKey EVENT_MOTION_SPEED_THRESHOLD = new ConfigKey<>( + public static final ConfigKey EVENT_MOTION_SPEED_THRESHOLD = new DoubleConfigKey( "event.motion.speedThreshold", - Collections.singletonList(KeyType.CONFIG), + List.of(KeyType.CONFIG), 0.01); /** * Global polyline geofence distance. Within that distance from the polyline, point is considered within the * geofence. Each individual geofence can also has 'polylineDistance' attribute which will take precedence. */ - public static final ConfigKey GEOFENCE_POLYLINE_DISTANCE = new ConfigKey<>( + public static final ConfigKey GEOFENCE_POLYLINE_DISTANCE = new DoubleConfigKey( "geofence.polylineDistance", - Collections.singletonList(KeyType.CONFIG), + List.of(KeyType.CONFIG), 25.0); /** * Path to the database driver JAR file. Traccar includes drivers for MySQL, PostgreSQL and H2 databases. If you use * one of those, you don't need to specify this parameter. */ - public static final ConfigKey DATABASE_DRIVER_FILE = new ConfigKey<>( + public static final ConfigKey DATABASE_DRIVER_FILE = new StringConfigKey( "database.driverFile", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Database driver Java class. For H2 use 'org.h2.Driver'. MySQL driver class name is 'com.mysql.jdbc.Driver'. */ - public static final ConfigKey DATABASE_DRIVER = new ConfigKey<>( + public static final ConfigKey DATABASE_DRIVER = new StringConfigKey( "database.driver", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Database connection URL. By default Traccar uses H2 database. */ - public static final ConfigKey DATABASE_URL = new ConfigKey<>( + public static final ConfigKey DATABASE_URL = new StringConfigKey( "database.url", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Database user name. Default administrator user for H2 database is 'sa'. */ - public static final ConfigKey DATABASE_USER = new ConfigKey<>( + public static final ConfigKey DATABASE_USER = new StringConfigKey( "database.user", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Database user password. Default password for H2 admin (sa) user is empty. */ - public static final ConfigKey DATABASE_PASSWORD = new ConfigKey<>( + public static final ConfigKey DATABASE_PASSWORD = new StringConfigKey( "database.password", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Path to Liquibase master changelog file. */ - public static final ConfigKey DATABASE_CHANGELOG = new ConfigKey<>( + public static final ConfigKey DATABASE_CHANGELOG = new StringConfigKey( "database.changelog", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Database connection pool size. Default value is defined by the HikariCP library. */ - public static final ConfigKey DATABASE_MAX_POOL_SIZE = new ConfigKey<>( + public static final ConfigKey DATABASE_MAX_POOL_SIZE = new IntegerConfigKey( "database.maxPoolSize", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * SQL query to check connection status. Default value is 'SELECT 1'. For Oracle database you can use * 'SELECT 1 FROM DUAL'. */ - public static final ConfigKey DATABASE_CHECK_CONNECTION = new ConfigKey<>( + public static final ConfigKey DATABASE_CHECK_CONNECTION = new StringConfigKey( "database.checkConnection", - Collections.singletonList(KeyType.CONFIG), + List.of(KeyType.CONFIG), "SELECT 1"); /** * Store original HEX or string data as "raw" attribute in the corresponding position. */ - public static final ConfigKey DATABASE_SAVE_ORIGINAL = new ConfigKey<>( + public static final ConfigKey DATABASE_SAVE_ORIGINAL = new BooleanConfigKey( "database.saveOriginal", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * By default server syncs with the database if it encounters and unknown device. This flag allows to disable that * behavior to improve performance in some cases. */ - public static final ConfigKey DATABASE_IGNORE_UNKNOWN = new ConfigKey<>( + public static final ConfigKey DATABASE_IGNORE_UNKNOWN = new BooleanConfigKey( "database.ignoreUnknown", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Automatically register unknown devices in the database. */ - public static final ConfigKey DATABASE_REGISTER_UNKNOWN = new ConfigKey<>( + public static final ConfigKey DATABASE_REGISTER_UNKNOWN = new BooleanConfigKey( "database.registerUnknown", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Default category for auto-registered devices. */ - public static final ConfigKey DATABASE_REGISTER_UNKNOWN_DEFAULT_CATEGORY = new ConfigKey<>( + public static final ConfigKey DATABASE_REGISTER_UNKNOWN_DEFAULT_CATEGORY = new StringConfigKey( "database.registerUnknown.defaultCategory", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * The group id assigned to auto-registered devices. */ - public static final ConfigKey DATABASE_REGISTER_UNKNOWN_DEFAULT_GROUP_ID = new ConfigKey<>( + public static final ConfigKey DATABASE_REGISTER_UNKNOWN_DEFAULT_GROUP_ID = new LongConfigKey( "database.registerUnknown.defaultGroupId", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Minimum device refresh timeout in seconds. Default timeout is 5 minutes. */ - public static final ConfigKey DATABASE_REFRESH_DELAY = new ConfigKey<>( + public static final ConfigKey DATABASE_REFRESH_DELAY = new LongConfigKey( "database.refreshDelay", - Collections.singletonList(KeyType.CONFIG), + List.of(KeyType.CONFIG), 300L); /** * Store empty messages as positions. For example, heartbeats. */ - public static final ConfigKey DATABASE_SAVE_EMPTY = new ConfigKey<>( + public static final ConfigKey DATABASE_SAVE_EMPTY = new BooleanConfigKey( "database.saveEmpty", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Device limit for self registered users. Default value is -1, which indicates no limit. */ - public static final ConfigKey USERS_DEFAULT_DEVICE_LIMIT = new ConfigKey<>( + public static final ConfigKey USERS_DEFAULT_DEVICE_LIMIT = new IntegerConfigKey( "users.defaultDeviceLimit", - Collections.singletonList(KeyType.CONFIG), + List.of(KeyType.CONFIG), -1); /** * Default user expiration for self registered users. Value is in days. By default no expiration is set. */ - public static final ConfigKey USERS_DEFAULT_EXPIRATION_DAYS = new ConfigKey<>( + public static final ConfigKey USERS_DEFAULT_EXPIRATION_DAYS = new IntegerConfigKey( "users.defaultExpirationDays", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * LDAP server URL. */ - public static final ConfigKey LDAP_URL = new ConfigKey<>( + public static final ConfigKey LDAP_URL = new StringConfigKey( "ldap.url", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * LDAP server login. */ - public static final ConfigKey LDAP_USER = new ConfigKey<>( + public static final ConfigKey LDAP_USER = new StringConfigKey( "ldap.user", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * LDAP server password. */ - public static final ConfigKey LDAP_PASSWORD = new ConfigKey<>( + public static final ConfigKey LDAP_PASSWORD = new StringConfigKey( "ldap.password", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Force LDAP authentication. */ - public static final ConfigKey LDAP_FORCE = new ConfigKey<>( + public static final ConfigKey LDAP_FORCE = new BooleanConfigKey( "ldap.force", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * LDAP user search base. */ - public static final ConfigKey LDAP_BASE = new ConfigKey<>( + public static final ConfigKey LDAP_BASE = new StringConfigKey( "ldap.base", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * LDAP attribute used as user id. Default value is 'uid'. */ - public static final ConfigKey LDAP_ID_ATTRIBUTE = new ConfigKey<>( + public static final ConfigKey LDAP_ID_ATTRIBUTE = new StringConfigKey( "ldap.idAttribute", - Collections.singletonList(KeyType.CONFIG), + List.of(KeyType.CONFIG), "uid"); /** * LDAP attribute used as user name. Default value is 'cn'. */ - public static final ConfigKey LDAP_NAME_ATTRIBUTE = new ConfigKey<>( + public static final ConfigKey LDAP_NAME_ATTRIBUTE = new StringConfigKey( "ldap.nameAttribute", - Collections.singletonList(KeyType.CONFIG), + List.of(KeyType.CONFIG), "cn"); /** * LDAP attribute used as user email. Default value is 'mail'. */ - public static final ConfigKey LDAP_MAIN_ATTRIBUTE = new ConfigKey<>( + public static final ConfigKey LDAP_MAIN_ATTRIBUTE = new StringConfigKey( "ldap.mailAttribute", - Collections.singletonList(KeyType.CONFIG), + List.of(KeyType.CONFIG), "mail"); /** * LDAP custom search filter. If not specified, '({idAttribute}=:login)' will be used as a filter. */ - public static final ConfigKey LDAP_SEARCH_FILTER = new ConfigKey<>( + public static final ConfigKey LDAP_SEARCH_FILTER = new StringConfigKey( "ldap.searchFilter", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * LDAP custom admin search filter. */ - public static final ConfigKey LDAP_ADMIN_FILTER = new ConfigKey<>( + public static final ConfigKey LDAP_ADMIN_FILTER = new StringConfigKey( "ldap.adminFilter", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * LDAP admin user group. Used if custom admin filter is not specified. */ - public static final ConfigKey LDAP_ADMIN_GROUP = new ConfigKey<>( + public static final ConfigKey LDAP_ADMIN_GROUP = new StringConfigKey( "ldap.adminGroup", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * If no data is reported by a device for the given amount of time, status changes from online to unknown. Value is * in seconds. Default timeout is 10 minutes. */ - public static final ConfigKey STATUS_TIMEOUT = new ConfigKey<>( + public static final ConfigKey STATUS_TIMEOUT = new LongConfigKey( "status.timeout", - Collections.singletonList(KeyType.CONFIG), + List.of(KeyType.CONFIG), 600L); /** * Force additional state check when device status changes to 'offline' or 'unknown'. Default false. */ - public static final ConfigKey STATUS_UPDATE_DEVICE_STATE = new ConfigKey<>( + public static final ConfigKey STATUS_UPDATE_DEVICE_STATE = new BooleanConfigKey( "status.updateDeviceState", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * List of protocol names to ignore offline status. Can be useful to not trigger status change when devices are * configured to disconnect after reporting a batch of data. */ - public static final ConfigKey STATUS_IGNORE_OFFLINE = new ConfigKey<>( + public static final ConfigKey STATUS_IGNORE_OFFLINE = new StringConfigKey( "status.ignoreOffline", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Path to the media folder. Server stores audio, video and photo files in that folder. Sub-folders will be * automatically created for each device by unique id. */ - public static final ConfigKey MEDIA_PATH = new ConfigKey<>( + public static final ConfigKey MEDIA_PATH = new StringConfigKey( "media.path", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Optional parameter to specify network interface for web interface to bind to. By default server will bind to all * available interfaces. */ - public static final ConfigKey WEB_ADDRESS = new ConfigKey<>( + public static final ConfigKey WEB_ADDRESS = new StringConfigKey( "web.address", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Web interface TCP port number. By default Traccar uses port 8082. To avoid specifying port in the browser you * can set it to 80 (default HTTP port). */ - public static final ConfigKey WEB_PORT = new ConfigKey<>( + public static final ConfigKey WEB_PORT = new IntegerConfigKey( "web.port", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Sanitize all strings returned via API. This is needed to fix XSS issues in the old web interface. New React-based * interface doesn't require this. */ - public static final ConfigKey WEB_SANITIZE = new ConfigKey<>( + public static final ConfigKey WEB_SANITIZE = new BooleanConfigKey( "web.sanitize", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Path to the web app folder. */ - public static final ConfigKey WEB_PATH = new ConfigKey<>( + public static final ConfigKey WEB_PATH = new StringConfigKey( "web.path", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * WebSocket connection timeout in milliseconds. Default timeout is 10 minutes. */ - public static final ConfigKey WEB_TIMEOUT = new ConfigKey<>( + public static final ConfigKey WEB_TIMEOUT = new LongConfigKey( "web.timeout", - Collections.singletonList(KeyType.CONFIG), + List.of(KeyType.CONFIG), 60000L); /** * Authentication sessions timeout in seconds. By default no timeout. */ - public static final ConfigKey WEB_SESSION_TIMEOUT = new ConfigKey<>( + public static final ConfigKey WEB_SESSION_TIMEOUT = new IntegerConfigKey( "web.sessionTimeout", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Enable database access console via '/console' URL. Use only for debugging. Never use in production. */ - public static final ConfigKey WEB_CONSOLE = new ConfigKey<>( + public static final ConfigKey WEB_CONSOLE = new BooleanConfigKey( "web.console", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Server debug version of the web app. Not recommended to use for performance reasons. It is intended to be used * for development and debugging purposes. */ - public static final ConfigKey WEB_DEBUG = new ConfigKey<>( + public static final ConfigKey WEB_DEBUG = new BooleanConfigKey( "web.debug", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Cross-origin resource sharing origin header value. */ - public static final ConfigKey WEB_ORIGIN = new ConfigKey<>( + public static final ConfigKey WEB_ORIGIN = new StringConfigKey( "web.origin", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Cache control header value. By default resources are cached for one hour. */ - public static final ConfigKey WEB_CACHE_CONTROL = new ConfigKey<>( + public static final ConfigKey WEB_CACHE_CONTROL = new StringConfigKey( "web.cacheControl", - Collections.singletonList(KeyType.CONFIG), + List.of(KeyType.CONFIG), "max-age=3600,public"); /** * URL to forward positions. Data is passed through URL parameters. For example, {uniqueId} for device identifier, * {latitude} and {longitude} for coordinates. */ - public static final ConfigKey FORWARD_URL = new ConfigKey<>( + public static final ConfigKey FORWARD_URL = new StringConfigKey( "forward.url", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Additional HTTP header, can be used for authorization. */ - public static final ConfigKey FORWARD_HEADER = new ConfigKey<>( + public static final ConfigKey FORWARD_HEADER = new StringConfigKey( "forward.header", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Boolean value to enable forwarding in JSON format. */ - public static final ConfigKey FORWARD_JSON = new ConfigKey<>( + public static final ConfigKey FORWARD_JSON = new BooleanConfigKey( "forward.json", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Boolean value to enable URL parameters in json mode. For example, {uniqueId} for device identifier, * {latitude} and {longitude} for coordinates. */ - public static final ConfigKey FORWARD_URL_VARIABLES = new ConfigKey<>( + public static final ConfigKey FORWARD_URL_VARIABLES = new BooleanConfigKey( "forward.urlVariables", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Position forwarding retrying enable. When enabled, additional attempts are made to deliver positions. If initial @@ -635,301 +707,301 @@ public final class Keys { * If forwarding is retried for 'forward.retry.count', retrying is canceled and the position is dropped. Positions * pending to be delivered are limited to 'forward.retry.limit'. If this limit is reached, positions get discarded. */ - public static final ConfigKey FORWARD_RETRY_ENABLE = new ConfigKey<>( + public static final ConfigKey FORWARD_RETRY_ENABLE = new BooleanConfigKey( "forward.retry.enable", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Position forwarding retry first delay in milliseconds. * Can be set to anything greater than 0. Defaults to 100 milliseconds. */ - public static final ConfigKey FORWARD_RETRY_DELAY = new ConfigKey<>( + public static final ConfigKey FORWARD_RETRY_DELAY = new IntegerConfigKey( "forward.retry.delay", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Position forwarding retry maximum retries. * Can be set to anything greater than 0. Defaults to 10 retries. */ - public static final ConfigKey FORWARD_RETRY_COUNT = new ConfigKey<>( + public static final ConfigKey FORWARD_RETRY_COUNT = new IntegerConfigKey( "forward.retry.count", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Position forwarding retry pending positions limit. * Can be set to anything greater than 0. Defaults to 100 positions. */ - public static final ConfigKey FORWARD_RETRY_LIMIT = new ConfigKey<>( + public static final ConfigKey FORWARD_RETRY_LIMIT = new IntegerConfigKey( "forward.retry.limit", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Events forwarding URL. */ - public static final ConfigKey EVENT_FORWARD_URL = new ConfigKey<>( + public static final ConfigKey EVENT_FORWARD_URL = new StringConfigKey( "event.forward.url", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Events forwarding headers. Example value: * FirstHeader: hello * SecondHeader: world */ - public static final ConfigKey EVENT_FORWARD_HEADERS = new ConfigKey<>( + public static final ConfigKey EVENT_FORWARD_HEADERS = new StringConfigKey( "event.forward.header", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Enable commands queuing when devices are offline. Commands are buffered in memory only, so restarting service * will clear the buffer. */ - public static final ConfigKey COMMANDS_QUEUEING = new ConfigKey<>( + public static final ConfigKey COMMANDS_QUEUEING = new BooleanConfigKey( "commands.queueing", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Root folder for all template files. */ - public static final ConfigKey TEMPLATES_ROOT = new ConfigKey<>( + public static final ConfigKey TEMPLATES_ROOT = new StringConfigKey( "templates.root", - Collections.singletonList(KeyType.CONFIG), + List.of(KeyType.CONFIG), "templates"); /** * SMS API service full URL. Enables SMS commands and notifications. */ - public static final ConfigKey SMS_HTTP_URL = new ConfigKey<>( + public static final ConfigKey SMS_HTTP_URL = new StringConfigKey( "sms.http.url", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * SMS API authorization header name. Default value is 'Authorization'. */ - public static final ConfigKey SMS_HTTP_AUTHORIZATION_HEADER = new ConfigKey<>( + public static final ConfigKey SMS_HTTP_AUTHORIZATION_HEADER = new StringConfigKey( "sms.http.authorizationHeader", - Collections.singletonList(KeyType.CONFIG), + List.of(KeyType.CONFIG), "Authorization"); /** * SMS API authorization header value. This value takes precedence over user and password. */ - public static final ConfigKey SMS_HTTP_AUTHORIZATION = new ConfigKey<>( + public static final ConfigKey SMS_HTTP_AUTHORIZATION = new StringConfigKey( "sms.http.authorization", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * SMS API basic authentication user. */ - public static final ConfigKey SMS_HTTP_USER = new ConfigKey<>( + public static final ConfigKey SMS_HTTP_USER = new StringConfigKey( "sms.http.user", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * SMS API basic authentication password. */ - public static final ConfigKey SMS_HTTP_PASSWORD = new ConfigKey<>( + public static final ConfigKey SMS_HTTP_PASSWORD = new StringConfigKey( "sms.http.password", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * SMS API body template. Placeholders {phone} and {message} can be used in the template. * If value starts with '{' or '[', server automatically assumes JSON format. */ - public static final ConfigKey SMS_HTTP_TEMPLATE = new ConfigKey<>( + public static final ConfigKey SMS_HTTP_TEMPLATE = new StringConfigKey( "sms.http.template", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * AWS Access Key with SNS permission. */ - public static final ConfigKey SMS_AWS_ACCESS = new ConfigKey<>( + public static final ConfigKey SMS_AWS_ACCESS = new StringConfigKey( "sms.aws.access", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * AWS Secret Access Key with SNS permission. */ - public static final ConfigKey SMS_AWS_SECRET = new ConfigKey<>( + public static final ConfigKey SMS_AWS_SECRET = new StringConfigKey( "sms.aws.secret", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * AWS Region for SNS service. * Make sure to use regions that are supported for messaging. */ - public static final ConfigKey SMS_AWS_REGION = new ConfigKey<>( + public static final ConfigKey SMS_AWS_REGION = new StringConfigKey( "sms.aws.region", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Enabled notification options. Comma-separated string is expected. * Example: web,mail,sms */ - public static final ConfigKey NOTIFICATOR_TYPES = new ConfigKey<>( + public static final ConfigKey NOTIFICATOR_TYPES = new StringConfigKey( "notificator.types", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Traccar notification API key. */ - public static final ConfigKey NOTIFICATOR_TRACCAR_KEY = new ConfigKey<>( + public static final ConfigKey NOTIFICATOR_TRACCAR_KEY = new StringConfigKey( "notificator.traccar.key", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Firebase server API key for push notifications. */ - public static final ConfigKey NOTIFICATOR_FIREBASE_KEY = new ConfigKey<>( + public static final ConfigKey NOTIFICATOR_FIREBASE_KEY = new StringConfigKey( "notificator.firebase.key", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Pushover notification user name. */ - public static final ConfigKey NOTIFICATOR_PUSHOVER_USER = new ConfigKey<>( + public static final ConfigKey NOTIFICATOR_PUSHOVER_USER = new StringConfigKey( "notificator.pushover.user", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Pushover notification user token. */ - public static final ConfigKey NOTIFICATOR_PUSHOVER_TOKEN = new ConfigKey<>( + public static final ConfigKey NOTIFICATOR_PUSHOVER_TOKEN = new StringConfigKey( "notificator.pushover.token", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Telegram notification API key. */ - public static final ConfigKey NOTIFICATOR_TELEGRAM_KEY = new ConfigKey<>( + public static final ConfigKey NOTIFICATOR_TELEGRAM_KEY = new StringConfigKey( "notificator.telegram.key", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Telegram notification chat id to post messages to. */ - public static final ConfigKey NOTIFICATOR_TELEGRAM_CHAT_ID = new ConfigKey<>( + public static final ConfigKey NOTIFICATOR_TELEGRAM_CHAT_ID = new StringConfigKey( "notificator.telegram.chatId", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Telegram notification send location message. */ - public static final ConfigKey NOTIFICATOR_TELEGRAM_SEND_LOCATION = new ConfigKey<>( + public static final ConfigKey NOTIFICATOR_TELEGRAM_SEND_LOCATION = new BooleanConfigKey( "notificator.telegram.sendLocation", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Maximum time period for reports in seconds. Can be useful to prevent users to request unreasonably long reports. * By default there is no limit. */ - public static final ConfigKey REPORT_PERIOD_LIMIT = new ConfigKey<>( + public static final ConfigKey REPORT_PERIOD_LIMIT = new LongConfigKey( "report.periodLimit", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Trips less than minimal duration and minimal distance are ignored. 300 seconds and 500 meters are default. */ - public static final ConfigKey REPORT_TRIP_MINIMAL_TRIP_DISTANCE = new ConfigKey<>( + public static final ConfigKey REPORT_TRIP_MINIMAL_TRIP_DISTANCE = new LongConfigKey( "report.trip.minimalTripDistance", - Collections.singletonList(KeyType.CONFIG), + List.of(KeyType.CONFIG), 500L); /** * Trips less than minimal duration and minimal distance are ignored. 300 seconds and 500 meters are default. */ - public static final ConfigKey REPORT_TRIP_MINIMAL_TRIP_DURATION = new ConfigKey<>( + public static final ConfigKey REPORT_TRIP_MINIMAL_TRIP_DURATION = new LongConfigKey( "report.trip.minimalTripDuration", - Collections.singletonList(KeyType.CONFIG), + List.of(KeyType.CONFIG), 300L); /** * Parking less than minimal duration does not cut trip. Default 300 seconds. */ - public static final ConfigKey REPORT_TRIP_MINIMAL_PARKING_DURATION = new ConfigKey<>( + public static final ConfigKey REPORT_TRIP_MINIMAL_PARKING_DURATION = new LongConfigKey( "report.trip.minimalParkingDuration", - Collections.singletonList(KeyType.CONFIG), + List.of(KeyType.CONFIG), 300L); /** * Gaps of more than specified time are counted as stops. Default value is one hour. */ - public static final ConfigKey REPORT_TRIP_MINIMAL_NO_DATA_DURATION = new ConfigKey<>( + public static final ConfigKey REPORT_TRIP_MINIMAL_NO_DATA_DURATION = new LongConfigKey( "report.trip.minimalNoDataDuration", - Collections.singletonList(KeyType.CONFIG), + List.of(KeyType.CONFIG), 3600L); /** * Flag to enable ignition use for trips calculation. */ - public static final ConfigKey REPORT_TRIP_USE_IGNITION = new ConfigKey<>( + public static final ConfigKey REPORT_TRIP_USE_IGNITION = new BooleanConfigKey( "report.trip.useIgnition", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Boolean flag to enable or disable position filtering. */ - public static final ConfigKey FILTER_ENABLE = new ConfigKey<>( + public static final ConfigKey FILTER_ENABLE = new BooleanConfigKey( "filter.enable", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Filter invalid (valid field is set to false) positions. */ - public static final ConfigKey FILTER_INVALID = new ConfigKey<>( + public static final ConfigKey FILTER_INVALID = new BooleanConfigKey( "filter.invalid", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Filter zero coordinates. Zero latitude and longitude are theoretically valid values, but it practice it usually * indicates invalid GPS data. */ - public static final ConfigKey FILTER_ZERO = new ConfigKey<>( + public static final ConfigKey FILTER_ZERO = new BooleanConfigKey( "filter.zero", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Filter duplicate records (duplicates are detected by time value). */ - public static final ConfigKey FILTER_DUPLICATE = new ConfigKey<>( + public static final ConfigKey FILTER_DUPLICATE = new BooleanConfigKey( "filter.duplicate", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Filter records with fix time in future. The values is specified in seconds. Records that have fix time more than * specified number of seconds later than current server time would be filtered out. */ - public static final ConfigKey FILTER_FUTURE = new ConfigKey<>( + public static final ConfigKey FILTER_FUTURE = new LongConfigKey( "filter.future", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Filter positions with accuracy less than specified value in meters. */ - public static final ConfigKey FILTER_ACCURACY = new ConfigKey<>( + public static final ConfigKey FILTER_ACCURACY = new IntegerConfigKey( "filter.accuracy", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Filter cell and wifi locations that are coming from geolocation provider. */ - public static final ConfigKey FILTER_APPROXIMATE = new ConfigKey<>( + public static final ConfigKey FILTER_APPROXIMATE = new BooleanConfigKey( "filter.approximate", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Filter positions with exactly zero speed values. */ - public static final ConfigKey FILTER_STATIC = new ConfigKey<>( + public static final ConfigKey FILTER_STATIC = new BooleanConfigKey( "filter.static", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Filter records by distance. The values is specified in meters. If the new position is less far than this value * from the last one it gets filtered out. */ - public static final ConfigKey FILTER_DISTANCE = new ConfigKey<>( + public static final ConfigKey FILTER_DISTANCE = new IntegerConfigKey( "filter.distance", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Filter records by Maximum Speed value in knots. Can be used to filter jumps to far locations even if Position @@ -938,16 +1010,16 @@ public final class Keys { * * Tip: Shouldn't be too low. Start testing with values at about 25000. */ - public static final ConfigKey FILTER_MAX_SPEED = new ConfigKey<>( + public static final ConfigKey FILTER_MAX_SPEED = new IntegerConfigKey( "filter.maxSpeed", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Filter position if time from previous position is less than specified value in seconds. */ - public static final ConfigKey FILTER_MIN_PERIOD = new ConfigKey<>( + public static final ConfigKey FILTER_MIN_PERIOD = new IntegerConfigKey( "filter.minPeriod", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * If false, the server expects all locations to come sequentially (for each device). Filter checks for duplicates, @@ -957,262 +1029,271 @@ public final class Keys { * Filter checks for duplicates, distance, speed, or time period against the preceding Position's. * Important: setting to true can cause potential performance issues. */ - public static final ConfigKey FILTER_RELATIVE = new ConfigKey<>( + public static final ConfigKey FILTER_RELATIVE = new BooleanConfigKey( "filter.relative", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Time limit for the filtering in seconds. If the time difference between the last position was received by server * and a new position is received by server is more than this limit, the new position will not be filtered out. */ - public static final ConfigKey FILTER_SKIP_LIMIT = new ConfigKey<>( + public static final ConfigKey FILTER_SKIP_LIMIT = new LongConfigKey( "filter.skipLimit", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Enable attributes skipping. Attribute skipping can be enabled in the config or device attributes. * If position contains any attribute mentioned in "filter.skipAttributes" config key, position is not filtered out. */ - public static final ConfigKey FILTER_SKIP_ATTRIBUTES_ENABLE = new ConfigKey<>( + public static final ConfigKey FILTER_SKIP_ATTRIBUTES_ENABLE = new BooleanConfigKey( "filter.skipAttributes.enable", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); + + /** + * Attribute skipping can be enabled in the config or device attributes. + * If position contains any attribute mentioned in "filter.skipAttributes" config key, position is not filtered out. + */ + public static final ConfigKey FILTER_SKIP_ATTRIBUTES = new StringConfigKey( + "filter.skipAttributes", + List.of(KeyType.CONFIG, KeyType.DEVICE), + ""); /** * Override device time. Possible values are 'deviceTime' and 'serverTime' */ - public static final ConfigKey TIME_OVERRIDE = new ConfigKey<>( + public static final ConfigKey TIME_OVERRIDE = new StringConfigKey( "time.override", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * List of protocols for overriding time. If not specified override is applied globally. List consist of protocol * names that can be separated by comma or single space character. */ - public static final ConfigKey TIME_PROTOCOLS = new ConfigKey<>( + public static final ConfigKey TIME_PROTOCOLS = new StringConfigKey( "time.protocols", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Replaces coordinates with last known if change is less than a 'coordinates.minError' meters * or more than a 'coordinates.maxError' meters. Helps to avoid coordinates jumps during parking period * or jumps to zero coordinates. */ - public static final ConfigKey COORDINATES_FILTER = new ConfigKey<>( + public static final ConfigKey COORDINATES_FILTER = new BooleanConfigKey( "coordinates.filter", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Distance in meters. Distances below this value gets handled like explained in 'coordinates.filter'. */ - public static final ConfigKey COORDINATES_MIN_ERROR = new ConfigKey<>( + public static final ConfigKey COORDINATES_MIN_ERROR = new IntegerConfigKey( "coordinates.minError", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Distance in meters. Distances above this value gets handled like explained in 'coordinates.filter', but only if * Position is also marked as 'invalid'. */ - public static final ConfigKey COORDINATES_MAX_ERROR = new ConfigKey<>( + public static final ConfigKey COORDINATES_MAX_ERROR = new IntegerConfigKey( "coordinates.maxError", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Enable to save device IP addresses information. Disabled by default. */ - public static final ConfigKey PROCESSING_REMOTE_ADDRESS_ENABLE = new ConfigKey<>( + public static final ConfigKey PROCESSING_REMOTE_ADDRESS_ENABLE = new BooleanConfigKey( "processing.remoteAddress.enable", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Enable copying of missing attributes from last position to the current one. Might be useful if device doesn't * send some values in every message. */ - public static final ConfigKey PROCESSING_COPY_ATTRIBUTES_ENABLE = new ConfigKey<>( + public static final ConfigKey PROCESSING_COPY_ATTRIBUTES_ENABLE = new BooleanConfigKey( "processing.copyAttributes.enable", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Enable computed attributes processing. */ - public static final ConfigKey PROCESSING_COMPUTED_ATTRIBUTES_DEVICE_ATTRIBUTES = new ConfigKey<>( + public static final ConfigKey PROCESSING_COMPUTED_ATTRIBUTES_DEVICE_ATTRIBUTES = new BooleanConfigKey( "processing.computedAttributes.deviceAttributes", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Boolean flag to enable or disable reverse geocoder. */ - public static final ConfigKey GEOCODER_ENABLE = new ConfigKey<>( + public static final ConfigKey GEOCODER_ENABLE = new BooleanConfigKey( "geocoder.enable", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Reverse geocoder type. Check reverse geocoding documentation for more info. By default (if the value is not * specified) server uses Google API. */ - public static final ConfigKey GEOCODER_TYPE = new ConfigKey<>( + public static final ConfigKey GEOCODER_TYPE = new StringConfigKey( "geocoder.type", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Geocoder server URL. Applicable only to Nominatim and Gisgraphy providers. */ - public static final ConfigKey GEOCODER_URL = new ConfigKey<>( + public static final ConfigKey GEOCODER_URL = new StringConfigKey( "geocoder.url", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * App id for use with Here provider. */ - public static final ConfigKey GEOCODER_ID = new ConfigKey<>( + public static final ConfigKey GEOCODER_ID = new StringConfigKey( "geocoder.id", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Provider API key. Most providers require API keys. */ - public static final ConfigKey GEOCODER_KEY = new ConfigKey<>( + public static final ConfigKey GEOCODER_KEY = new StringConfigKey( "geocoder.key", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Language parameter for providers that support localization (e.g. Google and Nominatim). */ - public static final ConfigKey GEOCODER_LANGUAGE = new ConfigKey<>( + public static final ConfigKey GEOCODER_LANGUAGE = new StringConfigKey( "geocoder.language", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Address format string. Default value is %h %r, %t, %s, %c. See AddressFormat for more info. */ - public static final ConfigKey GEOCODER_FORMAT = new ConfigKey<>( + public static final ConfigKey GEOCODER_FORMAT = new StringConfigKey( "geocoder.format", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Cache size for geocoding results. */ - public static final ConfigKey GEOCODER_CACHE_SIZE = new ConfigKey<>( + public static final ConfigKey GEOCODER_CACHE_SIZE = new IntegerConfigKey( "geocoder.cacheSize", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Disable automatic reverse geocoding requests for all positions. */ - public static final ConfigKey GEOCODER_IGNORE_POSITIONS = new ConfigKey<>( + public static final ConfigKey GEOCODER_IGNORE_POSITIONS = new BooleanConfigKey( "geocoder.ignorePositions", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Boolean flag to apply reverse geocoding to invalid positions. */ - public static final ConfigKey GEOCODER_PROCESS_INVALID_POSITIONS = new ConfigKey<>( + public static final ConfigKey GEOCODER_PROCESS_INVALID_POSITIONS = new BooleanConfigKey( "geocoder.processInvalidPositions", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Optional parameter to specify minimum distance for new reverse geocoding request. If distance is less than * specified value (in meters), then Traccar will reuse last known address. */ - public static final ConfigKey GEOCODER_REUSE_DISTANCE = new ConfigKey<>( + public static final ConfigKey GEOCODER_REUSE_DISTANCE = new IntegerConfigKey( "geocoder.reuseDistance", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Perform geocoding when preparing reports and sending notifications. */ - public static final ConfigKey GEOCODER_ON_REQUEST = new ConfigKey<>( + public static final ConfigKey GEOCODER_ON_REQUEST = new BooleanConfigKey( "geocoder.onRequest", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Boolean flag to enable LBS location resolution. Some devices send cell towers information and WiFi point when GPS * location is not available. Traccar can determine coordinates based on that information using third party * services. Default value is false. */ - public static final ConfigKey GEOLOCATION_ENABLE = new ConfigKey<>( + public static final ConfigKey GEOLOCATION_ENABLE = new BooleanConfigKey( "geolocation.enable", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Provider to use for LBS location. Available options: google, mozilla and opencellid. By default opencellid is * used. You have to supply a key that you get from corresponding provider. For more information see LBS geolocation * documentation. */ - public static final ConfigKey GEOLOCATION_TYPE = new ConfigKey<>( + public static final ConfigKey GEOLOCATION_TYPE = new StringConfigKey( "geolocation.type", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Geolocation provider API URL address. Not required for most providers. */ - public static final ConfigKey GEOLOCATION_URL = new ConfigKey<>( + public static final ConfigKey GEOLOCATION_URL = new StringConfigKey( "geolocation.url", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Provider API key. OpenCellID service requires API key. */ - public static final ConfigKey GEOLOCATION_KEY = new ConfigKey<>( + public static final ConfigKey GEOLOCATION_KEY = new StringConfigKey( "geolocation.key", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Boolean flag to apply geolocation to invalid positions. */ - public static final ConfigKey GEOLOCATION_PROCESS_INVALID_POSITIONS = new ConfigKey<>( + public static final ConfigKey GEOLOCATION_PROCESS_INVALID_POSITIONS = new BooleanConfigKey( "geolocation.processInvalidPositions", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Default MCC value to use if device doesn't report MCC. */ - public static final ConfigKey GEOLOCATION_MCC = new ConfigKey<>( + public static final ConfigKey GEOLOCATION_MCC = new IntegerConfigKey( "geolocation.mcc", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Default MNC value to use if device doesn't report MNC. */ - public static final ConfigKey GEOLOCATION_MNC = new ConfigKey<>( + public static final ConfigKey GEOLOCATION_MNC = new IntegerConfigKey( "geolocation.mnc", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Boolean flag to enable speed limit API to get speed limit values depending on location. Default value is false. */ - public static final ConfigKey SPEED_LIMIT_ENABLE = new ConfigKey<>( + public static final ConfigKey SPEED_LIMIT_ENABLE = new BooleanConfigKey( "speedLimit.enable", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Provider to use for speed limit. Available options: overpass. By default overpass is used. */ - public static final ConfigKey SPEED_LIMIT_TYPE = new ConfigKey<>( + public static final ConfigKey SPEED_LIMIT_TYPE = new StringConfigKey( "speedLimit.type", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Speed limit provider API URL address. */ - public static final ConfigKey SPEED_LIMIT_URL = new ConfigKey<>( + public static final ConfigKey SPEED_LIMIT_URL = new StringConfigKey( "speedLimit.url", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Override latitude sign / hemisphere. Useful in cases where value is incorrect because of device bug. Value can be * N for North or S for South. */ - public static final ConfigKey LOCATION_LATITUDE_HEMISPHERE = new ConfigKey<>( + public static final ConfigKey LOCATION_LATITUDE_HEMISPHERE = new StringConfigKey( "location.latitudeHemisphere", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Override longitude sign / hemisphere. Useful in cases where value is incorrect because of device bug. Value can * be E for East or W for West. */ - public static final ConfigKey LOCATION_LONGITUDE_HEMISPHERE = new ConfigKey<>( + public static final ConfigKey LOCATION_LONGITUDE_HEMISPHERE = new StringConfigKey( "location.longitudeHemisphere", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Jetty Request Log Path. @@ -1220,112 +1301,112 @@ public final class Keys { * over the file. * Example: ./logs/jetty-yyyy_mm_dd.request.log */ - public static final ConfigKey WEB_REQUEST_LOG_PATH = new ConfigKey<>( + public static final ConfigKey WEB_REQUEST_LOG_PATH = new StringConfigKey( "web.requestLog.path", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Set the number of days before rotated request log files are deleted. */ - public static final ConfigKey WEB_REQUEST_LOG_RETAIN_DAYS = new ConfigKey<>( + public static final ConfigKey WEB_REQUEST_LOG_RETAIN_DAYS = new IntegerConfigKey( "web.requestLog.retainDays", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Disable systemd health checks. */ - public static final ConfigKey WEB_DISABLE_HEALTH_CHECK = new ConfigKey<>( + public static final ConfigKey WEB_DISABLE_HEALTH_CHECK = new BooleanConfigKey( "web.disableHealthCheck", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Sets SameSite cookie attribute value. * Supported options: Lax, Strict, None. */ - public static final ConfigKey WEB_SAME_SITE_COOKIE = new ConfigKey<>( + public static final ConfigKey WEB_SAME_SITE_COOKIE = new StringConfigKey( "web.sameSiteCookie", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Enables persisting Jetty session to the database */ - public static final ConfigKey WEB_PERSIST_SESSION = new ConfigKey<>( + public static final ConfigKey WEB_PERSIST_SESSION = new BooleanConfigKey( "web.persistSession", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Public URL for the web app. Used for notification and report link. * * If not provided, Traccar will attempt to get a URL from the server IP address, but it might be a local address. */ - public static final ConfigKey WEB_URL = new ConfigKey<>( + public static final ConfigKey WEB_URL = new StringConfigKey( "web.url", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Output logging to the standard terminal output instead of a log file. */ - public static final ConfigKey LOGGER_CONSOLE = new ConfigKey<>( + public static final ConfigKey LOGGER_CONSOLE = new BooleanConfigKey( "logger.console", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Log executed SQL queries. */ - public static final ConfigKey LOGGER_QUERIES = new ConfigKey<>( + public static final ConfigKey LOGGER_QUERIES = new BooleanConfigKey( "logger.queries", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Log file name. For rotating logs, a date is added at the end of the file name for non-current logs. */ - public static final ConfigKey LOGGER_FILE = new ConfigKey<>( + public static final ConfigKey LOGGER_FILE = new StringConfigKey( "logger.file", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Logging level. Default value is 'info'. * Available options: off, severe, warning, info, config, fine, finer, finest, all. */ - public static final ConfigKey LOGGER_LEVEL = new ConfigKey<>( + public static final ConfigKey LOGGER_LEVEL = new StringConfigKey( "logger.level", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Print full exception traces. Useful for debugging. By default shortened traces are logged. */ - public static final ConfigKey LOGGER_FULL_STACK_TRACES = new ConfigKey<>( + public static final ConfigKey LOGGER_FULL_STACK_TRACES = new BooleanConfigKey( "logger.fullStackTraces", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Create a new log file daily. Helps with log management. For example, downloading and cleaning logs. Enabled by * default. */ - public static final ConfigKey LOGGER_ROTATE = new ConfigKey<>( + public static final ConfigKey LOGGER_ROTATE = new BooleanConfigKey( "logger.rotate", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * A list of position attributes to log. */ - public static final ConfigKey LOGGER_ATTRIBUTES = new ConfigKey<>( + public static final ConfigKey LOGGER_ATTRIBUTES = new StringConfigKey( "logger.attributes", - Collections.singletonList(KeyType.CONFIG), + List.of(KeyType.CONFIG), "time,position,speed,course,accuracy,result"); /** * Multicast address for broadcasting synchronization events. */ - public static final ConfigKey BROADCAST_ADDRESS = new ConfigKey<>( + public static final ConfigKey BROADCAST_ADDRESS = new StringConfigKey( "broadcast.address", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); /** * Multicast port for broadcasting synchronization events. */ - public static final ConfigKey BROADCAST_PORT = new ConfigKey<>( + public static final ConfigKey BROADCAST_PORT = new IntegerConfigKey( "broadcast.port", - Collections.singletonList(KeyType.CONFIG)); + List.of(KeyType.CONFIG)); } diff --git a/src/main/java/org/traccar/database/DeviceManager.java b/src/main/java/org/traccar/database/DeviceManager.java index 81043fd7a..a3e04f920 100644 --- a/src/main/java/org/traccar/database/DeviceManager.java +++ b/src/main/java/org/traccar/database/DeviceManager.java @@ -73,34 +73,6 @@ public class DeviceManager extends BaseObjectManager implements Identity refreshLastPositions(); } - @Override - public Device addUnknownDevice(String uniqueId) { - Device device = new Device(); - device.setName(uniqueId); - device.setUniqueId(uniqueId); - device.setCategory(Context.getConfig().getString(Keys.DATABASE_REGISTER_UNKNOWN_DEFAULT_CATEGORY)); - - long defaultGroupId = Context.getConfig().getLong(Keys.DATABASE_REGISTER_UNKNOWN_DEFAULT_GROUP_ID); - if (defaultGroupId != 0) { - device.setGroupId(defaultGroupId); - } - - try { - addItem(device); - - LOGGER.info("Automatically registered device " + uniqueId); - - if (defaultGroupId != 0) { - Context.getPermissionsManager().refreshDeviceAndGroupPermissions(); - } - - return device; - } catch (StorageException e) { - LOGGER.warn("Automatic device registration error", e); - return null; - } - } - public void updateDeviceCache(boolean force) { long lastUpdate = devicesLastUpdate.get(); if ((force || System.currentTimeMillis() - lastUpdate > dataRefreshDelay) @@ -316,35 +288,6 @@ public class DeviceManager extends BaseObjectManager implements Identity return result != null ? (String) result : defaultValue; } - @Override - public int lookupAttributeInteger( - long deviceId, String attributeName, int defaultValue, boolean lookupServer, boolean lookupConfig) { - Object result = lookupAttribute(deviceId, attributeName, lookupServer, lookupConfig); - if (result != null) { - return result instanceof String ? Integer.parseInt((String) result) : ((Number) result).intValue(); - } - return defaultValue; - } - - @Override - public long lookupAttributeLong( - long deviceId, String attributeName, long defaultValue, boolean lookupServer, boolean lookupConfig) { - Object result = lookupAttribute(deviceId, attributeName, lookupServer, lookupConfig); - if (result != null) { - return result instanceof String ? Long.parseLong((String) result) : ((Number) result).longValue(); - } - return defaultValue; - } - - public double lookupAttributeDouble( - long deviceId, String attributeName, double defaultValue, boolean lookupServer, boolean lookupConfig) { - Object result = lookupAttribute(deviceId, attributeName, lookupServer, lookupConfig); - if (result != null) { - return result instanceof String ? Double.parseDouble((String) result) : ((Number) result).doubleValue(); - } - return defaultValue; - } - private Object lookupAttribute(long deviceId, String attributeName, boolean lookupServer, boolean lookupConfig) { Object result = null; Device device = getById(deviceId); diff --git a/src/main/java/org/traccar/database/IdentityManager.java b/src/main/java/org/traccar/database/IdentityManager.java index ee386fdfd..10a64ebd9 100644 --- a/src/main/java/org/traccar/database/IdentityManager.java +++ b/src/main/java/org/traccar/database/IdentityManager.java @@ -20,8 +20,6 @@ import org.traccar.model.Position; public interface IdentityManager { - Device addUnknownDevice(String uniqueId); - Device getById(long id); Device getByUniqueId(String uniqueId) throws Exception; @@ -38,13 +36,4 @@ public interface IdentityManager { String lookupAttributeString( long deviceId, String attributeName, String defaultValue, boolean lookupServer, boolean lookupConfig); - int lookupAttributeInteger( - long deviceId, String attributeName, int defaultValue, boolean lookupServer, boolean lookupConfig); - - long lookupAttributeLong( - long deviceId, String attributeName, long defaultValue, boolean lookupServer, boolean lookupConfig); - - double lookupAttributeDouble( - long deviceId, String attributeName, double defaultValue, boolean lookupServer, boolean lookupConfig); - } diff --git a/src/main/java/org/traccar/handler/FilterHandler.java b/src/main/java/org/traccar/handler/FilterHandler.java index 0511ec98b..00cbf92a0 100644 --- a/src/main/java/org/traccar/handler/FilterHandler.java +++ b/src/main/java/org/traccar/handler/FilterHandler.java @@ -21,11 +21,18 @@ import org.slf4j.LoggerFactory; import org.traccar.BaseDataHandler; import org.traccar.config.Config; import org.traccar.config.Keys; -import org.traccar.database.DataManager; -import org.traccar.database.IdentityManager; import org.traccar.helper.UnitsConverter; +import org.traccar.helper.model.AttributeUtil; +import org.traccar.model.Device; import org.traccar.model.Position; +import org.traccar.session.cache.CacheManager; +import org.traccar.storage.Storage; import org.traccar.storage.StorageException; +import org.traccar.storage.query.Columns; +import org.traccar.storage.query.Condition; +import org.traccar.storage.query.Limit; +import org.traccar.storage.query.Order; +import org.traccar.storage.query.Request; import javax.inject.Inject; import java.util.Date; @@ -50,11 +57,11 @@ public class FilterHandler extends BaseDataHandler { private final long skipLimit; private final boolean skipAttributes; - private final IdentityManager identityManager; - private final DataManager dataManager; + private final CacheManager cacheManager; + private final Storage storage; @Inject - public FilterHandler(Config config, IdentityManager identityManager, DataManager dataManager) { + public FilterHandler(Config config, CacheManager cacheManager, Storage storage) { enabled = config.getBoolean(Keys.FILTER_ENABLE); filterInvalid = config.getBoolean(Keys.FILTER_INVALID); filterZero = config.getBoolean(Keys.FILTER_ZERO); @@ -69,8 +76,18 @@ public class FilterHandler extends BaseDataHandler { filterRelative = config.getBoolean(Keys.FILTER_RELATIVE); skipLimit = config.getLong(Keys.FILTER_SKIP_LIMIT) * 1000; skipAttributes = config.getBoolean(Keys.FILTER_SKIP_ATTRIBUTES_ENABLE); - this.identityManager = identityManager; - this.dataManager = dataManager; + this.cacheManager = cacheManager; + this.storage = storage; + } + + private Position getPrecedingPosition(long deviceId, Date date) throws StorageException { + return storage.getObject(Position.class, new Request( + new Columns.All(), + new Condition.And( + new Condition.Equals("deviceId", "deviceId", deviceId), + new Condition.Compare("fixTime", "<=", "time", date)), + new Order(true, "fixTime"), + new Limit(1))); } private boolean filterInvalid(Position position) { @@ -144,9 +161,8 @@ public class FilterHandler extends BaseDataHandler { private boolean skipAttributes(Position position) { if (skipAttributes) { - String attributesString = identityManager.lookupAttributeString( - position.getDeviceId(), "filter.skipAttributes", "", false, true); - for (String attribute : attributesString.split("[ ,]")) { + String string = AttributeUtil.lookup(cacheManager, Keys.FILTER_SKIP_ATTRIBUTES, position.getDeviceId()); + for (String attribute : string.split("[ ,]")) { if (position.getAttributes().containsKey(attribute)) { return true; } @@ -183,13 +199,13 @@ public class FilterHandler extends BaseDataHandler { if (filterRelative) { try { Date newFixTime = position.getFixTime(); - preceding = dataManager.getPrecedingPosition(deviceId, newFixTime); + preceding = getPrecedingPosition(deviceId, newFixTime); } catch (StorageException e) { LOGGER.warn("Error retrieving preceding position; fallbacking to last received position.", e); - preceding = getLastReceivedPosition(deviceId); + preceding = cacheManager.getPosition(deviceId); } } else { - preceding = getLastReceivedPosition(deviceId); + preceding = cacheManager.getPosition(deviceId); } if (filterDuplicate(position, preceding) && !skipLimit(position, preceding) && !skipAttributes(position)) { filterType.append("Duplicate "); @@ -209,7 +225,7 @@ public class FilterHandler extends BaseDataHandler { } if (filterType.length() > 0) { - String uniqueId = identityManager.getById(deviceId).getUniqueId(); + String uniqueId = cacheManager.getObject(Device.class, deviceId).getUniqueId(); LOGGER.info("Position filtered by {}filters from device: {}", filterType, uniqueId); return true; } @@ -217,10 +233,6 @@ public class FilterHandler extends BaseDataHandler { return false; } - private Position getLastReceivedPosition(long deviceId) { - return identityManager.getLastPosition(deviceId); - } - @Override protected Position handlePosition(Position position) { if (enabled && filter(position)) { diff --git a/src/main/java/org/traccar/handler/HemisphereHandler.java b/src/main/java/org/traccar/handler/HemisphereHandler.java index 2e3ed9d91..f760457a3 100644 --- a/src/main/java/org/traccar/handler/HemisphereHandler.java +++ b/src/main/java/org/traccar/handler/HemisphereHandler.java @@ -39,7 +39,7 @@ public class HemisphereHandler extends BaseDataHandler { latitudeFactor = -1; } } - String longitudeHemisphere = config.getString(Keys.LOCATION_LATITUDE_HEMISPHERE); + String longitudeHemisphere = config.getString(Keys.LOCATION_LONGITUDE_HEMISPHERE); if (longitudeHemisphere != null) { if (longitudeHemisphere.equalsIgnoreCase("E")) { longitudeFactor = 1; diff --git a/src/main/java/org/traccar/handler/events/FuelDropEventHandler.java b/src/main/java/org/traccar/handler/events/FuelDropEventHandler.java index 7849abff9..2d105af3e 100644 --- a/src/main/java/org/traccar/handler/events/FuelDropEventHandler.java +++ b/src/main/java/org/traccar/handler/events/FuelDropEventHandler.java @@ -16,10 +16,13 @@ package org.traccar.handler.events; import io.netty.channel.ChannelHandler; -import org.traccar.database.IdentityManager; +import org.traccar.config.Keys; +import org.traccar.helper.model.AttributeUtil; +import org.traccar.helper.model.PositionUtil; import org.traccar.model.Device; import org.traccar.model.Event; import org.traccar.model.Position; +import org.traccar.session.cache.CacheManager; import javax.inject.Inject; import java.util.Collections; @@ -28,31 +31,28 @@ import java.util.Map; @ChannelHandler.Sharable public class FuelDropEventHandler extends BaseEventHandler { - public static final String ATTRIBUTE_FUEL_DROP_THRESHOLD = "fuelDropThreshold"; - - private final IdentityManager identityManager; + private final CacheManager cacheManager; @Inject - public FuelDropEventHandler(IdentityManager identityManager) { - this.identityManager = identityManager; + public FuelDropEventHandler(CacheManager cacheManager) { + this.cacheManager = cacheManager; } @Override protected Map analyzePosition(Position position) { - Device device = identityManager.getById(position.getDeviceId()); + Device device = cacheManager.getObject(Device.class, position.getDeviceId()); if (device == null) { return null; } - if (!identityManager.isLatestPosition(position)) { + if (!PositionUtil.isLatest(cacheManager, position)) { return null; } - double fuelDropThreshold = identityManager - .lookupAttributeDouble(device.getId(), ATTRIBUTE_FUEL_DROP_THRESHOLD, 0, true, false); - + double fuelDropThreshold = AttributeUtil.lookup( + cacheManager, Keys.EVENT_FUEL_DROP_THRESHOLD, position.getDeviceId()); if (fuelDropThreshold > 0) { - Position lastPosition = identityManager.getLastPosition(position.getDeviceId()); + Position lastPosition = cacheManager.getPosition(position.getDeviceId()); if (position.getAttributes().containsKey(Position.KEY_FUEL_LEVEL) && lastPosition != null && lastPosition.getAttributes().containsKey(Position.KEY_FUEL_LEVEL)) { @@ -60,7 +60,6 @@ public class FuelDropEventHandler extends BaseEventHandler { - position.getDouble(Position.KEY_FUEL_LEVEL); if (drop >= fuelDropThreshold) { Event event = new Event(Event.TYPE_DEVICE_FUEL_DROP, position); - event.set(ATTRIBUTE_FUEL_DROP_THRESHOLD, fuelDropThreshold); return Collections.singletonMap(event, position); } } diff --git a/src/main/java/org/traccar/handler/events/OverspeedEventHandler.java b/src/main/java/org/traccar/handler/events/OverspeedEventHandler.java index 45bb13be5..6de56d11e 100644 --- a/src/main/java/org/traccar/handler/events/OverspeedEventHandler.java +++ b/src/main/java/org/traccar/handler/events/OverspeedEventHandler.java @@ -23,6 +23,8 @@ import io.netty.channel.ChannelHandler; import org.traccar.config.Config; import org.traccar.config.Keys; import org.traccar.database.DeviceManager; +import org.traccar.helper.model.AttributeUtil; +import org.traccar.helper.model.PositionUtil; import org.traccar.model.Device; import org.traccar.session.DeviceState; import org.traccar.model.Event; @@ -36,7 +38,6 @@ import javax.inject.Inject; public class OverspeedEventHandler extends BaseEventHandler { public static final String ATTRIBUTE_SPEED = "speed"; - public static final String ATTRIBUTE_SPEED_LIMIT = "speedLimit"; private final DeviceManager deviceManager; private final CacheManager cacheManager; @@ -58,7 +59,7 @@ public class OverspeedEventHandler extends BaseEventHandler { Position position = deviceState.getOverspeedPosition(); Event event = new Event(Event.TYPE_DEVICE_OVERSPEED, position); event.set(ATTRIBUTE_SPEED, deviceState.getOverspeedPosition().getSpeed()); - event.set(ATTRIBUTE_SPEED_LIMIT, speedLimit); + event.set(Position.KEY_SPEED_LIMIT, speedLimit); event.setGeofenceId(deviceState.getOverspeedGeofenceId()); deviceState.setOverspeedState(notRepeat); deviceState.setOverspeedPosition(null); @@ -115,15 +116,15 @@ public class OverspeedEventHandler extends BaseEventHandler { protected Map analyzePosition(Position position) { long deviceId = position.getDeviceId(); - Device device = deviceManager.getById(deviceId); + Device device = cacheManager.getObject(Device.class, position.getDeviceId()); if (device == null) { return null; } - if (!deviceManager.isLatestPosition(position) || !position.getValid()) { + if (!PositionUtil.isLatest(cacheManager, position) || !position.getValid()) { return null; } - double speedLimit = deviceManager.lookupAttributeDouble(deviceId, ATTRIBUTE_SPEED_LIMIT, 0, true, false); + double speedLimit = AttributeUtil.lookup(cacheManager, Keys.EVENT_OVERSPEED_LIMIT, deviceId); double positionSpeedLimit = position.getDouble(Position.KEY_SPEED_LIMIT); if (positionSpeedLimit > 0) { @@ -137,7 +138,7 @@ public class OverspeedEventHandler extends BaseEventHandler { for (long geofenceId : device.getGeofenceIds()) { Geofence geofence = cacheManager.getObject(Geofence.class, geofenceId); if (geofence != null) { - double currentSpeedLimit = geofence.getDouble(ATTRIBUTE_SPEED_LIMIT); + double currentSpeedLimit = geofence.getDouble(Keys.EVENT_OVERSPEED_LIMIT.getKey()); if (currentSpeedLimit > 0 && geofenceSpeedLimit == 0 || preferLowest && currentSpeedLimit < geofenceSpeedLimit || !preferLowest && currentSpeedLimit > geofenceSpeedLimit) { diff --git a/src/main/java/org/traccar/helper/model/AttributeUtil.java b/src/main/java/org/traccar/helper/model/AttributeUtil.java new file mode 100644 index 000000000..5b3fc1cbe --- /dev/null +++ b/src/main/java/org/traccar/helper/model/AttributeUtil.java @@ -0,0 +1,72 @@ +/* + * Copyright 2022 Anton Tananaev (anton@traccar.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.traccar.helper.model; + +import org.traccar.config.ConfigKey; +import org.traccar.config.KeyType; +import org.traccar.model.Device; +import org.traccar.model.Group; +import org.traccar.session.cache.CacheManager; + +public final class AttributeUtil { + + private AttributeUtil() { + } + + @SuppressWarnings({ "deprecation", "unchecked" }) + public static T lookup(CacheManager cacheManager, ConfigKey key, long deviceId) { + Device device = cacheManager.getObject(Device.class, deviceId); + Object result = device.getAttributes().get(key.getKey()); + long groupId = device.getGroupId(); + while (result == null && groupId > 0) { + Group group = cacheManager.getObject(Group.class, groupId); + if (group != null) { + result = group.getAttributes().get(key.getKey()); + } + } + if (result == null && key.hasType(KeyType.SERVER)) { + result = cacheManager.getServer().getAttributes().get(key.getKey()); + } + if (result == null && key.hasType(KeyType.CONFIG)) { + result = cacheManager.getConfig().getString(key.getKey()); + } + + if (result != null) { + Class valueClass = key.getValueClass(); + if (valueClass.equals(Boolean.class)) { + return (T) (result instanceof String + ? Boolean.parseBoolean((String) result) + : result); + } else if (valueClass.equals(Integer.class)) { + return (T) (Object) (result instanceof String + ? Integer.parseInt((String) result) + : ((Number) result).intValue()); + } else if (valueClass.equals(Long.class)) { + return (T) (Object) (result instanceof String + ? Long.parseLong((String) result) + : ((Number) result).longValue()); + } else if (valueClass.equals(Double.class)) { + return (T) (Object) (result instanceof String + ? Double.parseDouble((String) result) + : ((Number) result).doubleValue()); + } else { + return (T) result; + } + } + return key.getDefaultValue(); + } + +} diff --git a/src/main/java/org/traccar/model/CellTower.java b/src/main/java/org/traccar/model/CellTower.java index af33b1f5c..16a28ea79 100644 --- a/src/main/java/org/traccar/model/CellTower.java +++ b/src/main/java/org/traccar/model/CellTower.java @@ -38,7 +38,7 @@ public class CellTower { } public static CellTower fromLacCid(Config config, int lac, long cid) { - return from(config.getInteger(Keys.GEOLOCATION_MCC), config.getInteger(Keys.GEOLOCATION_MCC), lac, cid); + return from(config.getInteger(Keys.GEOLOCATION_MCC), config.getInteger(Keys.GEOLOCATION_MNC), lac, cid); } public static CellTower fromCidLac(Config config, long cid, int lac) { diff --git a/src/main/java/org/traccar/protocol/StarLinkProtocolDecoder.java b/src/main/java/org/traccar/protocol/StarLinkProtocolDecoder.java index 0ff668fa8..aa23bfac5 100644 --- a/src/main/java/org/traccar/protocol/StarLinkProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/StarLinkProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2017 - 2021 Anton Tananaev (anton@traccar.org) + * Copyright 2017 - 2022 Anton Tananaev (anton@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -17,6 +17,8 @@ package org.traccar.protocol; import io.netty.channel.Channel; import org.traccar.BaseProtocolDecoder; +import org.traccar.config.Keys; +import org.traccar.helper.model.AttributeUtil; import org.traccar.session.DeviceSession; import org.traccar.Protocol; import org.traccar.helper.DataConverter; @@ -66,8 +68,9 @@ public class StarLinkProtocolDecoder extends BaseProtocolDecoder { } public String[] getFormat(long deviceId) { - return getIdentityManager().lookupAttributeString( - deviceId, getProtocolName() + ".format", format, false, false).split(","); + String value = AttributeUtil.lookup( + getCacheManager(), Keys.PROTOCOL_FORMAT.withPrefix(getProtocolName()), deviceId); + return (value != null ? value : format).split(","); } public void setFormat(String format) { @@ -75,8 +78,9 @@ public class StarLinkProtocolDecoder extends BaseProtocolDecoder { } public DateFormat getDateFormat(long deviceId) { - DateFormat dateFormat = new SimpleDateFormat(getIdentityManager().lookupAttributeString( - deviceId, getProtocolName() + ".dateFormat", this.dateFormat, false, false)); + String value = AttributeUtil.lookup( + getCacheManager(), Keys.PROTOCOL_DATE_FORMAT.withPrefix(getProtocolName()), deviceId); + DateFormat dateFormat = new SimpleDateFormat(value != null ? value : this.dateFormat); dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); return dateFormat; } diff --git a/src/main/java/org/traccar/protocol/SuntechProtocolDecoder.java b/src/main/java/org/traccar/protocol/SuntechProtocolDecoder.java index 6340def86..44ba1da38 100644 --- a/src/main/java/org/traccar/protocol/SuntechProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/SuntechProtocolDecoder.java @@ -20,6 +20,8 @@ import io.netty.buffer.ByteBufUtil; import io.netty.buffer.Unpooled; import io.netty.channel.Channel; import org.traccar.BaseProtocolDecoder; +import org.traccar.config.Keys; +import org.traccar.helper.model.AttributeUtil; import org.traccar.session.DeviceSession; import org.traccar.Protocol; import org.traccar.helper.BitUtil; @@ -71,8 +73,8 @@ public class SuntechProtocolDecoder extends BaseProtocolDecoder { } public int getProtocolType(long deviceId) { - return getIdentityManager().lookupAttributeInteger( - deviceId, getProtocolName() + ".protocolType", protocolType, false, true); + Integer value = AttributeUtil.lookup(getCacheManager(), Keys.PROTOCOL_TYPE, deviceId); + return value != null ? value : protocolType; } public void setHbm(boolean hbm) { @@ -80,8 +82,8 @@ public class SuntechProtocolDecoder extends BaseProtocolDecoder { } public boolean isHbm(long deviceId) { - return getIdentityManager().lookupAttributeBoolean( - deviceId, getProtocolName() + ".hbm", hbm, false, true); + Boolean value = AttributeUtil.lookup(getCacheManager(), Keys.PROTOCOL_HBM, deviceId); + return value != null ? value : hbm; } public void setIncludeAdc(boolean includeAdc) { @@ -89,8 +91,9 @@ public class SuntechProtocolDecoder extends BaseProtocolDecoder { } public boolean isIncludeAdc(long deviceId) { - return getIdentityManager().lookupAttributeBoolean( - deviceId, getProtocolName() + ".includeAdc", includeAdc, false, true); + Boolean value = AttributeUtil.lookup( + getCacheManager(), Keys.PROTOCOL_INCLUDE_ADC.withPrefix(getProtocolName()), deviceId); + return value != null ? value : includeAdc; } public void setIncludeRpm(boolean includeRpm) { @@ -98,8 +101,9 @@ public class SuntechProtocolDecoder extends BaseProtocolDecoder { } public boolean isIncludeRpm(long deviceId) { - return getIdentityManager().lookupAttributeBoolean( - deviceId, getProtocolName() + ".includeRpm", includeRpm, false, true); + Boolean value = AttributeUtil.lookup( + getCacheManager(), Keys.PROTOCOL_INCLUDE_RPM.withPrefix(getProtocolName()), deviceId); + return value != null ? value : includeRpm; } public void setIncludeTemp(boolean includeTemp) { @@ -107,8 +111,9 @@ public class SuntechProtocolDecoder extends BaseProtocolDecoder { } public boolean isIncludeTemp(long deviceId) { - return getIdentityManager().lookupAttributeBoolean( - deviceId, getProtocolName() + ".includeTemp", includeTemp, false, true); + Boolean value = AttributeUtil.lookup( + getCacheManager(), Keys.PROTOCOL_INCLUDE_TEMPERATURE.withPrefix(getProtocolName()), deviceId); + return value != null ? value : includeTemp; } private Position decode9( diff --git a/src/main/java/org/traccar/session/ConnectionManager.java b/src/main/java/org/traccar/session/ConnectionManager.java index 6d5fefa75..3fa467b57 100644 --- a/src/main/java/org/traccar/session/ConnectionManager.java +++ b/src/main/java/org/traccar/session/ConnectionManager.java @@ -28,6 +28,7 @@ import org.traccar.config.Keys; import org.traccar.database.NotificationManager; import org.traccar.handler.events.MotionEventHandler; import org.traccar.handler.events.OverspeedEventHandler; +import org.traccar.helper.model.AttributeUtil; import org.traccar.model.Device; import org.traccar.model.Event; import org.traccar.model.Position; @@ -279,9 +280,9 @@ public class ConnectionManager { result.putAll(event); } + double speedLimit = AttributeUtil.lookup(cacheManager, Keys.EVENT_OVERSPEED_LIMIT, deviceId); event = Main.getInjector().getInstance(OverspeedEventHandler.class) - .updateOverspeedState(deviceState, Context.getDeviceManager(). - lookupAttributeDouble(deviceId, OverspeedEventHandler.ATTRIBUTE_SPEED_LIMIT, 0, true, false)); + .updateOverspeedState(deviceState, speedLimit); if (event != null) { result.putAll(event); } diff --git a/src/main/java/org/traccar/session/cache/CacheManager.java b/src/main/java/org/traccar/session/cache/CacheManager.java index 896df83e7..87384f746 100644 --- a/src/main/java/org/traccar/session/cache/CacheManager.java +++ b/src/main/java/org/traccar/session/cache/CacheManager.java @@ -74,6 +74,10 @@ public class CacheManager { invalidateUsers(); } + public Config getConfig() { + return config; + } + public T getObject(Class clazz, long id) { try { lock.readLock().lock(); diff --git a/src/test/java/org/traccar/BaseTest.java b/src/test/java/org/traccar/BaseTest.java index 1652a6694..add423cdd 100644 --- a/src/test/java/org/traccar/BaseTest.java +++ b/src/test/java/org/traccar/BaseTest.java @@ -9,6 +9,7 @@ import org.traccar.database.StatisticsManager; import org.traccar.model.Device; import org.traccar.session.ConnectionManager; import org.traccar.session.DeviceSession; +import org.traccar.session.cache.CacheManager; import java.net.SocketAddress; import java.util.HashSet; @@ -16,6 +17,7 @@ import java.util.HashSet; import static org.mockito.ArgumentMatchers.anyBoolean; import static org.mockito.ArgumentMatchers.anyInt; import static org.mockito.ArgumentMatchers.anyLong; +import static org.mockito.ArgumentMatchers.eq; import static org.mockito.Mockito.any; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -23,19 +25,18 @@ import static org.mockito.Mockito.when; public class BaseTest { protected T inject(T decoder) throws Exception { - decoder.setConfig(new Config()); + var config = new Config(); + decoder.setConfig(config); var device = mock(Device.class); when(device.getId()).thenReturn(1L); var identityManager = mock(IdentityManager.class); when(identityManager.getById(anyLong())).thenReturn(device); when(identityManager.getByUniqueId(any())).thenReturn(device); - when(identityManager.lookupAttributeBoolean(anyLong(), any(), anyBoolean(), anyBoolean(), anyBoolean())) - .thenAnswer(invocation -> invocation.getArguments()[2]); - when(identityManager.lookupAttributeString(anyLong(), any(), any(), anyBoolean(), anyBoolean())) - .thenAnswer(invocation -> invocation.getArguments()[2]); - when(identityManager.lookupAttributeInteger(anyLong(), any(), anyInt(), anyBoolean(), anyBoolean())) - .thenAnswer(invocation -> invocation.getArguments()[2]); decoder.setIdentityManager(identityManager); + var cacheManager = mock(CacheManager.class); + when(cacheManager.getConfig()).thenReturn(config); + when(cacheManager.getObject(eq(Device.class), anyLong())).thenReturn(device); + decoder.setCacheManager(cacheManager); var connectionManager = mock(ConnectionManager.class); var uniqueIdsProvided = new HashSet(); when(connectionManager.getDeviceSession(any(), any(), any(), any())).thenAnswer(invocation -> { diff --git a/src/test/java/org/traccar/handler/FilterHandlerTest.java b/src/test/java/org/traccar/handler/FilterHandlerTest.java index 10d6768cf..a1102da88 100644 --- a/src/test/java/org/traccar/handler/FilterHandlerTest.java +++ b/src/test/java/org/traccar/handler/FilterHandlerTest.java @@ -5,15 +5,16 @@ import org.junit.Test; import org.traccar.BaseTest; import org.traccar.config.Config; import org.traccar.config.Keys; -import org.traccar.database.DataManager; -import org.traccar.database.IdentityManager; import org.traccar.model.Device; import org.traccar.model.Position; +import org.traccar.session.cache.CacheManager; import java.util.Date; import static org.junit.Assert.assertNotNull; import static org.junit.Assert.assertNull; +import static org.mockito.ArgumentMatchers.any; +import static org.mockito.ArgumentMatchers.anyLong; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; @@ -26,9 +27,9 @@ public class FilterHandlerTest extends BaseTest { public void passingHandler() { var config = mock(Config.class); when(config.getBoolean(Keys.FILTER_ENABLE)).thenReturn(true); - var identityManager = mock(IdentityManager.class); - var dataManager = mock(DataManager.class); - passingHandler = new FilterHandler(config, identityManager, dataManager); + var cacheManager = mock(CacheManager.class); + when(cacheManager.getConfig()).thenReturn(config); + passingHandler = new FilterHandler(config, cacheManager, null); } @Before @@ -45,11 +46,11 @@ public class FilterHandlerTest extends BaseTest { when(config.getInteger(Keys.FILTER_MAX_SPEED)).thenReturn(500); when(config.getLong(Keys.FILTER_SKIP_LIMIT)).thenReturn(10L); when(config.getBoolean(Keys.FILTER_SKIP_ATTRIBUTES_ENABLE)).thenReturn(true); - var identityManager = mock(IdentityManager.class); - when(identityManager.lookupAttributeString(0, "filter.skipAttributes", "", false, true)).thenReturn("alarm,result"); - when(identityManager.getById(0)).thenReturn(mock(Device.class)); - var dataManager = mock(DataManager.class); - filteringHandler = new FilterHandler(config, identityManager, dataManager); + when(config.getString(Keys.FILTER_SKIP_ATTRIBUTES.getKey())).thenReturn("alarm,result"); + var cacheManager = mock(CacheManager.class); + when(cacheManager.getConfig()).thenReturn(config); + when(cacheManager.getObject(any(), anyLong())).thenReturn(mock(Device.class)); + filteringHandler = new FilterHandler(config, cacheManager, null); } private Position createPosition(Date time, boolean valid, double speed) { diff --git a/src/test/java/org/traccar/handler/events/OverspeedEventHandlerTest.java b/src/test/java/org/traccar/handler/events/OverspeedEventHandlerTest.java index 9e86031e8..46e142935 100644 --- a/src/test/java/org/traccar/handler/events/OverspeedEventHandlerTest.java +++ b/src/test/java/org/traccar/handler/events/OverspeedEventHandlerTest.java @@ -61,7 +61,7 @@ public class OverspeedEventHandlerTest extends BaseTest { Event event = events.keySet().iterator().next(); assertEquals(Event.TYPE_DEVICE_OVERSPEED, event.getType()); assertEquals(50, event.getDouble("speed"), 0.1); - assertEquals(40, event.getDouble(OverspeedEventHandler.ATTRIBUTE_SPEED_LIMIT), 0.1); + assertEquals(40, event.getDouble("speedLimit"), 0.1); assertEquals(geofenceId, event.getGeofenceId()); assertEquals(notRepeat, deviceState.getOverspeedState()); -- cgit v1.2.3 From 22bd8bcc80b850dc2308be50cf2886c39b0655da Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 18 Jun 2022 10:08:52 -0700 Subject: Refactor device password --- src/main/java/org/traccar/BaseProtocolEncoder.java | 20 +++++++++++++++++--- src/main/java/org/traccar/config/Keys.java | 7 +++++++ .../java/org/traccar/database/DeviceManager.java | 18 ------------------ .../java/org/traccar/database/IdentityManager.java | 2 -- .../org/traccar/helper/model/AttributeUtil.java | 21 +++++++++++++++++++++ .../org/traccar/protocol/Gt06ProtocolEncoder.java | 5 +++-- .../org/traccar/protocol/LaipacProtocolDecoder.java | 5 +++-- src/test/java/org/traccar/BaseTest.java | 6 ++++-- 8 files changed, 55 insertions(+), 29 deletions(-) (limited to 'src/main/java/org/traccar/helper') diff --git a/src/main/java/org/traccar/BaseProtocolEncoder.java b/src/main/java/org/traccar/BaseProtocolEncoder.java index 10b780fc8..612d91c57 100644 --- a/src/main/java/org/traccar/BaseProtocolEncoder.java +++ b/src/main/java/org/traccar/BaseProtocolEncoder.java @@ -15,7 +15,6 @@ */ package org.traccar; -import com.google.inject.Inject; import io.netty.channel.Channel; import io.netty.channel.ChannelHandlerContext; import io.netty.channel.ChannelOutboundHandlerAdapter; @@ -24,7 +23,11 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.traccar.database.IdentityManager; import org.traccar.helper.NetworkUtil; +import org.traccar.helper.model.AttributeUtil; import org.traccar.model.Command; +import org.traccar.session.cache.CacheManager; + +import javax.inject.Inject; public abstract class BaseProtocolEncoder extends ChannelOutboundHandlerAdapter { @@ -34,12 +37,23 @@ public abstract class BaseProtocolEncoder extends ChannelOutboundHandlerAdapter private final Protocol protocol; + private CacheManager cacheManager; + private IdentityManager identityManager; public BaseProtocolEncoder(Protocol protocol) { this.protocol = protocol; } + public CacheManager getCacheManager() { + return cacheManager; + } + + @Inject + public void setCacheManager(CacheManager cacheManager) { + this.cacheManager = cacheManager; + } + public IdentityManager getIdentityManager() { return identityManager; } @@ -59,8 +73,8 @@ public abstract class BaseProtocolEncoder extends ChannelOutboundHandlerAdapter protected void initDevicePassword(Command command, String defaultPassword) { if (!command.getAttributes().containsKey(Command.KEY_DEVICE_PASSWORD)) { - String password = identityManager - .getDevicePassword(command.getDeviceId(), getProtocolName(), defaultPassword); + String password = AttributeUtil.getDevicePassword( + cacheManager, command.getDeviceId(), getProtocolName(), defaultPassword); command.set(Command.KEY_DEVICE_PASSWORD, password); } } diff --git a/src/main/java/org/traccar/config/Keys.java b/src/main/java/org/traccar/config/Keys.java index 465751d38..410947079 100644 --- a/src/main/java/org/traccar/config/Keys.java +++ b/src/main/java/org/traccar/config/Keys.java @@ -69,6 +69,13 @@ public final class Keys { ".timeout", List.of(KeyType.CONFIG)); + /** + * Device password. Commonly used in some protocol for sending commands. + */ + public static final ConfigKey DEVICE_PASSWORD = new StringConfigKey( + "devicePassword", + List.of(KeyType.DEVICE)); + /** * Device password. Commonly used in some protocol for sending commands. */ diff --git a/src/main/java/org/traccar/database/DeviceManager.java b/src/main/java/org/traccar/database/DeviceManager.java index a3e04f920..eee19c4c2 100644 --- a/src/main/java/org/traccar/database/DeviceManager.java +++ b/src/main/java/org/traccar/database/DeviceManager.java @@ -99,24 +99,6 @@ public class DeviceManager extends BaseObjectManager implements Identity } } - @Override - public String getDevicePassword(long id, String protocol, String defaultPassword) { - - String password = lookupAttributeString(id, Command.KEY_DEVICE_PASSWORD, null, false, false); - if (password != null) { - return password; - } - - if (protocol != null) { - password = Context.getConfig().getString(Keys.PROTOCOL_DEVICE_PASSWORD.withPrefix(protocol)); - if (password != null) { - return password; - } - } - - return defaultPassword; - } - @Override public Set getAllItems() { Set result = super.getAllItems(); diff --git a/src/main/java/org/traccar/database/IdentityManager.java b/src/main/java/org/traccar/database/IdentityManager.java index 10a64ebd9..1897c637f 100644 --- a/src/main/java/org/traccar/database/IdentityManager.java +++ b/src/main/java/org/traccar/database/IdentityManager.java @@ -24,8 +24,6 @@ public interface IdentityManager { Device getByUniqueId(String uniqueId) throws Exception; - String getDevicePassword(long id, String protocol, String defaultPassword); - Position getLastPosition(long deviceId); boolean isLatestPosition(Position position); diff --git a/src/main/java/org/traccar/helper/model/AttributeUtil.java b/src/main/java/org/traccar/helper/model/AttributeUtil.java index 5b3fc1cbe..225089d5c 100644 --- a/src/main/java/org/traccar/helper/model/AttributeUtil.java +++ b/src/main/java/org/traccar/helper/model/AttributeUtil.java @@ -15,8 +15,11 @@ */ package org.traccar.helper.model; +import org.traccar.Context; import org.traccar.config.ConfigKey; import org.traccar.config.KeyType; +import org.traccar.config.Keys; +import org.traccar.model.Command; import org.traccar.model.Device; import org.traccar.model.Group; import org.traccar.session.cache.CacheManager; @@ -69,4 +72,22 @@ public final class AttributeUtil { return key.getDefaultValue(); } + public static String getDevicePassword( + CacheManager cacheManager, long deviceId, String protocol, String defaultPassword) { + + String password = lookup(cacheManager, Keys.DEVICE_PASSWORD, deviceId); + if (password != null) { + return password; + } + + if (protocol != null) { + password = cacheManager.getConfig().getString(Keys.PROTOCOL_DEVICE_PASSWORD.withPrefix(protocol)); + if (password != null) { + return password; + } + } + + return defaultPassword; + } + } diff --git a/src/main/java/org/traccar/protocol/Gt06ProtocolEncoder.java b/src/main/java/org/traccar/protocol/Gt06ProtocolEncoder.java index 3ed828fc7..569f4a809 100644 --- a/src/main/java/org/traccar/protocol/Gt06ProtocolEncoder.java +++ b/src/main/java/org/traccar/protocol/Gt06ProtocolEncoder.java @@ -20,6 +20,7 @@ import io.netty.buffer.Unpooled; import org.traccar.BaseProtocolEncoder; import org.traccar.Protocol; import org.traccar.helper.Checksum; +import org.traccar.helper.model.AttributeUtil; import org.traccar.model.Command; import java.nio.charset.StandardCharsets; @@ -68,8 +69,8 @@ public class Gt06ProtocolEncoder extends BaseProtocolEncoder { boolean alternative = getIdentityManager().lookupAttributeBoolean( command.getDeviceId(), getProtocolName() + ".alternative", false, false, true); - String password = getIdentityManager() - .getDevicePassword(command.getDeviceId(), getProtocolName(), "123456"); + String password = AttributeUtil.getDevicePassword( + getCacheManager(), command.getDeviceId(), getProtocolName(), "123456"); switch (command.getType()) { case Command.TYPE_ENGINE_STOP: diff --git a/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java b/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java index c55c0624d..e9570ee11 100644 --- a/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/LaipacProtocolDecoder.java @@ -17,6 +17,7 @@ package org.traccar.protocol; import io.netty.channel.Channel; import org.traccar.BaseProtocolDecoder; +import org.traccar.helper.model.AttributeUtil; import org.traccar.session.DeviceSession; import org.traccar.NetworkMessage; import org.traccar.Protocol; @@ -252,8 +253,8 @@ public class LaipacProtocolDecoder extends BaseProtocolDecoder { sendAcknowledge(status, event, checksum, channel, remoteAddress); - String devicePassword = getIdentityManager() - .getDevicePassword(deviceSession.getDeviceId(), getProtocolName(), DEFAULT_DEVICE_PASSWORD); + String devicePassword = AttributeUtil.getDevicePassword( + getCacheManager(), deviceSession.getDeviceId(), getProtocolName(), DEFAULT_DEVICE_PASSWORD); sendEventResponse(event, devicePassword, channel, remoteAddress); } diff --git a/src/test/java/org/traccar/BaseTest.java b/src/test/java/org/traccar/BaseTest.java index add423cdd..54035553f 100644 --- a/src/test/java/org/traccar/BaseTest.java +++ b/src/test/java/org/traccar/BaseTest.java @@ -66,9 +66,11 @@ public class BaseTest { var device = mock(Device.class); when(device.getId()).thenReturn(1L); when(device.getUniqueId()).thenReturn("123456789012345"); + var cacheManager = mock(CacheManager.class); + when(cacheManager.getConfig()).thenReturn(mock(Config.class)); + when(cacheManager.getObject(eq(Device.class), anyLong())).thenReturn(device); + encoder.setCacheManager(cacheManager); var identityManager = mock(IdentityManager.class); - when(identityManager.getDevicePassword(anyLong(), any(), any())) - .thenAnswer(invocation -> invocation.getArguments()[2]); when(identityManager.getById(anyLong())).thenReturn(device); when(identityManager.getByUniqueId(any())).thenReturn(device); encoder.setIdentityManager(identityManager); -- cgit v1.2.3 From 182656b6dc1fb5d167bb752c16ecf633add001a8 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 18 Jun 2022 10:37:21 -0700 Subject: Remove unused code --- src/main/java/org/traccar/Context.java | 2 - .../org/traccar/database/BaseObjectManager.java | 4 -- .../java/org/traccar/database/DeviceManager.java | 74 +--------------------- .../java/org/traccar/database/IdentityManager.java | 2 - .../org/traccar/helper/model/AttributeUtil.java | 2 - src/test/java/org/traccar/BaseTest.java | 2 - 6 files changed, 2 insertions(+), 84 deletions(-) (limited to 'src/main/java/org/traccar/helper') diff --git a/src/main/java/org/traccar/Context.java b/src/main/java/org/traccar/Context.java index 9e8e3c521..854af97c0 100644 --- a/src/main/java/org/traccar/Context.java +++ b/src/main/java/org/traccar/Context.java @@ -25,7 +25,6 @@ import org.traccar.helper.Log; import org.traccar.model.BaseModel; import org.traccar.model.Device; import org.traccar.session.ConnectionManager; -import org.traccar.session.cache.CacheManager; import org.traccar.storage.Storage; public final class Context { @@ -70,7 +69,6 @@ public final class Context { deviceManager = new DeviceManager( config, - Main.getInjector().getInstance(CacheManager.class), Main.getInjector().getInstance(DataManager.class), Main.getInjector().getInstance(ConnectionManager.class)); diff --git a/src/main/java/org/traccar/database/BaseObjectManager.java b/src/main/java/org/traccar/database/BaseObjectManager.java index dd8b3bae4..c94053985 100644 --- a/src/main/java/org/traccar/database/BaseObjectManager.java +++ b/src/main/java/org/traccar/database/BaseObjectManager.java @@ -67,10 +67,6 @@ public class BaseObjectManager { return dataManager; } - protected final Class getBaseClass() { - return baseClass; - } - public T getById(long itemId) { try { readLock(); diff --git a/src/main/java/org/traccar/database/DeviceManager.java b/src/main/java/org/traccar/database/DeviceManager.java index 86334ede8..841915f1c 100644 --- a/src/main/java/org/traccar/database/DeviceManager.java +++ b/src/main/java/org/traccar/database/DeviceManager.java @@ -20,14 +20,10 @@ import org.slf4j.LoggerFactory; import org.traccar.Context; import org.traccar.config.Config; import org.traccar.config.Keys; -import org.traccar.model.Command; import org.traccar.model.Device; -import org.traccar.model.Group; import org.traccar.model.Position; -import org.traccar.model.Server; import org.traccar.session.ConnectionManager; import org.traccar.session.DeviceState; -import org.traccar.session.cache.CacheManager; import org.traccar.storage.StorageException; import java.util.Collection; @@ -43,12 +39,9 @@ public class DeviceManager extends BaseObjectManager implements Identity private static final Logger LOGGER = LoggerFactory.getLogger(DeviceManager.class); - private final Config config; - private final CacheManager cacheManager; private final ConnectionManager connectionManager; private final long dataRefreshDelay; - private Map devicesByUniqueId; private final AtomicLong devicesLastUpdate = new AtomicLong(); private final Map positions = new ConcurrentHashMap<>(); @@ -56,19 +49,9 @@ public class DeviceManager extends BaseObjectManager implements Identity private final Map deviceStates = new ConcurrentHashMap<>(); public DeviceManager( - Config config, CacheManager cacheManager, DataManager dataManager, ConnectionManager connectionManager) { + Config config, DataManager dataManager, ConnectionManager connectionManager) { super(dataManager, Device.class); - this.config = config; - this.cacheManager = cacheManager; this.connectionManager = connectionManager; - try { - writeLock(); - if (devicesByUniqueId == null) { - devicesByUniqueId = new ConcurrentHashMap<>(); - } - } finally { - writeUnlock(); - } dataRefreshDelay = config.getLong(Keys.DATABASE_REFRESH_DELAY) * 1000; refreshLastPositions(); } @@ -81,24 +64,6 @@ public class DeviceManager extends BaseObjectManager implements Identity } } - @Override - public Device getByUniqueId(String uniqueId) { - boolean forceUpdate; - try { - readLock(); - forceUpdate = !devicesByUniqueId.containsKey(uniqueId) && !config.getBoolean(Keys.DATABASE_IGNORE_UNKNOWN); - } finally { - readUnlock(); - } - updateDeviceCache(forceUpdate); - try { - readLock(); - return devicesByUniqueId.get(uniqueId); - } finally { - readUnlock(); - } - } - @Override public Set getAllItems() { Set result = super.getAllItems(); @@ -132,35 +97,6 @@ public class DeviceManager extends BaseObjectManager implements Identity } } - private void addByUniqueId(Device device) { - try { - writeLock(); - if (devicesByUniqueId == null) { - devicesByUniqueId = new ConcurrentHashMap<>(); - } - devicesByUniqueId.put(device.getUniqueId(), device); - } finally { - writeUnlock(); - } - } - - private void removeByUniqueId(String deviceUniqueId) { - try { - writeLock(); - if (devicesByUniqueId != null) { - devicesByUniqueId.remove(deviceUniqueId); - } - } finally { - writeUnlock(); - } - } - - @Override - protected void addNewItem(Device device) { - super.addNewItem(device); - addByUniqueId(device); - } - @Override protected void updateCachedItem(Device device) { Device cachedDevice = getById(device.getId()); @@ -172,20 +108,14 @@ public class DeviceManager extends BaseObjectManager implements Identity cachedDevice.setModel(device.getModel()); cachedDevice.setDisabled(device.getDisabled()); cachedDevice.setAttributes(device.getAttributes()); - if (!device.getUniqueId().equals(cachedDevice.getUniqueId())) { - removeByUniqueId(cachedDevice.getUniqueId()); - cachedDevice.setUniqueId(device.getUniqueId()); - addByUniqueId(cachedDevice); - } + cachedDevice.setUniqueId(device.getUniqueId()); } @Override protected void removeCachedItem(long deviceId) { Device cachedDevice = getById(deviceId); if (cachedDevice != null) { - String deviceUniqueId = cachedDevice.getUniqueId(); super.removeCachedItem(deviceId); - removeByUniqueId(deviceUniqueId); } positions.remove(deviceId); } diff --git a/src/main/java/org/traccar/database/IdentityManager.java b/src/main/java/org/traccar/database/IdentityManager.java index 5ef1c8c5e..b42d4c292 100644 --- a/src/main/java/org/traccar/database/IdentityManager.java +++ b/src/main/java/org/traccar/database/IdentityManager.java @@ -22,8 +22,6 @@ public interface IdentityManager { Device getById(long id); - Device getByUniqueId(String uniqueId) throws Exception; - Position getLastPosition(long deviceId); boolean isLatestPosition(Position position); diff --git a/src/main/java/org/traccar/helper/model/AttributeUtil.java b/src/main/java/org/traccar/helper/model/AttributeUtil.java index 225089d5c..58b922d95 100644 --- a/src/main/java/org/traccar/helper/model/AttributeUtil.java +++ b/src/main/java/org/traccar/helper/model/AttributeUtil.java @@ -15,11 +15,9 @@ */ package org.traccar.helper.model; -import org.traccar.Context; import org.traccar.config.ConfigKey; import org.traccar.config.KeyType; import org.traccar.config.Keys; -import org.traccar.model.Command; import org.traccar.model.Device; import org.traccar.model.Group; import org.traccar.session.cache.CacheManager; diff --git a/src/test/java/org/traccar/BaseTest.java b/src/test/java/org/traccar/BaseTest.java index 54035553f..6db568300 100644 --- a/src/test/java/org/traccar/BaseTest.java +++ b/src/test/java/org/traccar/BaseTest.java @@ -31,7 +31,6 @@ public class BaseTest { when(device.getId()).thenReturn(1L); var identityManager = mock(IdentityManager.class); when(identityManager.getById(anyLong())).thenReturn(device); - when(identityManager.getByUniqueId(any())).thenReturn(device); decoder.setIdentityManager(identityManager); var cacheManager = mock(CacheManager.class); when(cacheManager.getConfig()).thenReturn(config); @@ -72,7 +71,6 @@ public class BaseTest { encoder.setCacheManager(cacheManager); var identityManager = mock(IdentityManager.class); when(identityManager.getById(anyLong())).thenReturn(device); - when(identityManager.getByUniqueId(any())).thenReturn(device); encoder.setIdentityManager(identityManager); return encoder; } -- cgit v1.2.3 From ddbe4d7de6ae7590e2b927066312597efa129393 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 18 Jun 2022 11:08:32 -0700 Subject: Remove positions from manager --- src/main/java/org/traccar/BaseProtocolDecoder.java | 2 +- src/main/java/org/traccar/Context.java | 4 +- src/main/java/org/traccar/MainEventHandler.java | 28 ++++++- src/main/java/org/traccar/MainModule.java | 4 +- src/main/java/org/traccar/api/AsyncSocket.java | 14 +++- .../java/org/traccar/api/AsyncSocketServlet.java | 7 +- .../org/traccar/api/resource/PositionResource.java | 14 +--- .../java/org/traccar/database/DataManager.java | 24 +----- .../java/org/traccar/database/DeviceManager.java | 93 +--------------------- .../java/org/traccar/database/IdentityManager.java | 5 -- .../java/org/traccar/handler/DistanceHandler.java | 10 +-- .../org/traccar/handler/EngineHoursHandler.java | 10 +-- .../java/org/traccar/handler/GeocoderHandler.java | 11 ++- .../traccar/handler/events/AlertEventHandler.java | 10 +-- .../handler/events/BehaviorEventHandler.java | 10 +-- .../traccar/handler/events/DriverEventHandler.java | 18 ++--- .../handler/events/IgnitionEventHandler.java | 15 ++-- .../handler/events/MaintenanceEventHandler.java | 3 +- .../traccar/handler/events/MotionEventHandler.java | 12 +-- .../org/traccar/helper/model/PositionUtil.java | 17 ++++ .../org/traccar/reports/common/ReportUtils.java | 2 +- .../org/traccar/handler/DistanceHandlerTest.java | 4 +- .../handler/events/AlertEventHandlerTest.java | 4 +- .../handler/events/IgnitionEventHandlerTest.java | 4 +- 24 files changed, 122 insertions(+), 203 deletions(-) (limited to 'src/main/java/org/traccar/helper') diff --git a/src/main/java/org/traccar/BaseProtocolDecoder.java b/src/main/java/org/traccar/BaseProtocolDecoder.java index 076b52e96..f7e726f02 100644 --- a/src/main/java/org/traccar/BaseProtocolDecoder.java +++ b/src/main/java/org/traccar/BaseProtocolDecoder.java @@ -156,7 +156,7 @@ public abstract class BaseProtocolDecoder extends ExtendedObjectDecoder { if (position.getDeviceId() != 0) { position.setOutdated(true); - Position last = identityManager.getLastPosition(position.getDeviceId()); + Position last = cacheManager.getPosition(position.getDeviceId()); if (last != null) { position.setFixTime(last.getFixTime()); position.setValid(last.getValid()); diff --git a/src/main/java/org/traccar/Context.java b/src/main/java/org/traccar/Context.java index 854af97c0..c549b20c2 100644 --- a/src/main/java/org/traccar/Context.java +++ b/src/main/java/org/traccar/Context.java @@ -24,7 +24,6 @@ import org.traccar.database.PermissionsManager; import org.traccar.helper.Log; import org.traccar.model.BaseModel; import org.traccar.model.Device; -import org.traccar.session.ConnectionManager; import org.traccar.storage.Storage; public final class Context { @@ -69,8 +68,7 @@ public final class Context { deviceManager = new DeviceManager( config, - Main.getInjector().getInstance(DataManager.class), - Main.getInjector().getInstance(ConnectionManager.class)); + Main.getInjector().getInstance(DataManager.class)); identityManager = deviceManager; diff --git a/src/main/java/org/traccar/MainEventHandler.java b/src/main/java/org/traccar/MainEventHandler.java index 7fff2e13f..e1aee3cc8 100644 --- a/src/main/java/org/traccar/MainEventHandler.java +++ b/src/main/java/org/traccar/MainEventHandler.java @@ -28,10 +28,16 @@ import org.traccar.config.Keys; import org.traccar.database.StatisticsManager; import org.traccar.helper.DateUtil; import org.traccar.helper.NetworkUtil; +import org.traccar.helper.model.PositionUtil; +import org.traccar.model.Device; import org.traccar.model.Position; import org.traccar.session.ConnectionManager; import org.traccar.session.cache.CacheManager; +import org.traccar.storage.Storage; import org.traccar.storage.StorageException; +import org.traccar.storage.query.Columns; +import org.traccar.storage.query.Condition; +import org.traccar.storage.query.Request; import javax.inject.Inject; import java.util.Arrays; @@ -46,10 +52,15 @@ public class MainEventHandler extends ChannelInboundHandlerAdapter { private final Set connectionlessProtocols = new HashSet<>(); private final Set logAttributes = new LinkedHashSet<>(); + private final CacheManager cacheManager; + private final Storage storage; private final ConnectionManager connectionManager; @Inject - public MainEventHandler(Config config, ConnectionManager connectionManager) { + public MainEventHandler( + Config config, CacheManager cacheManager, Storage storage, ConnectionManager connectionManager) { + this.cacheManager = cacheManager; + this.storage = storage; this.connectionManager = connectionManager; String connectionlessProtocolList = config.getString(Keys.STATUS_IGNORE_OFFLINE); if (connectionlessProtocolList != null) { @@ -64,8 +75,19 @@ public class MainEventHandler extends ChannelInboundHandlerAdapter { Position position = (Position) msg; try { - Context.getDeviceManager().updateLatestPosition(position); - Main.getInjector().getInstance(CacheManager.class).updatePosition(position); + if (PositionUtil.isLatest(cacheManager, position)) { + Device device = new Device(); + device.setId(position.getDeviceId()); + device.setPositionId(position.getId()); + storage.updateObject(device, new Request( + new Columns.Include("positionId"), + new Condition.Equals("id", "id"))); + + cacheManager.updatePosition(position); + cacheManager.getObject(Device.class, position.getDeviceId()).setPositionId(position.getId()); + + connectionManager.updatePosition(position); + } } catch (StorageException error) { LOGGER.warn("Failed to update device", error); } diff --git a/src/main/java/org/traccar/MainModule.java b/src/main/java/org/traccar/MainModule.java index a9337a3a2..a7e531808 100644 --- a/src/main/java/org/traccar/MainModule.java +++ b/src/main/java/org/traccar/MainModule.java @@ -252,9 +252,9 @@ public class MainModule extends AbstractModule { @Provides public static GeocoderHandler provideGeocoderHandler( - Config config, @Nullable Geocoder geocoder, IdentityManager identityManager) { + Config config, @Nullable Geocoder geocoder, CacheManager cacheManager) { if (geocoder != null) { - return new GeocoderHandler(config, geocoder, identityManager); + return new GeocoderHandler(config, geocoder, cacheManager); } return null; } diff --git a/src/main/java/org/traccar/api/AsyncSocket.java b/src/main/java/org/traccar/api/AsyncSocket.java index 3239d36c4..40aa68e88 100644 --- a/src/main/java/org/traccar/api/AsyncSocket.java +++ b/src/main/java/org/traccar/api/AsyncSocket.java @@ -21,11 +21,13 @@ import org.eclipse.jetty.websocket.api.Session; import org.eclipse.jetty.websocket.api.WebSocketAdapter; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.traccar.Context; +import org.traccar.helper.model.PositionUtil; import org.traccar.session.ConnectionManager; import org.traccar.model.Device; import org.traccar.model.Event; import org.traccar.model.Position; +import org.traccar.storage.Storage; +import org.traccar.storage.StorageException; import java.util.Collection; import java.util.Collections; @@ -42,11 +44,13 @@ public class AsyncSocket extends WebSocketAdapter implements ConnectionManager.U private final ObjectMapper objectMapper; private final ConnectionManager connectionManager; + private final Storage storage; private final long userId; - public AsyncSocket(ObjectMapper objectMapper, ConnectionManager connectionManager, long userId) { + public AsyncSocket(ObjectMapper objectMapper, ConnectionManager connectionManager, Storage storage, long userId) { this.objectMapper = objectMapper; this.connectionManager = connectionManager; + this.storage = storage; this.userId = userId; } @@ -55,7 +59,11 @@ public class AsyncSocket extends WebSocketAdapter implements ConnectionManager.U super.onWebSocketConnect(session); Map> data = new HashMap<>(); - data.put(KEY_POSITIONS, Context.getDeviceManager().getInitialState(userId)); + try { + data.put(KEY_POSITIONS, PositionUtil.getLatestPositions(storage, userId)); + } catch (StorageException e) { + throw new RuntimeException(e); + } sendData(data); connectionManager.addListener(userId, this); diff --git a/src/main/java/org/traccar/api/AsyncSocketServlet.java b/src/main/java/org/traccar/api/AsyncSocketServlet.java index 7c532179b..7d9fdf0ed 100644 --- a/src/main/java/org/traccar/api/AsyncSocketServlet.java +++ b/src/main/java/org/traccar/api/AsyncSocketServlet.java @@ -22,6 +22,7 @@ import org.traccar.Context; import org.traccar.api.resource.SessionResource; import org.traccar.config.Keys; import org.traccar.session.ConnectionManager; +import org.traccar.storage.Storage; import javax.inject.Inject; import javax.inject.Singleton; @@ -33,11 +34,13 @@ public class AsyncSocketServlet extends JettyWebSocketServlet { private final ObjectMapper objectMapper; private final ConnectionManager connectionManager; + private final Storage storage; @Inject - public AsyncSocketServlet(ObjectMapper objectMapper, ConnectionManager connectionManager) { + public AsyncSocketServlet(ObjectMapper objectMapper, ConnectionManager connectionManager, Storage storage) { this.objectMapper = objectMapper; this.connectionManager = connectionManager; + this.storage = storage; } @Override @@ -46,7 +49,7 @@ public class AsyncSocketServlet extends JettyWebSocketServlet { factory.setCreator((req, resp) -> { if (req.getSession() != null) { long userId = (Long) ((HttpSession) req.getSession()).getAttribute(SessionResource.USER_ID_KEY); - return new AsyncSocket(objectMapper, connectionManager, userId); + return new AsyncSocket(objectMapper, connectionManager, storage, userId); } else { return null; } diff --git a/src/main/java/org/traccar/api/resource/PositionResource.java b/src/main/java/org/traccar/api/resource/PositionResource.java index 099d97632..cac64feb1 100644 --- a/src/main/java/org/traccar/api/resource/PositionResource.java +++ b/src/main/java/org/traccar/api/resource/PositionResource.java @@ -17,10 +17,8 @@ package org.traccar.api.resource; import org.traccar.api.BaseResource; import org.traccar.helper.model.PositionUtil; -import org.traccar.model.BaseModel; import org.traccar.model.Device; import org.traccar.model.Position; -import org.traccar.model.User; import org.traccar.model.UserRestrictions; import org.traccar.storage.StorageException; import org.traccar.storage.query.Columns; @@ -37,7 +35,6 @@ import java.util.ArrayList; import java.util.Collection; import java.util.Date; import java.util.List; -import java.util.stream.Collectors; @Path("positions") @Produces(MediaType.APPLICATION_JSON) @@ -68,16 +65,7 @@ public class PositionResource extends BaseResource { new Columns.All(), new Condition.LatestPositions(deviceId))); } } else { - var devices = storage.getObjects(Device.class, new Request( - new Columns.Include("id"), - new Condition.Permission(User.class, getUserId(), Device.class))); - var deviceIds = devices.stream().map(BaseModel::getId).collect(Collectors.toUnmodifiableSet()); - - var positions = storage.getObjects(Position.class, new Request( - new Columns.All(), new Condition.LatestPositions())); - return positions.stream() - .filter(position -> deviceIds.contains(position.getDeviceId())) - .collect(Collectors.toList()); + return PositionUtil.getLatestPositions(storage, getUserId()); } } diff --git a/src/main/java/org/traccar/database/DataManager.java b/src/main/java/org/traccar/database/DataManager.java index aa600e375..f80f429e1 100644 --- a/src/main/java/org/traccar/database/DataManager.java +++ b/src/main/java/org/traccar/database/DataManager.java @@ -24,20 +24,17 @@ import org.traccar.storage.Storage; import org.traccar.storage.StorageException; import org.traccar.storage.query.Columns; import org.traccar.storage.query.Condition; -import org.traccar.storage.query.Limit; -import org.traccar.storage.query.Order; import org.traccar.storage.query.Request; import javax.inject.Inject; import java.util.Collection; -import java.util.Date; public class DataManager { private final Storage storage; @Inject - public DataManager(Storage storage) throws Exception { + public DataManager(Storage storage) { this.storage = storage; } @@ -47,25 +44,6 @@ public class DataManager { new Condition.Equals("id", "id"))); } - public Position getPrecedingPosition(long deviceId, Date date) throws StorageException { - return storage.getObject(Position.class, new Request( - new Columns.All(), - new Condition.And( - new Condition.Equals("deviceId", "deviceId", deviceId), - new Condition.Compare("fixTime", "<=", "time", date)), - new Order(true, "fixTime"), - new Limit(1))); - } - - public void updateLatestPosition(Position position) throws StorageException { - Device device = new Device(); - device.setId(position.getDeviceId()); - device.setPositionId(position.getId()); - storage.updateObject(device, new Request( - new Columns.Include("positionId"), - new Condition.Equals("id", "id"))); - } - public Collection getLatestPositions() throws StorageException { return storage.getObjects(Position.class, new Request( new Columns.All(), diff --git a/src/main/java/org/traccar/database/DeviceManager.java b/src/main/java/org/traccar/database/DeviceManager.java index 841915f1c..4516255c1 100644 --- a/src/main/java/org/traccar/database/DeviceManager.java +++ b/src/main/java/org/traccar/database/DeviceManager.java @@ -15,21 +15,13 @@ */ package org.traccar.database; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import org.traccar.Context; import org.traccar.config.Config; import org.traccar.config.Keys; import org.traccar.model.Device; -import org.traccar.model.Position; -import org.traccar.session.ConnectionManager; import org.traccar.session.DeviceState; import org.traccar.storage.StorageException; import java.util.Collection; -import java.util.HashSet; -import java.util.LinkedList; -import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.ConcurrentHashMap; @@ -37,23 +29,15 @@ import java.util.concurrent.atomic.AtomicLong; public class DeviceManager extends BaseObjectManager implements IdentityManager { - private static final Logger LOGGER = LoggerFactory.getLogger(DeviceManager.class); - - private final ConnectionManager connectionManager; private final long dataRefreshDelay; private final AtomicLong devicesLastUpdate = new AtomicLong(); - private final Map positions = new ConcurrentHashMap<>(); - private final Map deviceStates = new ConcurrentHashMap<>(); - public DeviceManager( - Config config, DataManager dataManager, ConnectionManager connectionManager) { + public DeviceManager(Config config, DataManager dataManager) { super(dataManager, Device.class); - this.connectionManager = connectionManager; dataRefreshDelay = config.getLong(Keys.DATABASE_REFRESH_DELAY) * 1000; - refreshLastPositions(); } public void updateDeviceCache(boolean force) { @@ -78,25 +62,6 @@ public class DeviceManager extends BaseObjectManager implements Identity return getItems(getAllItems()); } - public Set getAllUserItems(long userId) { - return Context.getPermissionsManager().getDevicePermissions(userId); - } - - public Set getUserItems(long userId) { - if (Context.getPermissionsManager() != null) { - Set result = new HashSet<>(); - for (long deviceId : Context.getPermissionsManager().getDevicePermissions(userId)) { - Device device = getById(deviceId); - if (device != null && !device.getDisabled()) { - result.add(deviceId); - } - } - return result; - } else { - return new HashSet<>(); - } - } - @Override protected void updateCachedItem(Device device) { Device cachedDevice = getById(device.getId()); @@ -117,7 +82,6 @@ public class DeviceManager extends BaseObjectManager implements Identity if (cachedDevice != null) { super.removeCachedItem(deviceId); } - positions.remove(deviceId); } public void updateDeviceStatus(Device device) throws StorageException { @@ -128,61 +92,6 @@ public class DeviceManager extends BaseObjectManager implements Identity } } - private void refreshLastPositions() { - if (getDataManager() != null) { - try { - for (Position position : getDataManager().getLatestPositions()) { - positions.put(position.getDeviceId(), position); - } - } catch (StorageException error) { - LOGGER.warn("Load latest positions error", error); - } - } - } - - public boolean isLatestPosition(Position position) { - Position lastPosition = getLastPosition(position.getDeviceId()); - return lastPosition == null || position.getFixTime().compareTo(lastPosition.getFixTime()) >= 0; - } - - public void updateLatestPosition(Position position) throws StorageException { - - if (isLatestPosition(position)) { - - getDataManager().updateLatestPosition(position); - - Device device = getById(position.getDeviceId()); - if (device != null) { - device.setPositionId(position.getId()); - } - - positions.put(position.getDeviceId(), position); - - connectionManager.updatePosition(position); - } - } - - @Override - public Position getLastPosition(long deviceId) { - return positions.get(deviceId); - } - - public Collection getInitialState(long userId) { - - List result = new LinkedList<>(); - - if (Context.getPermissionsManager() != null) { - for (long deviceId : Context.getPermissionsManager().getUserAdmin(userId) - ? getAllUserItems(userId) : getUserItems(userId)) { - if (positions.containsKey(deviceId)) { - result.add(positions.get(deviceId)); - } - } - } - - return result; - } - public DeviceState getDeviceState(long deviceId) { DeviceState deviceState = deviceStates.get(deviceId); if (deviceState == null) { diff --git a/src/main/java/org/traccar/database/IdentityManager.java b/src/main/java/org/traccar/database/IdentityManager.java index b42d4c292..1e0eb00c5 100644 --- a/src/main/java/org/traccar/database/IdentityManager.java +++ b/src/main/java/org/traccar/database/IdentityManager.java @@ -16,14 +16,9 @@ package org.traccar.database; import org.traccar.model.Device; -import org.traccar.model.Position; public interface IdentityManager { Device getById(long id); - Position getLastPosition(long deviceId); - - boolean isLatestPosition(Position position); - } diff --git a/src/main/java/org/traccar/handler/DistanceHandler.java b/src/main/java/org/traccar/handler/DistanceHandler.java index 08c8c068d..fb82b5d8e 100644 --- a/src/main/java/org/traccar/handler/DistanceHandler.java +++ b/src/main/java/org/traccar/handler/DistanceHandler.java @@ -20,9 +20,9 @@ import io.netty.channel.ChannelHandler; import org.traccar.BaseDataHandler; import org.traccar.config.Config; import org.traccar.config.Keys; -import org.traccar.database.IdentityManager; import org.traccar.helper.DistanceCalculator; import org.traccar.model.Position; +import org.traccar.session.cache.CacheManager; import javax.inject.Inject; import java.math.BigDecimal; @@ -31,15 +31,15 @@ import java.math.RoundingMode; @ChannelHandler.Sharable public class DistanceHandler extends BaseDataHandler { - private final IdentityManager identityManager; + private final CacheManager cacheManager; private final boolean filter; private final int coordinatesMinError; private final int coordinatesMaxError; @Inject - public DistanceHandler(Config config, IdentityManager identityManager) { - this.identityManager = identityManager; + public DistanceHandler(Config config, CacheManager cacheManager) { + this.cacheManager = cacheManager; this.filter = config.getBoolean(Keys.COORDINATES_FILTER); this.coordinatesMinError = config.getInteger(Keys.COORDINATES_MIN_ERROR); this.coordinatesMaxError = config.getInteger(Keys.COORDINATES_MAX_ERROR); @@ -54,7 +54,7 @@ public class DistanceHandler extends BaseDataHandler { } double totalDistance = 0.0; - Position last = identityManager != null ? identityManager.getLastPosition(position.getDeviceId()) : null; + Position last = cacheManager.getPosition(position.getDeviceId()); if (last != null) { totalDistance = last.getDouble(Position.KEY_TOTAL_DISTANCE); if (!position.getAttributes().containsKey(Position.KEY_DISTANCE)) { diff --git a/src/main/java/org/traccar/handler/EngineHoursHandler.java b/src/main/java/org/traccar/handler/EngineHoursHandler.java index be2a46ade..bfffdcb0c 100644 --- a/src/main/java/org/traccar/handler/EngineHoursHandler.java +++ b/src/main/java/org/traccar/handler/EngineHoursHandler.java @@ -18,25 +18,25 @@ package org.traccar.handler; import io.netty.channel.ChannelHandler; import org.traccar.BaseDataHandler; -import org.traccar.database.IdentityManager; import org.traccar.model.Position; +import org.traccar.session.cache.CacheManager; import javax.inject.Inject; @ChannelHandler.Sharable public class EngineHoursHandler extends BaseDataHandler { - private final IdentityManager identityManager; + private final CacheManager cacheManager; @Inject - public EngineHoursHandler(IdentityManager identityManager) { - this.identityManager = identityManager; + public EngineHoursHandler(CacheManager cacheManager) { + this.cacheManager = cacheManager; } @Override protected Position handlePosition(Position position) { if (!position.getAttributes().containsKey(Position.KEY_HOURS)) { - Position last = identityManager.getLastPosition(position.getDeviceId()); + Position last = cacheManager.getPosition(position.getDeviceId()); if (last != null) { long hours = last.getLong(Position.KEY_HOURS); if (last.getBoolean(Position.KEY_IGNITION) && position.getBoolean(Position.KEY_IGNITION)) { diff --git a/src/main/java/org/traccar/handler/GeocoderHandler.java b/src/main/java/org/traccar/handler/GeocoderHandler.java index 075bdf815..0248fca05 100644 --- a/src/main/java/org/traccar/handler/GeocoderHandler.java +++ b/src/main/java/org/traccar/handler/GeocoderHandler.java @@ -22,9 +22,9 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.traccar.config.Config; import org.traccar.config.Keys; -import org.traccar.database.IdentityManager; import org.traccar.geocoder.Geocoder; import org.traccar.model.Position; +import org.traccar.session.cache.CacheManager; @ChannelHandler.Sharable public class GeocoderHandler extends ChannelInboundHandlerAdapter { @@ -32,15 +32,14 @@ public class GeocoderHandler extends ChannelInboundHandlerAdapter { private static final Logger LOGGER = LoggerFactory.getLogger(GeocoderHandler.class); private final Geocoder geocoder; - private final IdentityManager identityManager; + private final CacheManager cacheManager; private final boolean ignorePositions; private final boolean processInvalidPositions; private final int geocoderReuseDistance; - public GeocoderHandler( - Config config, Geocoder geocoder, IdentityManager identityManager) { + public GeocoderHandler(Config config, Geocoder geocoder, CacheManager cacheManager) { this.geocoder = geocoder; - this.identityManager = identityManager; + this.cacheManager = cacheManager; ignorePositions = config.getBoolean(Keys.GEOCODER_IGNORE_POSITIONS); processInvalidPositions = config.getBoolean(Keys.GEOCODER_PROCESS_INVALID_POSITIONS); geocoderReuseDistance = config.getInteger(Keys.GEOCODER_REUSE_DISTANCE, 0); @@ -52,7 +51,7 @@ public class GeocoderHandler extends ChannelInboundHandlerAdapter { final Position position = (Position) message; if (processInvalidPositions || position.getValid()) { if (geocoderReuseDistance != 0) { - Position lastPosition = identityManager.getLastPosition(position.getDeviceId()); + Position lastPosition = cacheManager.getPosition(position.getDeviceId()); if (lastPosition != null && lastPosition.getAddress() != null && position.getDouble(Position.KEY_DISTANCE) <= geocoderReuseDistance) { position.setAddress(lastPosition.getAddress()); diff --git a/src/main/java/org/traccar/handler/events/AlertEventHandler.java b/src/main/java/org/traccar/handler/events/AlertEventHandler.java index 6e7b0b16e..75626ca6c 100644 --- a/src/main/java/org/traccar/handler/events/AlertEventHandler.java +++ b/src/main/java/org/traccar/handler/events/AlertEventHandler.java @@ -21,21 +21,21 @@ import java.util.Map; import io.netty.channel.ChannelHandler; import org.traccar.config.Config; import org.traccar.config.Keys; -import org.traccar.database.IdentityManager; import org.traccar.model.Event; import org.traccar.model.Position; +import org.traccar.session.cache.CacheManager; import javax.inject.Inject; @ChannelHandler.Sharable public class AlertEventHandler extends BaseEventHandler { - private final IdentityManager identityManager; + private final CacheManager cacheManager; private final boolean ignoreDuplicateAlerts; @Inject - public AlertEventHandler(Config config, IdentityManager identityManager) { - this.identityManager = identityManager; + public AlertEventHandler(Config config, CacheManager cacheManager) { + this.cacheManager = cacheManager; ignoreDuplicateAlerts = config.getBoolean(Keys.EVENT_IGNORE_DUPLICATE_ALERTS); } @@ -45,7 +45,7 @@ public class AlertEventHandler extends BaseEventHandler { if (alarm != null) { boolean ignoreAlert = false; if (ignoreDuplicateAlerts) { - Position lastPosition = identityManager.getLastPosition(position.getDeviceId()); + Position lastPosition = cacheManager.getPosition(position.getDeviceId()); if (lastPosition != null && alarm.equals(lastPosition.getAttributes().get(Position.KEY_ALARM))) { ignoreAlert = true; } diff --git a/src/main/java/org/traccar/handler/events/BehaviorEventHandler.java b/src/main/java/org/traccar/handler/events/BehaviorEventHandler.java index bbf749cdc..3c2fa6a97 100644 --- a/src/main/java/org/traccar/handler/events/BehaviorEventHandler.java +++ b/src/main/java/org/traccar/handler/events/BehaviorEventHandler.java @@ -18,10 +18,10 @@ package org.traccar.handler.events; import io.netty.channel.ChannelHandler; import org.traccar.config.Config; import org.traccar.config.Keys; -import org.traccar.database.IdentityManager; import org.traccar.helper.UnitsConverter; import org.traccar.model.Event; import org.traccar.model.Position; +import org.traccar.session.cache.CacheManager; import javax.inject.Inject; import java.util.Collections; @@ -33,19 +33,19 @@ public class BehaviorEventHandler extends BaseEventHandler { private final double accelerationThreshold; private final double brakingThreshold; - private final IdentityManager identityManager; + private final CacheManager cacheManager; @Inject - public BehaviorEventHandler(Config config, IdentityManager identityManager) { + public BehaviorEventHandler(Config config, CacheManager cacheManager) { accelerationThreshold = config.getDouble(Keys.EVENT_BEHAVIOR_ACCELERATION_THRESHOLD); brakingThreshold = config.getDouble(Keys.EVENT_BEHAVIOR_BRAKING_THRESHOLD); - this.identityManager = identityManager; + this.cacheManager = cacheManager; } @Override protected Map analyzePosition(Position position) { - Position lastPosition = identityManager.getLastPosition(position.getDeviceId()); + Position lastPosition = cacheManager.getPosition(position.getDeviceId()); if (lastPosition != null && position.getFixTime().equals(lastPosition.getFixTime())) { double acceleration = UnitsConverter.mpsFromKnots(position.getSpeed() - lastPosition.getSpeed()) * 1000 / (position.getFixTime().getTime() - lastPosition.getFixTime().getTime()); diff --git a/src/main/java/org/traccar/handler/events/DriverEventHandler.java b/src/main/java/org/traccar/handler/events/DriverEventHandler.java index 510ac3465..1ad66ba64 100644 --- a/src/main/java/org/traccar/handler/events/DriverEventHandler.java +++ b/src/main/java/org/traccar/handler/events/DriverEventHandler.java @@ -16,35 +16,35 @@ */ package org.traccar.handler.events; -import java.util.Collections; -import java.util.Map; - import io.netty.channel.ChannelHandler; -import org.traccar.database.IdentityManager; +import org.traccar.helper.model.PositionUtil; import org.traccar.model.Event; import org.traccar.model.Position; +import org.traccar.session.cache.CacheManager; import javax.inject.Inject; +import java.util.Collections; +import java.util.Map; @ChannelHandler.Sharable public class DriverEventHandler extends BaseEventHandler { - private final IdentityManager identityManager; + private final CacheManager cacheManager; @Inject - public DriverEventHandler(IdentityManager identityManager) { - this.identityManager = identityManager; + public DriverEventHandler(CacheManager cacheManager) { + this.cacheManager = cacheManager; } @Override protected Map analyzePosition(Position position) { - if (!identityManager.isLatestPosition(position)) { + if (!PositionUtil.isLatest(cacheManager, position)) { return null; } String driverUniqueId = position.getString(Position.KEY_DRIVER_UNIQUE_ID); if (driverUniqueId != null) { String oldDriverUniqueId = null; - Position lastPosition = identityManager.getLastPosition(position.getDeviceId()); + Position lastPosition = cacheManager.getPosition(position.getDeviceId()); if (lastPosition != null) { oldDriverUniqueId = lastPosition.getString(Position.KEY_DRIVER_UNIQUE_ID); } diff --git a/src/main/java/org/traccar/handler/events/IgnitionEventHandler.java b/src/main/java/org/traccar/handler/events/IgnitionEventHandler.java index 9887c9db6..6e411539c 100644 --- a/src/main/java/org/traccar/handler/events/IgnitionEventHandler.java +++ b/src/main/java/org/traccar/handler/events/IgnitionEventHandler.java @@ -20,27 +20,28 @@ import java.util.Collections; import java.util.Map; import io.netty.channel.ChannelHandler; -import org.traccar.database.IdentityManager; +import org.traccar.helper.model.PositionUtil; import org.traccar.model.Device; import org.traccar.model.Event; import org.traccar.model.Position; +import org.traccar.session.cache.CacheManager; import javax.inject.Inject; @ChannelHandler.Sharable public class IgnitionEventHandler extends BaseEventHandler { - private final IdentityManager identityManager; + private final CacheManager cacheManager; @Inject - public IgnitionEventHandler(IdentityManager identityManager) { - this.identityManager = identityManager; + public IgnitionEventHandler(CacheManager cacheManager) { + this.cacheManager = cacheManager; } @Override protected Map analyzePosition(Position position) { - Device device = identityManager.getById(position.getDeviceId()); - if (device == null || !identityManager.isLatestPosition(position)) { + Device device = cacheManager.getObject(Device.class, position.getDeviceId()); + if (device == null || !PositionUtil.isLatest(cacheManager, position)) { return null; } @@ -49,7 +50,7 @@ public class IgnitionEventHandler extends BaseEventHandler { if (position.getAttributes().containsKey(Position.KEY_IGNITION)) { boolean ignition = position.getBoolean(Position.KEY_IGNITION); - Position lastPosition = identityManager.getLastPosition(position.getDeviceId()); + Position lastPosition = cacheManager.getPosition(position.getDeviceId()); if (lastPosition != null && lastPosition.getAttributes().containsKey(Position.KEY_IGNITION)) { boolean oldIgnition = lastPosition.getBoolean(Position.KEY_IGNITION); diff --git a/src/main/java/org/traccar/handler/events/MaintenanceEventHandler.java b/src/main/java/org/traccar/handler/events/MaintenanceEventHandler.java index f85aab043..be3e9bf8d 100644 --- a/src/main/java/org/traccar/handler/events/MaintenanceEventHandler.java +++ b/src/main/java/org/traccar/handler/events/MaintenanceEventHandler.java @@ -20,7 +20,6 @@ import java.util.HashMap; import java.util.Map; import io.netty.channel.ChannelHandler; -import org.traccar.Context; import org.traccar.model.Event; import org.traccar.model.Maintenance; import org.traccar.model.Position; @@ -40,7 +39,7 @@ public class MaintenanceEventHandler extends BaseEventHandler { @Override protected Map analyzePosition(Position position) { - Position lastPosition = Context.getIdentityManager().getLastPosition(position.getDeviceId()); + Position lastPosition = cacheManager.getPosition(position.getDeviceId()); if (lastPosition == null || position.getFixTime().compareTo(lastPosition.getFixTime()) < 0) { return null; } diff --git a/src/main/java/org/traccar/handler/events/MotionEventHandler.java b/src/main/java/org/traccar/handler/events/MotionEventHandler.java index 2c381e530..724e9bf15 100644 --- a/src/main/java/org/traccar/handler/events/MotionEventHandler.java +++ b/src/main/java/org/traccar/handler/events/MotionEventHandler.java @@ -18,13 +18,13 @@ package org.traccar.handler.events; import io.netty.channel.ChannelHandler; import org.traccar.database.DeviceManager; -import org.traccar.database.IdentityManager; import org.traccar.helper.model.PositionUtil; import org.traccar.model.Device; import org.traccar.model.Event; import org.traccar.model.Position; import org.traccar.reports.common.TripsConfig; import org.traccar.session.DeviceState; +import org.traccar.session.cache.CacheManager; import javax.inject.Inject; import java.util.Collections; @@ -33,13 +33,13 @@ import java.util.Map; @ChannelHandler.Sharable public class MotionEventHandler extends BaseEventHandler { - private final IdentityManager identityManager; + private final CacheManager cacheManager; private final DeviceManager deviceManager; private final TripsConfig tripsConfig; @Inject - public MotionEventHandler(IdentityManager identityManager, DeviceManager deviceManager, TripsConfig tripsConfig) { - this.identityManager = identityManager; + public MotionEventHandler(CacheManager cacheManager, DeviceManager deviceManager, TripsConfig tripsConfig) { + this.cacheManager = cacheManager; this.deviceManager = deviceManager; this.tripsConfig = tripsConfig; } @@ -113,11 +113,11 @@ public class MotionEventHandler extends BaseEventHandler { protected Map analyzePosition(Position position) { long deviceId = position.getDeviceId(); - Device device = identityManager.getById(deviceId); + Device device = cacheManager.getObject(Device.class, deviceId); if (device == null) { return null; } - if (!identityManager.isLatestPosition(position) + if (!PositionUtil.isLatest(cacheManager, position) || !tripsConfig.getProcessInvalidPositions() && !position.getValid()) { return null; } diff --git a/src/main/java/org/traccar/helper/model/PositionUtil.java b/src/main/java/org/traccar/helper/model/PositionUtil.java index 566e31bc5..31f828947 100644 --- a/src/main/java/org/traccar/helper/model/PositionUtil.java +++ b/src/main/java/org/traccar/helper/model/PositionUtil.java @@ -15,7 +15,10 @@ */ package org.traccar.helper.model; +import org.traccar.model.BaseModel; +import org.traccar.model.Device; import org.traccar.model.Position; +import org.traccar.model.User; import org.traccar.session.cache.CacheManager; import org.traccar.storage.Storage; import org.traccar.storage.StorageException; @@ -26,6 +29,7 @@ import org.traccar.storage.query.Request; import java.util.Date; import java.util.List; +import java.util.stream.Collectors; public final class PositionUtil { @@ -60,4 +64,17 @@ public final class PositionUtil { new Order("fixTime"))); } + public static List getLatestPositions(Storage storage, long userId) throws StorageException { + var devices = storage.getObjects(Device.class, new Request( + new Columns.Include("id"), + new Condition.Permission(User.class, userId, Device.class))); + var deviceIds = devices.stream().map(BaseModel::getId).collect(Collectors.toUnmodifiableSet()); + + var positions = storage.getObjects(Position.class, new Request( + new Columns.All(), new Condition.LatestPositions())); + return positions.stream() + .filter(position -> deviceIds.contains(position.getDeviceId())) + .collect(Collectors.toList()); + } + } diff --git a/src/main/java/org/traccar/reports/common/ReportUtils.java b/src/main/java/org/traccar/reports/common/ReportUtils.java index 84866a67b..bb37bfa9c 100644 --- a/src/main/java/org/traccar/reports/common/ReportUtils.java +++ b/src/main/java/org/traccar/reports/common/ReportUtils.java @@ -346,7 +346,7 @@ public class ReportUtils { ArrayList positions = new ArrayList<>(positionCollection); if (!positions.isEmpty()) { boolean trips = reportClass.equals(TripReportItem.class); - MotionEventHandler motionHandler = new MotionEventHandler(identityManager, deviceManager, tripsConfig); + MotionEventHandler motionHandler = new MotionEventHandler(null, deviceManager, tripsConfig); DeviceState deviceState = new DeviceState(); deviceState.setMotionState(isMoving(positions, 0, tripsConfig)); int startEventIndex = trips == deviceState.getMotionState() ? 0 : -1; diff --git a/src/test/java/org/traccar/handler/DistanceHandlerTest.java b/src/test/java/org/traccar/handler/DistanceHandlerTest.java index f7c6e42cd..a18b14edd 100644 --- a/src/test/java/org/traccar/handler/DistanceHandlerTest.java +++ b/src/test/java/org/traccar/handler/DistanceHandlerTest.java @@ -3,15 +3,17 @@ package org.traccar.handler; import org.junit.Test; import org.traccar.config.Config; import org.traccar.model.Position; +import org.traccar.session.cache.CacheManager; import static org.junit.Assert.assertEquals; +import static org.mockito.Mockito.mock; public class DistanceHandlerTest { @Test public void testCalculateDistance() { - DistanceHandler distanceHandler = new DistanceHandler(new Config(), null); + DistanceHandler distanceHandler = new DistanceHandler(new Config(), mock(CacheManager.class)); Position position = distanceHandler.handlePosition(new Position()); diff --git a/src/test/java/org/traccar/handler/events/AlertEventHandlerTest.java b/src/test/java/org/traccar/handler/events/AlertEventHandlerTest.java index d6cf32ca3..550a93da3 100644 --- a/src/test/java/org/traccar/handler/events/AlertEventHandlerTest.java +++ b/src/test/java/org/traccar/handler/events/AlertEventHandlerTest.java @@ -3,9 +3,9 @@ package org.traccar.handler.events; import org.junit.Test; import org.traccar.BaseTest; import org.traccar.config.Config; -import org.traccar.database.IdentityManager; import org.traccar.model.Event; import org.traccar.model.Position; +import org.traccar.session.cache.CacheManager; import java.util.Map; @@ -18,7 +18,7 @@ public class AlertEventHandlerTest extends BaseTest { @Test public void testAlertEventHandler() { - AlertEventHandler alertEventHandler = new AlertEventHandler(new Config(), mock(IdentityManager.class)); + AlertEventHandler alertEventHandler = new AlertEventHandler(new Config(), mock(CacheManager.class)); Position position = new Position(); position.set(Position.KEY_ALARM, Position.ALARM_GENERAL); diff --git a/src/test/java/org/traccar/handler/events/IgnitionEventHandlerTest.java b/src/test/java/org/traccar/handler/events/IgnitionEventHandlerTest.java index 0de80dd70..84898bea0 100644 --- a/src/test/java/org/traccar/handler/events/IgnitionEventHandlerTest.java +++ b/src/test/java/org/traccar/handler/events/IgnitionEventHandlerTest.java @@ -2,9 +2,9 @@ package org.traccar.handler.events; import org.junit.Test; import org.traccar.BaseTest; -import org.traccar.database.IdentityManager; import org.traccar.model.Event; import org.traccar.model.Position; +import org.traccar.session.cache.CacheManager; import java.util.Map; @@ -16,7 +16,7 @@ public class IgnitionEventHandlerTest extends BaseTest { @Test public void testIgnitionEventHandler() { - IgnitionEventHandler ignitionEventHandler = new IgnitionEventHandler(mock(IdentityManager.class)); + IgnitionEventHandler ignitionEventHandler = new IgnitionEventHandler(mock(CacheManager.class)); Position position = new Position(); position.set(Position.KEY_IGNITION, true); -- cgit v1.2.3 From cc9eca495f93b8ffaee0fe5b10b62f1f3dfbf945 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Wed, 22 Jun 2022 07:22:14 -0700 Subject: Return storage info --- .../java/org/traccar/api/resource/ServerResource.java | 6 ++++++ src/main/java/org/traccar/helper/Log.java | 18 ++++++++++++++++++ src/main/java/org/traccar/model/Server.java | 12 ++++++++++++ 3 files changed, 36 insertions(+) (limited to 'src/main/java/org/traccar/helper') diff --git a/src/main/java/org/traccar/api/resource/ServerResource.java b/src/main/java/org/traccar/api/resource/ServerResource.java index b66f5a931..2ef99c578 100644 --- a/src/main/java/org/traccar/api/resource/ServerResource.java +++ b/src/main/java/org/traccar/api/resource/ServerResource.java @@ -18,8 +18,10 @@ package org.traccar.api.resource; import org.traccar.api.BaseResource; import org.traccar.database.MailManager; import org.traccar.geocoder.Geocoder; +import org.traccar.helper.Log; import org.traccar.helper.LogAction; import org.traccar.model.Server; +import org.traccar.model.User; import org.traccar.storage.Storage; import org.traccar.storage.StorageException; import org.traccar.storage.query.Columns; @@ -60,6 +62,10 @@ public class ServerResource extends BaseResource { public Server get() throws StorageException { Server server = storage.getObject(Server.class, new Request(new Columns.All())); server.setEmailEnabled(mailManager.getEmailEnabled()); + User user = permissionsService.getUser(getUserId()); + if (user != null && user.getAdministrator()) { + server.setStorageSpace(Log.getStorageSpace()); + } return server; } diff --git a/src/main/java/org/traccar/helper/Log.java b/src/main/java/org/traccar/helper/Log.java index 8c67f9ddc..e1b201f9f 100644 --- a/src/main/java/org/traccar/helper/Log.java +++ b/src/main/java/org/traccar/helper/Log.java @@ -28,6 +28,10 @@ import java.io.StringWriter; import java.io.Writer; import java.net.URL; import java.nio.charset.StandardCharsets; +import java.nio.file.FileStore; +import java.nio.file.FileSystems; +import java.nio.file.Files; +import java.nio.file.Path; import java.text.SimpleDateFormat; import java.util.Date; import java.util.logging.ConsoleHandler; @@ -269,4 +273,18 @@ public final class Log { return s.toString(); } + public static long[] getStorageSpace() { + long usable = 0; + long total = 0; + for (Path root : FileSystems.getDefault().getRootDirectories()) { + try { + FileStore store = Files.getFileStore(root); + usable += store.getUsableSpace(); + total += store.getTotalSpace(); + } catch (IOException ignored) { + } + } + return new long[]{usable, total}; + } + } diff --git a/src/main/java/org/traccar/model/Server.java b/src/main/java/org/traccar/model/Server.java index ee7f7069a..648be2991 100644 --- a/src/main/java/org/traccar/model/Server.java +++ b/src/main/java/org/traccar/model/Server.java @@ -214,4 +214,16 @@ public class Server extends ExtendedModel implements UserRestrictions { return emailEnabled; } + private long[] storageSpace; + + @QueryIgnore + public long[] getStorageSpace() { + return storageSpace; + } + + @QueryIgnore + public void setStorageSpace(long[] storageSpace) { + this.storageSpace = storageSpace; + } + } -- cgit v1.2.3 From 08d634d984c1388c3919d7c6645506b202307dac Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Mon, 27 Jun 2022 18:43:15 -0700 Subject: Temporary disable group lookup --- src/main/java/org/traccar/helper/model/AttributeUtil.java | 8 -------- 1 file changed, 8 deletions(-) (limited to 'src/main/java/org/traccar/helper') diff --git a/src/main/java/org/traccar/helper/model/AttributeUtil.java b/src/main/java/org/traccar/helper/model/AttributeUtil.java index 58b922d95..b438f97dc 100644 --- a/src/main/java/org/traccar/helper/model/AttributeUtil.java +++ b/src/main/java/org/traccar/helper/model/AttributeUtil.java @@ -19,7 +19,6 @@ import org.traccar.config.ConfigKey; import org.traccar.config.KeyType; import org.traccar.config.Keys; import org.traccar.model.Device; -import org.traccar.model.Group; import org.traccar.session.cache.CacheManager; public final class AttributeUtil { @@ -31,13 +30,6 @@ public final class AttributeUtil { public static T lookup(CacheManager cacheManager, ConfigKey key, long deviceId) { Device device = cacheManager.getObject(Device.class, deviceId); Object result = device.getAttributes().get(key.getKey()); - long groupId = device.getGroupId(); - while (result == null && groupId > 0) { - Group group = cacheManager.getObject(Group.class, groupId); - if (group != null) { - result = group.getAttributes().get(key.getKey()); - } - } if (result == null && key.hasType(KeyType.SERVER)) { result = cacheManager.getServer().getAttributes().get(key.getKey()); } -- cgit v1.2.3 From aed0411f4ae5cfc007d27e0521a39a242fab7840 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Wed, 29 Jun 2022 17:03:23 -0700 Subject: Unify signed magnitude int decoding --- src/main/java/org/traccar/helper/BitUtil.java | 4 ++-- src/main/java/org/traccar/helper/BufferUtil.java | 6 ++++++ .../java/org/traccar/protocol/NiotProtocolDecoder.java | 11 +++-------- .../java/org/traccar/protocol/SigfoxProtocolDecoder.java | 15 +++------------ .../java/org/traccar/protocol/SuntechProtocolDecoder.java | 13 +++---------- .../org/traccar/protocol/ThinkPowerProtocolDecoder.java | 1 + src/test/java/org/traccar/helper/BufferUtilTest.java | 6 ++++++ 7 files changed, 24 insertions(+), 32 deletions(-) (limited to 'src/main/java/org/traccar/helper') diff --git a/src/main/java/org/traccar/helper/BitUtil.java b/src/main/java/org/traccar/helper/BitUtil.java index b6108edff..829ddebc9 100644 --- a/src/main/java/org/traccar/helper/BitUtil.java +++ b/src/main/java/org/traccar/helper/BitUtil.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 2022 Anton Tananaev (anton@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,7 +21,7 @@ public final class BitUtil { } public static boolean check(long number, int index) { - return (number & (1 << index)) != 0; + return (number & (1L << index)) != 0; } public static int between(int number, int from, int to) { diff --git a/src/main/java/org/traccar/helper/BufferUtil.java b/src/main/java/org/traccar/helper/BufferUtil.java index 1e1a687fa..0dbe0a4ad 100644 --- a/src/main/java/org/traccar/helper/BufferUtil.java +++ b/src/main/java/org/traccar/helper/BufferUtil.java @@ -27,6 +27,12 @@ public final class BufferUtil { private BufferUtil() { } + public static int readSignedMagnitudeInt(ByteBuf buffer) { + long value = buffer.readUnsignedInt(); + int result = (int) BitUtil.to(value, 31); + return BitUtil.check(value, 31) ? -result : result; + } + public static int indexOf(ByteBuf buffer, int fromIndex, int toIndex, byte value, int count) { int startIndex = fromIndex; for (int i = 0; i < count; i++) { diff --git a/src/main/java/org/traccar/protocol/NiotProtocolDecoder.java b/src/main/java/org/traccar/protocol/NiotProtocolDecoder.java index 16d992938..35614ccca 100644 --- a/src/main/java/org/traccar/protocol/NiotProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/NiotProtocolDecoder.java @@ -20,6 +20,7 @@ import io.netty.buffer.ByteBufUtil; import io.netty.buffer.Unpooled; import io.netty.channel.Channel; import org.traccar.BaseProtocolDecoder; +import org.traccar.helper.BufferUtil; import org.traccar.session.DeviceSession; import org.traccar.NetworkMessage; import org.traccar.Protocol; @@ -57,12 +58,6 @@ public class NiotProtocolDecoder extends BaseProtocolDecoder { } } - private double readCoordinate(ByteBuf buf) { - long value = buf.readUnsignedInt(); - double result = BitUtil.to(value, 31) / 1800000.0; - return BitUtil.check(value, 31) ? -result : result; - } - @Override protected Object decode( Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { @@ -96,8 +91,8 @@ public class NiotProtocolDecoder extends BaseProtocolDecoder { .setSecond(BcdUtil.readInteger(buf, 2)); position.setTime(dateBuilder.getDate()); - position.setLatitude(readCoordinate(buf)); - position.setLongitude(readCoordinate(buf)); + position.setLatitude(BufferUtil.readSignedMagnitudeInt(buf) / 1800000.0); + position.setLongitude(BufferUtil.readSignedMagnitudeInt(buf) / 1800000.0); BcdUtil.readInteger(buf, 4); // reserved position.setCourse(BcdUtil.readInteger(buf, 4)); diff --git a/src/main/java/org/traccar/protocol/SigfoxProtocolDecoder.java b/src/main/java/org/traccar/protocol/SigfoxProtocolDecoder.java index bbb8bc1cc..4ed2bb51d 100644 --- a/src/main/java/org/traccar/protocol/SigfoxProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/SigfoxProtocolDecoder.java @@ -22,6 +22,7 @@ import io.netty.channel.Channel; import io.netty.handler.codec.http.FullHttpRequest; import io.netty.handler.codec.http.HttpResponseStatus; import org.traccar.BaseHttpProtocolDecoder; +import org.traccar.helper.BufferUtil; import org.traccar.session.DeviceSession; import org.traccar.Protocol; import org.traccar.helper.BitUtil; @@ -159,18 +160,8 @@ public class SigfoxProtocolDecoder extends BaseHttpProtocolDecoder { if (event == 0x0f || event == 0x1f) { position.setValid(event >> 4 > 0); - - long value; - value = buf.readUnsignedInt(); - position.setLatitude(BitUtil.to(value, 31) * 0.000001); - if (BitUtil.check(value, 31)) { - position.setLatitude(-position.getLatitude()); - } - value = buf.readUnsignedInt(); - position.setLongitude(BitUtil.to(value, 31) * 0.000001); - if (BitUtil.check(value, 31)) { - position.setLongitude(-position.getLongitude()); - } + position.setLatitude(BufferUtil.readSignedMagnitudeInt(buf) * 0.000001); + position.setLongitude(BufferUtil.readSignedMagnitudeInt(buf) * 0.000001); position.set(Position.KEY_BATTERY, (int) buf.readUnsignedByte()); diff --git a/src/main/java/org/traccar/protocol/SuntechProtocolDecoder.java b/src/main/java/org/traccar/protocol/SuntechProtocolDecoder.java index 67a82a688..938d290c0 100644 --- a/src/main/java/org/traccar/protocol/SuntechProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/SuntechProtocolDecoder.java @@ -21,6 +21,7 @@ import io.netty.buffer.Unpooled; import io.netty.channel.Channel; import org.traccar.BaseProtocolDecoder; import org.traccar.config.Keys; +import org.traccar.helper.BufferUtil; import org.traccar.helper.model.AttributeUtil; import org.traccar.session.DeviceSession; import org.traccar.Protocol; @@ -673,19 +674,11 @@ public class SuntechProtocolDecoder extends BaseProtocolDecoder { } if (BitUtil.check(mask, 11)) { - long value = buf.readUnsignedInt(); - if (BitUtil.check(value, 31)) { - value = -BitUtil.to(value, 31); - } - position.setLatitude(value / 1000000.0); + position.setLatitude(BufferUtil.readSignedMagnitudeInt(buf) / 1000000.0); } if (BitUtil.check(mask, 12)) { - long value = buf.readUnsignedInt(); - if (BitUtil.check(value, 31)) { - value = -BitUtil.to(value, 31); - } - position.setLongitude(value / 1000000.0); + position.setLongitude(BufferUtil.readSignedMagnitudeInt(buf) / 1000000.0); } if (BitUtil.check(mask, 13)) { diff --git a/src/main/java/org/traccar/protocol/ThinkPowerProtocolDecoder.java b/src/main/java/org/traccar/protocol/ThinkPowerProtocolDecoder.java index 085ce4c91..26d60daba 100644 --- a/src/main/java/org/traccar/protocol/ThinkPowerProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/ThinkPowerProtocolDecoder.java @@ -19,6 +19,7 @@ import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import io.netty.channel.Channel; import org.traccar.BaseProtocolDecoder; +import org.traccar.helper.BitUtil; import org.traccar.session.DeviceSession; import org.traccar.NetworkMessage; import org.traccar.Protocol; diff --git a/src/test/java/org/traccar/helper/BufferUtilTest.java b/src/test/java/org/traccar/helper/BufferUtilTest.java index b539b5b28..0196cef9d 100644 --- a/src/test/java/org/traccar/helper/BufferUtilTest.java +++ b/src/test/java/org/traccar/helper/BufferUtilTest.java @@ -10,6 +10,12 @@ import static org.junit.Assert.assertEquals; public class BufferUtilTest { + @Test + public void testReadSignedMagnitudeInt() { + ByteBuf buf = Unpooled.wrappedBuffer(DataConverter.parseHex("80000001")); + assertEquals(-1, BufferUtil.readSignedMagnitudeInt(buf)); + } + @Test public void test1() { ByteBuf buf = Unpooled.copiedBuffer("abcdef", StandardCharsets.US_ASCII); -- cgit v1.2.3 From d7c1345f6f070e3931af0ad3fac785130cc9f4dc Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Thu, 30 Jun 2022 17:16:03 -0700 Subject: Fix group attribute lookup (fix #4880) --- src/main/java/org/traccar/helper/model/AttributeUtil.java | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 'src/main/java/org/traccar/helper') diff --git a/src/main/java/org/traccar/helper/model/AttributeUtil.java b/src/main/java/org/traccar/helper/model/AttributeUtil.java index b438f97dc..43558e8f7 100644 --- a/src/main/java/org/traccar/helper/model/AttributeUtil.java +++ b/src/main/java/org/traccar/helper/model/AttributeUtil.java @@ -19,6 +19,7 @@ import org.traccar.config.ConfigKey; import org.traccar.config.KeyType; import org.traccar.config.Keys; import org.traccar.model.Device; +import org.traccar.model.Group; import org.traccar.session.cache.CacheManager; public final class AttributeUtil { @@ -30,6 +31,16 @@ public final class AttributeUtil { public static T lookup(CacheManager cacheManager, ConfigKey key, long deviceId) { Device device = cacheManager.getObject(Device.class, deviceId); Object result = device.getAttributes().get(key.getKey()); + long groupId = device.getGroupId(); + while (result == null && groupId > 0) { + Group group = cacheManager.getObject(Group.class, groupId); + if (group != null) { + result = group.getAttributes().get(key.getKey()); + groupId = group.getGroupId(); + } else { + groupId = 0; + } + } if (result == null && key.hasType(KeyType.SERVER)) { result = cacheManager.getServer().getAttributes().get(key.getKey()); } -- cgit v1.2.3 From c4509720c5dab9d7ba17dd6e89f0d846052b0c39 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Mon, 18 Jul 2022 20:47:11 -0700 Subject: Reset start on restart --- src/main/java/org/traccar/Main.java | 6 ++++ .../org/traccar/broadcast/BroadcastService.java | 1 + .../broadcast/MulticastBroadcastService.java | 5 ++++ .../traccar/broadcast/NullBroadcastService.java | 5 ++++ .../java/org/traccar/helper/model/DeviceUtil.java | 33 ++++++++++++++++++++++ 5 files changed, 50 insertions(+) create mode 100644 src/main/java/org/traccar/helper/model/DeviceUtil.java (limited to 'src/main/java/org/traccar/helper') diff --git a/src/main/java/org/traccar/Main.java b/src/main/java/org/traccar/Main.java index 6a968ac7e..e34fbb72a 100644 --- a/src/main/java/org/traccar/Main.java +++ b/src/main/java/org/traccar/Main.java @@ -20,8 +20,10 @@ import com.google.inject.Injector; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.traccar.broadcast.BroadcastService; +import org.traccar.helper.model.DeviceUtil; import org.traccar.schedule.ScheduleManager; import org.traccar.storage.DatabaseModule; +import org.traccar.storage.Storage; import org.traccar.web.WebModule; import org.traccar.web.WebServer; @@ -120,6 +122,10 @@ public final class Main { LOGGER.info("Version: " + Main.class.getPackage().getImplementationVersion()); LOGGER.info("Starting server..."); + if (injector.getInstance(BroadcastService.class).singleInstance()) { + DeviceUtil.resetStatus(injector.getInstance(Storage.class)); + } + var services = Stream.of( ServerManager.class, WebServer.class, ScheduleManager.class, BroadcastService.class) .map(injector::getInstance) diff --git a/src/main/java/org/traccar/broadcast/BroadcastService.java b/src/main/java/org/traccar/broadcast/BroadcastService.java index 8a2e4bafc..a86c43b5b 100644 --- a/src/main/java/org/traccar/broadcast/BroadcastService.java +++ b/src/main/java/org/traccar/broadcast/BroadcastService.java @@ -18,5 +18,6 @@ package org.traccar.broadcast; import org.traccar.LifecycleObject; public interface BroadcastService extends LifecycleObject, BroadcastInterface { + boolean singleInstance(); void registerListener(BroadcastInterface listener); } diff --git a/src/main/java/org/traccar/broadcast/MulticastBroadcastService.java b/src/main/java/org/traccar/broadcast/MulticastBroadcastService.java index 3eafe07d3..be65b7826 100644 --- a/src/main/java/org/traccar/broadcast/MulticastBroadcastService.java +++ b/src/main/java/org/traccar/broadcast/MulticastBroadcastService.java @@ -70,6 +70,11 @@ public class MulticastBroadcastService implements BroadcastService { group = new InetSocketAddress(address, port); } + @Override + public boolean singleInstance() { + return false; + } + @Override public void registerListener(BroadcastInterface listener) { listeners.add(listener); diff --git a/src/main/java/org/traccar/broadcast/NullBroadcastService.java b/src/main/java/org/traccar/broadcast/NullBroadcastService.java index 3f41299db..f95037990 100644 --- a/src/main/java/org/traccar/broadcast/NullBroadcastService.java +++ b/src/main/java/org/traccar/broadcast/NullBroadcastService.java @@ -17,6 +17,11 @@ package org.traccar.broadcast; public class NullBroadcastService implements BroadcastService { + @Override + public boolean singleInstance() { + return true; + } + @Override public void registerListener(BroadcastInterface listener) { } diff --git a/src/main/java/org/traccar/helper/model/DeviceUtil.java b/src/main/java/org/traccar/helper/model/DeviceUtil.java new file mode 100644 index 000000000..597078caf --- /dev/null +++ b/src/main/java/org/traccar/helper/model/DeviceUtil.java @@ -0,0 +1,33 @@ +/* + * Copyright 2022 Anton Tananaev (anton@traccar.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.traccar.helper.model; + +import org.traccar.model.Device; +import org.traccar.storage.Storage; +import org.traccar.storage.StorageException; +import org.traccar.storage.query.Columns; +import org.traccar.storage.query.Request; + +public final class DeviceUtil { + + private DeviceUtil() { + } + + public static void resetStatus(Storage storage) throws StorageException { + storage.updateObject(new Device(), new Request(new Columns.Include("status"))); + } + +} -- cgit v1.2.3 From 42e88c2bf95962f1274a8bbb6e8fc09af95f627f Mon Sep 17 00:00:00 2001 From: Stefan Clark Date: Thu, 28 Jul 2022 22:37:15 +0100 Subject: Added udp() to Checksum helper and Updated Xexun2 procotol --- src/main/java/org/traccar/helper/Checksum.java | 19 +++++++++++++++++ .../traccar/protocol/Xexun2ProtocolDecoder.java | 11 +++++++--- .../traccar/protocol/Xexun2ProtocolEncoder.java | 24 ++-------------------- 3 files changed, 29 insertions(+), 25 deletions(-) (limited to 'src/main/java/org/traccar/helper') diff --git a/src/main/java/org/traccar/helper/Checksum.java b/src/main/java/org/traccar/helper/Checksum.java index 8c3d0063a..e660790ef 100644 --- a/src/main/java/org/traccar/helper/Checksum.java +++ b/src/main/java/org/traccar/helper/Checksum.java @@ -200,4 +200,23 @@ public final class Checksum { return (10 - (checksum % 10)) % 10; } + public static int udp(ByteBuffer data) { + int sum = 0; + int len = data.capacity(); + for (int j = 0; len > 1; len--) { + sum += data.get() & 0xff; + if ((sum & 0x80000000) > 0) { + sum = (sum & 0xffff) + (sum >> 16); + } + } + if (len == 1) { + sum += data.get() & 0xff; + } + while ((sum >> 16) > 0) { + sum = (sum & 0xffff) + sum >> 16; + } + sum = (sum == 0xffff) ? sum & 0xffff : (~sum) & 0xffff; + return sum; + } + } diff --git a/src/main/java/org/traccar/protocol/Xexun2ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Xexun2ProtocolDecoder.java index 8deb2328b..f0158e6ce 100644 --- a/src/main/java/org/traccar/protocol/Xexun2ProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Xexun2ProtocolDecoder.java @@ -24,6 +24,7 @@ import org.traccar.session.DeviceSession; import org.traccar.NetworkMessage; import org.traccar.Protocol; import org.traccar.helper.BitUtil; +import org.traccar.helper.Checksum; import org.traccar.helper.UnitsConverter; import org.traccar.model.CellTower; import org.traccar.model.Network; @@ -97,13 +98,17 @@ public class Xexun2ProtocolDecoder extends BaseProtocolDecoder { return null; } + int payloadSize = buf.readUnsignedShort() & 0x03ff; + int checksum = buf.readUnsignedShort(); // checksum + + if (checksum != Checksum.udp(buf.nioBuffer(buf.readerIndex(), payloadSize))) { + return null; + } + if (type != Xexun2ProtocolEncoder.MSG_COMMAND) { sendResponse(channel, type, index, imei); } - buf.readUnsignedShort(); // attributes - buf.readUnsignedShort(); // checksum - if (type == MSG_POSITION) { List lengths = new ArrayList<>(); List positions = new ArrayList<>(); diff --git a/src/main/java/org/traccar/protocol/Xexun2ProtocolEncoder.java b/src/main/java/org/traccar/protocol/Xexun2ProtocolEncoder.java index f876853bf..6e1e1d68d 100644 --- a/src/main/java/org/traccar/protocol/Xexun2ProtocolEncoder.java +++ b/src/main/java/org/traccar/protocol/Xexun2ProtocolEncoder.java @@ -18,6 +18,7 @@ package org.traccar.protocol; import io.netty.buffer.ByteBuf; import io.netty.buffer.Unpooled; import org.traccar.BaseProtocolEncoder; +import org.traccar.helper.Checksum; import org.traccar.helper.DataConverter; import org.traccar.model.Command; import org.traccar.Protocol; @@ -62,26 +63,6 @@ public class Xexun2ProtocolEncoder extends BaseProtocolEncoder { return result; } - private static int udpchecksum(ByteBuf data) { - int sum = 0; - int len = data.capacity(); - for (int j = 0; len > 1; len--) { - sum += data.readByte() & 0xff; - if ((sum & 0x80000000) > 0) { - sum = (sum & 0xffff) + (sum >> 16); - } - } - if (len == 1) { - sum += data.readByte() & 0xff; - } - while ((sum >> 16) > 0) { - sum = (sum & 0xffff) + sum >> 16; - } - sum = (sum == 0xffff) ? sum & 0xffff : (~sum) & 0xffff; - return sum; - } - - private static ByteBuf encodeContent(String uniqueId, String content) { ByteBuf buf = Unpooled.buffer(); @@ -92,8 +73,7 @@ public class Xexun2ProtocolEncoder extends BaseProtocolEncoder { buf.writeShort(1); // index buf.writeBytes(DataConverter.parseHex(uniqueId + "0")); buf.writeShort(message.capacity()); - buf.writeShort(udpchecksum(message)); - message.resetReaderIndex(); + buf.writeShort(Checksum.udp(message.nioBuffer())); buf.writeBytes(message); buf.writeShort(FLAG); -- cgit v1.2.3 From 910965c3d08745d68cbf812ed96eef7323dbb893 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Mon, 1 Aug 2022 19:06:04 -0700 Subject: Handle GPS103 no GPS (fix #4915) --- src/main/java/org/traccar/helper/Parser.java | 13 +++++++------ .../java/org/traccar/protocol/Gps103ProtocolDecoder.java | 15 ++++++++++----- .../org/traccar/protocol/Gps103ProtocolDecoderTest.java | 6 +++++- 3 files changed, 22 insertions(+), 12 deletions(-) (limited to 'src/main/java/org/traccar/helper') diff --git a/src/main/java/org/traccar/helper/Parser.java b/src/main/java/org/traccar/helper/Parser.java index 22e98ded1..aa39e1ad7 100644 --- a/src/main/java/org/traccar/helper/Parser.java +++ b/src/main/java/org/traccar/helper/Parser.java @@ -48,13 +48,14 @@ public class Parser { } public boolean hasNext(int number) { - String value = matcher.group(position); - if (value != null && !value.isEmpty()) { - return true; - } else { - position += number; - return false; + for (int i = position; i < position + number; i++) { + String value = matcher.group(i); + if (value != null && !value.isEmpty()) { + return true; + } } + position += number; + return false; } public String next() { diff --git a/src/main/java/org/traccar/protocol/Gps103ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Gps103ProtocolDecoder.java index b63bcd0c0..28efa3c30 100644 --- a/src/main/java/org/traccar/protocol/Gps103ProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Gps103ProtocolDecoder.java @@ -56,9 +56,12 @@ public class Gps103ProtocolDecoder extends BaseProtocolDecoder { .groupEnd() .expression("([^,]+)?,") // rfid .groupBegin() - .text("L,,,") + .text("L,") + .groupBegin() + .text(",,") .number("(x+),,") // lac .number("(x+),,,") // cid + .groupEnd("?") .or() .text("F,") .groupBegin() @@ -218,13 +221,11 @@ public class Gps103ProtocolDecoder extends BaseProtocolDecoder { } if (parser.hasNext(2)) { - - getLastLocation(position, null); - position.setNetwork(new Network(CellTower.fromLacCid( getConfig(), parser.nextHexInt(0), parser.nextHexInt(0)))); + } - } else { + if (parser.hasNext(20)) { String utcHours = parser.next(); String utcMinutes = parser.next(); @@ -262,6 +263,10 @@ public class Gps103ProtocolDecoder extends BaseProtocolDecoder { position.set("fuel2", parser.nextDouble()); position.set(Position.PREFIX_TEMP + 1, parser.nextInt()); + } else { + + getLastLocation(position, null); + } return position; diff --git a/src/test/java/org/traccar/protocol/Gps103ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Gps103ProtocolDecoderTest.java index 425fcd8ae..cf5786d75 100644 --- a/src/test/java/org/traccar/protocol/Gps103ProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Gps103ProtocolDecoderTest.java @@ -11,6 +11,10 @@ public class Gps103ProtocolDecoderTest extends ProtocolTest { var decoder = inject(new Gps103ProtocolDecoder(null)); + verifyAttribute(decoder, text( + "imei:865456055519122,sensor alarm,2208011920,,L,;"), + Position.KEY_ALARM, Position.ALARM_VIBRATION); + verifyPosition(decoder, text( "imei:864035050002451,tracker,201223064947,,F,064947,A,1935.70640,N,09859.94436,W,0.025,;")); @@ -155,7 +159,7 @@ public class Gps103ProtocolDecoderTest extends ProtocolTest { "359586015829802")); // No GPS signal - verifyNull(decoder, text( + verifyNotNull(decoder, text( "imei:359586015829802,tracker,000000000,13554900601,L,;")); verifyPosition(decoder, text( -- cgit v1.2.3 From dbc5fc5dcf697dcc00d357bbca5fe4669325148b Mon Sep 17 00:00:00 2001 From: Stefan Clark Date: Sat, 6 Aug 2022 17:42:22 +0100 Subject: Updated Xexun2 Protocol --- src/main/java/org/traccar/helper/Checksum.java | 8 +--- .../org/traccar/protocol/Xexun2FrameEncoder.java | 48 ++++++++++++++++++++++ .../java/org/traccar/protocol/Xexun2Protocol.java | 1 + .../traccar/protocol/Xexun2ProtocolDecoder.java | 12 +++--- .../traccar/protocol/Xexun2ProtocolEncoder.java | 48 ++++------------------ .../traccar/protocol/Xexun2FrameDecoderTest.java | 4 ++ .../traccar/protocol/Xexun2FrameEncoderTest.java | 20 +++++++++ 7 files changed, 90 insertions(+), 51 deletions(-) create mode 100644 src/main/java/org/traccar/protocol/Xexun2FrameEncoder.java create mode 100644 src/test/java/org/traccar/protocol/Xexun2FrameEncoderTest.java (limited to 'src/main/java/org/traccar/helper') diff --git a/src/main/java/org/traccar/helper/Checksum.java b/src/main/java/org/traccar/helper/Checksum.java index e660790ef..db5817275 100644 --- a/src/main/java/org/traccar/helper/Checksum.java +++ b/src/main/java/org/traccar/helper/Checksum.java @@ -200,18 +200,14 @@ public final class Checksum { return (10 - (checksum % 10)) % 10; } - public static int udp(ByteBuffer data) { + public static int ip(ByteBuffer data) { int sum = 0; - int len = data.capacity(); - for (int j = 0; len > 1; len--) { + while (data.remaining() > 0) { sum += data.get() & 0xff; if ((sum & 0x80000000) > 0) { sum = (sum & 0xffff) + (sum >> 16); } } - if (len == 1) { - sum += data.get() & 0xff; - } while ((sum >> 16) > 0) { sum = (sum & 0xffff) + sum >> 16; } diff --git a/src/main/java/org/traccar/protocol/Xexun2FrameEncoder.java b/src/main/java/org/traccar/protocol/Xexun2FrameEncoder.java new file mode 100644 index 000000000..52d43c36c --- /dev/null +++ b/src/main/java/org/traccar/protocol/Xexun2FrameEncoder.java @@ -0,0 +1,48 @@ +/* + * Copyright 2022 Stefan Clark (stefan@stefanclark.co.uk) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.traccar.protocol; + +import io.netty.buffer.ByteBuf; +import io.netty.channel.ChannelHandlerContext; +import io.netty.handler.codec.MessageToByteEncoder; + +public class Xexun2FrameEncoder extends MessageToByteEncoder { + + @Override + protected void encode(ChannelHandlerContext ctx, ByteBuf msg, ByteBuf out) { + out.writeBytes(msg.readBytes(2)); + + while (msg.readableBytes() > 2) { + int b = msg.readUnsignedByte(); + if (b == 0xfa && msg.isReadable() && msg.getUnsignedByte(msg.readerIndex()) == 0xaf) { + msg.readUnsignedByte(); + out.writeByte(0xfb); + out.writeByte(0xbf); + out.writeByte(0x01); + } else if (b == 0xfb && msg.isReadable() && msg.getUnsignedByte(msg.readerIndex()) == 0xbf) { + msg.readUnsignedByte(); + out.writeByte(0xfb); + out.writeByte(0xbf); + out.writeByte(0x02); + } else { + out.writeByte(b); + } + } + + out.writeBytes(msg.readBytes(2)); + + } +} diff --git a/src/main/java/org/traccar/protocol/Xexun2Protocol.java b/src/main/java/org/traccar/protocol/Xexun2Protocol.java index 1d5038a22..52cf731f0 100644 --- a/src/main/java/org/traccar/protocol/Xexun2Protocol.java +++ b/src/main/java/org/traccar/protocol/Xexun2Protocol.java @@ -35,6 +35,7 @@ public class Xexun2Protocol extends BaseProtocol { addServer(new TrackerServer(config, getName(), false) { @Override protected void addProtocolHandlers(PipelineBuilder pipeline, Config config) { + pipeline.addLast(new Xexun2FrameEncoder()); pipeline.addLast(new Xexun2FrameDecoder()); pipeline.addLast(new Xexun2ProtocolDecoder(Xexun2Protocol.this)); pipeline.addLast(new Xexun2ProtocolEncoder(Xexun2Protocol.this)); diff --git a/src/main/java/org/traccar/protocol/Xexun2ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Xexun2ProtocolDecoder.java index f0158e6ce..913dfaf28 100644 --- a/src/main/java/org/traccar/protocol/Xexun2ProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Xexun2ProtocolDecoder.java @@ -42,12 +42,14 @@ public class Xexun2ProtocolDecoder extends BaseProtocolDecoder { super(protocol); } + public static final int FLAG = 0xfaaf; + public static final int MSG_COMMAND = 0x07; public static final int MSG_POSITION = 0x14; private void sendResponse(Channel channel, int type, int index, ByteBuf imei) { if (channel != null) { ByteBuf response = Unpooled.buffer(); - response.writeShort(Xexun2ProtocolEncoder.FLAG); + response.writeShort(FLAG); response.writeShort(type); response.writeShort(index); @@ -56,7 +58,7 @@ public class Xexun2ProtocolDecoder extends BaseProtocolDecoder { response.writeShort(0xfffe); // checksum response.writeByte(1); // response - response.writeShort(Xexun2ProtocolEncoder.FLAG); + response.writeShort(FLAG); channel.writeAndFlush(new NetworkMessage(response, channel.remoteAddress())); } @@ -99,13 +101,13 @@ public class Xexun2ProtocolDecoder extends BaseProtocolDecoder { } int payloadSize = buf.readUnsignedShort() & 0x03ff; - int checksum = buf.readUnsignedShort(); // checksum + int checksum = buf.readUnsignedShort(); - if (checksum != Checksum.udp(buf.nioBuffer(buf.readerIndex(), payloadSize))) { + if (checksum != Checksum.ip(buf.nioBuffer(buf.readerIndex(), payloadSize))) { return null; } - if (type != Xexun2ProtocolEncoder.MSG_COMMAND) { + if (type != MSG_COMMAND) { sendResponse(channel, type, index, imei); } diff --git a/src/main/java/org/traccar/protocol/Xexun2ProtocolEncoder.java b/src/main/java/org/traccar/protocol/Xexun2ProtocolEncoder.java index 6e1e1d68d..c315cab30 100644 --- a/src/main/java/org/traccar/protocol/Xexun2ProtocolEncoder.java +++ b/src/main/java/org/traccar/protocol/Xexun2ProtocolEncoder.java @@ -23,61 +23,29 @@ import org.traccar.helper.DataConverter; import org.traccar.model.Command; import org.traccar.Protocol; +import java.nio.charset.StandardCharsets; + public class Xexun2ProtocolEncoder extends BaseProtocolEncoder { public Xexun2ProtocolEncoder(Protocol protocol) { super(protocol); } - public static final int FLAG = 0xfaaf; - public static final int MSG_COMMAND = 0x07; - - private static ByteBuf encodeFrame(ByteBuf buf) { - int bufLength = buf.readableBytes(); - if (bufLength < 5) { - return null; - } - - ByteBuf result = Unpooled.buffer(); - - result.writeBytes(buf.readBytes(2)); - - while (buf.readerIndex() < bufLength - 2) { - int b = buf.readUnsignedByte(); - if (b == 0xfa && buf.isReadable() && buf.getUnsignedByte(buf.readerIndex()) == 0xaf) { - buf.readUnsignedByte(); - result.writeByte(0xfb); - result.writeByte(0xbf); - result.writeByte(0x01); - } else if (b == 0xfb && buf.isReadable() && buf.getUnsignedByte(buf.readerIndex()) == 0xbf) { - buf.readUnsignedByte(); - result.writeByte(0xfb); - result.writeByte(0xbf); - result.writeByte(0x02); - } else { - result.writeByte(b); - } - } - result.writeBytes(buf.readBytes(2)); - - return result; - } - private static ByteBuf encodeContent(String uniqueId, String content) { ByteBuf buf = Unpooled.buffer(); - ByteBuf message = Unpooled.copiedBuffer(content.getBytes()); + ByteBuf message = Unpooled.copiedBuffer(content.getBytes(StandardCharsets.US_ASCII)); - buf.writeShort(FLAG); - buf.writeShort(MSG_COMMAND); + buf.writeShort(Xexun2ProtocolDecoder.FLAG); + buf.writeShort(Xexun2ProtocolDecoder.MSG_COMMAND); buf.writeShort(1); // index buf.writeBytes(DataConverter.parseHex(uniqueId + "0")); buf.writeShort(message.capacity()); - buf.writeShort(Checksum.udp(message.nioBuffer())); + buf.writeShort(Checksum.ip(message.nioBuffer())); buf.writeBytes(message); - buf.writeShort(FLAG); + buf.writeShort(Xexun2ProtocolDecoder.FLAG); - return encodeFrame(buf); + return buf; } @Override diff --git a/src/test/java/org/traccar/protocol/Xexun2FrameDecoderTest.java b/src/test/java/org/traccar/protocol/Xexun2FrameDecoderTest.java index 7209a423b..34437862c 100644 --- a/src/test/java/org/traccar/protocol/Xexun2FrameDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Xexun2FrameDecoderTest.java @@ -14,6 +14,10 @@ public class Xexun2FrameDecoderTest extends ProtocolTest { binary("faaf0014000286147503139003400032f2b001002f4260b0d6a0008019104a3378323130333135317c323130333132303100704020308715758089502023015648643670faaf"), decoder.decode(null, null, binary("faaf0014000286147503139003400032f2b001002f4260b0d6a0008019104a3378323130333135317c323130333132303100704020308715758089502023015648643670faaf"))); + verifyFrame( + binary("FAAF123456FAAF123456FBBF123456FAAF"), + decoder.decode(null, null, binary("FAAF123456FBBF01123456FBBF02123456FAAF"))); + } } diff --git a/src/test/java/org/traccar/protocol/Xexun2FrameEncoderTest.java b/src/test/java/org/traccar/protocol/Xexun2FrameEncoderTest.java new file mode 100644 index 000000000..54a8aaa14 --- /dev/null +++ b/src/test/java/org/traccar/protocol/Xexun2FrameEncoderTest.java @@ -0,0 +1,20 @@ +package org.traccar.protocol; + +import io.netty.buffer.ByteBuf; +import io.netty.buffer.Unpooled; +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class Xexun2FrameEncoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + Xexun2FrameEncoder encoder = new Xexun2FrameEncoder(); + + ByteBuf result = Unpooled.buffer(); + encoder.encode(null, binary("FAAF123456FAAF123456FBBF123456FAAF"), result); + verifyFrame(binary("FAAF123456FBBF01123456FBBF02123456FAAF"), result); + } + +} -- cgit v1.2.3 From 1fb6c86ea12f325bfdb372d98400c8a904c6e927 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 20 Aug 2022 09:00:27 -0700 Subject: Support TK103 cell info (fix #4925) --- src/main/java/org/traccar/helper/PatternUtil.java | 2 +- .../org/traccar/protocol/Tk103ProtocolDecoder.java | 49 +++++++++++++++++++++- .../traccar/protocol/Tk103ProtocolDecoderTest.java | 6 +++ 3 files changed, 54 insertions(+), 3 deletions(-) (limited to 'src/main/java/org/traccar/helper') diff --git a/src/main/java/org/traccar/helper/PatternUtil.java b/src/main/java/org/traccar/helper/PatternUtil.java index 74813e1d9..a46c7b7b4 100644 --- a/src/main/java/org/traccar/helper/PatternUtil.java +++ b/src/main/java/org/traccar/helper/PatternUtil.java @@ -63,7 +63,7 @@ public final class PatternUtil { for (int i = 0; i < pattern.length(); i++) { try { - Matcher matcher = Pattern.compile("(" + pattern.substring(0, i) + ").*").matcher(input); + Matcher matcher = Pattern.compile("(" + pattern.substring(0, i) + ")[\\s\\S]*").matcher(input); if (matcher.matches()) { result.patternMatch = pattern.substring(0, i); result.patternTail = pattern.substring(i); diff --git a/src/main/java/org/traccar/protocol/Tk103ProtocolDecoder.java b/src/main/java/org/traccar/protocol/Tk103ProtocolDecoder.java index e197a8a41..b343c3b33 100644 --- a/src/main/java/org/traccar/protocol/Tk103ProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/Tk103ProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2012 - 2021 Anton Tananaev (anton@traccar.org) + * Copyright 2012 - 2022 Anton Tananaev (anton@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -99,6 +99,16 @@ public class Tk103ProtocolDecoder extends BaseProtocolDecoder { .any() .compile(); + private static final Pattern PATTERN_CELL = new PatternBuilder() + .text("(") + .number("(d{12})") // device id + .expression(".{4}") // type + .number("(?:d{15})?,") // imei + .expression("(.+),") // cell + .number("(d{8})") // odometer + .text(")") + .compile(); + private static final Pattern PATTERN_NETWORK = new PatternBuilder() .text("(").optional() .number("(d{12})") // device id @@ -297,6 +307,39 @@ public class Tk103ProtocolDecoder extends BaseProtocolDecoder { return position; } + private Position decodeCell(Channel channel, SocketAddress remoteAddress, String sentence) { + Parser parser = new Parser(PATTERN_CELL, sentence); + if (!parser.matches()) { + return null; + } + + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, parser.next()); + if (deviceSession == null) { + return null; + } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + getLastLocation(position, null); + + Network network = new Network(); + + String[] cells = parser.next().split("\n"); + for (String cell : cells) { + String[] values = cell.substring(1, cell.length() - 1).split(","); + network.addCellTower(CellTower.from( + Integer.parseInt(values[0]), Integer.parseInt(values[1]), + Integer.parseInt(values[2]), Integer.parseInt(values[3]))); + } + + position.setNetwork(network); + + position.set(Position.KEY_ODOMETER, parser.nextLong(16, 0)); + + return position; + } + private Position decodeNetwork(Channel channel, SocketAddress remoteAddress, String sentence) { Parser parser = new Parser(PATTERN_NETWORK, sentence); if (!parser.matches()) { @@ -422,7 +465,9 @@ public class Tk103ProtocolDecoder extends BaseProtocolDecoder { } } - if (sentence.contains("ZC20")) { + if (sentence.indexOf('{') > 0 && sentence.indexOf('}') > 0) { + return decodeCell(channel, remoteAddress, sentence); + } else if (sentence.contains("ZC20")) { return decodeBattery(channel, remoteAddress, sentence); } else if (sentence.contains("BZ00")) { return decodeNetwork(channel, remoteAddress, sentence); diff --git a/src/test/java/org/traccar/protocol/Tk103ProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/Tk103ProtocolDecoderTest.java index 6c01c14f7..8b3177136 100644 --- a/src/test/java/org/traccar/protocol/Tk103ProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/Tk103ProtocolDecoderTest.java @@ -11,6 +11,12 @@ public class Tk103ProtocolDecoderTest extends ProtocolTest { var decoder = inject(new Tk103ProtocolDecoder(null)); + verifyAttributes(decoder, text( + "(027046434858BZ00,{460,0,20949,58711}\n{460,0,20494,54003}\n{460,0,20951,19569}\n,01000000)")); + + verifyAttributes(decoder, text( + "(027045009305BP05355227045009305,{413,2,30073,16724}\n{413,2,30073,16730}\n{413,2,30073,49860}\n,01000000)")); + verifyPosition(decoder, text( "(868822040452227,DW3B,150421,A,4154.51607N,45.78950E,0.050,103142,0.000,595.200,7,0)")); -- cgit v1.2.3 From 3ead0772172daeb3d6fedab5f04a32c33b9d5ebb Mon Sep 17 00:00:00 2001 From: anton2920 Date: Sun, 24 Jul 2022 17:53:21 +0100 Subject: Added NMEA parser (that doesn't s**ck) --- src/main/java/org/traccar/helper/NMEA.java | 126 +++++++++++++++++++++++++++++ 1 file changed, 126 insertions(+) create mode 100644 src/main/java/org/traccar/helper/NMEA.java (limited to 'src/main/java/org/traccar/helper') diff --git a/src/main/java/org/traccar/helper/NMEA.java b/src/main/java/org/traccar/helper/NMEA.java new file mode 100644 index 000000000..cae47a8f6 --- /dev/null +++ b/src/main/java/org/traccar/helper/NMEA.java @@ -0,0 +1,126 @@ +package org.traccar.helper; + +import java.util.HashMap; +import java.util.Map; + + +public class NMEA { + + // fucking java interfaces + interface SentenceParser { + public boolean parse(String[] tokens, GPSPosition position); + } + + // utils + static float Latitude2Decimal(String lat, String NS) { + float med = Float.parseFloat(lat.substring(2)) / 60.0f; + med += Float.parseFloat(lat.substring(0, 2)); + if (NS.startsWith("S")) { + med = -med; + } + return med; + } + + static float Longitude2Decimal(String lon, String WE) { + float med = Float.parseFloat(lon.substring(3)) / 60.0f; + med += Float.parseFloat(lon.substring(0, 3)); + if (WE.startsWith("W")) { + med = -med; + } + return med; + } + + // parsers + class GPGGA implements SentenceParser { + public boolean parse(String[] tokens, GPSPosition position) { + position.time = Float.parseFloat(tokens[1]); + position.lat = Latitude2Decimal(tokens[2], tokens[3]); + position.lon = Longitude2Decimal(tokens[4], tokens[5]); + position.quality = Integer.parseInt(tokens[6]); + position.altitude = Float.parseFloat(tokens[9]); + return true; + } + } + + class GPGGL implements SentenceParser { + public boolean parse(String[] tokens, GPSPosition position) { + position.lat = Latitude2Decimal(tokens[1], tokens[2]); + position.lon = Longitude2Decimal(tokens[3], tokens[4]); + position.time = Float.parseFloat(tokens[5]); + return true; + } + } + + class GPRMC implements SentenceParser { + public boolean parse(String[] tokens, GPSPosition position) { + position.time = Float.parseFloat(tokens[1]); + position.lat = Latitude2Decimal(tokens[3], tokens[4]); + position.lon = Longitude2Decimal(tokens[5], tokens[6]); + position.velocity = Float.parseFloat(tokens[7]); + position.dir = Float.parseFloat(tokens[8]); + return true; + } + } + + class GPVTG implements SentenceParser { + public boolean parse(String[] tokens, GPSPosition position) { + position.dir = Float.parseFloat(tokens[3]); + return true; + } + } + + class GPRMZ implements SentenceParser { + public boolean parse(String[] tokens, GPSPosition position) { + position.altitude = Float.parseFloat(tokens[1]); + return true; + } + } + + public class GPSPosition { + public float time = 0.0f; + public float lat = 0.0f; + public float lon = 0.0f; + public boolean fixed = false; + public int quality = 0; + public float dir = 0.0f; + public float altitude = 0.0f; + public float velocity = 0.0f; + + public void updatefix() { + fixed = quality > 0; + } + + public String toString() { + return String.format("POSITION: lat: %f, lon: %f, time: %f, Q: %d, dir: %f, alt: %f, vel: %f", lat, lon, time, quality, dir, altitude, velocity); + } + } + + GPSPosition position = new GPSPosition(); + + private static final Map sentenceParsers = new HashMap(); + + public NMEA() { + sentenceParsers.put("GPGGA", new GPGGA()); + sentenceParsers.put("GPGGL", new GPGGL()); + sentenceParsers.put("GPRMC", new GPRMC()); + sentenceParsers.put("GPRMZ", new GPRMZ()); + //only really good GPS devices have this sentence but ... + sentenceParsers.put("GPVTG", new GPVTG()); + } + + public GPSPosition parse(String line) { + + if (line.startsWith("$")) { + String nmea = line.substring(1); + String[] tokens = nmea.split(","); + String type = tokens[0]; + //TODO check crc + if (sentenceParsers.containsKey(type)) { + sentenceParsers.get(type).parse(tokens, position); + } + position.updatefix(); + } + + return position; + } +} -- cgit v1.2.3 From 4de8efe1ef0810af492c161bfc1d3200958d75d8 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 18 Sep 2022 10:01:28 -0700 Subject: Refactor M-5000/10000 decoding --- src/main/java/org/traccar/helper/NMEA.java | 126 --------------------- .../traccar/protocol/PiligrimProtocolDecoder.java | 125 ++++++++------------ .../protocol/PiligrimProtocolDecoderTest.java | 4 + 3 files changed, 52 insertions(+), 203 deletions(-) delete mode 100644 src/main/java/org/traccar/helper/NMEA.java (limited to 'src/main/java/org/traccar/helper') diff --git a/src/main/java/org/traccar/helper/NMEA.java b/src/main/java/org/traccar/helper/NMEA.java deleted file mode 100644 index cae47a8f6..000000000 --- a/src/main/java/org/traccar/helper/NMEA.java +++ /dev/null @@ -1,126 +0,0 @@ -package org.traccar.helper; - -import java.util.HashMap; -import java.util.Map; - - -public class NMEA { - - // fucking java interfaces - interface SentenceParser { - public boolean parse(String[] tokens, GPSPosition position); - } - - // utils - static float Latitude2Decimal(String lat, String NS) { - float med = Float.parseFloat(lat.substring(2)) / 60.0f; - med += Float.parseFloat(lat.substring(0, 2)); - if (NS.startsWith("S")) { - med = -med; - } - return med; - } - - static float Longitude2Decimal(String lon, String WE) { - float med = Float.parseFloat(lon.substring(3)) / 60.0f; - med += Float.parseFloat(lon.substring(0, 3)); - if (WE.startsWith("W")) { - med = -med; - } - return med; - } - - // parsers - class GPGGA implements SentenceParser { - public boolean parse(String[] tokens, GPSPosition position) { - position.time = Float.parseFloat(tokens[1]); - position.lat = Latitude2Decimal(tokens[2], tokens[3]); - position.lon = Longitude2Decimal(tokens[4], tokens[5]); - position.quality = Integer.parseInt(tokens[6]); - position.altitude = Float.parseFloat(tokens[9]); - return true; - } - } - - class GPGGL implements SentenceParser { - public boolean parse(String[] tokens, GPSPosition position) { - position.lat = Latitude2Decimal(tokens[1], tokens[2]); - position.lon = Longitude2Decimal(tokens[3], tokens[4]); - position.time = Float.parseFloat(tokens[5]); - return true; - } - } - - class GPRMC implements SentenceParser { - public boolean parse(String[] tokens, GPSPosition position) { - position.time = Float.parseFloat(tokens[1]); - position.lat = Latitude2Decimal(tokens[3], tokens[4]); - position.lon = Longitude2Decimal(tokens[5], tokens[6]); - position.velocity = Float.parseFloat(tokens[7]); - position.dir = Float.parseFloat(tokens[8]); - return true; - } - } - - class GPVTG implements SentenceParser { - public boolean parse(String[] tokens, GPSPosition position) { - position.dir = Float.parseFloat(tokens[3]); - return true; - } - } - - class GPRMZ implements SentenceParser { - public boolean parse(String[] tokens, GPSPosition position) { - position.altitude = Float.parseFloat(tokens[1]); - return true; - } - } - - public class GPSPosition { - public float time = 0.0f; - public float lat = 0.0f; - public float lon = 0.0f; - public boolean fixed = false; - public int quality = 0; - public float dir = 0.0f; - public float altitude = 0.0f; - public float velocity = 0.0f; - - public void updatefix() { - fixed = quality > 0; - } - - public String toString() { - return String.format("POSITION: lat: %f, lon: %f, time: %f, Q: %d, dir: %f, alt: %f, vel: %f", lat, lon, time, quality, dir, altitude, velocity); - } - } - - GPSPosition position = new GPSPosition(); - - private static final Map sentenceParsers = new HashMap(); - - public NMEA() { - sentenceParsers.put("GPGGA", new GPGGA()); - sentenceParsers.put("GPGGL", new GPGGL()); - sentenceParsers.put("GPRMC", new GPRMC()); - sentenceParsers.put("GPRMZ", new GPRMZ()); - //only really good GPS devices have this sentence but ... - sentenceParsers.put("GPVTG", new GPVTG()); - } - - public GPSPosition parse(String line) { - - if (line.startsWith("$")) { - String nmea = line.substring(1); - String[] tokens = nmea.split(","); - String type = tokens[0]; - //TODO check crc - if (sentenceParsers.containsKey(type)) { - sentenceParsers.get(type).parse(tokens, position); - } - position.updatefix(); - } - - return position; - } -} diff --git a/src/main/java/org/traccar/protocol/PiligrimProtocolDecoder.java b/src/main/java/org/traccar/protocol/PiligrimProtocolDecoder.java index 6ca9b0795..34c879cb8 100644 --- a/src/main/java/org/traccar/protocol/PiligrimProtocolDecoder.java +++ b/src/main/java/org/traccar/protocol/PiligrimProtocolDecoder.java @@ -1,5 +1,5 @@ /* - * Copyright 2014 - 2020 Anton Tananaev (anton@traccar.org) + * Copyright 2014 - 2022 Anton Tananaev (anton@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -21,27 +21,23 @@ import io.netty.channel.Channel; import io.netty.handler.codec.http.FullHttpRequest; import io.netty.handler.codec.http.HttpResponseStatus; import io.netty.handler.codec.http.QueryStringDecoder; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.traccar.BaseHttpProtocolDecoder; -import org.traccar.WebDataHandler; -import org.traccar.session.DeviceSession; import org.traccar.Protocol; import org.traccar.helper.BitUtil; import org.traccar.helper.DateBuilder; -import org.traccar.helper.NMEA; +import org.traccar.helper.Parser; +import org.traccar.helper.PatternBuilder; import org.traccar.model.Position; +import org.traccar.session.DeviceSession; import java.net.SocketAddress; import java.nio.charset.StandardCharsets; -import java.util.Date; import java.util.LinkedList; import java.util.List; +import java.util.regex.Pattern; public class PiligrimProtocolDecoder extends BaseHttpProtocolDecoder { - private static final Logger LOGGER = LoggerFactory.getLogger(WebDataHandler.class); - public PiligrimProtocolDecoder(Protocol protocol) { super(protocol); } @@ -54,6 +50,21 @@ public class PiligrimProtocolDecoder extends BaseHttpProtocolDecoder { public static final int MSG_GPS_SENSORS = 0xF2; public static final int MSG_EVENTS = 0xF3; + private static final Pattern PATTERN = new PatternBuilder() + .expression("[^$]+") + .text("$GPRMC,") + .number("(dd)(dd)(dd).d+,") // time (hhmmss) + .expression("([AV]),") // validity + .number("(dd)(dd.d+),") // latitude + .expression("([NS]),") + .number("(d{2,3})(dd.d+),") // longitude + .expression("([EW]),") + .number("(d+.d+),") // speed + .number("(d+.d+),") // course + .number("(dd)(dd)(dd),") // date (ddmmyy) + .any() + .compile(); + @Override protected Object decode( Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { @@ -157,82 +168,42 @@ public class PiligrimProtocolDecoder extends BaseHttpProtocolDecoder { } return positions; + } else if (uri.startsWith("/push.do")) { + sendResponse(channel, "PUSH.DO: OK"); - /* Getting payload */ - ByteBuf contentStream = request.content(); - byte[] payloadBytes = new byte[Integer.parseInt(request.headers().get("Content-Length"))]; - contentStream.readBytes(payloadBytes); - String payload = new String(payloadBytes); - - /* Payload structure: - * &phone&message - */ - String[] payloadParts = payload.split("&"); - /* LOGGER.debug("Payload parts: " + Arrays.toString(payloadParts)); */ - String phoneNumber = payloadParts[1].substring(15); - DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, phoneNumber.substring(1)); + String sentence = request.content().toString(StandardCharsets.US_ASCII); + + String[] parts = sentence.split("&"); + String phone = parts[1].substring(16); + DeviceSession deviceSession = getDeviceSession(channel, remoteAddress, phone); if (deviceSession == null) { return null; } - /* TODO: use keys for flags in 'positions'. */ - String message = payloadParts[2].substring(8).replaceFirst("[a-zA-Z! ]*; ", ""); - /* LOGGER.debug("Phone number: " + phoneNumber); */ - /* LOGGER.debug("Message: " + message); */ - - if (message.startsWith("$GPRMC")) { - /* Supported message structure: - * GPS NMEA Command; GSM info; Unknown; Battery voltage? - * Example: $GPRMC,180752.000,A,5314.0857,N,03421.8173,E,0.00,104.74,220722,,,A,V* 29,05; GSM: 250-01 0b54-0519,1c30,3e96,3ebe,412e 25; S; Batt: 405,M - */ - LOGGER.debug("Supported message"); - - String[] messageParts = message.split(";"); - /* LOGGER.debug("Message parts: " + Arrays.toString(messageParts)); */ - - /* Parsing GPS */ - String unprocessedGpsCommand = messageParts[0]; - - /* Getting rid of checksum */ - String gpsCommand = unprocessedGpsCommand.replaceFirst("A,V[*].*", ""); - /* LOGGER.debug("GPS command: " + gpsCommand); */ - - NMEA gpsParser = new NMEA(); - - NMEA.GPSPosition gpsPosition = gpsParser.parse(gpsCommand); - - /* LOGGER.debug("Time: " + gpsPosition.time); */ - /* LOGGER.debug("Coordinates: " + gpsPosition.lat + " " + gpsPosition.lon); */ - /* LOGGER.debug("Speed over ground: " + gpsPosition.velocity + " knots"); */ - - /* Parsing other fields */ - /* String gsmInfo = messageParts[1]; */ - /* String unknown = messageParts[2]; */ - String batteryInfo = messageParts[messageParts.length - 1].substring(7).substring(0, 3); - /* LOGGER.debug("Battery: " + batteryInfo); */ - - /* Constructing response */ - Position position = new Position(getProtocolName()); - - position.setDeviceId(deviceSession.getDeviceId()); - position.setValid(true); - position.setLatitude(gpsPosition.lat); - position.setLongitude(gpsPosition.lon); - position.setTime(new Date(System.currentTimeMillis())); - position.setSpeed(gpsPosition.velocity); - position.setCourse(gpsPosition.dir); - position.setAccuracy(gpsPosition.quality); - position.setAltitude(gpsPosition.altitude); - position.set(Position.KEY_BATTERY, Integer.parseInt(batteryInfo) / 100); - - LOGGER.debug("Supported message finish"); - - return position; - } else { - LOGGER.error("Unsupported message"); + Parser parser = new Parser(PATTERN, parts[2]); + if (!parser.matches()) { + return null; } + + Position position = new Position(getProtocolName()); + position.setDeviceId(deviceSession.getDeviceId()); + + DateBuilder dateBuilder = new DateBuilder() + .setTime(parser.nextInt(), parser.nextInt(), parser.nextInt()); + + position.setValid(parser.next().equals("A")); + position.setLatitude(parser.nextCoordinate()); + position.setLongitude(parser.nextCoordinate()); + position.setSpeed(parser.nextDouble()); + position.setCourse(parser.nextDouble()); + + dateBuilder.setDateReverse(parser.nextInt(), parser.nextInt(), parser.nextInt()); + position.setTime(dateBuilder.getDate()); + + return position; + } return null; diff --git a/src/test/java/org/traccar/protocol/PiligrimProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/PiligrimProtocolDecoderTest.java index 475ac0125..0dd00462d 100644 --- a/src/test/java/org/traccar/protocol/PiligrimProtocolDecoderTest.java +++ b/src/test/java/org/traccar/protocol/PiligrimProtocolDecoderTest.java @@ -15,6 +15,10 @@ public class PiligrimProtocolDecoderTest extends ProtocolTest { "/bingps?imei=868204005544720&csq=18&vout=00&vin=4050&dataid=00000000", binary("fff2200d4110061a32354f3422310062000a0005173b0000a101000300005e00fff2200d4110100932354f2b22310042000b000e173b00009f01000700006000"))); + verifyPosition(decoder, request(HttpMethod.POST, + "/push.do", + buffer("&phoneNumber=%2B+78000000000&message=ALARM KEY; $GPRMC,180752.000,A,5314.0857,N,03421.8173,E,0.00,104.74,220722,,,A,V* 29,05; GSM: 250-01 0b54-0519,1c30,3e96,3ebe,412e 25; S; Batt: 405,M"))); + } } -- cgit v1.2.3 From abb26e80a5617424d960a0f7d0b98fcb379a5224 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Wed, 21 Sep 2022 21:47:45 -0700 Subject: Fix forwarding date format --- src/main/java/org/traccar/MainModule.java | 9 +++-- .../helper/ObjectMapperContextResolver.java | 38 ++++++++++++++++++++++ 2 files changed, 42 insertions(+), 5 deletions(-) create mode 100644 src/main/java/org/traccar/helper/ObjectMapperContextResolver.java (limited to 'src/main/java/org/traccar/helper') diff --git a/src/main/java/org/traccar/MainModule.java b/src/main/java/org/traccar/MainModule.java index e0617a734..94669915b 100644 --- a/src/main/java/org/traccar/MainModule.java +++ b/src/main/java/org/traccar/MainModule.java @@ -62,6 +62,7 @@ import org.traccar.geolocation.UnwiredGeolocationProvider; import org.traccar.handler.GeocoderHandler; import org.traccar.handler.GeolocationHandler; import org.traccar.handler.SpeedLimitHandler; +import org.traccar.helper.ObjectMapperContextResolver; import org.traccar.helper.SanitizerModule; import org.traccar.mail.LogMailManager; import org.traccar.mail.MailManager; @@ -81,7 +82,6 @@ import javax.annotation.Nullable; import javax.inject.Singleton; import javax.ws.rs.client.Client; import javax.ws.rs.client.ClientBuilder; -import javax.ws.rs.ext.ContextResolver; import java.io.IOException; import java.net.InetAddress; import java.net.UnknownHostException; @@ -110,14 +110,13 @@ public class MainModule extends AbstractModule { objectMapper.registerModule(new SanitizerModule()); } objectMapper.registerModule(new JSR353Module()); - objectMapper.setConfig(objectMapper - .getSerializationConfig().without(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS)); + objectMapper.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS); return objectMapper; } @Provides - public static Client provideClient(ObjectMapper objectMapper) { - return ClientBuilder.newClient().register((ContextResolver) clazz -> objectMapper); + public static Client provideClient(ObjectMapperContextResolver objectMapperContextResolver) { + return ClientBuilder.newClient().register(objectMapperContextResolver); } @Singleton diff --git a/src/main/java/org/traccar/helper/ObjectMapperContextResolver.java b/src/main/java/org/traccar/helper/ObjectMapperContextResolver.java new file mode 100644 index 000000000..b40e30d76 --- /dev/null +++ b/src/main/java/org/traccar/helper/ObjectMapperContextResolver.java @@ -0,0 +1,38 @@ +/* + * Copyright 2022 Anton Tananaev (anton@traccar.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.traccar.helper; + +import com.fasterxml.jackson.databind.ObjectMapper; + +import javax.inject.Inject; +import javax.ws.rs.ext.ContextResolver; + +// This does not work as a lambda +public class ObjectMapperContextResolver implements ContextResolver { + + private final ObjectMapper objectMapper; + + @Inject + public ObjectMapperContextResolver(ObjectMapper objectMapper) { + this.objectMapper = objectMapper; + } + + @Override + public ObjectMapper getContext(Class clazz) { + return objectMapper; + } + +} -- cgit v1.2.3 From b06dd882bf7b8e2067240d5957315499836138c8 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 2 Oct 2022 11:15:46 -0700 Subject: Update Java dependencies --- build.gradle | 40 ++++++++++++------------ src/main/java/org/traccar/helper/BufferUtil.java | 18 +++++------ 2 files changed, 29 insertions(+), 29 deletions(-) (limited to 'src/main/java/org/traccar/helper') diff --git a/build.gradle b/build.gradle index a9d97a825..6dcf6871a 100644 --- a/build.gradle +++ b/build.gradle @@ -10,10 +10,10 @@ repositories { } ext { - guiceVersion = "5.0.1" - jettyVersion = "10.0.7" // jetty 11 javax to jakarta - jerseyVersion = "2.36" // jersey 3 javax to jakarta - jacksonVersion = "2.13.3" // same version as jersey-media-json-jackson dependency + guiceVersion = "5.1.0" + jettyVersion = "10.0.12" // jetty 11 javax to jakarta + jerseyVersion = "2.37" // jersey 3 javax to jakarta + jacksonVersion = "2.13.4" // same version as jersey-media-json-jackson dependency protobufVersion = "3.21.7" } @@ -41,13 +41,13 @@ enforce { dependencies { implementation "commons-codec:commons-codec:1.15" - implementation "com.h2database:h2:2.0.206" - implementation "mysql:mysql-connector-java:8.0.27" - implementation "org.postgresql:postgresql:42.3.1" - implementation "com.microsoft.sqlserver:mssql-jdbc:9.4.1.jre11" + implementation "com.h2database:h2:2.1.214" + implementation "mysql:mysql-connector-java:8.0.30" + implementation "org.postgresql:postgresql:42.5.0" + implementation "com.microsoft.sqlserver:mssql-jdbc:11.2.1.jre11" implementation "com.zaxxer:HikariCP:5.0.1" - implementation "io.netty:netty-all:4.1.66.Final" - implementation "org.slf4j:slf4j-jdk14:2.0.0-alpha6" + implementation "io.netty:netty-all:4.1.82.Final" + implementation "org.slf4j:slf4j-jdk14:2.0.3" implementation "com.google.inject:guice:$guiceVersion" implementation "com.google.inject.extensions:guice-servlet:$guiceVersion" implementation "org.owasp.encoder:encoder:1.2.3" @@ -65,29 +65,29 @@ dependencies { implementation "org.glassfish.hk2:guice-bridge:2.6.1" // same version as jersey-hk2 implementation "com.fasterxml.jackson.jaxrs:jackson-jaxrs-json-provider:$jacksonVersion" implementation "com.fasterxml.jackson.datatype:jackson-datatype-jsr353:$jacksonVersion" - implementation "org.liquibase:liquibase-core:4.7.0" + implementation "org.liquibase:liquibase-core:4.16.1" implementation "com.sun.mail:javax.mail:1.6.2" implementation "org.jxls:jxls:2.4.7" // needs upgrade (wait for jexl 4) implementation "org.jxls:jxls-poi:1.0.16" // needs upgrade (wait for jexl 4) - implementation "org.apache.velocity:velocity:1.7" - implementation "org.apache.velocity:velocity-tools:2.0" + implementation "org.apache.velocity:velocity:1.7" // needs upgrade + implementation "org.apache.velocity:velocity-tools:2.0" // needs upgrade implementation "org.apache.commons:commons-collections4:4.4" - implementation "org.mnode.ical4j:ical4j:3.1.2" + implementation "org.mnode.ical4j:ical4j:3.2.5" implementation "org.locationtech.spatial4j:spatial4j:0.8" - implementation "org.locationtech.jts:jts-core:1.18.2" - implementation "net.java.dev.jna:jna-platform:5.10.0" + implementation "org.locationtech.jts:jts-core:1.19.0" + implementation "net.java.dev.jna:jna-platform:5.12.1" implementation "com.github.jnr:jnr-posix:3.1.15" implementation "com.google.protobuf:protobuf-java:$protobufVersion" implementation "javax.xml.bind:jaxb-api:2.3.1" - implementation "com.sun.xml.bind:jaxb-core:3.0.2" - implementation "com.sun.xml.bind:jaxb-impl:3.0.2" + implementation "com.sun.xml.bind:jaxb-core:3.0.2" // needs upgrade + implementation "com.sun.xml.bind:jaxb-impl:3.0.2" // needs upgrade implementation "javax.activation:activation:1.1.1" - implementation "com.amazonaws:aws-java-sdk-sns:1.12.141" + implementation "com.amazonaws:aws-java-sdk-sns:1.12.314" implementation ("com.google.firebase:firebase-admin:9.0.0") { exclude group: 'com.google.cloud', module: 'google-cloud-firestore' } testImplementation "junit:junit:4.13.2" - testImplementation "org.mockito:mockito-core:3.+" + testImplementation "org.mockito:mockito-core:4.+" } task copyDependencies(type: Copy) { diff --git a/src/main/java/org/traccar/helper/BufferUtil.java b/src/main/java/org/traccar/helper/BufferUtil.java index 0dbe0a4ad..d1025f548 100644 --- a/src/main/java/org/traccar/helper/BufferUtil.java +++ b/src/main/java/org/traccar/helper/BufferUtil.java @@ -59,16 +59,16 @@ public final class BufferUtil { } public static int indexOf(ByteBuf needle, ByteBuf haystack, int startIndex, int endIndex) { - ByteBuf wrappedHaystack; - if (startIndex == haystack.readerIndex() && endIndex == haystack.writerIndex()) { - wrappedHaystack = haystack; - } else { - wrappedHaystack = Unpooled.wrappedBuffer(haystack); - wrappedHaystack.readerIndex(startIndex - haystack.readerIndex()); - wrappedHaystack.writerIndex(endIndex - haystack.readerIndex()); + int originalReaderIndex = haystack.readerIndex(); + int originalWriterIndex = haystack.writerIndex(); + try { + haystack.readerIndex(startIndex); + haystack.writerIndex(endIndex); + return ByteBufUtil.indexOf(needle, haystack); + } finally { + haystack.readerIndex(originalReaderIndex); + haystack.writerIndex(originalWriterIndex); } - int result = ByteBufUtil.indexOf(needle, wrappedHaystack); - return result < 0 ? result : startIndex + result; } } -- cgit v1.2.3 From 4c8e98ed409df6e12128591eb1d8d0cf0856deb7 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Thu, 13 Oct 2022 10:31:54 -0700 Subject: Refactor database code (fix #4961) --- src/main/java/org/traccar/MainEventHandler.java | 2 +- .../java/org/traccar/api/BaseObjectResource.java | 11 +++-- src/main/java/org/traccar/api/MediaFilter.java | 2 +- .../org/traccar/api/resource/CommandResource.java | 2 +- .../org/traccar/api/resource/DeviceResource.java | 8 ++-- .../org/traccar/api/resource/EventResource.java | 2 +- .../org/traccar/api/resource/PasswordResource.java | 7 +-- .../org/traccar/api/resource/PositionResource.java | 2 +- .../org/traccar/api/resource/ServerResource.java | 2 +- .../org/traccar/api/resource/SessionResource.java | 2 +- .../org/traccar/api/resource/UserResource.java | 3 +- .../org/traccar/api/security/LoginService.java | 7 +-- .../traccar/api/security/PermissionsService.java | 4 +- .../java/org/traccar/database/CommandsManager.java | 8 ++-- .../org/traccar/database/DeviceLookupService.java | 2 +- .../java/org/traccar/handler/FilterHandler.java | 2 +- .../handler/events/GeofenceEventHandler.java | 3 +- .../traccar/handler/events/MotionEventHandler.java | 2 +- .../handler/events/OverspeedEventHandler.java | 2 +- .../org/traccar/helper/model/PositionUtil.java | 2 +- src/main/java/org/traccar/model/Device.java | 7 ++- .../org/traccar/reports/EventsReportProvider.java | 4 +- .../org/traccar/reports/GpxExportProvider.java | 2 +- .../org/traccar/reports/KmlExportProvider.java | 2 +- .../org/traccar/reports/RouteReportProvider.java | 2 +- .../org/traccar/reports/StopsReportProvider.java | 2 +- .../org/traccar/reports/TripsReportProvider.java | 2 +- .../org/traccar/reports/common/ReportUtils.java | 4 +- .../org/traccar/session/ConnectionManager.java | 4 +- .../org/traccar/session/cache/CacheManager.java | 12 ++--- .../java/org/traccar/storage/DatabaseStorage.java | 25 +++++----- .../java/org/traccar/storage/QueryBuilder.java | 54 +++++++++++----------- .../java/org/traccar/storage/query/Columns.java | 3 +- .../java/org/traccar/storage/query/Condition.java | 8 +--- 34 files changed, 102 insertions(+), 104 deletions(-) (limited to 'src/main/java/org/traccar/helper') diff --git a/src/main/java/org/traccar/MainEventHandler.java b/src/main/java/org/traccar/MainEventHandler.java index 17bcad0dd..877f03ae7 100644 --- a/src/main/java/org/traccar/MainEventHandler.java +++ b/src/main/java/org/traccar/MainEventHandler.java @@ -90,7 +90,7 @@ public class MainEventHandler extends ChannelInboundHandlerAdapter { updatedDevice.setPositionId(position.getId()); storage.updateObject(updatedDevice, new Request( new Columns.Include("positionId"), - new Condition.Equals("id", "id"))); + new Condition.Equals("id", updatedDevice.getId()))); cacheManager.updatePosition(position); connectionManager.updatePosition(true, position); diff --git a/src/main/java/org/traccar/api/BaseObjectResource.java b/src/main/java/org/traccar/api/BaseObjectResource.java index 0ec2bfeaa..904781e54 100644 --- a/src/main/java/org/traccar/api/BaseObjectResource.java +++ b/src/main/java/org/traccar/api/BaseObjectResource.java @@ -56,7 +56,7 @@ public abstract class BaseObjectResource extends BaseResour public Response getSingle(@PathParam("id") long id) throws StorageException { permissionsService.checkPermission(baseClass, getUserId(), id); T entity = storage.getObject(baseClass, new Request( - new Columns.All(), new Condition.Equals("id", "id", id))); + new Columns.All(), new Condition.Equals("id", id))); if (entity != null) { return Response.ok(entity).build(); } else { @@ -86,7 +86,7 @@ public abstract class BaseObjectResource extends BaseResour if (entity instanceof User) { User before = storage.getObject(User.class, new Request( - new Columns.All(), new Condition.Equals("id", "id", entity.getId()))); + new Columns.All(), new Condition.Equals("id", entity.getId()))); permissionsService.checkUserUpdate(getUserId(), before, (User) entity); } else if (entity instanceof Group) { Group group = (Group) entity; @@ -97,12 +97,13 @@ public abstract class BaseObjectResource extends BaseResour storage.updateObject(entity, new Request( new Columns.Exclude("id"), - new Condition.Equals("id", "id"))); + new Condition.Equals("id", entity.getId()))); if (entity instanceof User) { User user = (User) entity; if (user.getHashedPassword() != null) { storage.updateObject(entity, new Request( - new Columns.Include("hashedPassword", "salt"), new Condition.Equals("id", "id"))); + new Columns.Include("hashedPassword", "salt"), + new Condition.Equals("id", entity.getId()))); } } cacheManager.updateOrInvalidate(true, entity); @@ -117,7 +118,7 @@ public abstract class BaseObjectResource extends BaseResour permissionsService.checkEdit(getUserId(), baseClass, false); permissionsService.checkPermission(baseClass, getUserId(), id); - storage.removeObject(baseClass, new Request(new Condition.Equals("id", "id", id))); + storage.removeObject(baseClass, new Request(new Condition.Equals("id", id))); cacheManager.invalidate(baseClass, id); LogAction.remove(getUserId(), baseClass, id); diff --git a/src/main/java/org/traccar/api/MediaFilter.java b/src/main/java/org/traccar/api/MediaFilter.java index 6d95c66a8..ab75bdc5d 100644 --- a/src/main/java/org/traccar/api/MediaFilter.java +++ b/src/main/java/org/traccar/api/MediaFilter.java @@ -84,7 +84,7 @@ public class MediaFilter implements Filter { String[] parts = path != null ? path.split("/") : null; if (parts != null && parts.length >= 2) { Device device = storage.getObject(Device.class, new Request( - new Columns.All(), new Condition.Equals("uniqueId", "uniqueId", parts[1]))); + new Columns.All(), new Condition.Equals("uniqueId", parts[1]))); if (device != null) { permissionsServiceProvider.get().checkPermission(Device.class, userId, device.getId()); chain.doFilter(request, response); diff --git a/src/main/java/org/traccar/api/resource/CommandResource.java b/src/main/java/org/traccar/api/resource/CommandResource.java index 92804e725..80b9fd18f 100644 --- a/src/main/java/org/traccar/api/resource/CommandResource.java +++ b/src/main/java/org/traccar/api/resource/CommandResource.java @@ -110,7 +110,7 @@ public class CommandResource extends ExtendedObjectResource { permissionsService.checkPermission(Command.class, getUserId(), entity.getId()); long deviceId = entity.getDeviceId(); entity = storage.getObject(baseClass, new Request( - new Columns.All(), new Condition.Equals("id", "id", entity.getId()))); + new Columns.All(), new Condition.Equals("id", entity.getId()))); entity.setDeviceId(deviceId); } else { permissionsService.checkRestriction(getUserId(), UserRestrictions::getLimitCommands); diff --git a/src/main/java/org/traccar/api/resource/DeviceResource.java b/src/main/java/org/traccar/api/resource/DeviceResource.java index 1d9bc20ec..c0b0cea0d 100644 --- a/src/main/java/org/traccar/api/resource/DeviceResource.java +++ b/src/main/java/org/traccar/api/resource/DeviceResource.java @@ -84,14 +84,14 @@ public class DeviceResource extends BaseObjectResource { result.addAll(storage.getObjects(Device.class, new Request( new Columns.All(), new Condition.And( - new Condition.Equals("uniqueId", "uniqueId", uniqueId), + new Condition.Equals("uniqueId", uniqueId), new Condition.Permission(User.class, getUserId(), Device.class))))); } for (Long deviceId : deviceIds) { result.addAll(storage.getObjects(Device.class, new Request( new Columns.All(), new Condition.And( - new Condition.Equals("id", "id", deviceId), + new Condition.Equals("id", deviceId), new Condition.Permission(User.class, getUserId(), Device.class))))); } return result; @@ -142,7 +142,7 @@ public class DeviceResource extends BaseObjectResource { device.setPositionId(position.getId()); storage.updateObject(device, new Request( new Columns.Include("positionId"), - new Condition.Equals("id", "id"))); + new Condition.Equals("id", device.getId()))); try { cacheManager.addDevice(position.getDeviceId()); @@ -169,7 +169,7 @@ public class DeviceResource extends BaseObjectResource { Device device = storage.getObject(Device.class, new Request( new Columns.All(), new Condition.And( - new Condition.Equals("id", "id", deviceId), + new Condition.Equals("id", deviceId), new Condition.Permission(User.class, getUserId(), Device.class)))); if (device != null) { String name = "device"; diff --git a/src/main/java/org/traccar/api/resource/EventResource.java b/src/main/java/org/traccar/api/resource/EventResource.java index 3870e9af9..afdaf52b5 100644 --- a/src/main/java/org/traccar/api/resource/EventResource.java +++ b/src/main/java/org/traccar/api/resource/EventResource.java @@ -41,7 +41,7 @@ public class EventResource extends BaseResource { @GET public Event get(@PathParam("id") long id) throws StorageException { Event event = storage.getObject(Event.class, new Request( - new Columns.All(), new Condition.Equals("id", "id", id))); + new Columns.All(), new Condition.Equals("id", id))); if (event == null) { throw new WebApplicationException(Response.status(Response.Status.NOT_FOUND).build()); } diff --git a/src/main/java/org/traccar/api/resource/PasswordResource.java b/src/main/java/org/traccar/api/resource/PasswordResource.java index 625ff4cb1..ebf4e3b91 100644 --- a/src/main/java/org/traccar/api/resource/PasswordResource.java +++ b/src/main/java/org/traccar/api/resource/PasswordResource.java @@ -59,7 +59,7 @@ public class PasswordResource extends BaseResource { throws StorageException, MessagingException, GeneralSecurityException, IOException { User user = storage.getObject(User.class, new Request( - new Columns.All(), new Condition.Equals("email", "email", email))); + new Columns.All(), new Condition.Equals("email", email))); if (user != null) { var velocityContext = textTemplateFormatter.prepareContext(permissionsService.getServer(), user); velocityContext.put("token", tokenManager.generateToken(user.getId())); @@ -78,11 +78,12 @@ public class PasswordResource extends BaseResource { long userId = tokenManager.verifyToken(token); User user = storage.getObject(User.class, new Request( - new Columns.All(), new Condition.Equals("id", "id", userId))); + new Columns.All(), new Condition.Equals("id", userId))); if (user != null) { user.setPassword(password); storage.updateObject(user, new Request( - new Columns.Include("hashedPassword", "salt"), new Condition.Equals("id", "id"))); + new Columns.Include("hashedPassword", "salt"), + new Condition.Equals("id", userId))); return Response.ok().build(); } return Response.status(Response.Status.NOT_FOUND).build(); diff --git a/src/main/java/org/traccar/api/resource/PositionResource.java b/src/main/java/org/traccar/api/resource/PositionResource.java index 7d7921085..042dd1e23 100644 --- a/src/main/java/org/traccar/api/resource/PositionResource.java +++ b/src/main/java/org/traccar/api/resource/PositionResource.java @@ -67,7 +67,7 @@ public class PositionResource extends BaseResource { var positions = new ArrayList(); for (long positionId : positionIds) { Position position = storage.getObject(Position.class, new Request( - new Columns.All(), new Condition.Equals("id", "id", positionId))); + new Columns.All(), new Condition.Equals("id", positionId))); permissionsService.checkPermission(Device.class, getUserId(), position.getDeviceId()); positions.add(position); } diff --git a/src/main/java/org/traccar/api/resource/ServerResource.java b/src/main/java/org/traccar/api/resource/ServerResource.java index e35cd7d95..e7f0b93ca 100644 --- a/src/main/java/org/traccar/api/resource/ServerResource.java +++ b/src/main/java/org/traccar/api/resource/ServerResource.java @@ -76,7 +76,7 @@ public class ServerResource extends BaseResource { permissionsService.checkAdmin(getUserId()); storage.updateObject(entity, new Request( new Columns.Exclude("id"), - new Condition.Equals("id", "id"))); + new Condition.Equals("id", entity.getId()))); cacheManager.updateOrInvalidate(true, entity); LogAction.edit(getUserId(), entity); return Response.ok(entity).build(); diff --git a/src/main/java/org/traccar/api/resource/SessionResource.java b/src/main/java/org/traccar/api/resource/SessionResource.java index 05f492d73..1e984fbd0 100644 --- a/src/main/java/org/traccar/api/resource/SessionResource.java +++ b/src/main/java/org/traccar/api/resource/SessionResource.java @@ -122,7 +122,7 @@ public class SessionResource extends BaseResource { public User get(@PathParam("id") long userId) throws StorageException { permissionsService.checkAdmin(getUserId()); User user = storage.getObject(User.class, new Request( - new Columns.All(), new Condition.Equals("id", "id", userId))); + new Columns.All(), new Condition.Equals("id", userId))); request.getSession().setAttribute(USER_ID_KEY, user.getId()); LogAction.login(user.getId(), ServletHelper.retrieveRemoteAddress(request)); return user; diff --git a/src/main/java/org/traccar/api/resource/UserResource.java b/src/main/java/org/traccar/api/resource/UserResource.java index dd71de4c6..91875ef51 100644 --- a/src/main/java/org/traccar/api/resource/UserResource.java +++ b/src/main/java/org/traccar/api/resource/UserResource.java @@ -100,7 +100,8 @@ public class UserResource extends BaseObjectResource { entity.setId(storage.addObject(entity, new Request(new Columns.Exclude("id")))); storage.updateObject(entity, new Request( - new Columns.Include("hashedPassword", "salt"), new Condition.Equals("id", "id"))); + new Columns.Include("hashedPassword", "salt"), + new Condition.Equals("id", entity.getId()))); LogAction.create(getUserId(), entity); diff --git a/src/main/java/org/traccar/api/security/LoginService.java b/src/main/java/org/traccar/api/security/LoginService.java index 32487f06b..88bafcfb5 100644 --- a/src/main/java/org/traccar/api/security/LoginService.java +++ b/src/main/java/org/traccar/api/security/LoginService.java @@ -58,7 +58,7 @@ public class LoginService { } long userId = tokenManager.verifyToken(token); User user = storage.getObject(User.class, new Request( - new Columns.All(), new Condition.Equals("id", "id", userId))); + new Columns.All(), new Condition.Equals("id", userId))); if (user != null) { checkUserEnabled(user); } @@ -66,11 +66,12 @@ public class LoginService { } public User login(String email, String password) throws StorageException { + email = email.trim(); User user = storage.getObject(User.class, new Request( new Columns.All(), new Condition.Or( - new Condition.Equals("email", "email", email.trim()), - new Condition.Equals("login", "email")))); + new Condition.Equals("email", email), + new Condition.Equals("login", email)))); if (user != null) { if (ldapProvider != null && user.getLogin() != null && ldapProvider.login(user.getLogin(), password) || !forceLdap && user.isPasswordValid(password)) { diff --git a/src/main/java/org/traccar/api/security/PermissionsService.java b/src/main/java/org/traccar/api/security/PermissionsService.java index ddfaaab94..0d4877fdb 100644 --- a/src/main/java/org/traccar/api/security/PermissionsService.java +++ b/src/main/java/org/traccar/api/security/PermissionsService.java @@ -62,7 +62,7 @@ public class PermissionsService { user = new ServiceAccountUser(); } else { user = storage.getObject( - User.class, new Request(new Columns.All(), new Condition.Equals("id", "id", userId))); + User.class, new Request(new Columns.All(), new Condition.Equals("id", userId))); } } return user; @@ -187,7 +187,7 @@ public class PermissionsService { var object = storage.getObject(clazz, new Request( new Columns.Include("id"), new Condition.And( - new Condition.Equals("id", "id", objectId), + new Condition.Equals("id", objectId), new Condition.Permission( User.class, userId, clazz.equals(User.class) ? ManagedUser.class : clazz)))); if (object == null) { diff --git a/src/main/java/org/traccar/database/CommandsManager.java b/src/main/java/org/traccar/database/CommandsManager.java index 53040ad53..764ea637b 100644 --- a/src/main/java/org/traccar/database/CommandsManager.java +++ b/src/main/java/org/traccar/database/CommandsManager.java @@ -69,9 +69,9 @@ public class CommandsManager implements BroadcastInterface { throw new RuntimeException("SMS not configured"); } Device device = storage.getObject(Device.class, new Request( - new Columns.Include("positionId", "phone"), new Condition.Equals("id", "id", deviceId))); + new Columns.Include("positionId", "phone"), new Condition.Equals("id", deviceId))); Position position = storage.getObject(Position.class, new Request( - new Columns.All(), new Condition.Equals("id", "id", device.getPositionId()))); + new Columns.All(), new Condition.Equals("id", device.getPositionId()))); if (position != null) { BaseProtocol protocol = serverManager.getProtocol(position.getProtocol()); protocol.sendTextCommand(device.getPhone(), command); @@ -101,12 +101,12 @@ public class CommandsManager implements BroadcastInterface { try { var commands = storage.getObjects(QueuedCommand.class, new Request( new Columns.All(), - new Condition.Equals("deviceId", "deviceId", deviceId), + new Condition.Equals("deviceId", deviceId), new Order(false, "id"), new Limit(count))); for (var command : commands) { storage.removeObject(QueuedCommand.class, new Request( - new Condition.Equals("id", "id", command.getId()))); + new Condition.Equals("id", command.getId()))); } return commands.stream().map(QueuedCommand::toCommand).collect(Collectors.toList()); } catch (StorageException e) { diff --git a/src/main/java/org/traccar/database/DeviceLookupService.java b/src/main/java/org/traccar/database/DeviceLookupService.java index 9cf0899ee..28910c24a 100644 --- a/src/main/java/org/traccar/database/DeviceLookupService.java +++ b/src/main/java/org/traccar/database/DeviceLookupService.java @@ -108,7 +108,7 @@ public class DeviceLookupService { for (String uniqueId : uniqueIds) { if (!isThrottled(uniqueId)) { device = storage.getObject(Device.class, new Request( - new Columns.All(), new Condition.Equals("uniqueId", "uniqueId", uniqueId))); + new Columns.All(), new Condition.Equals("uniqueId", uniqueId))); if (device != null) { lookupSucceeded(uniqueId); break; diff --git a/src/main/java/org/traccar/handler/FilterHandler.java b/src/main/java/org/traccar/handler/FilterHandler.java index f09cb16a3..3722f2a22 100644 --- a/src/main/java/org/traccar/handler/FilterHandler.java +++ b/src/main/java/org/traccar/handler/FilterHandler.java @@ -88,7 +88,7 @@ public class FilterHandler extends BaseDataHandler { return storage.getObject(Position.class, new Request( new Columns.All(), new Condition.And( - new Condition.Equals("deviceId", "deviceId", deviceId), + new Condition.Equals("deviceId", deviceId), new Condition.Compare("fixTime", "<=", "time", date)), new Order(true, "fixTime"), new Limit(1))); diff --git a/src/main/java/org/traccar/handler/events/GeofenceEventHandler.java b/src/main/java/org/traccar/handler/events/GeofenceEventHandler.java index b1be7e8ad..9414f4b31 100644 --- a/src/main/java/org/traccar/handler/events/GeofenceEventHandler.java +++ b/src/main/java/org/traccar/handler/events/GeofenceEventHandler.java @@ -82,7 +82,8 @@ public class GeofenceEventHandler extends BaseEventHandler { try { storage.updateObject(device, new Request( - new Columns.Include("geofenceIds"), new Condition.Equals("id", "id"))); + new Columns.Include("geofenceIds"), + new Condition.Equals("id", device.getId()))); } catch (StorageException e) { throw new RuntimeException("Update device geofences error", e); } diff --git a/src/main/java/org/traccar/handler/events/MotionEventHandler.java b/src/main/java/org/traccar/handler/events/MotionEventHandler.java index 3511cf682..1b9763c41 100644 --- a/src/main/java/org/traccar/handler/events/MotionEventHandler.java +++ b/src/main/java/org/traccar/handler/events/MotionEventHandler.java @@ -76,7 +76,7 @@ public class MotionEventHandler extends BaseEventHandler { try { storage.updateObject(device, new Request( new Columns.Include("motionState", "motionTime", "motionDistance"), - new Condition.Equals("id", "id"))); + new Condition.Equals("id", device.getId()))); } catch (StorageException e) { LOGGER.warn("Update device motion error", e); } diff --git a/src/main/java/org/traccar/handler/events/OverspeedEventHandler.java b/src/main/java/org/traccar/handler/events/OverspeedEventHandler.java index 3928fcc88..4d6aa8857 100644 --- a/src/main/java/org/traccar/handler/events/OverspeedEventHandler.java +++ b/src/main/java/org/traccar/handler/events/OverspeedEventHandler.java @@ -113,7 +113,7 @@ public class OverspeedEventHandler extends BaseEventHandler { try { storage.updateObject(device, new Request( new Columns.Include("overspeedState", "overspeedTime", "overspeedGeofenceId"), - new Condition.Equals("id", "id"))); + new Condition.Equals("id", device.getId()))); } catch (StorageException e) { LOGGER.warn("Update device overspeed error", e); } diff --git a/src/main/java/org/traccar/helper/model/PositionUtil.java b/src/main/java/org/traccar/helper/model/PositionUtil.java index 31f828947..6c380b81a 100644 --- a/src/main/java/org/traccar/helper/model/PositionUtil.java +++ b/src/main/java/org/traccar/helper/model/PositionUtil.java @@ -59,7 +59,7 @@ public final class PositionUtil { return storage.getObjects(Position.class, new Request( new Columns.All(), new Condition.And( - new Condition.Equals("deviceId", "deviceId", deviceId), + new Condition.Equals("deviceId", deviceId), new Condition.Between("fixTime", "from", from, "to", to)), new Order("fixTime"))); } diff --git a/src/main/java/org/traccar/model/Device.java b/src/main/java/org/traccar/model/Device.java index 147b0fd20..7728172cb 100644 --- a/src/main/java/org/traccar/model/Device.java +++ b/src/main/java/org/traccar/model/Device.java @@ -52,22 +52,22 @@ public class Device extends GroupedModel implements Disableable { private String status; + @QueryIgnore public String getStatus() { return status != null ? status : STATUS_OFFLINE; } - @QueryIgnore public void setStatus(String status) { this.status = status != null ? status.trim() : null; } private Date lastUpdate; + @QueryIgnore public Date getLastUpdate() { return this.lastUpdate; } - @QueryIgnore public void setLastUpdate(Date lastUpdate) { this.lastUpdate = lastUpdate; } @@ -79,18 +79,17 @@ public class Device extends GroupedModel implements Disableable { return positionId; } - @QueryIgnore public void setPositionId(long positionId) { this.positionId = positionId; } private List geofenceIds; + @QueryIgnore public List getGeofenceIds() { return geofenceIds; } - @QueryIgnore public void setGeofenceIds(List geofenceIds) { if (geofenceIds != null) { this.geofenceIds = geofenceIds.stream().map(Number::longValue).collect(Collectors.toList()); diff --git a/src/main/java/org/traccar/reports/EventsReportProvider.java b/src/main/java/org/traccar/reports/EventsReportProvider.java index 878c0265d..d0d4fe8bf 100644 --- a/src/main/java/org/traccar/reports/EventsReportProvider.java +++ b/src/main/java/org/traccar/reports/EventsReportProvider.java @@ -64,7 +64,7 @@ public class EventsReportProvider { return storage.getObjects(Event.class, new Request( new Columns.All(), new Condition.And( - new Condition.Equals("deviceId", "deviceId", deviceId), + new Condition.Equals("deviceId", deviceId), new Condition.Between("eventTime", "from", from, "to", to)), new Order("eventTime"))); } @@ -134,7 +134,7 @@ public class EventsReportProvider { sheetNames.add(WorkbookUtil.createSafeSheetName(deviceEvents.getDeviceName())); if (device.getGroupId() > 0) { Group group = storage.getObject(Group.class, new Request( - new Columns.All(), new Condition.Equals("id", "id", device.getGroupId()))); + new Columns.All(), new Condition.Equals("id", device.getGroupId()))); if (group != null) { deviceEvents.setGroupName(group.getName()); } diff --git a/src/main/java/org/traccar/reports/GpxExportProvider.java b/src/main/java/org/traccar/reports/GpxExportProvider.java index f1a0f292d..ccbd97fc3 100644 --- a/src/main/java/org/traccar/reports/GpxExportProvider.java +++ b/src/main/java/org/traccar/reports/GpxExportProvider.java @@ -42,7 +42,7 @@ public class GpxExportProvider { OutputStream outputStream, long deviceId, Date from, Date to) throws StorageException { var device = storage.getObject(Device.class, new Request( - new Columns.All(), new Condition.Equals("id", "id", deviceId))); + new Columns.All(), new Condition.Equals("id", deviceId))); var positions = PositionUtil.getPositions(storage, deviceId, from, to); try (PrintWriter writer = new PrintWriter(outputStream)) { diff --git a/src/main/java/org/traccar/reports/KmlExportProvider.java b/src/main/java/org/traccar/reports/KmlExportProvider.java index e8b5c4278..24fcfb8ab 100644 --- a/src/main/java/org/traccar/reports/KmlExportProvider.java +++ b/src/main/java/org/traccar/reports/KmlExportProvider.java @@ -43,7 +43,7 @@ public class KmlExportProvider { OutputStream outputStream, long deviceId, Date from, Date to) throws StorageException { var device = storage.getObject(Device.class, new Request( - new Columns.All(), new Condition.Equals("id", "id", deviceId))); + new Columns.All(), new Condition.Equals("id", deviceId))); var positions = PositionUtil.getPositions(storage, deviceId, from, to); var dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm"); diff --git a/src/main/java/org/traccar/reports/RouteReportProvider.java b/src/main/java/org/traccar/reports/RouteReportProvider.java index 0f618822e..3ee651619 100644 --- a/src/main/java/org/traccar/reports/RouteReportProvider.java +++ b/src/main/java/org/traccar/reports/RouteReportProvider.java @@ -80,7 +80,7 @@ public class RouteReportProvider { sheetNames.add(WorkbookUtil.createSafeSheetName(deviceRoutes.getDeviceName())); if (device.getGroupId() > 0) { Group group = storage.getObject(Group.class, new Request( - new Columns.All(), new Condition.Equals("id", "id", device.getGroupId()))); + new Columns.All(), new Condition.Equals("id", device.getGroupId()))); if (group != null) { deviceRoutes.setGroupName(group.getName()); } diff --git a/src/main/java/org/traccar/reports/StopsReportProvider.java b/src/main/java/org/traccar/reports/StopsReportProvider.java index ba61ef6a1..ec3fd2215 100644 --- a/src/main/java/org/traccar/reports/StopsReportProvider.java +++ b/src/main/java/org/traccar/reports/StopsReportProvider.java @@ -87,7 +87,7 @@ public class StopsReportProvider { sheetNames.add(WorkbookUtil.createSafeSheetName(deviceStops.getDeviceName())); if (device.getGroupId() > 0) { Group group = storage.getObject(Group.class, new Request( - new Columns.All(), new Condition.Equals("id", "id", device.getGroupId()))); + new Columns.All(), new Condition.Equals("id", device.getGroupId()))); if (group != null) { deviceStops.setGroupName(group.getName()); } diff --git a/src/main/java/org/traccar/reports/TripsReportProvider.java b/src/main/java/org/traccar/reports/TripsReportProvider.java index 2d9bcdfbf..265811354 100644 --- a/src/main/java/org/traccar/reports/TripsReportProvider.java +++ b/src/main/java/org/traccar/reports/TripsReportProvider.java @@ -87,7 +87,7 @@ public class TripsReportProvider { sheetNames.add(WorkbookUtil.createSafeSheetName(deviceTrips.getDeviceName())); if (device.getGroupId() > 0) { Group group = storage.getObject(Group.class, new Request( - new Columns.All(), new Condition.Equals("id", "id", device.getGroupId()))); + new Columns.All(), new Condition.Equals("id", device.getGroupId()))); if (group != null) { deviceTrips.setGroupName(group.getName()); } diff --git a/src/main/java/org/traccar/reports/common/ReportUtils.java b/src/main/java/org/traccar/reports/common/ReportUtils.java index 1de774dab..120dadcf5 100644 --- a/src/main/java/org/traccar/reports/common/ReportUtils.java +++ b/src/main/java/org/traccar/reports/common/ReportUtils.java @@ -95,7 +95,7 @@ public class ReportUtils { return storage.getObject(clazz, new Request( new Columns.All(), new Condition.And( - new Condition.Equals("id", "id", objectId), + new Condition.Equals("id", objectId), new Condition.Permission(User.class, userId, clazz)))); } @@ -166,7 +166,7 @@ public class ReportUtils { if (driverUniqueId != null) { Driver driver = storage.getObject(Driver.class, new Request( new Columns.All(), - new Condition.Equals("uniqueId", "uniqueId", driverUniqueId))); + new Condition.Equals("uniqueId", driverUniqueId))); if (driver != null) { return driver.getName(); } diff --git a/src/main/java/org/traccar/session/ConnectionManager.java b/src/main/java/org/traccar/session/ConnectionManager.java index 9e50c9ead..37a42d827 100644 --- a/src/main/java/org/traccar/session/ConnectionManager.java +++ b/src/main/java/org/traccar/session/ConnectionManager.java @@ -215,7 +215,7 @@ public class ConnectionManager implements BroadcastInterface { if (device == null) { try { device = storage.getObject(Device.class, new Request( - new Columns.All(), new Condition.Equals("id", "id", deviceId))); + new Columns.All(), new Condition.Equals("id", deviceId))); } catch (StorageException e) { LOGGER.warn("Failed to get device", e); } @@ -265,7 +265,7 @@ public class ConnectionManager implements BroadcastInterface { try { storage.updateObject(device, new Request( new Columns.Include("status", "lastUpdate"), - new Condition.Equals("id", "id"))); + new Condition.Equals("id", deviceId))); } catch (StorageException e) { LOGGER.warn("Update device status error", e); } diff --git a/src/main/java/org/traccar/session/cache/CacheManager.java b/src/main/java/org/traccar/session/cache/CacheManager.java index ed67ed70e..8f2e7ba93 100644 --- a/src/main/java/org/traccar/session/cache/CacheManager.java +++ b/src/main/java/org/traccar/session/cache/CacheManager.java @@ -201,7 +201,7 @@ public class CacheManager implements BroadcastInterface { public void invalidateObject(boolean local, Class clazz, long id) { try { var object = storage.getObject(clazz, new Request( - new Columns.All(), new Condition.Equals("id", "id", id))); + new Columns.All(), new Condition.Equals("id", id))); if (object != null) { updateOrInvalidate(local, object); } else { @@ -286,7 +286,7 @@ public class CacheManager implements BroadcastInterface { Map, Set> links = new HashMap<>(); Device device = storage.getObject(Device.class, new Request( - new Columns.All(), new Condition.Equals("id", "id", deviceId))); + new Columns.All(), new Condition.Equals("id", deviceId))); if (device != null) { addObject(deviceId, device); @@ -294,7 +294,7 @@ public class CacheManager implements BroadcastInterface { long groupId = device.getGroupId(); while (groupDepth < GROUP_DEPTH_LIMIT && groupId > 0) { Group group = storage.getObject(Group.class, new Request( - new Columns.All(), new Condition.Equals("id", "id", groupId))); + new Columns.All(), new Condition.Equals("id", groupId))); links.computeIfAbsent(Group.class, k -> new LinkedHashSet<>()).add(group.getId()); addObject(deviceId, group); groupId = group.getGroupId(); @@ -311,7 +311,7 @@ public class CacheManager implements BroadcastInterface { var scheduled = (ScheduledModel) object; if (scheduled.getCalendarId() > 0) { var calendar = storage.getObject(Calendar.class, new Request( - new Columns.All(), new Condition.Equals("id", "id", scheduled.getCalendarId()))); + new Columns.All(), new Condition.Equals("id", scheduled.getCalendarId()))); links.computeIfAbsent(Notification.class, k -> new LinkedHashSet<>()) .add(calendar.getId()); addObject(deviceId, calendar); @@ -336,7 +336,7 @@ public class CacheManager implements BroadcastInterface { addObject(deviceId, notification); if (notification.getCalendarId() > 0) { var calendar = storage.getObject(Calendar.class, new Request( - new Columns.All(), new Condition.Equals("id", "id", notification.getCalendarId()))); + new Columns.All(), new Condition.Equals("id", notification.getCalendarId()))); links.computeIfAbsent(Notification.class, k -> new LinkedHashSet<>()) .add(calendar.getId()); addObject(deviceId, calendar); @@ -348,7 +348,7 @@ public class CacheManager implements BroadcastInterface { if (device.getPositionId() > 0) { devicePositions.put(deviceId, storage.getObject(Position.class, new Request( - new Columns.All(), new Condition.Equals("id", "id", device.getPositionId())))); + new Columns.All(), new Condition.Equals("id", device.getPositionId())))); } } } diff --git a/src/main/java/org/traccar/storage/DatabaseStorage.java b/src/main/java/org/traccar/storage/DatabaseStorage.java index 8ca464147..884c8fca8 100644 --- a/src/main/java/org/traccar/storage/DatabaseStorage.java +++ b/src/main/java/org/traccar/storage/DatabaseStorage.java @@ -57,7 +57,7 @@ public class DatabaseStorage extends Storage { if (request.getColumns() instanceof Columns.All) { query.append('*'); } else { - query.append(formatColumns(request.getColumns(), clazz, "get", c -> c)); + query.append(formatColumns(request.getColumns().getColumns(clazz, "set"), c -> c)); } query.append(" FROM ").append(getStorageName(clazz)); query.append(formatCondition(request.getCondition())); @@ -76,16 +76,17 @@ public class DatabaseStorage extends Storage { @Override public long addObject(T entity, Request request) throws StorageException { + List columns = request.getColumns().getColumns(entity.getClass(), "get"); StringBuilder query = new StringBuilder("INSERT INTO "); query.append(getStorageName(entity.getClass())); query.append("("); - query.append(formatColumns(request.getColumns(), entity.getClass(), "set", c -> c)); + query.append(formatColumns(columns, c -> c)); query.append(") VALUES ("); - query.append(formatColumns(request.getColumns(), entity.getClass(), "set", c -> ':' + c)); + query.append(formatColumns(columns, c -> ':' + c)); query.append(")"); try { QueryBuilder builder = QueryBuilder.create(config, dataSource, objectMapper, query.toString(), true); - builder.setObject(entity); + builder.setObject(entity, columns); return builder.executeUpdate(); } catch (SQLException e) { throw new StorageException(e); @@ -94,14 +95,15 @@ public class DatabaseStorage extends Storage { @Override public void updateObject(T entity, Request request) throws StorageException { + List columns = request.getColumns().getColumns(entity.getClass(), "get"); StringBuilder query = new StringBuilder("UPDATE "); query.append(getStorageName(entity.getClass())); query.append(" SET "); - query.append(formatColumns(request.getColumns(), entity.getClass(), "set", c -> c + " = :" + c)); + query.append(formatColumns(columns, c -> c + " = :" + c)); query.append(formatCondition(request.getCondition())); try { QueryBuilder builder = QueryBuilder.create(config, dataSource, objectMapper, query.toString()); - builder.setObject(entity); + builder.setObject(entity, columns); for (Map.Entry variable : getConditionVariables(request.getCondition()).entrySet()) { builder.setValue(variable.getKey(), variable.getValue()); } @@ -135,12 +137,10 @@ public class DatabaseStorage extends Storage { query.append(Permission.getStorageName(ownerClass, propertyClass)); var conditions = new LinkedList(); if (ownerId > 0) { - conditions.add(new Condition.Equals( - Permission.getKey(ownerClass), Permission.getKey(ownerClass), ownerId)); + conditions.add(new Condition.Equals(Permission.getKey(ownerClass), ownerId)); } if (propertyId > 0) { - conditions.add(new Condition.Equals( - Permission.getKey(propertyClass), Permission.getKey(propertyClass), propertyId)); + conditions.add(new Condition.Equals(Permission.getKey(propertyClass), propertyId)); } Condition combinedCondition = Condition.merge(conditions); query.append(formatCondition(combinedCondition)); @@ -230,9 +230,8 @@ public class DatabaseStorage extends Storage { return results; } - private String formatColumns( - Columns columns, Class clazz, String type, Function mapper) { - return columns.getColumns(clazz, type).stream().map(mapper).collect(Collectors.joining(", ")); + private String formatColumns(List columns, Function mapper) { + return columns.stream().map(mapper).collect(Collectors.joining(", ")); } private String formatCondition(Condition genericCondition) throws StorageException { diff --git a/src/main/java/org/traccar/storage/QueryBuilder.java b/src/main/java/org/traccar/storage/QueryBuilder.java index a58ebe2b4..fa71a8e8f 100644 --- a/src/main/java/org/traccar/storage/QueryBuilder.java +++ b/src/main/java/org/traccar/storage/QueryBuilder.java @@ -37,10 +37,12 @@ import java.sql.Timestamp; import java.sql.Types; import java.util.Date; import java.util.HashMap; +import java.util.HashSet; import java.util.LinkedHashMap; import java.util.LinkedList; import java.util.List; import java.util.Map; +import java.util.Set; @SuppressWarnings("UnusedReturnValue") public final class QueryBuilder { @@ -283,36 +285,32 @@ public final class QueryBuilder { return this; } - public QueryBuilder setObject(Object object) throws SQLException { - - Method[] methods = object.getClass().getMethods(); - - for (Method method : methods) { - if (method.getName().startsWith("get") && method.getParameterTypes().length == 0 - && !method.getName().equals("getClass")) { - String name = method.getName().substring(3); - try { - if (method.getReturnType().equals(boolean.class)) { - setBoolean(name, (Boolean) method.invoke(object)); - } else if (method.getReturnType().equals(int.class)) { - setInteger(name, (Integer) method.invoke(object)); - } else if (method.getReturnType().equals(long.class)) { - setLong(name, (Long) method.invoke(object), name.endsWith("Id")); - } else if (method.getReturnType().equals(double.class)) { - setDouble(name, (Double) method.invoke(object)); - } else if (method.getReturnType().equals(String.class)) { - setString(name, (String) method.invoke(object)); - } else if (method.getReturnType().equals(Date.class)) { - setDate(name, (Date) method.invoke(object)); - } else if (method.getReturnType().equals(byte[].class)) { - setBlob(name, (byte[]) method.invoke(object)); - } else { - setString(name, objectMapper.writeValueAsString(method.invoke(object))); - } - } catch (IllegalAccessException | InvocationTargetException | JsonProcessingException error) { - LOGGER.warn("Get property error", error); + public QueryBuilder setObject(Object object, List columns) throws SQLException { + + try { + for (String column : columns) { + Method method = object.getClass().getMethod( + "get" + Character.toUpperCase(column.charAt(0)) + column.substring(1)); + if (method.getReturnType().equals(boolean.class)) { + setBoolean(column, (Boolean) method.invoke(object)); + } else if (method.getReturnType().equals(int.class)) { + setInteger(column, (Integer) method.invoke(object)); + } else if (method.getReturnType().equals(long.class)) { + setLong(column, (Long) method.invoke(object), column.endsWith("Id")); + } else if (method.getReturnType().equals(double.class)) { + setDouble(column, (Double) method.invoke(object)); + } else if (method.getReturnType().equals(String.class)) { + setString(column, (String) method.invoke(object)); + } else if (method.getReturnType().equals(Date.class)) { + setDate(column, (Date) method.invoke(object)); + } else if (method.getReturnType().equals(byte[].class)) { + setBlob(column, (byte[]) method.invoke(object)); + } else { + setString(column, objectMapper.writeValueAsString(method.invoke(object))); } } + } catch (ReflectiveOperationException | JsonProcessingException e) { + LOGGER.warn("Set object error", e); } return this; diff --git a/src/main/java/org/traccar/storage/query/Columns.java b/src/main/java/org/traccar/storage/query/Columns.java index 545995b3c..a00400b36 100644 --- a/src/main/java/org/traccar/storage/query/Columns.java +++ b/src/main/java/org/traccar/storage/query/Columns.java @@ -17,6 +17,7 @@ package org.traccar.storage.query; import org.traccar.storage.QueryIgnore; +import java.beans.Introspector; import java.lang.reflect.Method; import java.util.Arrays; import java.util.LinkedList; @@ -36,7 +37,7 @@ public abstract class Columns { if (method.getName().startsWith(type) && method.getParameterTypes().length == parameterCount && !method.isAnnotationPresent(QueryIgnore.class) && !method.getName().equals("getClass")) { - columns.add(method.getName().substring(3).toLowerCase()); + columns.add(Introspector.decapitalize(method.getName().substring(3))); } } return columns; diff --git a/src/main/java/org/traccar/storage/query/Condition.java b/src/main/java/org/traccar/storage/query/Condition.java index 136b0402b..08b199052 100644 --- a/src/main/java/org/traccar/storage/query/Condition.java +++ b/src/main/java/org/traccar/storage/query/Condition.java @@ -34,12 +34,8 @@ public interface Condition { } class Equals extends Compare { - public Equals(String column, String variable) { - this(column, variable, null); - } - - public Equals(String column, String variable, Object value) { - super(column, "=", variable, value); + public Equals(String column, Object value) { + super(column, "=", column, value); } } -- cgit v1.2.3 From 1417098fa45a3060f17e0cca6d8226b12e7f174e Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 15 Jan 2023 17:37:20 -0800 Subject: Remove default admin --- schema/changelog-4.0-clean.xml | 8 -------- src/main/java/org/traccar/api/resource/ServerResource.java | 8 ++++++++ src/main/java/org/traccar/api/resource/SessionResource.java | 5 ++++- src/main/java/org/traccar/api/resource/UserResource.java | 5 +++++ src/main/java/org/traccar/helper/model/UserUtil.java | 11 +++++++++++ src/main/java/org/traccar/model/Server.java | 12 ++++++++++++ src/main/java/org/traccar/storage/query/Request.java | 6 +++--- 7 files changed, 43 insertions(+), 12 deletions(-) (limited to 'src/main/java/org/traccar/helper') diff --git a/schema/changelog-4.0-clean.xml b/schema/changelog-4.0-clean.xml index f3f814eba..b4d8ac0ba 100644 --- a/schema/changelog-4.0-clean.xml +++ b/schema/changelog-4.0-clean.xml @@ -620,14 +620,6 @@ - - - - - - - - diff --git a/src/main/java/org/traccar/api/resource/ServerResource.java b/src/main/java/org/traccar/api/resource/ServerResource.java index e7f0b93ca..4b7ee9189 100644 --- a/src/main/java/org/traccar/api/resource/ServerResource.java +++ b/src/main/java/org/traccar/api/resource/ServerResource.java @@ -16,6 +16,7 @@ package org.traccar.api.resource; import org.traccar.api.BaseResource; +import org.traccar.helper.model.UserUtil; import org.traccar.mail.MailManager; import org.traccar.geocoder.Geocoder; import org.traccar.helper.Log; @@ -65,6 +66,13 @@ public class ServerResource extends BaseResource { server.setEmailEnabled(mailManager.getEmailEnabled()); server.setGeocoderEnabled(geocoder != null); User user = permissionsService.getUser(getUserId()); + if (user != null) { + if (user.getAdministrator()) { + server.setStorageSpace(Log.getStorageSpace()); + } + } else { + server.setNewServer(UserUtil.isEmpty(storage)); + } if (user != null && user.getAdministrator()) { server.setStorageSpace(Log.getStorageSpace()); } diff --git a/src/main/java/org/traccar/api/resource/SessionResource.java b/src/main/java/org/traccar/api/resource/SessionResource.java index 1e984fbd0..7025d5fa7 100644 --- a/src/main/java/org/traccar/api/resource/SessionResource.java +++ b/src/main/java/org/traccar/api/resource/SessionResource.java @@ -110,7 +110,10 @@ public class SessionResource extends BaseResource { } else { - return permissionsService.getUser(userId); + User user = permissionsService.getUser(userId); + if (user != null) { + return user; + } } diff --git a/src/main/java/org/traccar/api/resource/UserResource.java b/src/main/java/org/traccar/api/resource/UserResource.java index 91875ef51..e41ebbe61 100644 --- a/src/main/java/org/traccar/api/resource/UserResource.java +++ b/src/main/java/org/traccar/api/resource/UserResource.java @@ -19,6 +19,7 @@ import org.traccar.api.BaseObjectResource; import org.traccar.config.Config; import org.traccar.config.Keys; import org.traccar.helper.LogAction; +import org.traccar.helper.model.UserUtil; import org.traccar.model.ManagedUser; import org.traccar.model.Permission; import org.traccar.model.User; @@ -98,6 +99,10 @@ public class UserResource extends BaseObjectResource { } } + if (UserUtil.isEmpty(storage)) { + entity.setAdministrator(true); + } + entity.setId(storage.addObject(entity, new Request(new Columns.Exclude("id")))); storage.updateObject(entity, new Request( new Columns.Include("hashedPassword", "salt"), diff --git a/src/main/java/org/traccar/helper/model/UserUtil.java b/src/main/java/org/traccar/helper/model/UserUtil.java index 9919e1d95..9f93afeae 100644 --- a/src/main/java/org/traccar/helper/model/UserUtil.java +++ b/src/main/java/org/traccar/helper/model/UserUtil.java @@ -17,6 +17,11 @@ package org.traccar.helper.model; import org.traccar.model.Server; import org.traccar.model.User; +import org.traccar.storage.Storage; +import org.traccar.storage.StorageException; +import org.traccar.storage.query.Columns; +import org.traccar.storage.query.Order; +import org.traccar.storage.query.Request; import java.util.TimeZone; @@ -25,6 +30,12 @@ public final class UserUtil { private UserUtil() { } + public static boolean isEmpty(Storage storage) throws StorageException { + return storage.getObjects(User.class, new Request( + new Columns.Include("id"), + new Order("id", false, 1))).isEmpty(); + } + public static String getDistanceUnit(Server server, User user) { return lookupStringAttribute(server, user, "distanceUnit", "km"); } diff --git a/src/main/java/org/traccar/model/Server.java b/src/main/java/org/traccar/model/Server.java index 9e248e7bb..73645721b 100644 --- a/src/main/java/org/traccar/model/Server.java +++ b/src/main/java/org/traccar/model/Server.java @@ -249,4 +249,16 @@ public class Server extends ExtendedModel implements UserRestrictions { this.storageSpace = storageSpace; } + private boolean newServer; + + @QueryIgnore + public boolean getNewServer() { + return newServer; + } + + @QueryIgnore + public void setNewServer(boolean newServer) { + this.newServer = newServer; + } + } diff --git a/src/main/java/org/traccar/storage/query/Request.java b/src/main/java/org/traccar/storage/query/Request.java index 6e9cecc63..b9c2c963c 100644 --- a/src/main/java/org/traccar/storage/query/Request.java +++ b/src/main/java/org/traccar/storage/query/Request.java @@ -33,11 +33,11 @@ public class Request { this(columns, condition, null); } - public Request(Columns columns, Condition condition, Order order) { - this(columns, condition, order, null); + public Request(Columns columns, Order order) { + this(columns, null, order); } - public Request(Columns columns, Condition condition, Order order, Limit limit) { + public Request(Columns columns, Condition condition, Order order) { this.columns = columns; this.condition = condition; this.order = order; -- cgit v1.2.3