aboutsummaryrefslogtreecommitdiff
path: root/src/main/java/org/traccar/database
diff options
context:
space:
mode:
authorcasswarry0 <casswarry0@gmail.com>2023-01-17 17:14:53 -0700
committercasswarry0 <casswarry0@gmail.com>2023-01-17 17:14:53 -0700
commit7338b8730949ed027b3f8b31d7dca20687ebbb8b (patch)
treec2d171e6121818ab511460a786f69aab97a2a628 /src/main/java/org/traccar/database
parentcdecd3fa4427a382c0b09f8ad9d69ec14388960a (diff)
parent85501f9cf4918d5eee345f83aed7a31eecb26b8d (diff)
downloadtrackermap-server-7338b8730949ed027b3f8b31d7dca20687ebbb8b.tar.gz
trackermap-server-7338b8730949ed027b3f8b31d7dca20687ebbb8b.tar.bz2
trackermap-server-7338b8730949ed027b3f8b31d7dca20687ebbb8b.zip
Merge branch 'master' into develop
Diffstat (limited to 'src/main/java/org/traccar/database')
-rw-r--r--src/main/java/org/traccar/database/ActiveDevice.java58
-rw-r--r--src/main/java/org/traccar/database/AttributesManager.java36
-rw-r--r--src/main/java/org/traccar/database/BaseObjectManager.java178
-rw-r--r--src/main/java/org/traccar/database/CalendarManager.java27
-rw-r--r--src/main/java/org/traccar/database/CommandsManager.java221
-rw-r--r--src/main/java/org/traccar/database/ConnectionManager.java216
-rw-r--r--src/main/java/org/traccar/database/DataManager.java452
-rw-r--r--src/main/java/org/traccar/database/DeviceLookupService.java141
-rw-r--r--src/main/java/org/traccar/database/DeviceManager.java483
-rw-r--r--src/main/java/org/traccar/database/DriversManager.java100
-rw-r--r--src/main/java/org/traccar/database/ExtendedObjectManager.java143
-rw-r--r--src/main/java/org/traccar/database/GeofenceManager.java66
-rw-r--r--src/main/java/org/traccar/database/GroupsManager.java83
-rw-r--r--src/main/java/org/traccar/database/IdentityManager.java50
-rw-r--r--src/main/java/org/traccar/database/LdapProvider.java2
-rw-r--r--src/main/java/org/traccar/database/MailManager.java151
-rw-r--r--src/main/java/org/traccar/database/MaintenancesManager.java27
-rw-r--r--src/main/java/org/traccar/database/ManagableObjects.java27
-rw-r--r--src/main/java/org/traccar/database/MediaManager.java19
-rw-r--r--src/main/java/org/traccar/database/NotificationManager.java199
-rw-r--r--src/main/java/org/traccar/database/OrderManager.java26
-rw-r--r--src/main/java/org/traccar/database/PermissionsManager.java516
-rw-r--r--src/main/java/org/traccar/database/QueryBuilder.java485
-rw-r--r--src/main/java/org/traccar/database/QueryExtended.java27
-rw-r--r--src/main/java/org/traccar/database/QueryIgnore.java26
-rw-r--r--src/main/java/org/traccar/database/SimpleObjectManager.java100
-rw-r--r--src/main/java/org/traccar/database/StatisticsManager.java19
-rw-r--r--src/main/java/org/traccar/database/UsersManager.java84
28 files changed, 353 insertions, 3609 deletions
diff --git a/src/main/java/org/traccar/database/ActiveDevice.java b/src/main/java/org/traccar/database/ActiveDevice.java
deleted file mode 100644
index c05d56ad2..000000000
--- a/src/main/java/org/traccar/database/ActiveDevice.java
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- * Copyright 2015 - 2020 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 io.netty.channel.Channel;
-import io.netty.handler.codec.http.HttpRequestDecoder;
-import org.traccar.BasePipelineFactory;
-import org.traccar.Protocol;
-import org.traccar.model.Command;
-
-import java.net.SocketAddress;
-
-public class ActiveDevice {
-
- private final long deviceId;
- private final Protocol protocol;
- private final Channel channel;
- private final SocketAddress remoteAddress;
- private final boolean supportsLiveCommands;
-
- public ActiveDevice(long deviceId, Protocol protocol, Channel channel, SocketAddress remoteAddress) {
- this.deviceId = deviceId;
- this.protocol = protocol;
- this.channel = channel;
- this.remoteAddress = remoteAddress;
- supportsLiveCommands = BasePipelineFactory.getHandler(channel.pipeline(), HttpRequestDecoder.class) == null;
- }
-
- public Channel getChannel() {
- return channel;
- }
-
- public long getDeviceId() {
- return deviceId;
- }
-
- public boolean supportsLiveCommands() {
- return supportsLiveCommands;
- }
-
- public void sendCommand(Command command) {
- protocol.sendDataCommand(channel, remoteAddress, command);
- }
-
-}
diff --git a/src/main/java/org/traccar/database/AttributesManager.java b/src/main/java/org/traccar/database/AttributesManager.java
deleted file mode 100644
index 28816645a..000000000
--- a/src/main/java/org/traccar/database/AttributesManager.java
+++ /dev/null
@@ -1,36 +0,0 @@
-/*
- * Copyright 2017 Anton Tananaev (anton@traccar.org)
- * Copyright 2017 Andrey Kunitsyn (andrey@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 org.traccar.model.Attribute;
-
-public class AttributesManager extends ExtendedObjectManager<Attribute> {
-
- public AttributesManager(DataManager dataManager) {
- super(dataManager, Attribute.class);
- }
-
- @Override
- public void updateCachedItem(Attribute attribute) {
- Attribute cachedAttribute = getById(attribute.getId());
- cachedAttribute.setDescription(attribute.getDescription());
- cachedAttribute.setAttribute(attribute.getAttribute());
- cachedAttribute.setExpression(attribute.getExpression());
- cachedAttribute.setType(attribute.getType());
- }
-
-}
diff --git a/src/main/java/org/traccar/database/BaseObjectManager.java b/src/main/java/org/traccar/database/BaseObjectManager.java
deleted file mode 100644
index be6310033..000000000
--- a/src/main/java/org/traccar/database/BaseObjectManager.java
+++ /dev/null
@@ -1,178 +0,0 @@
-/*
- * Copyright 2017 - 2020 Anton Tananaev (anton@traccar.org)
- * Copyright 2017 Andrey Kunitsyn (andrey@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.sql.SQLException;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.LinkedList;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.locks.ReadWriteLock;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.traccar.model.BaseModel;
-
-public class BaseObjectManager<T extends BaseModel> {
-
- private static final Logger LOGGER = LoggerFactory.getLogger(BaseObjectManager.class);
-
- private final ReadWriteLock lock = new ReentrantReadWriteLock();
-
- private final DataManager dataManager;
-
- private final Class<T> baseClass;
- private Map<Long, T> items;
-
- protected BaseObjectManager(DataManager dataManager, Class<T> baseClass) {
- this.dataManager = dataManager;
- this.baseClass = baseClass;
- refreshItems();
- }
-
- protected final void readLock() {
- lock.readLock().lock();
- }
-
- protected final void readUnlock() {
- lock.readLock().unlock();
- }
-
- protected final void writeLock() {
- lock.writeLock().lock();
- }
-
- protected final void writeUnlock() {
- lock.writeLock().unlock();
- }
-
- protected final DataManager getDataManager() {
- return dataManager;
- }
-
- protected final Class<T> getBaseClass() {
- return baseClass;
- }
-
- public T getById(long itemId) {
- try {
- readLock();
- return items.get(itemId);
- } finally {
- readUnlock();
- }
- }
-
- public void refreshItems() {
- if (dataManager != null) {
- try {
- writeLock();
- Collection<T> databaseItems = dataManager.getObjects(baseClass);
- if (items == null) {
- items = new ConcurrentHashMap<>(databaseItems.size());
- }
- Set<Long> databaseItemIds = new HashSet<>();
- for (T item : databaseItems) {
- databaseItemIds.add(item.getId());
- if (items.containsKey(item.getId())) {
- updateCachedItem(item);
- } else {
- addNewItem(item);
- }
- }
- for (Long cachedItemId : items.keySet()) {
- if (!databaseItemIds.contains(cachedItemId)) {
- removeCachedItem(cachedItemId);
- }
- }
- } catch (SQLException error) {
- LOGGER.warn("Error refreshing items", error);
- } finally {
- writeUnlock();
- }
- }
- }
-
- protected void addNewItem(T item) {
- try {
- writeLock();
- items.put(item.getId(), item);
- } finally {
- writeUnlock();
- }
- }
-
- public void addItem(T item) throws SQLException {
- dataManager.addObject(item);
- addNewItem(item);
- }
-
- protected void updateCachedItem(T item) {
- try {
- writeLock();
- items.put(item.getId(), item);
- } finally {
- writeUnlock();
- }
- }
-
- public void updateItem(T item) throws SQLException {
- dataManager.updateObject(item);
- updateCachedItem(item);
- }
-
- protected void removeCachedItem(long itemId) {
- try {
- writeLock();
- items.remove(itemId);
- } finally {
- writeUnlock();
- }
- }
-
- public void removeItem(long itemId) throws SQLException {
- BaseModel item = getById(itemId);
- if (item != null) {
- dataManager.removeObject(baseClass, itemId);
- removeCachedItem(itemId);
- }
- }
-
- public final Collection<T> getItems(Set<Long> itemIds) {
- Collection<T> result = new LinkedList<>();
- for (long itemId : itemIds) {
- T item = getById(itemId);
- if (item != null) {
- result.add(item);
- }
- }
- return result;
- }
-
- public Set<Long> getAllItems() {
- try {
- readLock();
- return items.keySet();
- } finally {
- readUnlock();
- }
- }
-
-}
diff --git a/src/main/java/org/traccar/database/CalendarManager.java b/src/main/java/org/traccar/database/CalendarManager.java
deleted file mode 100644
index 44ced1082..000000000
--- a/src/main/java/org/traccar/database/CalendarManager.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright 2016 - 2017 Anton Tananaev (anton@traccar.org)
- * Copyright 2016 - 2017 Andrey Kunitsyn (andrey@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 org.traccar.model.Calendar;
-
-public class CalendarManager extends SimpleObjectManager<Calendar> {
-
- public CalendarManager(DataManager dataManager) {
- super(dataManager, Calendar.class);
- }
-
-}
diff --git a/src/main/java/org/traccar/database/CommandsManager.java b/src/main/java/org/traccar/database/CommandsManager.java
index 843c89e82..df399cd7a 100644
--- a/src/main/java/org/traccar/database/CommandsManager.java
+++ b/src/main/java/org/traccar/database/CommandsManager.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017 - 2020 Anton Tananaev (anton@traccar.org)
+ * Copyright 2017 - 2022 Anton Tananaev (anton@traccar.org)
* Copyright 2017 Andrey Kunitsyn (andrey@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,177 +16,112 @@
*/
package org.traccar.database;
-import java.lang.reflect.Field;
-import java.lang.reflect.Modifier;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.Collections;
-import java.util.List;
-import java.util.Map;
-import java.util.Queue;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.ConcurrentLinkedQueue;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
import org.traccar.BaseProtocol;
-import org.traccar.Context;
+import org.traccar.ServerManager;
+import org.traccar.broadcast.BroadcastInterface;
+import org.traccar.broadcast.BroadcastService;
import org.traccar.model.Command;
-import org.traccar.model.Typed;
+import org.traccar.model.Device;
import org.traccar.model.Position;
-
-public class CommandsManager extends ExtendedObjectManager<Command> {
-
- private static final Logger LOGGER = LoggerFactory.getLogger(CommandsManager.class);
-
- private final Map<Long, Queue<Command>> deviceQueues = new ConcurrentHashMap<>();
-
- private final boolean queueing;
-
- public CommandsManager(DataManager dataManager, boolean queueing) {
- super(dataManager, Command.class);
- this.queueing = queueing;
- }
-
- public boolean checkDeviceCommand(long deviceId, long commandId) {
- return !getAllDeviceItems(deviceId).contains(commandId);
+import org.traccar.model.QueuedCommand;
+import org.traccar.session.ConnectionManager;
+import org.traccar.session.DeviceSession;
+import org.traccar.sms.SmsManager;
+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 javax.annotation.Nullable;
+import javax.inject.Inject;
+import javax.inject.Singleton;
+import java.util.Collection;
+import java.util.stream.Collectors;
+
+@Singleton
+public class CommandsManager implements BroadcastInterface {
+
+ private final Storage storage;
+ private final ServerManager serverManager;
+ private final SmsManager smsManager;
+ private final ConnectionManager connectionManager;
+ private final BroadcastService broadcastService;
+
+ @Inject
+ public CommandsManager(
+ Storage storage, ServerManager serverManager, @Nullable SmsManager smsManager,
+ ConnectionManager connectionManager, BroadcastService broadcastService) {
+ this.storage = storage;
+ this.serverManager = serverManager;
+ this.smsManager = smsManager;
+ this.connectionManager = connectionManager;
+ this.broadcastService = broadcastService;
+ broadcastService.registerListener(this);
}
public boolean sendCommand(Command command) throws Exception {
long deviceId = command.getDeviceId();
- if (command.getId() != 0) {
- command = getById(command.getId()).clone();
- command.setDeviceId(deviceId);
- }
if (command.getTextChannel()) {
- Position lastPosition = Context.getIdentityManager().getLastPosition(deviceId);
- String phone = Context.getIdentityManager().getById(deviceId).getPhone();
- if (lastPosition != null) {
- BaseProtocol protocol = Context.getServerManager().getProtocol(lastPosition.getProtocol());
- protocol.sendTextCommand(phone, command);
+ if (smsManager == null) {
+ throw new RuntimeException("SMS not configured");
+ }
+ Device device = storage.getObject(Device.class, new Request(
+ 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", device.getPositionId())));
+ if (position != null) {
+ BaseProtocol protocol = serverManager.getProtocol(position.getProtocol());
+ protocol.sendTextCommand(device.getPhone(), command);
} else if (command.getType().equals(Command.TYPE_CUSTOM)) {
- if (Context.getSmsManager() != null) {
- Context.getSmsManager().sendMessageSync(phone, command.getString(Command.KEY_DATA), true);
- } else {
- throw new RuntimeException("SMS is not enabled");
- }
+ smsManager.sendMessage(device.getPhone(), command.getString(Command.KEY_DATA), true);
} else {
throw new RuntimeException("Command " + command.getType() + " is not supported");
}
} else {
- ActiveDevice activeDevice = Context.getConnectionManager().getActiveDevice(deviceId);
- if (activeDevice != null) {
- if (activeDevice.supportsLiveCommands()) {
- activeDevice.sendCommand(command);
- } else {
- getDeviceQueue(deviceId).add(command);
- return false;
- }
- } else if (!queueing) {
- throw new RuntimeException("Device is not online");
+ DeviceSession deviceSession = connectionManager.getDeviceSession(deviceId);
+ if (deviceSession != null && deviceSession.supportsLiveCommands()) {
+ deviceSession.sendCommand(command);
} else {
- getDeviceQueue(deviceId).add(command);
+ storage.addObject(QueuedCommand.fromCommand(command), new Request(new Columns.Exclude("id")));
+ broadcastService.updateCommand(true, deviceId);
return false;
}
}
return true;
}
- public Collection<Long> getSupportedCommands(long deviceId) {
- List<Long> result = new ArrayList<>();
- Position lastPosition = Context.getIdentityManager().getLastPosition(deviceId);
- for (long commandId : getAllDeviceItems(deviceId)) {
- Command command = getById(commandId);
- if (lastPosition != null) {
- BaseProtocol protocol = Context.getServerManager().getProtocol(lastPosition.getProtocol());
- if (command.getTextChannel() && protocol.getSupportedTextCommands().contains(command.getType())
- || !command.getTextChannel()
- && protocol.getSupportedDataCommands().contains(command.getType())) {
- result.add(commandId);
- }
- } else if (command.getType().equals(Command.TYPE_CUSTOM)) {
- result.add(commandId);
- }
- }
- return result;
- }
-
- public Collection<Typed> getCommandTypes(long deviceId, boolean textChannel) {
- Position lastPosition = Context.getIdentityManager().getLastPosition(deviceId);
- if (lastPosition != null) {
- return getCommandTypes(lastPosition.getProtocol(), textChannel);
- } else {
- return Collections.singletonList(new Typed(Command.TYPE_CUSTOM));
- }
- }
-
- public Collection<Typed> getCommandTypes(String protocolName, boolean textChannel) {
- List<Typed> result = new ArrayList<>();
- BaseProtocol protocol = Context.getServerManager().getProtocol(protocolName);
- Collection<String> commands;
- commands = textChannel ? protocol.getSupportedTextCommands() : protocol.getSupportedDataCommands();
- for (String commandKey : commands) {
- result.add(new Typed(commandKey));
- }
- return result;
- }
-
- public Collection<Typed> getAllCommandTypes() {
- List<Typed> result = new ArrayList<>();
- Field[] fields = Command.class.getDeclaredFields();
- for (Field field : fields) {
- if (Modifier.isStatic(field.getModifiers()) && field.getName().startsWith("TYPE_")) {
- try {
- result.add(new Typed(field.get(null).toString()));
- } catch (IllegalArgumentException | IllegalAccessException error) {
- LOGGER.warn("Get command types error", error);
- }
- }
- }
- return result;
- }
-
- private Queue<Command> getDeviceQueue(long deviceId) {
- Queue<Command> deviceQueue;
- try {
- readLock();
- deviceQueue = deviceQueues.get(deviceId);
- } finally {
- readUnlock();
- }
- if (deviceQueue != null) {
- return deviceQueue;
- } else {
- try {
- writeLock();
- return deviceQueues.computeIfAbsent(deviceId, key -> new ConcurrentLinkedQueue<>());
- } finally {
- writeUnlock();
- }
- }
- }
-
public Collection<Command> readQueuedCommands(long deviceId) {
return readQueuedCommands(deviceId, Integer.MAX_VALUE);
}
public Collection<Command> readQueuedCommands(long deviceId, int count) {
- Queue<Command> deviceQueue;
try {
- readLock();
- deviceQueue = deviceQueues.get(deviceId);
- } finally {
- readUnlock();
+ var commands = storage.getObjects(QueuedCommand.class, new Request(
+ new Columns.All(),
+ new Condition.Equals("deviceId", deviceId),
+ new Order("id", false, count)));
+ for (var command : commands) {
+ storage.removeObject(QueuedCommand.class, new Request(
+ new Condition.Equals("id", command.getId())));
+ }
+ return commands.stream().map(QueuedCommand::toCommand).collect(Collectors.toList());
+ } catch (StorageException e) {
+ throw new RuntimeException(e);
}
- Collection<Command> result = new ArrayList<>();
- if (deviceQueue != null) {
- Command command = deviceQueue.poll();
- while (command != null && result.size() < count) {
- result.add(command);
- command = deviceQueue.poll();
+ }
+
+ @Override
+ public void updateCommand(boolean local, long deviceId) {
+ if (!local) {
+ DeviceSession deviceSession = connectionManager.getDeviceSession(deviceId);
+ if (deviceSession != null && deviceSession.supportsLiveCommands()) {
+ for (Command command : readQueuedCommands(deviceId)) {
+ deviceSession.sendCommand(command);
+ }
}
}
- return result;
}
}
diff --git a/src/main/java/org/traccar/database/ConnectionManager.java b/src/main/java/org/traccar/database/ConnectionManager.java
deleted file mode 100644
index e12d44612..000000000
--- a/src/main/java/org/traccar/database/ConnectionManager.java
+++ /dev/null
@@ -1,216 +0,0 @@
-/*
- * Copyright 2015 - 2020 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 io.netty.channel.Channel;
-import io.netty.util.Timeout;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.traccar.Context;
-import org.traccar.GlobalTimer;
-import org.traccar.Main;
-import org.traccar.Protocol;
-import org.traccar.config.Keys;
-import org.traccar.handler.events.MotionEventHandler;
-import org.traccar.handler.events.OverspeedEventHandler;
-import org.traccar.model.Device;
-import org.traccar.model.DeviceState;
-import org.traccar.model.Event;
-import org.traccar.model.Position;
-
-import java.net.SocketAddress;
-import java.sql.SQLException;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-import java.util.concurrent.TimeUnit;
-
-public class ConnectionManager {
-
- private static final Logger LOGGER = LoggerFactory.getLogger(ConnectionManager.class);
-
- private final long deviceTimeout;
- private final boolean updateDeviceState;
-
- private final Map<Long, ActiveDevice> activeDevices = new ConcurrentHashMap<>();
- private final Map<Long, Set<UpdateListener>> listeners = new ConcurrentHashMap<>();
- private final Map<Long, Timeout> timeouts = new ConcurrentHashMap<>();
-
- public ConnectionManager() {
- deviceTimeout = Context.getConfig().getLong(Keys.STATUS_TIMEOUT) * 1000;
- updateDeviceState = Context.getConfig().getBoolean(Keys.STATUS_UPDATE_DEVICE_STATE);
- }
-
- public void addActiveDevice(long deviceId, Protocol protocol, Channel channel, SocketAddress remoteAddress) {
- activeDevices.put(deviceId, new ActiveDevice(deviceId, protocol, channel, remoteAddress));
- }
-
- public void removeActiveDevice(Channel channel) {
- for (ActiveDevice activeDevice : activeDevices.values()) {
- if (activeDevice.getChannel() == channel) {
- updateDevice(activeDevice.getDeviceId(), Device.STATUS_OFFLINE, null);
- activeDevices.remove(activeDevice.getDeviceId());
- break;
- }
- }
- }
-
- public ActiveDevice getActiveDevice(long deviceId) {
- return activeDevices.get(deviceId);
- }
-
- public void updateDevice(final long deviceId, String status, Date time) {
- Device device = Context.getIdentityManager().getById(deviceId);
- if (device == null) {
- return;
- }
-
- String oldStatus = device.getStatus();
- device.setStatus(status);
-
- if (!status.equals(oldStatus)) {
- String eventType;
- Map<Event, Position> events = new HashMap<>();
- switch (status) {
- case Device.STATUS_ONLINE:
- eventType = Event.TYPE_DEVICE_ONLINE;
- break;
- case Device.STATUS_UNKNOWN:
- eventType = Event.TYPE_DEVICE_UNKNOWN;
- if (updateDeviceState) {
- events.putAll(updateDeviceState(deviceId));
- }
- break;
- default:
- eventType = Event.TYPE_DEVICE_OFFLINE;
- if (updateDeviceState) {
- events.putAll(updateDeviceState(deviceId));
- }
- break;
- }
- events.put(new Event(eventType, deviceId), null);
- Context.getNotificationManager().updateEvents(events);
- }
-
- Timeout timeout = timeouts.remove(deviceId);
- if (timeout != null) {
- timeout.cancel();
- }
-
- if (time != null) {
- device.setLastUpdate(time);
- }
-
- if (status.equals(Device.STATUS_ONLINE)) {
- timeouts.put(deviceId, GlobalTimer.getTimer().newTimeout(timeout1 -> {
- if (!timeout1.isCancelled()) {
- updateDevice(deviceId, Device.STATUS_UNKNOWN, null);
- }
- }, deviceTimeout, TimeUnit.MILLISECONDS));
- }
-
- try {
- Context.getDeviceManager().updateDeviceStatus(device);
- } catch (SQLException error) {
- LOGGER.warn("Update device status error", error);
- }
-
- updateDevice(device);
- }
-
- public Map<Event, Position> updateDeviceState(long deviceId) {
- DeviceState deviceState = Context.getDeviceManager().getDeviceState(deviceId);
- Map<Event, Position> result = new HashMap<>();
-
- Map<Event, Position> event = Main.getInjector()
- .getInstance(MotionEventHandler.class).updateMotionState(deviceState);
- if (event != null) {
- result.putAll(event);
- }
-
- event = Main.getInjector().getInstance(OverspeedEventHandler.class)
- .updateOverspeedState(deviceState, Context.getDeviceManager().
- lookupAttributeDouble(deviceId, OverspeedEventHandler.ATTRIBUTE_SPEED_LIMIT, 0, true, false));
- if (event != null) {
- result.putAll(event);
- }
-
- return result;
- }
-
- public synchronized void sendKeepalive() {
- for (Set<UpdateListener> userListeners : listeners.values()) {
- for (UpdateListener listener : userListeners) {
- listener.onKeepalive();
- }
- }
- }
-
- public synchronized void updateDevice(Device device) {
- for (long userId : Context.getPermissionsManager().getDeviceUsers(device.getId())) {
- if (listeners.containsKey(userId)) {
- for (UpdateListener listener : listeners.get(userId)) {
- listener.onUpdateDevice(device);
- }
- }
- }
- }
-
- public synchronized void updatePosition(Position position) {
- long deviceId = position.getDeviceId();
-
- for (long userId : Context.getPermissionsManager().getDeviceUsers(deviceId)) {
- if (listeners.containsKey(userId)) {
- for (UpdateListener listener : listeners.get(userId)) {
- listener.onUpdatePosition(position);
- }
- }
- }
- }
-
- public synchronized void updateEvent(long userId, Event event) {
- if (listeners.containsKey(userId)) {
- for (UpdateListener listener : listeners.get(userId)) {
- listener.onUpdateEvent(event);
- }
- }
- }
-
- public interface UpdateListener {
- void onKeepalive();
- void onUpdateDevice(Device device);
- void onUpdatePosition(Position position);
- void onUpdateEvent(Event event);
- }
-
- public synchronized void addListener(long userId, UpdateListener listener) {
- if (!listeners.containsKey(userId)) {
- listeners.put(userId, new HashSet<>());
- }
- listeners.get(userId).add(listener);
- }
-
- public synchronized void removeListener(long userId, UpdateListener listener) {
- if (!listeners.containsKey(userId)) {
- listeners.put(userId, new HashSet<>());
- }
- listeners.get(userId).remove(listener);
- }
-
-}
diff --git a/src/main/java/org/traccar/database/DataManager.java b/src/main/java/org/traccar/database/DataManager.java
deleted file mode 100644
index 00c802fde..000000000
--- a/src/main/java/org/traccar/database/DataManager.java
+++ /dev/null
@@ -1,452 +0,0 @@
-/*
- * Copyright 2012 - 2021 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 com.zaxxer.hikari.HikariConfig;
-import com.zaxxer.hikari.HikariDataSource;
-import liquibase.Contexts;
-import liquibase.Liquibase;
-import liquibase.database.Database;
-import liquibase.database.DatabaseFactory;
-import liquibase.exception.LiquibaseException;
-import liquibase.resource.FileSystemResourceAccessor;
-import liquibase.resource.ResourceAccessor;
-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.Attribute;
-import org.traccar.model.BaseModel;
-import org.traccar.model.Calendar;
-import org.traccar.model.Command;
-import org.traccar.model.Device;
-import org.traccar.model.Driver;
-import org.traccar.model.Event;
-import org.traccar.model.Geofence;
-import org.traccar.model.Group;
-import org.traccar.model.Maintenance;
-import org.traccar.model.ManagedUser;
-import org.traccar.model.Notification;
-import org.traccar.model.Order;
-import org.traccar.model.Permission;
-import org.traccar.model.Position;
-import org.traccar.model.Server;
-import org.traccar.model.Statistics;
-import org.traccar.model.User;
-
-import javax.sql.DataSource;
-import java.beans.Introspector;
-import java.io.File;
-import java.lang.reflect.Method;
-import java.net.URL;
-import java.sql.SQLException;
-import java.util.Arrays;
-import java.util.Collection;
-import java.util.Date;
-import java.util.HashSet;
-import java.util.Set;
-
-public class DataManager {
-
- private static final Logger LOGGER = LoggerFactory.getLogger(DataManager.class);
-
- public static final String ACTION_SELECT_ALL = "selectAll";
- public static final String ACTION_SELECT = "select";
- public static final String ACTION_INSERT = "insert";
- public static final String ACTION_UPDATE = "update";
- public static final String ACTION_DELETE = "delete";
-
- private final Config config;
-
- private DataSource dataSource;
-
- public DataSource getDataSource() {
- return dataSource;
- }
-
- private boolean generateQueries;
-
- private final boolean forceLdap;
-
- public DataManager(Config config) throws Exception {
- this.config = config;
-
- forceLdap = config.getBoolean(Keys.LDAP_FORCE);
-
- initDatabase();
- initDatabaseSchema();
- }
-
- private void initDatabase() throws Exception {
-
- String driverFile = config.getString(Keys.DATABASE_DRIVER_FILE);
- if (driverFile != null) {
- ClassLoader classLoader = ClassLoader.getSystemClassLoader();
- try {
- Method method = classLoader.getClass().getDeclaredMethod("addURL", URL.class);
- method.setAccessible(true);
- method.invoke(classLoader, new File(driverFile).toURI().toURL());
- } catch (NoSuchMethodException e) {
- Method method = classLoader.getClass()
- .getDeclaredMethod("appendToClassPathForInstrumentation", String.class);
- method.setAccessible(true);
- method.invoke(classLoader, driverFile);
- }
- }
-
- String driver = config.getString(Keys.DATABASE_DRIVER);
- if (driver != null) {
- Class.forName(driver);
- }
-
- HikariConfig hikariConfig = new HikariConfig();
- hikariConfig.setDriverClassName(driver);
- hikariConfig.setJdbcUrl(config.getString(Keys.DATABASE_URL));
- hikariConfig.setUsername(config.getString(Keys.DATABASE_USER));
- hikariConfig.setPassword(config.getString(Keys.DATABASE_PASSWORD));
- hikariConfig.setConnectionInitSql(config.getString(Keys.DATABASE_CHECK_CONNECTION));
- hikariConfig.setIdleTimeout(600000);
-
- int maxPoolSize = config.getInteger(Keys.DATABASE_MAX_POOL_SIZE);
- if (maxPoolSize != 0) {
- hikariConfig.setMaximumPoolSize(maxPoolSize);
- }
-
- generateQueries = config.getBoolean(Keys.DATABASE_GENERATE_QUERIES);
-
- dataSource = new HikariDataSource(hikariConfig);
- }
-
- public static String constructObjectQuery(String action, Class<?> clazz, boolean extended) {
- switch (action) {
- case ACTION_INSERT:
- case ACTION_UPDATE:
- StringBuilder result = new StringBuilder();
- StringBuilder fields = new StringBuilder();
- StringBuilder values = new StringBuilder();
-
- Set<Method> methods = new HashSet<>(Arrays.asList(clazz.getMethods()));
- methods.removeAll(Arrays.asList(Object.class.getMethods()));
- methods.removeAll(Arrays.asList(BaseModel.class.getMethods()));
- for (Method method : methods) {
- boolean skip;
- if (extended) {
- skip = !method.isAnnotationPresent(QueryExtended.class);
- } else {
- skip = method.isAnnotationPresent(QueryIgnore.class)
- || method.isAnnotationPresent(QueryExtended.class) && !action.equals(ACTION_INSERT);
- }
- if (!skip && method.getName().startsWith("get") && method.getParameterTypes().length == 0) {
- String name = Introspector.decapitalize(method.getName().substring(3));
- if (action.equals(ACTION_INSERT)) {
- fields.append(name).append(", ");
- values.append(":").append(name).append(", ");
- } else {
- fields.append(name).append(" = :").append(name).append(", ");
- }
- }
- }
- fields.setLength(fields.length() - 2);
- if (action.equals(ACTION_INSERT)) {
- values.setLength(values.length() - 2);
- result.append("INSERT INTO ").append(getObjectsTableName(clazz)).append(" (");
- result.append(fields).append(") ");
- result.append("VALUES (").append(values).append(")");
- } else {
- result.append("UPDATE ").append(getObjectsTableName(clazz)).append(" SET ");
- result.append(fields);
- result.append(" WHERE id = :id");
- }
- return result.toString();
- case ACTION_SELECT_ALL:
- return "SELECT * FROM " + getObjectsTableName(clazz);
- case ACTION_SELECT:
- return "SELECT * FROM " + getObjectsTableName(clazz) + " WHERE id = :id";
- case ACTION_DELETE:
- return "DELETE FROM " + getObjectsTableName(clazz) + " WHERE id = :id";
- default:
- throw new IllegalArgumentException("Unknown action");
- }
- }
-
- public static String constructPermissionQuery(String action, Class<?> owner, Class<?> property) {
- switch (action) {
- case ACTION_SELECT_ALL:
- return "SELECT " + makeNameId(owner) + ", " + makeNameId(property) + " FROM "
- + getPermissionsTableName(owner, property);
- case ACTION_INSERT:
- return "INSERT INTO " + getPermissionsTableName(owner, property)
- + " (" + makeNameId(owner) + ", " + makeNameId(property) + ") VALUES (:"
- + makeNameId(owner) + ", :" + makeNameId(property) + ")";
- case ACTION_DELETE:
- return "DELETE FROM " + getPermissionsTableName(owner, property)
- + " WHERE " + makeNameId(owner) + " = :" + makeNameId(owner)
- + " AND " + makeNameId(property) + " = :" + makeNameId(property);
- default:
- throw new IllegalArgumentException("Unknown action");
- }
- }
-
- private String getQuery(String key) {
- String query = config.getString(key);
- if (query == null) {
- LOGGER.info("Query not provided: " + key);
- }
- return query;
- }
-
- public String getQuery(String action, Class<?> clazz) {
- return getQuery(action, clazz, false);
- }
-
- public String getQuery(String action, Class<?> clazz, boolean extended) {
- String queryName;
- if (action.equals(ACTION_SELECT_ALL)) {
- queryName = "database.select" + clazz.getSimpleName() + "s";
- } else {
- queryName = "database." + action.toLowerCase() + clazz.getSimpleName();
- if (extended) {
- queryName += "Extended";
- }
- }
- String query = config.getString(queryName);
- if (query == null) {
- if (generateQueries) {
- query = constructObjectQuery(action, clazz, extended);
- } else {
- LOGGER.info("Query not provided: " + queryName);
- }
- }
- return query;
- }
-
- public String getQuery(String action, Class<?> owner, Class<?> property) {
- String queryName;
- switch (action) {
- case ACTION_SELECT_ALL:
- queryName = "database.select" + owner.getSimpleName() + property.getSimpleName() + "s";
- break;
- case ACTION_INSERT:
- queryName = "database.link" + owner.getSimpleName() + property.getSimpleName();
- break;
- default:
- queryName = "database.unlink" + owner.getSimpleName() + property.getSimpleName();
- break;
- }
- String query = config.getString(queryName);
- if (query == null) {
- if (generateQueries) {
- query = constructPermissionQuery(
- action, owner, property.equals(User.class) ? ManagedUser.class : property);
- } else {
- LOGGER.info("Query not provided: " + queryName);
- }
- }
- return query;
- }
-
- private static String getPermissionsTableName(Class<?> owner, Class<?> property) {
- String propertyName = property.getSimpleName();
- if (propertyName.equals("ManagedUser")) {
- propertyName = "User";
- }
- return "tc_" + Introspector.decapitalize(owner.getSimpleName())
- + "_" + Introspector.decapitalize(propertyName);
- }
-
- private static String getObjectsTableName(Class<?> clazz) {
- String result = "tc_" + Introspector.decapitalize(clazz.getSimpleName());
- // Add "s" ending if object name is not plural already
- if (!result.endsWith("s")) {
- result += "s";
- }
- return result;
- }
-
- private void initDatabaseSchema() throws LiquibaseException {
-
- if (config.hasKey(Keys.DATABASE_CHANGELOG)) {
-
- ResourceAccessor resourceAccessor = new FileSystemResourceAccessor(new File("."));
-
- Database database = DatabaseFactory.getInstance().openDatabase(
- config.getString(Keys.DATABASE_URL),
- config.getString(Keys.DATABASE_USER),
- config.getString(Keys.DATABASE_PASSWORD),
- config.getString(Keys.DATABASE_DRIVER),
- null, null, null, resourceAccessor);
-
- Liquibase liquibase = new Liquibase(
- config.getString(Keys.DATABASE_CHANGELOG), resourceAccessor, database);
-
- liquibase.clearCheckSums();
-
- liquibase.update(new Contexts());
- }
- }
-
- public User login(String email, String password) throws SQLException {
- User user = QueryBuilder.create(dataSource, getQuery("database.loginUser"))
- .setString("email", email.trim())
- .executeQuerySingle(User.class);
- LdapProvider ldapProvider = Context.getLdapProvider();
- if (user != null) {
- if (ldapProvider != null && user.getLogin() != null && ldapProvider.login(user.getLogin(), password)
- || !forceLdap && user.isPasswordValid(password)) {
- return user;
- }
- } else {
- if (ldapProvider != null && ldapProvider.login(email, password)) {
- user = ldapProvider.getUser(email);
- Context.getUsersManager().addItem(user);
- return user;
- }
- }
- return null;
- }
-
- public void updateDeviceStatus(Device device) throws SQLException {
- QueryBuilder.create(dataSource, getQuery(ACTION_UPDATE, Device.class, true))
- .setObject(device)
- .executeUpdate();
- }
-
- public Collection<Position> getPositions(long deviceId, Date from, Date to) throws SQLException {
- return QueryBuilder.create(dataSource, getQuery("database.selectPositions"))
- .setLong("deviceId", deviceId)
- .setDate("from", from)
- .setDate("to", to)
- .executeQuery(Position.class);
- }
-
- public void updateLatestPosition(Position position) throws SQLException {
- QueryBuilder.create(dataSource, getQuery("database.updateLatestPosition"))
- .setDate("now", new Date())
- .setObject(position)
- .executeUpdate();
- }
-
- public Collection<Position> getLatestPositions() throws SQLException {
- return QueryBuilder.create(dataSource, getQuery("database.selectLatestPositions"))
- .executeQuery(Position.class);
- }
-
- public Server getServer() throws SQLException {
- return QueryBuilder.create(dataSource, getQuery(ACTION_SELECT_ALL, Server.class))
- .executeQuerySingle(Server.class);
- }
-
- public Collection<Event> getEvents(long deviceId, Date from, Date to) throws SQLException {
- return QueryBuilder.create(dataSource, getQuery("database.selectEvents"))
- .setLong("deviceId", deviceId)
- .setDate("from", from)
- .setDate("to", to)
- .executeQuery(Event.class);
- }
-
- public Collection<Statistics> getStatistics(Date from, Date to) throws SQLException {
- return QueryBuilder.create(dataSource, getQuery("database.selectStatistics"))
- .setDate("from", from)
- .setDate("to", to)
- .executeQuery(Statistics.class);
- }
-
- public static Class<?> getClassByName(String name) throws ClassNotFoundException {
- switch (name.toLowerCase().replace("id", "")) {
- case "device":
- return Device.class;
- case "group":
- return Group.class;
- case "user":
- return User.class;
- case "manageduser":
- return ManagedUser.class;
- case "geofence":
- return Geofence.class;
- case "driver":
- return Driver.class;
- case "attribute":
- return Attribute.class;
- case "calendar":
- return Calendar.class;
- case "command":
- return Command.class;
- case "maintenance":
- return Maintenance.class;
- case "notification":
- return Notification.class;
- case "order":
- return Order.class;
- default:
- throw new ClassNotFoundException();
- }
- }
-
- private static String makeNameId(Class<?> clazz) {
- String name = clazz.getSimpleName();
- return Introspector.decapitalize(name) + (!name.contains("Id") ? "Id" : "");
- }
-
- public Collection<Permission> getPermissions(Class<? extends BaseModel> owner, Class<? extends BaseModel> property)
- throws SQLException, ClassNotFoundException {
- return QueryBuilder.create(dataSource, getQuery(ACTION_SELECT_ALL, owner, property))
- .executePermissionsQuery();
- }
-
- public void linkObject(Class<?> owner, long ownerId, Class<?> property, long propertyId, boolean link)
- throws SQLException {
- QueryBuilder.create(dataSource, getQuery(link ? ACTION_INSERT : ACTION_DELETE, owner, property))
- .setLong(makeNameId(owner), ownerId)
- .setLong(makeNameId(property), propertyId)
- .executeUpdate();
- }
-
- public <T extends BaseModel> T getObject(Class<T> clazz, long entityId) throws SQLException {
- return QueryBuilder.create(dataSource, getQuery(ACTION_SELECT, clazz))
- .setLong("id", entityId)
- .executeQuerySingle(clazz);
- }
-
- public <T extends BaseModel> Collection<T> getObjects(Class<T> clazz) throws SQLException {
- return QueryBuilder.create(dataSource, getQuery(ACTION_SELECT_ALL, clazz))
- .executeQuery(clazz);
- }
-
- public void addObject(BaseModel entity) throws SQLException {
- entity.setId(QueryBuilder.create(dataSource, getQuery(ACTION_INSERT, entity.getClass()), true)
- .setObject(entity)
- .executeUpdate());
- }
-
- public void updateObject(BaseModel entity) throws SQLException {
- QueryBuilder.create(dataSource, getQuery(ACTION_UPDATE, entity.getClass()))
- .setObject(entity)
- .executeUpdate();
- if (entity instanceof User && ((User) entity).getHashedPassword() != null) {
- QueryBuilder.create(dataSource, getQuery(ACTION_UPDATE, User.class, true))
- .setObject(entity)
- .executeUpdate();
- }
- }
-
- public void removeObject(Class<? extends BaseModel> clazz, long entityId) throws SQLException {
- QueryBuilder.create(dataSource, getQuery(ACTION_DELETE, clazz))
- .setLong("id", entityId)
- .executeUpdate();
- }
-
-}
diff --git a/src/main/java/org/traccar/database/DeviceLookupService.java b/src/main/java/org/traccar/database/DeviceLookupService.java
new file mode 100644
index 000000000..583b2ae35
--- /dev/null
+++ b/src/main/java/org/traccar/database/DeviceLookupService.java
@@ -0,0 +1,141 @@
+/*
+ * 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.database;
+
+import io.netty.util.Timeout;
+import io.netty.util.Timer;
+import io.netty.util.TimerTask;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.traccar.config.Config;
+import org.traccar.config.Keys;
+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.Condition;
+import org.traccar.storage.query.Request;
+
+import javax.inject.Inject;
+import javax.inject.Singleton;
+import java.util.Map;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.TimeUnit;
+
+@Singleton
+public class DeviceLookupService {
+
+ private static final Logger LOGGER = LoggerFactory.getLogger(DeviceLookupService.class);
+
+ private static final long INFO_TIMEOUT_MS = TimeUnit.MINUTES.toMillis(60);
+ private static final long THROTTLE_MIN_MS = TimeUnit.MINUTES.toMillis(1);
+ private static final long THROTTLE_MAX_MS = TimeUnit.MINUTES.toMillis(30);
+
+ private final Storage storage;
+ private final Timer timer;
+
+ private final boolean throttlingEnabled;
+
+ private static class IdentifierInfo {
+ private long lastQuery;
+ private long delay;
+ private Timeout timeout;
+ }
+
+ private final class IdentifierTask implements TimerTask {
+ private final String uniqueId;
+
+ private IdentifierTask(String uniqueId) {
+ this.uniqueId = uniqueId;
+ }
+
+ @Override
+ public void run(Timeout timeout) {
+ LOGGER.debug("Device lookup expired {}", uniqueId);
+ synchronized (DeviceLookupService.this) {
+ identifierMap.remove(uniqueId);
+ }
+ }
+ }
+
+ private final Map<String, IdentifierInfo> identifierMap = new ConcurrentHashMap<>();
+
+ @Inject
+ public DeviceLookupService(Config config, Storage storage, Timer timer) {
+ this.storage = storage;
+ this.timer = timer;
+ throttlingEnabled = config.getBoolean(Keys.DATABASE_THROTTLE_UNKNOWN);
+ }
+
+ private synchronized boolean isThrottled(String uniqueId) {
+ if (throttlingEnabled) {
+ IdentifierInfo info = identifierMap.get(uniqueId);
+ return info != null && System.currentTimeMillis() < info.lastQuery + info.delay;
+ } else {
+ return false;
+ }
+ }
+
+ private synchronized void lookupSucceeded(String uniqueId) {
+ if (throttlingEnabled) {
+ IdentifierInfo info = identifierMap.remove(uniqueId);
+ if (info != null) {
+ info.timeout.cancel();
+ }
+ }
+ }
+
+ private synchronized void lookupFailed(String uniqueId) {
+ if (throttlingEnabled) {
+ IdentifierInfo info = identifierMap.get(uniqueId);
+ if (info != null) {
+ info.timeout.cancel();
+ info.delay = Math.min(info.delay * 2, THROTTLE_MAX_MS);
+ } else {
+ info = new IdentifierInfo();
+ identifierMap.put(uniqueId, info);
+ info.delay = THROTTLE_MIN_MS;
+ }
+ info.lastQuery = System.currentTimeMillis();
+ info.timeout = timer.newTimeout(new IdentifierTask(uniqueId), INFO_TIMEOUT_MS, TimeUnit.MILLISECONDS);
+ LOGGER.debug("Device lookup {} throttled for {} ms", uniqueId, info.delay);
+ }
+ }
+
+ public Device lookup(String[] uniqueIds) {
+ Device device = null;
+ try {
+ for (String uniqueId : uniqueIds) {
+ if (!isThrottled(uniqueId)) {
+ device = storage.getObject(Device.class, new Request(
+ new Columns.All(), new Condition.Equals("uniqueId", uniqueId)));
+ if (device != null) {
+ lookupSucceeded(uniqueId);
+ break;
+ } else {
+ lookupFailed(uniqueId);
+ }
+ } else {
+ LOGGER.debug("Device lookup throttled {}", uniqueId);
+ }
+ }
+ } catch (StorageException e) {
+ LOGGER.warn("Find device error", e);
+ }
+ return device;
+ }
+
+}
diff --git a/src/main/java/org/traccar/database/DeviceManager.java b/src/main/java/org/traccar/database/DeviceManager.java
deleted file mode 100644
index c8a99274c..000000000
--- a/src/main/java/org/traccar/database/DeviceManager.java
+++ /dev/null
@@ -1,483 +0,0 @@
-/*
- * Copyright 2016 - 2020 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.sql.SQLException;
-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;
-import java.util.concurrent.atomic.AtomicLong;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.traccar.config.Config;
-import org.traccar.Context;
-import org.traccar.config.Keys;
-import org.traccar.model.Command;
-import org.traccar.model.Device;
-import org.traccar.model.DeviceState;
-import org.traccar.model.DeviceAccumulators;
-import org.traccar.model.Group;
-import org.traccar.model.Position;
-import org.traccar.model.Server;
-
-public class DeviceManager extends BaseObjectManager<Device> implements IdentityManager, ManagableObjects {
-
- private static final Logger LOGGER = LoggerFactory.getLogger(DeviceManager.class);
-
- private final Config config;
- private final long dataRefreshDelay;
-
- private Map<String, Device> devicesByUniqueId;
- private Map<String, Device> devicesByPhone;
- private final AtomicLong devicesLastUpdate = new AtomicLong();
-
- private final Map<Long, Position> positions = new ConcurrentHashMap<>();
-
- private final Map<Long, DeviceState> deviceStates = new ConcurrentHashMap<>();
-
- public DeviceManager(DataManager dataManager) {
- super(dataManager, Device.class);
- this.config = Context.getConfig();
- try {
- writeLock();
- if (devicesByPhone == null) {
- devicesByPhone = new ConcurrentHashMap<>();
- }
- if (devicesByUniqueId == null) {
- devicesByUniqueId = new ConcurrentHashMap<>();
- }
- } finally {
- writeUnlock();
- }
- dataRefreshDelay = config.getLong(Keys.DATABASE_REFRESH_DELAY) * 1000;
- refreshLastPositions();
- }
-
- @Override
- public long 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();
- Context.getPermissionsManager().refreshAllExtendedPermissions();
- }
-
- return device.getId();
- } catch (SQLException e) {
- LOGGER.warn("Automatic device registration error", e);
- return 0;
- }
- }
-
- public void updateDeviceCache(boolean force) throws SQLException {
- long lastUpdate = devicesLastUpdate.get();
- if ((force || System.currentTimeMillis() - lastUpdate > dataRefreshDelay)
- && devicesLastUpdate.compareAndSet(lastUpdate, System.currentTimeMillis())) {
- refreshItems();
- }
- }
-
- @Override
- public Device getByUniqueId(String uniqueId) throws SQLException {
- 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 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;
- }
-
- public Device getDeviceByPhone(String phone) {
- try {
- readLock();
- return devicesByPhone.get(phone);
- } finally {
- readUnlock();
- }
- }
-
- @Override
- public Set<Long> getAllItems() {
- Set<Long> result = super.getAllItems();
- if (result.isEmpty()) {
- try {
- updateDeviceCache(true);
- } catch (SQLException e) {
- LOGGER.warn("Update device cache error", e);
- }
- result = super.getAllItems();
- }
- return result;
- }
-
- public Collection<Device> getAllDevices() {
- return getItems(getAllItems());
- }
-
- public Set<Long> getAllUserItems(long userId) {
- return Context.getPermissionsManager().getDevicePermissions(userId);
- }
-
- @Override
- public Set<Long> getUserItems(long userId) {
- if (Context.getPermissionsManager() != null) {
- Set<Long> 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<>();
- }
- }
-
- public Set<Long> getAllManagedItems(long userId) {
- Set<Long> result = new HashSet<>(getAllUserItems(userId));
- for (long managedUserId : Context.getUsersManager().getUserItems(userId)) {
- result.addAll(getAllUserItems(managedUserId));
- }
- return result;
- }
-
- @Override
- public Set<Long> getManagedItems(long userId) {
- Set<Long> result = new HashSet<>(getUserItems(userId));
- for (long managedUserId : Context.getUsersManager().getUserItems(userId)) {
- result.addAll(getUserItems(managedUserId));
- }
- return result;
- }
-
- 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();
- }
- }
-
- private void addByPhone(Device device) {
- try {
- writeLock();
- if (devicesByPhone == null) {
- devicesByPhone = new ConcurrentHashMap<>();
- }
- devicesByPhone.put(device.getPhone(), device);
- } finally {
- writeUnlock();
- }
- }
-
- private void removeByPhone(String phone) {
- if (phone == null || phone.isEmpty()) {
- return;
- }
- try {
- writeLock();
- if (devicesByPhone != null) {
- devicesByPhone.remove(phone);
- }
- } finally {
- writeUnlock();
- }
- }
-
- @Override
- protected void addNewItem(Device device) {
- super.addNewItem(device);
- addByUniqueId(device);
- if (device.getPhone() != null && !device.getPhone().isEmpty()) {
- addByPhone(device);
- }
- if (Context.getGeofenceManager() != null) {
- Position lastPosition = getLastPosition(device.getId());
- if (lastPosition != null) {
- device.setGeofenceIds(Context.getGeofenceManager().getCurrentDeviceGeofences(lastPosition));
- }
- }
- }
-
- @Override
- protected void updateCachedItem(Device device) {
- Device cachedDevice = getById(device.getId());
- cachedDevice.setName(device.getName());
- cachedDevice.setGroupId(device.getGroupId());
- cachedDevice.setCategory(device.getCategory());
- cachedDevice.setContact(device.getContact());
- 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);
- }
- if (device.getPhone() != null && !device.getPhone().isEmpty()
- && !device.getPhone().equals(cachedDevice.getPhone())) {
- String phone = cachedDevice.getPhone();
- removeByPhone(phone);
- cachedDevice.setPhone(device.getPhone());
- addByPhone(cachedDevice);
- }
- }
-
- @Override
- protected void removeCachedItem(long deviceId) {
- Device cachedDevice = getById(deviceId);
- if (cachedDevice != null) {
- String deviceUniqueId = cachedDevice.getUniqueId();
- String phone = cachedDevice.getPhone();
- super.removeCachedItem(deviceId);
- removeByUniqueId(deviceUniqueId);
- removeByPhone(phone);
- }
- positions.remove(deviceId);
- }
-
- public void updateDeviceStatus(Device device) throws SQLException {
- getDataManager().updateDeviceStatus(device);
- Device cachedDevice = getById(device.getId());
- if (cachedDevice != null) {
- cachedDevice.setStatus(device.getStatus());
- }
- }
-
- private void refreshLastPositions() {
- if (getDataManager() != null) {
- try {
- for (Position position : getDataManager().getLatestPositions()) {
- positions.put(position.getDeviceId(), position);
- }
- } catch (SQLException 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 SQLException {
-
- if (isLatestPosition(position)) {
-
- getDataManager().updateLatestPosition(position);
-
- Device device = getById(position.getDeviceId());
- if (device != null) {
- device.setPositionId(position.getId());
- }
-
- positions.put(position.getDeviceId(), position);
-
- if (Context.getConnectionManager() != null) {
- Context.getConnectionManager().updatePosition(position);
- }
- }
- }
-
- @Override
- public Position getLastPosition(long deviceId) {
- return positions.get(deviceId);
- }
-
- public Collection<Position> getInitialState(long userId) {
-
- List<Position> 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;
- }
-
- @Override
- public boolean lookupAttributeBoolean(
- long deviceId, String attributeName, boolean defaultValue, boolean lookupServer, boolean lookupConfig) {
- Object result = lookupAttribute(deviceId, attributeName, lookupServer, lookupConfig);
- if (result != null) {
- return result instanceof String ? Boolean.parseBoolean((String) result) : (Boolean) result;
- }
- return defaultValue;
- }
-
- @Override
- public String lookupAttributeString(
- long deviceId, String attributeName, String defaultValue, boolean lookupServer, boolean lookupConfig) {
- Object result = lookupAttribute(deviceId, attributeName, lookupServer, lookupConfig);
- 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);
- if (device != null) {
- result = device.getAttributes().get(attributeName);
- if (result == null) {
- long groupId = device.getGroupId();
- while (groupId != 0) {
- Group group = Context.getGroupsManager().getById(groupId);
- if (group != null) {
- result = group.getAttributes().get(attributeName);
- if (result != null) {
- break;
- }
- groupId = group.getGroupId();
- } else {
- groupId = 0;
- }
- }
- }
- if (result == null && lookupServer) {
- Server server = Context.getPermissionsManager().getServer();
- result = server.getAttributes().get(attributeName);
- }
- if (result == null && lookupConfig) {
- result = Context.getConfig().getString(attributeName);
- }
- }
- return result;
- }
-
- public void resetDeviceAccumulators(DeviceAccumulators deviceAccumulators) throws SQLException {
- Position last = positions.get(deviceAccumulators.getDeviceId());
- if (last != null) {
- if (deviceAccumulators.getTotalDistance() != null) {
- last.getAttributes().put(Position.KEY_TOTAL_DISTANCE, deviceAccumulators.getTotalDistance());
- }
- if (deviceAccumulators.getHours() != null) {
- last.getAttributes().put(Position.KEY_HOURS, deviceAccumulators.getHours());
- }
- getDataManager().addObject(last);
- updateLatestPosition(last);
- } else {
- throw new IllegalArgumentException();
- }
- }
-
- public DeviceState getDeviceState(long deviceId) {
- DeviceState deviceState = deviceStates.get(deviceId);
- if (deviceState == null) {
- deviceState = new DeviceState();
- deviceStates.put(deviceId, deviceState);
- }
- return deviceState;
- }
-
- public void setDeviceState(long deviceId, DeviceState deviceState) {
- deviceStates.put(deviceId, deviceState);
- }
-
-}
diff --git a/src/main/java/org/traccar/database/DriversManager.java b/src/main/java/org/traccar/database/DriversManager.java
deleted file mode 100644
index d111cd643..000000000
--- a/src/main/java/org/traccar/database/DriversManager.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright 2017 - 2020 Anton Tananaev (anton@traccar.org)
- * Copyright 2017 Andrey Kunitsyn (andrey@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.Map;
-import java.util.concurrent.ConcurrentHashMap;
-
-import org.traccar.model.Driver;
-
-public class DriversManager extends ExtendedObjectManager<Driver> {
-
- private Map<String, Driver> driversByUniqueId;
-
- public DriversManager(DataManager dataManager) {
- super(dataManager, Driver.class);
- try {
- writeLock();
- if (driversByUniqueId == null) {
- driversByUniqueId = new ConcurrentHashMap<>();
- }
- } finally {
- writeUnlock();
- }
- }
-
- private void addByUniqueId(Driver driver) {
- try {
- writeLock();
- if (driversByUniqueId == null) {
- driversByUniqueId = new ConcurrentHashMap<>();
- }
- driversByUniqueId.put(driver.getUniqueId(), driver);
- } finally {
- writeUnlock();
- }
- }
-
- private void removeByUniqueId(String driverUniqueId) {
- try {
- writeLock();
- if (driversByUniqueId == null) {
- driversByUniqueId = new ConcurrentHashMap<>();
- }
- driversByUniqueId.remove(driverUniqueId);
- } finally {
- writeUnlock();
- }
- }
-
- @Override
- protected void addNewItem(Driver driver) {
- super.addNewItem(driver);
- addByUniqueId(driver);
- }
-
- @Override
- protected void updateCachedItem(Driver driver) {
- Driver cachedDriver = getById(driver.getId());
- cachedDriver.setName(driver.getName());
- if (!driver.getUniqueId().equals(cachedDriver.getUniqueId())) {
- removeByUniqueId(cachedDriver.getUniqueId());
- cachedDriver.setUniqueId(driver.getUniqueId());
- addByUniqueId(cachedDriver);
- }
- cachedDriver.setAttributes(driver.getAttributes());
- }
-
- @Override
- protected void removeCachedItem(long driverId) {
- Driver cachedDriver = getById(driverId);
- if (cachedDriver != null) {
- String driverUniqueId = cachedDriver.getUniqueId();
- super.removeCachedItem(driverId);
- removeByUniqueId(driverUniqueId);
- }
- }
-
- public Driver getDriverByUniqueId(String uniqueId) {
- try {
- readLock();
- return driversByUniqueId.get(uniqueId);
- } finally {
- readUnlock();
- }
- }
-}
diff --git a/src/main/java/org/traccar/database/ExtendedObjectManager.java b/src/main/java/org/traccar/database/ExtendedObjectManager.java
deleted file mode 100644
index 93e5820fb..000000000
--- a/src/main/java/org/traccar/database/ExtendedObjectManager.java
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * Copyright 2017 - 2020 Anton Tananaev (anton@traccar.org)
- * Copyright 2017 Andrey Kunitsyn (andrey@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.sql.SQLException;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.traccar.Context;
-import org.traccar.model.Device;
-import org.traccar.model.Group;
-import org.traccar.model.Permission;
-import org.traccar.model.BaseModel;
-
-public abstract class ExtendedObjectManager<T extends BaseModel> extends SimpleObjectManager<T> {
-
- private static final Logger LOGGER = LoggerFactory.getLogger(ExtendedObjectManager.class);
-
- private final Map<Long, Set<Long>> deviceItems = new ConcurrentHashMap<>();
- private final Map<Long, Set<Long>> deviceItemsWithGroups = new ConcurrentHashMap<>();
- private final Map<Long, Set<Long>> groupItems = new ConcurrentHashMap<>();
-
- protected ExtendedObjectManager(DataManager dataManager, Class<T> baseClass) {
- super(dataManager, baseClass);
- refreshExtendedPermissions();
- }
-
- public final Set<Long> getGroupItems(long groupId) {
- try {
- readLock();
- Set<Long> result = groupItems.get(groupId);
- if (result != null) {
- return new HashSet<>(result);
- } else {
- return new HashSet<>();
- }
- } finally {
- readUnlock();
- }
- }
-
- public final Set<Long> getDeviceItems(long deviceId) {
- try {
- readLock();
- Set<Long> result = deviceItems.get(deviceId);
- if (result != null) {
- return new HashSet<>(result);
- } else {
- return new HashSet<>();
- }
- } finally {
- readUnlock();
- }
- }
-
- public Set<Long> getAllDeviceItems(long deviceId) {
- try {
- readLock();
- Set<Long> result = deviceItemsWithGroups.get(deviceId);
- if (result != null) {
- return new HashSet<>(result);
- } else {
- return new HashSet<>();
- }
- } finally {
- readUnlock();
- }
- }
-
- @Override
- public void removeItem(long itemId) throws SQLException {
- super.removeItem(itemId);
- refreshExtendedPermissions();
- }
-
- public void refreshExtendedPermissions() {
- if (getDataManager() != null) {
- try {
- Collection<Permission> databaseGroupPermissions =
- getDataManager().getPermissions(Group.class, getBaseClass());
-
- Collection<Permission> databaseDevicePermissions =
- getDataManager().getPermissions(Device.class, getBaseClass());
-
- writeLock();
-
- groupItems.clear();
- deviceItems.clear();
- deviceItemsWithGroups.clear();
-
- for (Permission groupPermission : databaseGroupPermissions) {
- groupItems
- .computeIfAbsent(groupPermission.getOwnerId(), key -> new HashSet<>())
- .add(groupPermission.getPropertyId());
- }
-
- for (Permission devicePermission : databaseDevicePermissions) {
- deviceItems
- .computeIfAbsent(devicePermission.getOwnerId(), key -> new HashSet<>())
- .add(devicePermission.getPropertyId());
- deviceItemsWithGroups
- .computeIfAbsent(devicePermission.getOwnerId(), key -> new HashSet<>())
- .add(devicePermission.getPropertyId());
- }
-
- for (Device device : Context.getDeviceManager().getAllDevices()) {
- long groupId = device.getGroupId();
- while (groupId > 0) {
- deviceItemsWithGroups
- .computeIfAbsent(device.getId(), key -> new HashSet<>())
- .addAll(groupItems.getOrDefault(groupId, new HashSet<>()));
- Group group = Context.getGroupsManager().getById(groupId);
- groupId = group != null ? group.getGroupId() : 0;
- }
- }
-
- } catch (SQLException | ClassNotFoundException error) {
- LOGGER.warn("Refresh permissions error", error);
- } finally {
- writeUnlock();
- }
- }
- }
-}
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<Geofence> {
-
- public GeofenceManager(DataManager dataManager) {
- super(dataManager, Geofence.class);
- }
-
- @Override
- public final void refreshExtendedPermissions() {
- super.refreshExtendedPermissions();
- recalculateDevicesGeofences();
- }
-
- public List<Long> getCurrentDeviceGeofences(Position position) {
- List<Long> 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<Long> 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/GroupsManager.java b/src/main/java/org/traccar/database/GroupsManager.java
deleted file mode 100644
index c35f35f93..000000000
--- a/src/main/java/org/traccar/database/GroupsManager.java
+++ /dev/null
@@ -1,83 +0,0 @@
-/*
- * Copyright 2017 - 2020 Anton Tananaev (anton@traccar.org)
- * Copyright 2017 Andrey Kunitsyn (andrey@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.sql.SQLException;
-import java.util.HashSet;
-import java.util.Set;
-
-import org.traccar.Context;
-import org.traccar.model.Group;
-
-public class GroupsManager extends BaseObjectManager<Group> implements ManagableObjects {
-
- public GroupsManager(DataManager dataManager) {
- super(dataManager, Group.class);
- }
-
- private void checkGroupCycles(Group group) {
- Set<Long> groups = new HashSet<>();
- while (group != null) {
- if (groups.contains(group.getId())) {
- throw new IllegalArgumentException("Cycle in group hierarchy");
- }
- groups.add(group.getId());
- group = getById(group.getGroupId());
- }
- }
-
- @Override
- public Set<Long> getAllItems() {
- Set<Long> result = super.getAllItems();
- if (result.isEmpty()) {
- refreshItems();
- result = super.getAllItems();
- }
- return result;
- }
-
- @Override
- protected void addNewItem(Group group) {
- checkGroupCycles(group);
- super.addNewItem(group);
- }
-
- @Override
- public void updateItem(Group group) throws SQLException {
- checkGroupCycles(group);
- super.updateItem(group);
- }
-
- @Override
- public Set<Long> getUserItems(long userId) {
- if (Context.getPermissionsManager() != null) {
- return Context.getPermissionsManager().getGroupPermissions(userId);
- } else {
- return new HashSet<>();
- }
- }
-
- @Override
- public Set<Long> getManagedItems(long userId) {
- Set<Long> result = getUserItems(userId);
- for (long managedUserId : Context.getUsersManager().getUserItems(userId)) {
- result.addAll(getUserItems(managedUserId));
- }
- return result;
- }
-
-}
diff --git a/src/main/java/org/traccar/database/IdentityManager.java b/src/main/java/org/traccar/database/IdentityManager.java
deleted file mode 100644
index af6a6ce71..000000000
--- a/src/main/java/org/traccar/database/IdentityManager.java
+++ /dev/null
@@ -1,50 +0,0 @@
-/*
- * Copyright 2015 - 2019 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 org.traccar.model.Device;
-import org.traccar.model.Position;
-
-public interface IdentityManager {
-
- long addUnknownDevice(String uniqueId);
-
- Device getById(long id);
-
- Device getByUniqueId(String uniqueId) throws Exception;
-
- String getDevicePassword(long id, String protocol, String defaultPassword);
-
- Position getLastPosition(long deviceId);
-
- boolean isLatestPosition(Position position);
-
- boolean lookupAttributeBoolean(
- long deviceId, String attributeName, boolean defaultValue, boolean lookupServer, boolean lookupConfig);
-
- 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/database/LdapProvider.java b/src/main/java/org/traccar/database/LdapProvider.java
index d659a11a1..d517294b8 100644
--- a/src/main/java/org/traccar/database/LdapProvider.java
+++ b/src/main/java/org/traccar/database/LdapProvider.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017 - 2020 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.
diff --git a/src/main/java/org/traccar/database/MailManager.java b/src/main/java/org/traccar/database/MailManager.java
deleted file mode 100644
index d94f55cda..000000000
--- a/src/main/java/org/traccar/database/MailManager.java
+++ /dev/null
@@ -1,151 +0,0 @@
-/*
- * Copyright 2016 - 2021 Anton Tananaev (anton@traccar.org)
- * Copyright 2017 - 2018 Andrey Kunitsyn (andrey@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 org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.traccar.Context;
-import org.traccar.Main;
-import org.traccar.model.User;
-import org.traccar.notification.PropertiesProvider;
-
-import javax.mail.BodyPart;
-import javax.mail.Message;
-import javax.mail.MessagingException;
-import javax.mail.Multipart;
-import javax.mail.Session;
-import javax.mail.Transport;
-import javax.mail.internet.InternetAddress;
-import javax.mail.internet.MimeBodyPart;
-import javax.mail.internet.MimeMessage;
-import javax.mail.internet.MimeMultipart;
-import java.util.Date;
-import java.util.Properties;
-
-public final class MailManager {
-
- private static final Logger LOGGER = LoggerFactory.getLogger(MailManager.class);
-
- private static Properties getProperties(PropertiesProvider provider) {
- Properties properties = new Properties();
- String host = provider.getString("mail.smtp.host");
- if (host != null) {
- properties.put("mail.transport.protocol", provider.getString("mail.transport.protocol", "smtp"));
- properties.put("mail.smtp.host", host);
- properties.put("mail.smtp.port", String.valueOf(provider.getInteger("mail.smtp.port", 25)));
-
- Boolean starttlsEnable = provider.getBoolean("mail.smtp.starttls.enable");
- if (starttlsEnable != null) {
- properties.put("mail.smtp.starttls.enable", String.valueOf(starttlsEnable));
- }
- Boolean starttlsRequired = provider.getBoolean("mail.smtp.starttls.required");
- if (starttlsRequired != null) {
- properties.put("mail.smtp.starttls.required", String.valueOf(starttlsRequired));
- }
-
- Boolean sslEnable = provider.getBoolean("mail.smtp.ssl.enable");
- if (sslEnable != null) {
- properties.put("mail.smtp.ssl.enable", String.valueOf(sslEnable));
- }
- String sslTrust = provider.getString("mail.smtp.ssl.trust");
- if (sslTrust != null) {
- properties.put("mail.smtp.ssl.trust", sslTrust);
- }
-
- String sslProtocols = provider.getString("mail.smtp.ssl.protocols");
- if (sslProtocols != null) {
- properties.put("mail.smtp.ssl.protocols", sslProtocols);
- }
-
- String username = provider.getString("mail.smtp.username");
- if (username != null) {
- properties.put("mail.smtp.username", username);
- }
- String password = provider.getString("mail.smtp.password");
- if (password != null) {
- properties.put("mail.smtp.password", password);
- }
- String from = provider.getString("mail.smtp.from");
- if (from != null) {
- properties.put("mail.smtp.from", from);
- }
- }
- return properties;
- }
-
- public boolean getEmailEnabled() {
- return Context.getConfig().hasKey("mail.smtp.host");
- }
-
- public void sendMessage(
- long userId, String subject, String body) throws MessagingException {
- sendMessage(userId, subject, body, null);
- }
-
- public void sendMessage(
- long userId, String subject, String body, MimeBodyPart attachment) throws MessagingException {
- User user = Context.getPermissionsManager().getUser(userId);
-
- Properties properties = null;
- if (!Context.getConfig().getBoolean("mail.smtp.ignoreUserConfig")) {
- properties = getProperties(new PropertiesProvider(user));
- }
- if (properties == null || !properties.containsKey("mail.smtp.host")) {
- properties = getProperties(new PropertiesProvider(Context.getConfig()));
- }
- if (!properties.containsKey("mail.smtp.host")) {
- LOGGER.warn("No SMTP configuration found");
- return;
- }
-
- Session session = Session.getInstance(properties);
-
- MimeMessage message = new MimeMessage(session);
-
- String from = properties.getProperty("mail.smtp.from");
- if (from != null) {
- message.setFrom(new InternetAddress(from));
- }
-
- message.addRecipient(Message.RecipientType.TO, new InternetAddress(user.getEmail()));
- message.setSubject(subject);
- message.setSentDate(new Date());
-
- if (attachment != null) {
- Multipart multipart = new MimeMultipart();
-
- BodyPart messageBodyPart = new MimeBodyPart();
- messageBodyPart.setContent(body, "text/html; charset=utf-8");
- multipart.addBodyPart(messageBodyPart);
- multipart.addBodyPart(attachment);
-
- message.setContent(multipart);
- } else {
- message.setContent(body, "text/html; charset=utf-8");
- }
-
- try (Transport transport = session.getTransport()) {
- Main.getInjector().getInstance(StatisticsManager.class).registerMail();
- transport.connect(
- properties.getProperty("mail.smtp.host"),
- properties.getProperty("mail.smtp.username"),
- properties.getProperty("mail.smtp.password"));
- transport.sendMessage(message, message.getAllRecipients());
- }
- }
-
-}
diff --git a/src/main/java/org/traccar/database/MaintenancesManager.java b/src/main/java/org/traccar/database/MaintenancesManager.java
deleted file mode 100644
index 4e266cb78..000000000
--- a/src/main/java/org/traccar/database/MaintenancesManager.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright 2018 Anton Tananaev (anton@traccar.org)
- * Copyright 2018 Andrey Kunitsyn (andrey@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 org.traccar.model.Maintenance;
-
-public class MaintenancesManager extends ExtendedObjectManager<Maintenance> {
-
- public MaintenancesManager(DataManager dataManager) {
- super(dataManager, Maintenance.class);
- }
-
-}
diff --git a/src/main/java/org/traccar/database/ManagableObjects.java b/src/main/java/org/traccar/database/ManagableObjects.java
deleted file mode 100644
index ec9549493..000000000
--- a/src/main/java/org/traccar/database/ManagableObjects.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright 2017 Anton Tananaev (anton@traccar.org)
- * Copyright 2017 Andrey Kunitsyn (andrey@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.Set;
-
-public interface ManagableObjects {
-
- Set<Long> getUserItems(long userId);
-
- Set<Long> getManagedItems(long userId);
-
-}
diff --git a/src/main/java/org/traccar/database/MediaManager.java b/src/main/java/org/traccar/database/MediaManager.java
index edade5766..c1ef810ee 100644
--- a/src/main/java/org/traccar/database/MediaManager.java
+++ b/src/main/java/org/traccar/database/MediaManager.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2017 - 2018 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.
@@ -18,10 +18,15 @@ package org.traccar.database;
import io.netty.buffer.ByteBuf;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
+import org.traccar.config.Config;
+import org.traccar.config.Keys;
+import javax.inject.Inject;
+import javax.inject.Singleton;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
+import java.io.OutputStream;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import java.nio.file.Files;
@@ -30,14 +35,16 @@ import java.nio.file.Paths;
import java.text.SimpleDateFormat;
import java.util.Date;
+@Singleton
public class MediaManager {
private static final Logger LOGGER = LoggerFactory.getLogger(MediaManager.class);
- private String path;
+ private final String path;
- public MediaManager(String path) {
- this.path = path;
+ @Inject
+ public MediaManager(Config config) {
+ this.path = config.getString(Keys.MEDIA_PATH);
}
private File createFile(String uniqueId, String name) throws IOException {
@@ -49,6 +56,10 @@ public class MediaManager {
return filePath.toFile();
}
+ public OutputStream createFileStream(String uniqueId, String name, String extension) throws IOException {
+ return new FileOutputStream(createFile(uniqueId, name + "." + extension));
+ }
+
public String writeFile(String uniqueId, ByteBuf buf, String extension) {
if (path != null) {
int size = buf.readableBytes();
diff --git a/src/main/java/org/traccar/database/NotificationManager.java b/src/main/java/org/traccar/database/NotificationManager.java
index 9f9a83cd2..cb971b082 100644
--- a/src/main/java/org/traccar/database/NotificationManager.java
+++ b/src/main/java/org/traccar/database/NotificationManager.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016 - 2021 Anton Tananaev (anton@traccar.org)
+ * Copyright 2016 - 2022 Anton Tananaev (anton@traccar.org)
* Copyright 2016 - 2018 Andrey Kunitsyn (andrey@traccar.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
@@ -16,128 +16,141 @@
*/
package org.traccar.database;
-import java.lang.reflect.Field;
-import java.lang.reflect.Modifier;
-import java.sql.SQLException;
-import java.util.Arrays;
-import java.util.Date;
-import java.util.HashSet;
-import java.util.List;
-import java.util.Map;
-import java.util.Map.Entry;
-import java.util.Set;
-
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.forward.EventData;
+import org.traccar.forward.EventForwarder;
+import org.traccar.geocoder.Geocoder;
import org.traccar.model.Calendar;
+import org.traccar.model.Device;
import org.traccar.model.Event;
+import org.traccar.model.Geofence;
+import org.traccar.model.Maintenance;
import org.traccar.model.Notification;
import org.traccar.model.Position;
-import org.traccar.model.Typed;
+import org.traccar.notification.MessageException;
+import org.traccar.notification.NotificatorManager;
+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.Request;
+
+import javax.annotation.Nullable;
+import javax.inject.Inject;
+import javax.inject.Singleton;
+import java.util.Arrays;
+import java.util.Map;
+import java.util.Map.Entry;
+import java.util.stream.Collectors;
-public class NotificationManager extends ExtendedObjectManager<Notification> {
+@Singleton
+public class NotificationManager {
private static final Logger LOGGER = LoggerFactory.getLogger(NotificationManager.class);
- private final boolean geocodeOnRequest;
+ private final Storage storage;
+ private final CacheManager cacheManager;
+ private final EventForwarder eventForwarder;
+ private final NotificatorManager notificatorManager;
+ private final Geocoder geocoder;
- public NotificationManager(DataManager dataManager) {
- super(dataManager, Notification.class);
- geocodeOnRequest = Context.getConfig().getBoolean(Keys.GEOCODER_ON_REQUEST);
- }
+ private final boolean geocodeOnRequest;
- private Set<Long> getEffectiveNotifications(long userId, long deviceId, Date time) {
- Set<Long> result = new HashSet<>();
- Set<Long> deviceNotifications = getAllDeviceItems(deviceId);
- for (long itemId : getUserItems(userId)) {
- if (getById(itemId).getAlways() || deviceNotifications.contains(itemId)) {
- long calendarId = getById(itemId).getCalendarId();
- Calendar calendar = calendarId != 0 ? Context.getCalendarManager().getById(calendarId) : null;
- if (calendar == null || calendar.checkMoment(time)) {
- result.add(itemId);
- }
- }
- }
- return result;
+ @Inject
+ public NotificationManager(
+ Config config, Storage storage, CacheManager cacheManager, @Nullable EventForwarder eventForwarder,
+ NotificatorManager notificatorManager, @Nullable Geocoder geocoder) {
+ this.storage = storage;
+ this.cacheManager = cacheManager;
+ this.eventForwarder = eventForwarder;
+ this.notificatorManager = notificatorManager;
+ this.geocoder = geocoder;
+ geocodeOnRequest = config.getBoolean(Keys.GEOCODER_ON_REQUEST);
}
- public void updateEvent(Event event, Position position) {
+ private void updateEvent(Event event, Position position) {
try {
- getDataManager().addObject(event);
- } catch (SQLException error) {
+ event.setId(storage.addObject(event, new Request(new Columns.Exclude("id"))));
+ } catch (StorageException error) {
LOGGER.warn("Event save error", error);
}
- long deviceId = event.getDeviceId();
- Set<Long> users = Context.getPermissionsManager().getDeviceUsers(deviceId);
- Set<Long> usersToForward = null;
- if (Context.getEventForwarder() != null) {
- usersToForward = new HashSet<>();
- }
- for (long userId : users) {
- if ((event.getGeofenceId() == 0
- || Context.getGeofenceManager().checkItemPermission(userId, event.getGeofenceId()))
- && (event.getMaintenanceId() == 0
- || Context.getMaintenancesManager().checkItemPermission(userId, event.getMaintenanceId()))) {
- if (usersToForward != null) {
- usersToForward.add(userId);
- }
- final Set<String> notificators = new HashSet<>();
- for (long notificationId : getEffectiveNotifications(userId, deviceId, event.getEventTime())) {
- Notification notification = getById(notificationId);
- if (getById(notificationId).getType().equals(event.getType())) {
- boolean filter = false;
- if (event.getType().equals(Event.TYPE_ALARM)) {
- String alarmsAttribute = notification.getString("alarms");
- if (alarmsAttribute == null) {
- filter = true;
- } else {
- List<String> alarms = Arrays.asList(alarmsAttribute.split(","));
- filter = !alarms.contains(event.getString(Position.KEY_ALARM));
- }
- }
- if (!filter) {
- notificators.addAll(notification.getNotificatorsTypes());
+ var notifications = cacheManager.getDeviceObjects(event.getDeviceId(), Notification.class).stream()
+ .filter(notification -> notification.getType().equals(event.getType()))
+ .filter(notification -> {
+ if (event.getType().equals(Event.TYPE_ALARM)) {
+ String alarmsAttribute = notification.getString("alarms");
+ if (alarmsAttribute != null) {
+ return Arrays.asList(alarmsAttribute.split(","))
+ .contains(event.getString(Position.KEY_ALARM));
}
+ return false;
}
- }
-
- if (position != null && position.getAddress() == null
- && geocodeOnRequest && Context.getGeocoder() != null) {
- position.setAddress(Context.getGeocoder()
- .getAddress(position.getLatitude(), position.getLongitude(), null));
- }
+ return true;
+ })
+ .filter(notification -> {
+ long calendarId = notification.getCalendarId();
+ Calendar calendar = calendarId != 0 ? cacheManager.getObject(Calendar.class, calendarId) : null;
+ return calendar == null || calendar.checkMoment(event.getEventTime());
+ })
+ .collect(Collectors.toUnmodifiableList());
- for (String notificator : notificators) {
- Context.getNotificatorManager().getNotificator(notificator).sendAsync(userId, event, position);
- }
+ if (!notifications.isEmpty()) {
+ if (position != null && position.getAddress() == null && geocodeOnRequest && geocoder != null) {
+ position.setAddress(geocoder.getAddress(position.getLatitude(), position.getLongitude(), null));
}
+
+ notifications.forEach(notification -> {
+ cacheManager.getNotificationUsers(notification.getId(), event.getDeviceId()).forEach(user -> {
+ for (String notificator : notification.getNotificatorsTypes()) {
+ try {
+ notificatorManager.getNotificator(notificator).send(user, event, position);
+ } catch (MessageException | InterruptedException exception) {
+ LOGGER.warn("Notification failed", exception);
+ }
+ }
+ });
+ });
}
- if (Context.getEventForwarder() != null) {
- Context.getEventForwarder().forwardEvent(event, position, usersToForward);
- }
+
+ forwardEvent(event, position);
}
- public void updateEvents(Map<Event, Position> events) {
- for (Entry<Event, Position> event : events.entrySet()) {
- updateEvent(event.getKey(), event.getValue());
+ private void forwardEvent(Event event, Position position) {
+ if (eventForwarder != null) {
+ EventData eventData = new EventData();
+ eventData.setEvent(event);
+ eventData.setPosition(position);
+ eventData.setDevice(cacheManager.getObject(Device.class, event.getDeviceId()));
+ if (event.getGeofenceId() != 0) {
+ eventData.setGeofence(cacheManager.getObject(Geofence.class, event.getGeofenceId()));
+ }
+ if (event.getMaintenanceId() != 0) {
+ eventData.setMaintenance(cacheManager.getObject(Maintenance.class, event.getMaintenanceId()));
+ }
+ eventForwarder.forward(eventData, (success, throwable) -> {
+ if (!success) {
+ LOGGER.warn("Event forwarding failed", throwable);
+ }
+ });
}
}
- public Set<Typed> getAllNotificationTypes() {
- Set<Typed> types = new HashSet<>();
- Field[] fields = Event.class.getDeclaredFields();
- for (Field field : fields) {
- if (Modifier.isStatic(field.getModifiers()) && field.getName().startsWith("TYPE_")) {
- try {
- types.add(new Typed(field.get(null).toString()));
- } catch (IllegalArgumentException | IllegalAccessException error) {
- LOGGER.warn("Get event types error", error);
- }
+ public void updateEvents(Map<Event, Position> events) {
+ for (Entry<Event, Position> entry : events.entrySet()) {
+ Event event = entry.getKey();
+ Position position = entry.getValue();
+ try {
+ cacheManager.addDevice(event.getDeviceId());
+ updateEvent(event, position);
+ } catch (StorageException e) {
+ throw new RuntimeException(e);
+ } finally {
+ cacheManager.removeDevice(event.getDeviceId());
}
}
- return types;
}
}
diff --git a/src/main/java/org/traccar/database/OrderManager.java b/src/main/java/org/traccar/database/OrderManager.java
deleted file mode 100644
index c3253e52f..000000000
--- a/src/main/java/org/traccar/database/OrderManager.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright 2021 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 org.traccar.model.Order;
-
-public class OrderManager extends ExtendedObjectManager<Order> {
-
- public OrderManager(DataManager dataManager) {
- super(dataManager, Order.class);
- }
-
-}
diff --git a/src/main/java/org/traccar/database/PermissionsManager.java b/src/main/java/org/traccar/database/PermissionsManager.java
deleted file mode 100644
index 32464cf90..000000000
--- a/src/main/java/org/traccar/database/PermissionsManager.java
+++ /dev/null
@@ -1,516 +0,0 @@
-/*
- * Copyright 2015 - 2021 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 org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.traccar.Context;
-import org.traccar.model.Attribute;
-import org.traccar.model.BaseModel;
-import org.traccar.model.Calendar;
-import org.traccar.model.Command;
-import org.traccar.model.Device;
-import org.traccar.model.Driver;
-import org.traccar.model.Geofence;
-import org.traccar.model.Group;
-import org.traccar.model.Maintenance;
-import org.traccar.model.ManagedUser;
-import org.traccar.model.Notification;
-import org.traccar.model.Order;
-import org.traccar.model.Permission;
-import org.traccar.model.Server;
-import org.traccar.model.User;
-
-import java.sql.SQLException;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.locks.ReadWriteLock;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
-
-public class PermissionsManager {
-
- private static final Logger LOGGER = LoggerFactory.getLogger(PermissionsManager.class);
-
- private final DataManager dataManager;
- private final UsersManager usersManager;
-
- private volatile Server server;
-
- private final ReadWriteLock lock = new ReentrantReadWriteLock();
-
- private final Map<Long, Set<Long>> groupPermissions = new HashMap<>();
- private final Map<Long, Set<Long>> devicePermissions = new HashMap<>();
- private final Map<Long, Set<Long>> deviceUsers = new HashMap<>();
- private final Map<Long, Set<Long>> groupDevices = new HashMap<>();
-
- public PermissionsManager(DataManager dataManager, UsersManager usersManager) {
- this.dataManager = dataManager;
- this.usersManager = usersManager;
- refreshServer();
- refreshDeviceAndGroupPermissions();
- }
-
- protected final void readLock() {
- lock.readLock().lock();
- }
-
- protected final void readUnlock() {
- lock.readLock().unlock();
- }
-
- protected final void writeLock() {
- lock.writeLock().lock();
- }
-
- protected final void writeUnlock() {
- lock.writeLock().unlock();
- }
-
- public User getUser(long userId) {
- readLock();
- try {
- return usersManager.getById(userId);
- } finally {
- readUnlock();
- }
- }
-
- public Set<Long> getGroupPermissions(long userId) {
- readLock();
- try {
- if (!groupPermissions.containsKey(userId)) {
- groupPermissions.put(userId, new HashSet<>());
- }
- return groupPermissions.get(userId);
- } finally {
- readUnlock();
- }
- }
-
- public Set<Long> getDevicePermissions(long userId) {
- readLock();
- try {
- if (!devicePermissions.containsKey(userId)) {
- devicePermissions.put(userId, new HashSet<>());
- }
- return devicePermissions.get(userId);
- } finally {
- readUnlock();
- }
- }
-
- private Set<Long> getAllDeviceUsers(long deviceId) {
- readLock();
- try {
- if (!deviceUsers.containsKey(deviceId)) {
- deviceUsers.put(deviceId, new HashSet<>());
- }
- return deviceUsers.get(deviceId);
- } finally {
- readUnlock();
- }
- }
-
- public Set<Long> getDeviceUsers(long deviceId) {
- Device device = Context.getIdentityManager().getById(deviceId);
- if (device != null && !device.getDisabled()) {
- return getAllDeviceUsers(deviceId);
- } else {
- Set<Long> result = new HashSet<>();
- for (long userId : getAllDeviceUsers(deviceId)) {
- if (getUserAdmin(userId)) {
- result.add(userId);
- }
- }
- return result;
- }
- }
-
- public Set<Long> getGroupDevices(long groupId) {
- readLock();
- try {
- if (!groupDevices.containsKey(groupId)) {
- groupDevices.put(groupId, new HashSet<>());
- }
- return groupDevices.get(groupId);
- } finally {
- readUnlock();
- }
- }
-
- public void refreshServer() {
- try {
- server = dataManager.getServer();
- } catch (SQLException error) {
- LOGGER.warn("Refresh server config error", error);
- }
- }
-
- public final void refreshDeviceAndGroupPermissions() {
- writeLock();
- try {
- groupPermissions.clear();
- devicePermissions.clear();
- try {
- GroupTree groupTree = new GroupTree(Context.getGroupsManager().getItems(
- Context.getGroupsManager().getAllItems()),
- Context.getDeviceManager().getAllDevices());
- for (Permission groupPermission : dataManager.getPermissions(User.class, Group.class)) {
- Set<Long> userGroupPermissions = getGroupPermissions(groupPermission.getOwnerId());
- Set<Long> userDevicePermissions = getDevicePermissions(groupPermission.getOwnerId());
- userGroupPermissions.add(groupPermission.getPropertyId());
- for (Group group : groupTree.getGroups(groupPermission.getPropertyId())) {
- userGroupPermissions.add(group.getId());
- }
- for (Device device : groupTree.getDevices(groupPermission.getPropertyId())) {
- userDevicePermissions.add(device.getId());
- }
- }
-
- for (Permission devicePermission : dataManager.getPermissions(User.class, Device.class)) {
- getDevicePermissions(devicePermission.getOwnerId()).add(devicePermission.getPropertyId());
- }
-
- groupDevices.clear();
- for (long groupId : Context.getGroupsManager().getAllItems()) {
- for (Device device : groupTree.getDevices(groupId)) {
- getGroupDevices(groupId).add(device.getId());
- }
- }
-
- } catch (SQLException | ClassNotFoundException error) {
- LOGGER.warn("Refresh device permissions error", error);
- }
-
- deviceUsers.clear();
- for (Map.Entry<Long, Set<Long>> entry : devicePermissions.entrySet()) {
- for (long deviceId : entry.getValue()) {
- getAllDeviceUsers(deviceId).add(entry.getKey());
- }
- }
- } finally {
- writeUnlock();
- }
- }
-
- public boolean getUserAdmin(long userId) {
- User user = getUser(userId);
- return user != null && user.getAdministrator();
- }
-
- public void checkAdmin(long userId) throws SecurityException {
- if (!getUserAdmin(userId)) {
- throw new SecurityException("Admin access required");
- }
- }
-
- public boolean getUserManager(long userId) {
- User user = getUser(userId);
- return user != null && user.getUserLimit() != 0;
- }
-
- public void checkManager(long userId) throws SecurityException {
- if (!getUserManager(userId)) {
- throw new SecurityException("Manager access required");
- }
- }
-
- public void checkManager(long userId, long managedUserId) throws SecurityException {
- checkManager(userId);
- if (!usersManager.getUserItems(userId).contains(managedUserId)) {
- throw new SecurityException("User access denied");
- }
- }
-
- public void checkUserLimit(long userId) throws SecurityException {
- int userLimit = getUser(userId).getUserLimit();
- if (userLimit != -1 && usersManager.getUserItems(userId).size() >= userLimit) {
- throw new SecurityException("Manager user limit reached");
- }
- }
-
- public void checkDeviceLimit(long userId) throws SecurityException {
- int deviceLimit = getUser(userId).getDeviceLimit();
- if (deviceLimit != -1) {
- int deviceCount;
- if (getUserManager(userId)) {
- deviceCount = Context.getDeviceManager().getAllManagedItems(userId).size();
- } else {
- deviceCount = Context.getDeviceManager().getAllUserItems(userId).size();
- }
- if (deviceCount >= deviceLimit) {
- throw new SecurityException("User device limit reached");
- }
- }
- }
-
- public boolean getUserReadonly(long userId) {
- User user = getUser(userId);
- return user != null && user.getReadonly();
- }
-
- public boolean getUserDeviceReadonly(long userId) {
- User user = getUser(userId);
- return user != null && user.getDeviceReadonly();
- }
-
- public boolean getUserLimitCommands(long userId) {
- User user = getUser(userId);
- return user != null && user.getLimitCommands();
- }
-
- public void checkReadonly(long userId) throws SecurityException {
- if (!getUserAdmin(userId) && (server.getReadonly() || getUserReadonly(userId))) {
- throw new SecurityException("Account is readonly");
- }
- }
-
- public void checkDeviceReadonly(long userId) throws SecurityException {
- if (!getUserAdmin(userId) && (server.getDeviceReadonly() || getUserDeviceReadonly(userId))) {
- throw new SecurityException("Account is device readonly");
- }
- }
-
- public void checkLimitCommands(long userId) throws SecurityException {
- if (!getUserAdmin(userId) && (server.getLimitCommands() || getUserLimitCommands(userId))) {
- throw new SecurityException("Account has limit sending commands");
- }
- }
-
- public void checkUserDeviceCommand(long userId, long deviceId, long commandId) throws SecurityException {
- if (!getUserAdmin(userId) && Context.getCommandsManager().checkDeviceCommand(deviceId, commandId)) {
- throw new SecurityException("Command can not be sent to this device");
- }
- }
-
- public void checkUserEnabled(long userId) throws SecurityException {
- User user = getUser(userId);
- if (user == null) {
- throw new SecurityException("Unknown account");
- }
- if (user.getDisabled()) {
- throw new SecurityException("Account is disabled");
- }
- if (user.getExpirationTime() != null && System.currentTimeMillis() > user.getExpirationTime().getTime()) {
- throw new SecurityException("Account has expired");
- }
- }
-
- public void checkUserUpdate(long userId, User before, User after) throws SecurityException {
- if (before.getAdministrator() != after.getAdministrator()
- || before.getDeviceLimit() != after.getDeviceLimit()
- || before.getUserLimit() != after.getUserLimit()) {
- checkAdmin(userId);
- }
- User user = getUser(userId);
- if (user != null && user.getExpirationTime() != null
- && (after.getExpirationTime() == null
- || user.getExpirationTime().compareTo(after.getExpirationTime()) < 0)) {
- checkAdmin(userId);
- }
- if (before.getReadonly() != after.getReadonly()
- || before.getDeviceReadonly() != after.getDeviceReadonly()
- || before.getDisabled() != after.getDisabled()
- || before.getLimitCommands() != after.getLimitCommands()) {
- if (userId == after.getId()) {
- checkAdmin(userId);
- }
- if (!getUserAdmin(userId)) {
- checkManager(userId);
- }
- }
- }
-
- public void checkUser(long userId, long managedUserId) throws SecurityException {
- if (userId != managedUserId && !getUserAdmin(userId)) {
- checkManager(userId, managedUserId);
- }
- }
-
- public void checkGroup(long userId, long groupId) throws SecurityException {
- if (!getGroupPermissions(userId).contains(groupId) && !getUserAdmin(userId)) {
- checkManager(userId);
- for (long managedUserId : usersManager.getUserItems(userId)) {
- if (getGroupPermissions(managedUserId).contains(groupId)) {
- return;
- }
- }
- throw new SecurityException("Group access denied");
- }
- }
-
- public void checkDevice(long userId, long deviceId) throws SecurityException {
- if (!Context.getDeviceManager().getUserItems(userId).contains(deviceId) && !getUserAdmin(userId)) {
- checkManager(userId);
- for (long managedUserId : usersManager.getUserItems(userId)) {
- if (Context.getDeviceManager().getUserItems(managedUserId).contains(deviceId)) {
- return;
- }
- }
- throw new SecurityException("Device access denied");
- }
- }
-
- public void checkRegistration(long userId) {
- if (!server.getRegistration() && !getUserAdmin(userId)) {
- throw new SecurityException("Registration disabled");
- }
- }
-
- public void checkPermission(Class<?> object, long userId, long objectId)
- throws SecurityException {
- SimpleObjectManager<? extends BaseModel> manager = null;
-
- if (object.equals(Device.class)) {
- checkDevice(userId, objectId);
- } else if (object.equals(Group.class)) {
- checkGroup(userId, objectId);
- } else if (object.equals(User.class) || object.equals(ManagedUser.class)) {
- checkUser(userId, objectId);
- } else if (object.equals(Geofence.class)) {
- manager = Context.getGeofenceManager();
- } else if (object.equals(Attribute.class)) {
- manager = Context.getAttributesManager();
- } else if (object.equals(Driver.class)) {
- manager = Context.getDriversManager();
- } else if (object.equals(Calendar.class)) {
- manager = Context.getCalendarManager();
- } else if (object.equals(Command.class)) {
- manager = Context.getCommandsManager();
- } else if (object.equals(Maintenance.class)) {
- manager = Context.getMaintenancesManager();
- } else if (object.equals(Notification.class)) {
- manager = Context.getNotificationManager();
- } else if (object.equals(Order.class)) {
- manager = Context.getOrderManager();
- } else {
- throw new IllegalArgumentException("Unknown object type");
- }
-
- if (manager != null && !manager.checkItemPermission(userId, objectId) && !getUserAdmin(userId)) {
- checkManager(userId);
- for (long managedUserId : usersManager.getManagedItems(userId)) {
- if (manager.checkItemPermission(managedUserId, objectId)) {
- return;
- }
- }
- throw new SecurityException("Type " + object + " access denied");
- }
- }
-
- public void refreshAllUsersPermissions() {
- if (Context.getGeofenceManager() != null) {
- Context.getGeofenceManager().refreshUserItems();
- }
- Context.getCalendarManager().refreshUserItems();
- Context.getDriversManager().refreshUserItems();
- Context.getAttributesManager().refreshUserItems();
- Context.getCommandsManager().refreshUserItems();
- Context.getMaintenancesManager().refreshUserItems();
- if (Context.getNotificationManager() != null) {
- Context.getNotificationManager().refreshUserItems();
- }
- }
-
- public void refreshAllExtendedPermissions() {
- if (Context.getGeofenceManager() != null) {
- Context.getGeofenceManager().refreshExtendedPermissions();
- }
- Context.getDriversManager().refreshExtendedPermissions();
- Context.getAttributesManager().refreshExtendedPermissions();
- Context.getCommandsManager().refreshExtendedPermissions();
- Context.getMaintenancesManager().refreshExtendedPermissions();
- }
-
- public void refreshPermissions(Permission permission) {
- if (permission.getOwnerClass().equals(User.class)) {
- if (permission.getPropertyClass().equals(Device.class)
- || permission.getPropertyClass().equals(Group.class)) {
- refreshDeviceAndGroupPermissions();
- 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(Driver.class)) {
- Context.getDriversManager().refreshUserItems();
- } else if (permission.getPropertyClass().equals(Attribute.class)) {
- Context.getAttributesManager().refreshUserItems();
- } else if (permission.getPropertyClass().equals(Calendar.class)) {
- Context.getCalendarManager().refreshUserItems();
- } else if (permission.getPropertyClass().equals(Command.class)) {
- Context.getCommandsManager().refreshUserItems();
- } else if (permission.getPropertyClass().equals(Maintenance.class)) {
- Context.getMaintenancesManager().refreshUserItems();
- } else if (permission.getPropertyClass().equals(Order.class)) {
- Context.getOrderManager().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(Driver.class)) {
- Context.getDriversManager().refreshExtendedPermissions();
- } else if (permission.getPropertyClass().equals(Attribute.class)) {
- Context.getAttributesManager().refreshExtendedPermissions();
- } else if (permission.getPropertyClass().equals(Command.class)) {
- Context.getCommandsManager().refreshExtendedPermissions();
- } else if (permission.getPropertyClass().equals(Maintenance.class)) {
- Context.getMaintenancesManager().refreshExtendedPermissions();
- } else if (permission.getPropertyClass().equals(Order.class)) {
- Context.getOrderManager().refreshExtendedPermissions();
- } else if (permission.getPropertyClass().equals(Notification.class)
- && Context.getNotificationManager() != null) {
- Context.getNotificationManager().refreshExtendedPermissions();
- }
- }
- }
-
- public Server getServer() {
- return server;
- }
-
- public void updateServer(Server server) throws SQLException {
- dataManager.updateObject(server);
- this.server = server;
- }
-
- public User login(String email, String password) throws SQLException {
- User user = dataManager.login(email, password);
- if (user != null) {
- checkUserEnabled(user.getId());
- return getUser(user.getId());
- }
- 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/database/QueryBuilder.java b/src/main/java/org/traccar/database/QueryBuilder.java
deleted file mode 100644
index 396cbf562..000000000
--- a/src/main/java/org/traccar/database/QueryBuilder.java
+++ /dev/null
@@ -1,485 +0,0 @@
-/*
- * Copyright 2015 - 2020 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 com.fasterxml.jackson.core.JsonProcessingException;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.traccar.Context;
-import org.traccar.model.Permission;
-
-import javax.sql.DataSource;
-import java.io.IOException;
-import java.lang.reflect.InvocationTargetException;
-import java.lang.reflect.Method;
-import java.sql.Connection;
-import java.sql.PreparedStatement;
-import java.sql.ResultSet;
-import java.sql.ResultSetMetaData;
-import java.sql.SQLException;
-import java.sql.Statement;
-import java.sql.Timestamp;
-import java.sql.Types;
-import java.util.Collection;
-import java.util.Date;
-import java.util.HashMap;
-import java.util.LinkedHashMap;
-import java.util.LinkedList;
-import java.util.List;
-import java.util.Map;
-
-public final class QueryBuilder {
-
- private static final Logger LOGGER = LoggerFactory.getLogger(QueryBuilder.class);
-
- private final Map<String, List<Integer>> indexMap = new HashMap<>();
- private Connection connection;
- private PreparedStatement statement;
- private final String query;
- private final boolean returnGeneratedKeys;
-
- private QueryBuilder(DataSource dataSource, String query, boolean returnGeneratedKeys) throws SQLException {
- this.query = query;
- this.returnGeneratedKeys = returnGeneratedKeys;
- if (query != null) {
- connection = dataSource.getConnection();
- String parsedQuery = parse(query.trim(), indexMap);
- try {
- if (returnGeneratedKeys) {
- statement = connection.prepareStatement(parsedQuery, Statement.RETURN_GENERATED_KEYS);
- } else {
- statement = connection.prepareStatement(parsedQuery);
- }
- } catch (SQLException error) {
- connection.close();
- throw error;
- }
- }
- }
-
- private static String parse(String query, Map<String, List<Integer>> paramMap) {
-
- int length = query.length();
- StringBuilder parsedQuery = new StringBuilder(length);
- boolean inSingleQuote = false;
- boolean inDoubleQuote = false;
- int index = 1;
-
- for (int i = 0; i < length; i++) {
-
- char c = query.charAt(i);
-
- // String end
- if (inSingleQuote) {
- if (c == '\'') {
- inSingleQuote = false;
- }
- } else if (inDoubleQuote) {
- if (c == '"') {
- inDoubleQuote = false;
- }
- } else {
-
- // String begin
- if (c == '\'') {
- inSingleQuote = true;
- } else if (c == '"') {
- inDoubleQuote = true;
- } else if (c == ':' && i + 1 < length
- && Character.isJavaIdentifierStart(query.charAt(i + 1))) {
-
- // Identifier name
- int j = i + 2;
- while (j < length && Character.isJavaIdentifierPart(query.charAt(j))) {
- j++;
- }
-
- String name = query.substring(i + 1, j);
- c = '?';
- i += name.length();
- name = name.toLowerCase();
-
- // Add to list
- List<Integer> indexList = paramMap.computeIfAbsent(name, k -> new LinkedList<>());
- indexList.add(index);
-
- index++;
- }
- }
-
- parsedQuery.append(c);
- }
-
- return parsedQuery.toString();
- }
-
- public static QueryBuilder create(DataSource dataSource, String query) throws SQLException {
- return new QueryBuilder(dataSource, query, false);
- }
-
- public static QueryBuilder create(
- DataSource dataSource, String query, boolean returnGeneratedKeys) throws SQLException {
- return new QueryBuilder(dataSource, query, returnGeneratedKeys);
- }
-
- private List<Integer> indexes(String name) {
- name = name.toLowerCase();
- List<Integer> result = indexMap.get(name);
- if (result == null) {
- result = new LinkedList<>();
- }
- return result;
- }
-
- public QueryBuilder setBoolean(String name, boolean value) throws SQLException {
- for (int i : indexes(name)) {
- try {
- statement.setBoolean(i, value);
- } catch (SQLException error) {
- statement.close();
- connection.close();
- throw error;
- }
- }
- return this;
- }
-
- public QueryBuilder setInteger(String name, int value) throws SQLException {
- for (int i : indexes(name)) {
- try {
- statement.setInt(i, value);
- } catch (SQLException error) {
- statement.close();
- connection.close();
- throw error;
- }
- }
- return this;
- }
-
- public QueryBuilder setLong(String name, long value) throws SQLException {
- return setLong(name, value, false);
- }
-
- public QueryBuilder setLong(String name, long value, boolean nullIfZero) throws SQLException {
- for (int i : indexes(name)) {
- try {
- if (value == 0 && nullIfZero) {
- statement.setNull(i, Types.INTEGER);
- } else {
- statement.setLong(i, value);
- }
- } catch (SQLException error) {
- statement.close();
- connection.close();
- throw error;
- }
- }
- return this;
- }
-
- public QueryBuilder setDouble(String name, double value) throws SQLException {
- for (int i : indexes(name)) {
- try {
- statement.setDouble(i, value);
- } catch (SQLException error) {
- statement.close();
- connection.close();
- throw error;
- }
- }
- return this;
- }
-
- public QueryBuilder setString(String name, String value) throws SQLException {
- for (int i : indexes(name)) {
- try {
- if (value == null) {
- statement.setNull(i, Types.VARCHAR);
- } else {
- statement.setString(i, value);
- }
- } catch (SQLException error) {
- statement.close();
- connection.close();
- throw error;
- }
- }
- return this;
- }
-
- public QueryBuilder setDate(String name, Date value) throws SQLException {
- for (int i : indexes(name)) {
- try {
- if (value == null) {
- statement.setNull(i, Types.TIMESTAMP);
- } else {
- statement.setTimestamp(i, new Timestamp(value.getTime()));
- }
- } catch (SQLException error) {
- statement.close();
- connection.close();
- throw error;
- }
- }
- return this;
- }
-
- public QueryBuilder setBlob(String name, byte[] value) throws SQLException {
- for (int i : indexes(name)) {
- try {
- if (value == null) {
- statement.setNull(i, Types.BLOB);
- } else {
- statement.setBytes(i, value);
- }
- } catch (SQLException error) {
- statement.close();
- connection.close();
- throw error;
- }
- }
- 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.isAnnotationPresent(QueryIgnore.class)) {
- 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, Context.getObjectMapper().writeValueAsString(method.invoke(object)));
- }
- } catch (IllegalAccessException | InvocationTargetException | JsonProcessingException error) {
- LOGGER.warn("Get property error", error);
- }
- }
- }
-
- return this;
- }
-
- private interface ResultSetProcessor<T> {
- void process(T object, ResultSet resultSet) throws SQLException;
- }
-
- public <T> T executeQuerySingle(Class<T> clazz) throws SQLException {
- Collection<T> result = executeQuery(clazz);
- if (!result.isEmpty()) {
- return result.iterator().next();
- } else {
- return null;
- }
- }
-
- private <T> void addProcessors(
- List<ResultSetProcessor<T>> processors,
- final Class<?> parameterType, final Method method, final String name) {
-
- if (parameterType.equals(boolean.class)) {
- processors.add((object, resultSet) -> {
- try {
- method.invoke(object, resultSet.getBoolean(name));
- } catch (IllegalAccessException | InvocationTargetException error) {
- LOGGER.warn("Set property error", error);
- }
- });
- } else if (parameterType.equals(int.class)) {
- processors.add((object, resultSet) -> {
- try {
- method.invoke(object, resultSet.getInt(name));
- } catch (IllegalAccessException | InvocationTargetException error) {
- LOGGER.warn("Set property error", error);
- }
- });
- } else if (parameterType.equals(long.class)) {
- processors.add((object, resultSet) -> {
- try {
- method.invoke(object, resultSet.getLong(name));
- } catch (IllegalAccessException | InvocationTargetException error) {
- LOGGER.warn("Set property error", error);
- }
- });
- } else if (parameterType.equals(double.class)) {
- processors.add((object, resultSet) -> {
- try {
- method.invoke(object, resultSet.getDouble(name));
- } catch (IllegalAccessException | InvocationTargetException error) {
- LOGGER.warn("Set property error", error);
- }
- });
- } else if (parameterType.equals(String.class)) {
- processors.add((object, resultSet) -> {
- try {
- method.invoke(object, resultSet.getString(name));
- } catch (IllegalAccessException | InvocationTargetException error) {
- LOGGER.warn("Set property error", error);
- }
- });
- } else if (parameterType.equals(Date.class)) {
- processors.add((object, resultSet) -> {
- try {
- Timestamp timestamp = resultSet.getTimestamp(name);
- if (timestamp != null) {
- method.invoke(object, new Date(timestamp.getTime()));
- }
- } catch (IllegalAccessException | InvocationTargetException error) {
- LOGGER.warn("Set property error", error);
- }
- });
- } else if (parameterType.equals(byte[].class)) {
- processors.add((object, resultSet) -> {
- try {
- method.invoke(object, resultSet.getBytes(name));
- } catch (IllegalAccessException | InvocationTargetException error) {
- LOGGER.warn("Set property error", error);
- }
- });
- } else {
- processors.add((object, resultSet) -> {
- String value = resultSet.getString(name);
- if (value != null && !value.isEmpty()) {
- try {
- method.invoke(object, Context.getObjectMapper().readValue(value, parameterType));
- } catch (InvocationTargetException | IllegalAccessException | IOException error) {
- LOGGER.warn("Set property error", error);
- }
- }
- });
- }
- }
-
- public <T> Collection<T> executeQuery(Class<T> clazz) throws SQLException {
- List<T> result = new LinkedList<>();
-
- if (query != null) {
-
- try {
-
- try (ResultSet resultSet = statement.executeQuery()) {
-
- ResultSetMetaData resultMetaData = resultSet.getMetaData();
-
- List<ResultSetProcessor<T>> processors = new LinkedList<>();
-
- Method[] methods = clazz.getMethods();
-
- for (final Method method : methods) {
- if (method.getName().startsWith("set") && method.getParameterTypes().length == 1
- && !method.isAnnotationPresent(QueryIgnore.class)) {
-
- final String name = method.getName().substring(3);
-
- // Check if column exists
- boolean column = false;
- for (int i = 1; i <= resultMetaData.getColumnCount(); i++) {
- if (name.equalsIgnoreCase(resultMetaData.getColumnLabel(i))) {
- column = true;
- break;
- }
- }
- if (!column) {
- continue;
- }
-
- addProcessors(processors, method.getParameterTypes()[0], method, name);
- }
- }
-
- while (resultSet.next()) {
- try {
- T object = clazz.getDeclaredConstructor().newInstance();
- for (ResultSetProcessor<T> processor : processors) {
- processor.process(object, resultSet);
- }
- result.add(object);
- } catch (ReflectiveOperationException e) {
- throw new IllegalArgumentException();
- }
- }
- }
-
- } finally {
- statement.close();
- connection.close();
- }
- }
-
- return result;
- }
-
- public long executeUpdate() throws SQLException {
-
- if (query != null) {
- try {
- statement.execute();
- if (returnGeneratedKeys) {
- ResultSet resultSet = statement.getGeneratedKeys();
- if (resultSet.next()) {
- return resultSet.getLong(1);
- }
- }
- } finally {
- statement.close();
- connection.close();
- }
- }
- return 0;
- }
-
- public Collection<Permission> executePermissionsQuery() throws SQLException, ClassNotFoundException {
- List<Permission> result = new LinkedList<>();
- if (query != null) {
- try {
- try (ResultSet resultSet = statement.executeQuery()) {
- ResultSetMetaData resultMetaData = resultSet.getMetaData();
- while (resultSet.next()) {
- LinkedHashMap<String, Long> map = new LinkedHashMap<>();
- for (int i = 1; i <= resultMetaData.getColumnCount(); i++) {
- String label = resultMetaData.getColumnLabel(i);
- map.put(label, resultSet.getLong(label));
- }
- result.add(new Permission(map));
- }
- }
- } finally {
- statement.close();
- connection.close();
- }
- }
-
- return result;
- }
-
-}
diff --git a/src/main/java/org/traccar/database/QueryExtended.java b/src/main/java/org/traccar/database/QueryExtended.java
deleted file mode 100644
index 07bc2c211..000000000
--- a/src/main/java/org/traccar/database/QueryExtended.java
+++ /dev/null
@@ -1,27 +0,0 @@
-/*
- * Copyright 2017 Anton Tananaev (anton@traccar.org)
- * Copyright 2017 Andrey Kunitsyn (andrey@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.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-@Target(ElementType.METHOD)
-@Retention(RetentionPolicy.RUNTIME)
-public @interface QueryExtended {
-}
diff --git a/src/main/java/org/traccar/database/QueryIgnore.java b/src/main/java/org/traccar/database/QueryIgnore.java
deleted file mode 100644
index ac835cf2f..000000000
--- a/src/main/java/org/traccar/database/QueryIgnore.java
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- * Copyright 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.lang.annotation.ElementType;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
-import java.lang.annotation.Target;
-
-@Target(ElementType.METHOD)
-@Retention(RetentionPolicy.RUNTIME)
-public @interface QueryIgnore {
-}
diff --git a/src/main/java/org/traccar/database/SimpleObjectManager.java b/src/main/java/org/traccar/database/SimpleObjectManager.java
deleted file mode 100644
index eb8284d4e..000000000
--- a/src/main/java/org/traccar/database/SimpleObjectManager.java
+++ /dev/null
@@ -1,100 +0,0 @@
-/*
- * Copyright 2017 - 2020 Anton Tananaev (anton@traccar.org)
- * Copyright 2017 Andrey Kunitsyn (andrey@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.sql.SQLException;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.traccar.Context;
-import org.traccar.model.BaseModel;
-import org.traccar.model.Permission;
-import org.traccar.model.User;
-
-public abstract class SimpleObjectManager<T extends BaseModel> extends BaseObjectManager<T>
- implements ManagableObjects {
-
- private static final Logger LOGGER = LoggerFactory.getLogger(SimpleObjectManager.class);
-
- private Map<Long, Set<Long>> userItems;
-
- protected SimpleObjectManager(DataManager dataManager, Class<T> baseClass) {
- super(dataManager, baseClass);
- }
-
- @Override
- public final Set<Long> getUserItems(long userId) {
- try {
- readLock();
- Set<Long> result = userItems.get(userId);
- if (result != null) {
- return new HashSet<>(result);
- } else {
- return new HashSet<>();
- }
- } finally {
- readUnlock();
- }
- }
-
- @Override
- public Set<Long> getManagedItems(long userId) {
- Set<Long> result = getUserItems(userId);
- for (long managedUserId : Context.getUsersManager().getUserItems(userId)) {
- result.addAll(getUserItems(managedUserId));
- }
- return result;
- }
-
- public final boolean checkItemPermission(long userId, long itemId) {
- return getUserItems(userId).contains(itemId);
- }
-
- @Override
- public void refreshItems() {
- super.refreshItems();
- refreshUserItems();
- }
-
- public final void refreshUserItems() {
- if (getDataManager() != null) {
- try {
- writeLock();
- userItems = new ConcurrentHashMap<>();
- for (Permission permission : getDataManager().getPermissions(User.class, getBaseClass())) {
- Set<Long> items = userItems.computeIfAbsent(permission.getOwnerId(), key -> new HashSet<>());
- items.add(permission.getPropertyId());
- }
- } catch (SQLException | ClassNotFoundException error) {
- LOGGER.warn("Error getting permissions", error);
- } finally {
- writeUnlock();
- }
- }
- }
-
- @Override
- public void removeItem(long itemId) throws SQLException {
- super.removeItem(itemId);
- refreshUserItems();
- }
-
-}
diff --git a/src/main/java/org/traccar/database/StatisticsManager.java b/src/main/java/org/traccar/database/StatisticsManager.java
index 4ad6d9d5c..e0995dabc 100644
--- a/src/main/java/org/traccar/database/StatisticsManager.java
+++ b/src/main/java/org/traccar/database/StatisticsManager.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2016 - 2020 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.
@@ -23,12 +23,16 @@ import org.traccar.config.Config;
import org.traccar.config.Keys;
import org.traccar.helper.DateUtil;
import org.traccar.model.Statistics;
+import org.traccar.storage.Storage;
+import org.traccar.storage.StorageException;
+import org.traccar.storage.query.Columns;
+import org.traccar.storage.query.Request;
import javax.inject.Inject;
+import javax.inject.Singleton;
import javax.ws.rs.client.Client;
import javax.ws.rs.client.Entity;
import javax.ws.rs.core.Form;
-import java.sql.SQLException;
import java.util.Calendar;
import java.util.Date;
import java.util.HashMap;
@@ -37,6 +41,7 @@ import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicInteger;
+@Singleton
public class StatisticsManager {
private static final Logger LOGGER = LoggerFactory.getLogger(StatisticsManager.class);
@@ -44,7 +49,7 @@ public class StatisticsManager {
private static final int SPLIT_MODE = Calendar.DAY_OF_MONTH;
private final Config config;
- private final DataManager dataManager;
+ private final Storage storage;
private final Client client;
private final ObjectMapper objectMapper;
@@ -62,9 +67,9 @@ public class StatisticsManager {
private int geolocationRequests;
@Inject
- public StatisticsManager(Config config, DataManager dataManager, Client client, ObjectMapper objectMapper) {
+ public StatisticsManager(Config config, Storage storage, Client client, ObjectMapper objectMapper) {
this.config = config;
- this.dataManager = dataManager;
+ this.storage = storage;
this.client = client;
this.objectMapper = objectMapper;
}
@@ -105,8 +110,8 @@ public class StatisticsManager {
}
try {
- dataManager.addObject(statistics);
- } catch (SQLException e) {
+ storage.addObject(statistics, new Request(new Columns.Exclude("id")));
+ } catch (StorageException e) {
LOGGER.warn("Error saving statistics", e);
}
diff --git a/src/main/java/org/traccar/database/UsersManager.java b/src/main/java/org/traccar/database/UsersManager.java
deleted file mode 100644
index b741a85b6..000000000
--- a/src/main/java/org/traccar/database/UsersManager.java
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- * Copyright 2017 - 2020 Anton Tananaev (anton@traccar.org)
- * Copyright 2017 Andrey Kunitsyn (andrey@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.Map;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-
-import org.traccar.model.User;
-
-public class UsersManager extends SimpleObjectManager<User> {
-
- private Map<String, User> usersTokens;
-
- public UsersManager(DataManager dataManager) {
- super(dataManager, User.class);
- if (usersTokens == null) {
- usersTokens = new ConcurrentHashMap<>();
- }
- }
-
- private void putToken(User user) {
- if (usersTokens == null) {
- usersTokens = new ConcurrentHashMap<>();
- }
- if (user.getToken() != null) {
- usersTokens.put(user.getToken(), user);
- }
- }
-
- @Override
- protected void addNewItem(User user) {
- super.addNewItem(user);
- putToken(user);
- }
-
- @Override
- protected void updateCachedItem(User user) {
- User cachedUser = getById(user.getId());
- super.updateCachedItem(user);
- putToken(user);
- if (cachedUser.getToken() != null && !cachedUser.getToken().equals(user.getToken())) {
- usersTokens.remove(cachedUser.getToken());
- }
- }
-
- @Override
- protected void removeCachedItem(long userId) {
- User cachedUser = getById(userId);
- if (cachedUser != null) {
- String userToken = cachedUser.getToken();
- super.removeCachedItem(userId);
- if (userToken != null) {
- usersTokens.remove(userToken);
- }
- }
- }
-
- @Override
- public Set<Long> getManagedItems(long userId) {
- Set<Long> result = getUserItems(userId);
- result.add(userId);
- return result;
- }
-
- public User getUserByToken(String token) {
- return usersTokens.get(token);
- }
-
-}