aboutsummaryrefslogtreecommitdiff
path: root/src/org/traccar/database
diff options
context:
space:
mode:
Diffstat (limited to 'src/org/traccar/database')
-rw-r--r--src/org/traccar/database/AliasesManager.java113
-rw-r--r--src/org/traccar/database/AttributesManager.java173
-rw-r--r--src/org/traccar/database/BaseObjectManager.java124
-rw-r--r--src/org/traccar/database/CalendarManager.java99
-rw-r--r--src/org/traccar/database/CommandsManager.java149
-rw-r--r--src/org/traccar/database/ConnectionManager.java45
-rw-r--r--src/org/traccar/database/DataManager.java624
-rw-r--r--src/org/traccar/database/DeviceManager.java435
-rw-r--r--src/org/traccar/database/DriversManager.java73
-rw-r--r--src/org/traccar/database/ExtendedObjectManager.java112
-rw-r--r--src/org/traccar/database/GeofenceManager.java288
-rw-r--r--src/org/traccar/database/GroupsManager.java103
-rw-r--r--src/org/traccar/database/IdentityManager.java4
-rw-r--r--src/org/traccar/database/ManagableObjects.java27
-rw-r--r--src/org/traccar/database/NotificationManager.java196
-rw-r--r--src/org/traccar/database/PermissionsManager.java373
-rw-r--r--src/org/traccar/database/QueryBuilder.java26
-rw-r--r--src/org/traccar/database/QueryExtended.java27
-rw-r--r--src/org/traccar/database/SimpleObjectManager.java91
-rw-r--r--src/org/traccar/database/StatisticsManager.java2
-rw-r--r--src/org/traccar/database/UsersManager.java86
21 files changed, 1482 insertions, 1688 deletions
diff --git a/src/org/traccar/database/AliasesManager.java b/src/org/traccar/database/AliasesManager.java
deleted file mode 100644
index 4f4f09731..000000000
--- a/src/org/traccar/database/AliasesManager.java
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- * Copyright 2016 Anton Tananaev (anton@traccar.org)
- * Copyright 2016 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.ArrayList;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-
-import org.traccar.Context;
-import org.traccar.helper.Log;
-import org.traccar.model.AttributeAlias;
-
-public class AliasesManager {
-
- private final DataManager dataManager;
-
- private final Map<Long, Set<AttributeAlias>> deviceAliases = new ConcurrentHashMap<>();
- private final Map<Long, AttributeAlias> aliasesById = new ConcurrentHashMap<>();
-
- public AliasesManager(DataManager dataManager) {
- this.dataManager = dataManager;
- if (dataManager != null) {
- try {
- for (AttributeAlias attributeAlias : dataManager.getAttributeAliases()) {
- getAttributeAliases(attributeAlias.getDeviceId())
- .add(attributeAlias);
- aliasesById.put(attributeAlias.getId(), attributeAlias);
- }
- } catch (SQLException error) {
- Log.warning(error);
- }
- }
- }
-
- public Set<AttributeAlias> getAttributeAliases(long deviceId) {
- if (!deviceAliases.containsKey(deviceId)) {
- deviceAliases.put(deviceId, new HashSet<AttributeAlias>());
- }
- return deviceAliases.get(deviceId);
- }
-
- public void removeDevice(long deviceId) {
- for (AttributeAlias attributeAlias : getAttributeAliases(deviceId)) {
- aliasesById.remove(attributeAlias.getId());
- }
- deviceAliases.remove(deviceId);
- }
-
- public void addAttributeAlias(AttributeAlias attributeAlias) throws SQLException {
- dataManager.addAttributeAlias(attributeAlias);
- aliasesById.put(attributeAlias.getId(), attributeAlias);
- getAttributeAliases(attributeAlias.getDeviceId()).add(attributeAlias);
- }
-
- public void updateAttributeAlias(AttributeAlias attributeAlias) throws SQLException {
- dataManager.updateAttributeAlias(attributeAlias);
- AttributeAlias cachedAlias = aliasesById.get(attributeAlias.getId());
- if (cachedAlias.getDeviceId() != attributeAlias.getDeviceId()) {
- getAttributeAliases(cachedAlias.getDeviceId()).remove(cachedAlias);
- cachedAlias.setDeviceId(attributeAlias.getDeviceId());
- getAttributeAliases(cachedAlias.getDeviceId()).add(cachedAlias);
- }
- cachedAlias.setAttribute(attributeAlias.getAttribute());
- cachedAlias.setAlias(attributeAlias.getAlias());
- }
-
- public void removeArrtibuteAlias(long attributeAliasId) throws SQLException {
- dataManager.removeAttributeAlias(attributeAliasId);
- AttributeAlias cachedAlias = aliasesById.get(attributeAliasId);
- getAttributeAliases(cachedAlias.getDeviceId()).remove(cachedAlias);
- aliasesById.remove(attributeAliasId);
- }
-
- public AttributeAlias getAttributeAlias(long deviceId, String attribute) {
- for (AttributeAlias alias : getAttributeAliases(deviceId)) {
- if (alias.getAttribute().equals(attribute)) {
- return alias;
- }
- }
- return null;
- }
-
- public Collection<AttributeAlias> getAllAttributeAliases(long userId) {
- Collection<AttributeAlias> userDevicesAliases = new ArrayList<>();
- for (long deviceId : Context.getPermissionsManager().getDevicePermissions(userId)) {
- userDevicesAliases.addAll(getAttributeAliases(deviceId));
- }
- return userDevicesAliases;
- }
-
- public AttributeAlias getAttributeAlias(long id) {
- return aliasesById.get(id);
- }
-
-}
diff --git a/src/org/traccar/database/AttributesManager.java b/src/org/traccar/database/AttributesManager.java
index 362d6130f..28816645a 100644
--- a/src/org/traccar/database/AttributesManager.java
+++ b/src/org/traccar/database/AttributesManager.java
@@ -16,184 +16,21 @@
*/
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 org.traccar.Context;
-import org.traccar.helper.Log;
-import org.traccar.model.AttributePermission;
import org.traccar.model.Attribute;
-import org.traccar.model.Device;
-import org.traccar.model.DeviceAttribute;
-import org.traccar.model.GroupAttribute;
-
-public class AttributesManager {
-
- private final DataManager dataManager;
- private final Map<Long, Attribute> attributes = new ConcurrentHashMap<>();
- private final Map<Long, Set<Long>> deviceAttributes = new ConcurrentHashMap<>();
- private final Map<Long, Set<Long>> deviceAttributesWithGroups = new ConcurrentHashMap<>();
- private final Map<Long, Set<Long>> groupAttributes = new ConcurrentHashMap<>();
- private final Map<Long, Set<Long>> userAttributes = new ConcurrentHashMap<>();
+public class AttributesManager extends ExtendedObjectManager<Attribute> {
public AttributesManager(DataManager dataManager) {
- this.dataManager = dataManager;
- refreshAttributes();
- }
-
- public Set<Long> getUserAttributes(long userId) {
- if (!userAttributes.containsKey(userId)) {
- userAttributes.put(userId, new HashSet<Long>());
- }
- return userAttributes.get(userId);
- }
-
- public Set<Long> getGroupAttributes(long groupId) {
- if (!groupAttributes.containsKey(groupId)) {
- groupAttributes.put(groupId, new HashSet<Long>());
- }
- return groupAttributes.get(groupId);
- }
-
- public Set<Long> getDeviceAttributes(long deviceId) {
- return getDeviceAttributes(deviceAttributes, deviceId);
- }
-
- public Set<Long> getAllDeviceAttributes(long deviceId) {
- return getDeviceAttributes(deviceAttributesWithGroups, deviceId);
- }
-
- private Set<Long> getDeviceAttributes(Map<Long, Set<Long>> deviceAttributes, long deviceId) {
- if (!deviceAttributes.containsKey(deviceId)) {
- deviceAttributes.put(deviceId, new HashSet<Long>());
- }
- return deviceAttributes.get(deviceId);
- }
-
- public final void refreshAttributes() {
- if (dataManager != null) {
- try {
- attributes.clear();
- for (Attribute attribute : dataManager.getAttributes()) {
- attributes.put(attribute.getId(), attribute);
- }
- } catch (SQLException error) {
- Log.warning(error);
- }
- }
- refreshUserAttributes();
- refresh();
- }
-
- public final void refreshUserAttributes() {
- if (dataManager != null) {
- try {
- userAttributes.clear();
- for (AttributePermission attributePermission : dataManager.getAttributePermissions()) {
- getUserAttributes(attributePermission.getUserId()).add(attributePermission.getAttributeId());
- }
- } catch (SQLException error) {
- Log.warning(error);
- }
- }
- }
-
- public final void refresh() {
- if (dataManager != null) {
- try {
-
- Collection<GroupAttribute> databaseGroupAttributes = dataManager.getGroupAttributes();
-
- groupAttributes.clear();
- for (GroupAttribute groupAttribute : databaseGroupAttributes) {
- getGroupAttributes(groupAttribute.getGroupId()).add(groupAttribute.getAttributeId());
- }
-
- Collection<DeviceAttribute> databaseDeviceAttributes = dataManager.getDeviceAttributes();
- Collection<Device> allDevices = Context.getDeviceManager().getAllDevices();
-
- deviceAttributes.clear();
- deviceAttributesWithGroups.clear();
-
- for (DeviceAttribute deviceAttribute : databaseDeviceAttributes) {
- getDeviceAttributes(deviceAttribute.getDeviceId())
- .add(deviceAttribute.getAttributeId());
- getAllDeviceAttributes(deviceAttribute.getDeviceId())
- .add(deviceAttribute.getAttributeId());
- }
-
- for (Device device : allDevices) {
- long groupId = device.getGroupId();
- while (groupId != 0) {
- getAllDeviceAttributes(device.getId()).addAll(getGroupAttributes(groupId));
- if (Context.getDeviceManager().getGroupById(groupId) != null) {
- groupId = Context.getDeviceManager().getGroupById(groupId).getGroupId();
- } else {
- groupId = 0;
- }
- }
- }
-
- } catch (SQLException error) {
- Log.warning(error);
- }
- }
- }
-
- public void addAttribute(Attribute attribute) throws SQLException {
- dataManager.addAttribute(attribute);
- attributes.put(attribute.getId(), attribute);
+ super(dataManager, Attribute.class);
}
- public void updateAttribute(Attribute attribute) throws SQLException {
- dataManager.updateAttribute(attribute);
- Attribute cachedAttribute = attributes.get(attribute.getId());
+ @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());
}
- public void removeAttribute(long computedAttributeId) throws SQLException {
- dataManager.removeAttribute(computedAttributeId);
- attributes.remove(computedAttributeId);
- refreshUserAttributes();
- refresh();
- }
-
- public boolean checkAttribute(long userId, long attributeId) {
- return getUserAttributes(userId).contains(attributeId);
- }
-
- public Attribute getAttribute(long id) {
- return attributes.get(id);
- }
-
- public final Collection<Attribute> getAttributes(Set<Long> attributeIds) {
- Collection<Attribute> result = new LinkedList<>();
- for (long attributeId : attributeIds) {
- result.add(getAttribute(attributeId));
- }
- return result;
- }
-
- public final Set<Long> getAllAttributes() {
- return attributes.keySet();
- }
-
- public final Set<Long> getManagedAttributes(long userId) {
- Set<Long> attributes = new HashSet<>();
- attributes.addAll(getUserAttributes(userId));
- for (long managedUserId : Context.getPermissionsManager().getUserPermissions(userId)) {
- attributes.addAll(getUserAttributes(managedUserId));
- }
- return attributes;
- }
-
}
diff --git a/src/org/traccar/database/BaseObjectManager.java b/src/org/traccar/database/BaseObjectManager.java
new file mode 100644
index 000000000..cc1dbde5f
--- /dev/null
+++ b/src/org/traccar/database/BaseObjectManager.java
@@ -0,0 +1,124 @@
+/*
+ * 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.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 org.traccar.helper.Log;
+import org.traccar.model.BaseModel;
+
+public class BaseObjectManager<T extends BaseModel> {
+
+ private final DataManager dataManager;
+
+ private Map<Long, T> items;
+ private Class<T> baseClass;
+
+ protected BaseObjectManager(DataManager dataManager, Class<T> baseClass) {
+ this.dataManager = dataManager;
+ this.baseClass = baseClass;
+ refreshItems();
+ }
+
+ protected final DataManager getDataManager() {
+ return dataManager;
+ }
+
+ protected final Class<T> getBaseClass() {
+ return baseClass;
+ }
+
+ public T getById(long itemId) {
+ return items.get(itemId);
+ }
+
+ public void refreshItems() {
+ if (dataManager != null) {
+ try {
+ 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) {
+ Log.warning(error);
+ }
+ }
+ }
+
+ protected void addNewItem(T item) {
+ items.put(item.getId(), item);
+ }
+
+ public void addItem(T item) throws SQLException {
+ dataManager.addObject(item);
+ addNewItem(item);
+ }
+
+ protected void updateCachedItem(T item) {
+ items.put(item.getId(), item);
+ }
+
+ public void updateItem(T item) throws SQLException {
+ dataManager.updateObject(item);
+ updateCachedItem(item);
+ }
+
+ protected void removeCachedItem(long itemId) {
+ items.remove(itemId);
+ }
+
+ 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) {
+ result.add(getById(itemId));
+ }
+ return result;
+ }
+
+ public Set<Long> getAllItems() {
+ return items.keySet();
+ }
+
+}
diff --git a/src/org/traccar/database/CalendarManager.java b/src/org/traccar/database/CalendarManager.java
index 31d484327..44ced1082 100644
--- a/src/org/traccar/database/CalendarManager.java
+++ b/src/org/traccar/database/CalendarManager.java
@@ -16,107 +16,12 @@
*/
package org.traccar.database;
-import java.sql.SQLException;
-import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashSet;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
-
-import org.traccar.Context;
-import org.traccar.helper.Log;
import org.traccar.model.Calendar;
-import org.traccar.model.CalendarPermission;
-
-public class CalendarManager {
-
- private final DataManager dataManager;
- private final Map<Long, Calendar> calendars = new ConcurrentHashMap<>();
- private final Map<Long, Set<Long>> userCalendars = new ConcurrentHashMap<>();
+public class CalendarManager extends SimpleObjectManager<Calendar> {
public CalendarManager(DataManager dataManager) {
- this.dataManager = dataManager;
- refreshCalendars();
- }
-
- public final void refreshCalendars() {
- if (dataManager != null) {
- try {
- calendars.clear();
- for (Calendar calendar : dataManager.getCalendars()) {
- calendars.put(calendar.getId(), calendar);
- }
- } catch (SQLException error) {
- Log.warning(error);
- }
- }
- refreshUserCalendars();
- }
-
- private Set<Long> getUserCalendarIds(long userId) {
- if (!userCalendars.containsKey(userId)) {
- userCalendars.put(userId, new HashSet<Long>());
- }
- return userCalendars.get(userId);
- }
-
- public Collection<Calendar> getUserCalendars(long userId) {
- ArrayList<Calendar> result = new ArrayList<>();
- for (long calendarId : getUserCalendarIds(userId)) {
- result.add(calendars.get(calendarId));
- }
- return result;
- }
-
- public Collection<Calendar> getManagedCalendars(long userId) {
- ArrayList<Calendar> result = new ArrayList<>();
- result.addAll(getUserCalendars(userId));
- for (long managedUserId : Context.getPermissionsManager().getUserPermissions(userId)) {
- result.addAll(getUserCalendars(managedUserId));
- }
- return result;
- }
-
- public final void refreshUserCalendars() {
- if (dataManager != null) {
- try {
- userCalendars.clear();
- for (CalendarPermission calendarsPermission : dataManager.getCalendarPermissions()) {
- getUserCalendarIds(calendarsPermission.getUserId()).add(calendarsPermission.getCalendarId());
- }
- } catch (SQLException error) {
- Log.warning(error);
- }
- }
- }
-
- public Calendar getCalendar(long calendarId) {
- return calendars.get(calendarId);
- }
-
- public final void addCalendar(Calendar calendar) throws SQLException {
- dataManager.addCalendar(calendar);
- calendars.put(calendar.getId(), calendar);
- }
-
- public final void updateCalendar(Calendar calendar) throws SQLException {
- dataManager.updateCalendar(calendar);
- calendars.put(calendar.getId(), calendar);
- }
-
- public final void removeCalendar(long calendarId) throws SQLException {
- dataManager.removeCalendar(calendarId);
- calendars.remove(calendarId);
- refreshUserCalendars();
+ super(dataManager, Calendar.class);
}
- public Collection<Calendar> getAllCalendars() {
- return calendars.values();
- }
-
- public boolean checkCalendar(long userId, long calendarId) {
- return getUserCalendarIds(userId).contains(calendarId);
- }
}
diff --git a/src/org/traccar/database/CommandsManager.java b/src/org/traccar/database/CommandsManager.java
new file mode 100644
index 000000000..9ceb995ef
--- /dev/null
+++ b/src/org/traccar/database/CommandsManager.java
@@ -0,0 +1,149 @@
+/*
+ * 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.reflect.Field;
+import java.lang.reflect.Modifier;
+import java.util.ArrayList;
+import java.util.Collection;
+import java.util.List;
+import java.util.Map;
+import java.util.Queue;
+import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.ConcurrentLinkedQueue;
+
+import org.traccar.BaseProtocol;
+import org.traccar.Context;
+import org.traccar.helper.Log;
+import org.traccar.model.Command;
+import org.traccar.model.Typed;
+import org.traccar.model.Position;
+
+public class CommandsManager extends ExtendedObjectManager<Command> {
+
+ private final Map<Long, Queue<Command>> deviceQueues = new ConcurrentHashMap<>();
+
+ public CommandsManager(DataManager dataManager) {
+ super(dataManager, Command.class);
+ }
+
+ public boolean checkDeviceCommand(long deviceId, long commandId) {
+ return !getAllDeviceItems(deviceId).contains(commandId);
+ }
+
+ 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);
+ } else if (command.getType().equals(Command.TYPE_CUSTOM)) {
+ if (Context.getSmppManager() != null) {
+ Context.getSmppManager().sendMessageSync(phone, command.getString(Command.KEY_DATA), true);
+ } else {
+ throw new RuntimeException("SMPP client is not enabled");
+ }
+ } else {
+ throw new RuntimeException("Command " + command.getType() + " is not supported");
+ }
+ } else {
+ ActiveDevice activeDevice = Context.getConnectionManager().getActiveDevice(deviceId);
+ if (activeDevice != null) {
+ activeDevice.sendCommand(command);
+ } else {
+ getDeviceQueue(deviceId).add(command);
+ 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) {
+ List<Typed> result = new ArrayList<>();
+ Position lastPosition = Context.getIdentityManager().getLastPosition(deviceId);
+ if (lastPosition != null) {
+ BaseProtocol protocol = Context.getServerManager().getProtocol(lastPosition.getProtocol());
+ Collection<String> commands;
+ commands = textChannel ? protocol.getSupportedTextCommands() : protocol.getSupportedDataCommands();
+ for (String commandKey : commands) {
+ result.add(new Typed(commandKey));
+ }
+ } else {
+ result.add(new Typed(Command.TYPE_CUSTOM));
+ }
+ 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) {
+ Log.warning(error);
+ }
+ }
+ }
+ return result;
+ }
+
+ private Queue<Command> getDeviceQueue(long deviceId) {
+ if (!deviceQueues.containsKey(deviceId)) {
+ deviceQueues.put(deviceId, new ConcurrentLinkedQueue<Command>());
+ }
+ return deviceQueues.get(deviceId);
+ }
+
+ public void sendQueuedCommands(ActiveDevice activeDevice) {
+ Queue<Command> deviceQueue = deviceQueues.get(activeDevice.getDeviceId());
+ if (deviceQueue != null) {
+ Command command = deviceQueue.poll();
+ while (command != null) {
+ activeDevice.sendCommand(command);
+ command = deviceQueue.poll();
+ }
+ }
+ }
+
+}
diff --git a/src/org/traccar/database/ConnectionManager.java b/src/org/traccar/database/ConnectionManager.java
index 0baafb578..e5a7a272f 100644
--- a/src/org/traccar/database/ConnectionManager.java
+++ b/src/org/traccar/database/ConnectionManager.java
@@ -1,5 +1,5 @@
/*
- * Copyright 2015 - 2016 Anton Tananaev (anton@traccar.org)
+ * Copyright 2015 - 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.
@@ -21,14 +21,17 @@ import org.jboss.netty.util.TimerTask;
import org.traccar.Context;
import org.traccar.GlobalTimer;
import org.traccar.Protocol;
+import org.traccar.events.OverspeedEventHandler;
import org.traccar.helper.Log;
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;
@@ -41,6 +44,7 @@ public class ConnectionManager {
private final long deviceTimeout;
private final boolean enableStatusEvents;
+ private final boolean updateDeviceState;
private final Map<Long, ActiveDevice> activeDevices = new ConcurrentHashMap<>();
private final Map<Long, Set<UpdateListener>> listeners = new ConcurrentHashMap<>();
@@ -49,10 +53,13 @@ public class ConnectionManager {
public ConnectionManager() {
deviceTimeout = Context.getConfig().getLong("status.timeout", DEFAULT_TIMEOUT) * 1000;
enableStatusEvents = Context.getConfig().getBoolean("event.enable");
+ updateDeviceState = Context.getConfig().getBoolean("status.updateDeviceState");
}
public void addActiveDevice(long deviceId, Protocol protocol, Channel channel, SocketAddress remoteAddress) {
- activeDevices.put(deviceId, new ActiveDevice(deviceId, protocol, channel, remoteAddress));
+ ActiveDevice activeDevice = new ActiveDevice(deviceId, protocol, channel, remoteAddress);
+ activeDevices.put(deviceId, activeDevice);
+ Context.getCommandsManager().sendQueuedCommands(activeDevice);
}
public void removeActiveDevice(Channel channel) {
@@ -70,7 +77,7 @@ public class ConnectionManager {
}
public void updateDevice(final long deviceId, String status, Date time) {
- Device device = Context.getIdentityManager().getDeviceById(deviceId);
+ Device device = Context.getIdentityManager().getById(deviceId);
if (device == null) {
return;
}
@@ -80,21 +87,26 @@ public class ConnectionManager {
if (enableStatusEvents && !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;
}
- Event event = new Event(eventType, deviceId);
- if (Context.getNotificationManager() != null) {
- Context.getNotificationManager().updateEvent(event, null);
- }
+ events.put(new Event(eventType, deviceId), null);
+ Context.getNotificationManager().updateEvents(events);
}
Timeout timeout = timeouts.remove(deviceId);
@@ -112,6 +124,7 @@ public class ConnectionManager {
public void run(Timeout timeout) throws Exception {
if (!timeout.isCancelled()) {
updateDevice(deviceId, Device.STATUS_UNKNOWN, null);
+ activeDevices.remove(deviceId);
}
}
}, deviceTimeout, TimeUnit.MILLISECONDS));
@@ -126,6 +139,24 @@ public class ConnectionManager {
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 = Context.getMotionEventHandler().updateMotionState(deviceState);
+ if (event != null) {
+ result.putAll(event);
+ }
+
+ event = Context.getOverspeedEventHandler().updateOverspeedState(deviceState, Context.getDeviceManager().
+ lookupAttributeDouble(deviceId, OverspeedEventHandler.ATTRIBUTE_SPEED_LIMIT, 0, false));
+ if (event != null) {
+ result.putAll(event);
+ }
+
+ return result;
+ }
+
public synchronized void updateDevice(Device device) {
for (long userId : Context.getPermissionsManager().getDeviceUsers(device.getId())) {
if (listeners.containsKey(userId)) {
diff --git a/src/org/traccar/database/DataManager.java b/src/org/traccar/database/DataManager.java
index dd65289e4..e88ff7f0d 100644
--- a/src/org/traccar/database/DataManager.java
+++ b/src/org/traccar/database/DataManager.java
@@ -15,14 +15,18 @@
*/
package org.traccar.database;
+import java.beans.Introspector;
import java.io.File;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;
import java.sql.SQLException;
import java.text.SimpleDateFormat;
+import java.util.Arrays;
import java.util.Collection;
import java.util.Date;
+import java.util.HashSet;
+import java.util.Set;
import javax.naming.InitialContext;
import javax.sql.DataSource;
@@ -37,38 +41,40 @@ import liquibase.resource.ResourceAccessor;
import org.traccar.Config;
import org.traccar.helper.Log;
-import org.traccar.model.AttributeAlias;
-import org.traccar.model.AttributePermission;
-import org.traccar.model.Calendar;
-import org.traccar.model.CalendarPermission;
import org.traccar.model.Attribute;
import org.traccar.model.Device;
-import org.traccar.model.DeviceAttribute;
-import org.traccar.model.DevicePermission;
+import org.traccar.model.Driver;
import org.traccar.model.Event;
import org.traccar.model.Geofence;
import org.traccar.model.Group;
-import org.traccar.model.GroupAttribute;
-import org.traccar.model.GroupGeofence;
-import org.traccar.model.GroupPermission;
+import org.traccar.model.ManagedUser;
import org.traccar.model.Notification;
+import org.traccar.model.Permission;
+import org.traccar.model.BaseModel;
+import org.traccar.model.Calendar;
+import org.traccar.model.Command;
import org.traccar.model.Position;
import org.traccar.model.Server;
import org.traccar.model.Statistics;
import org.traccar.model.User;
-import org.traccar.model.UserPermission;
-import org.traccar.model.DeviceGeofence;
-import org.traccar.model.GeofencePermission;
import com.zaxxer.hikari.HikariConfig;
import com.zaxxer.hikari.HikariDataSource;
public class DataManager {
+ 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;
+ private boolean generateQueries;
+
public DataManager(Config config) throws Exception {
this.config = config;
@@ -117,11 +123,83 @@ public class DataManager {
hikariConfig.setMaximumPoolSize(maxPoolSize);
}
+ generateQueries = config.getBoolean("database.generateQueries");
+
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) {
@@ -130,6 +208,73 @@ public class DataManager {
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);
+ config.setString(queryName, query);
+ } else {
+ Log.info("Query not provided: " + queryName);
+ }
+ }
+
+ return query;
+ }
+
+ public String getQuery(String action, Class<?> owner, Class<?> property) {
+ String queryName;
+ if (action.equals(ACTION_SELECT_ALL)) {
+ queryName = "database.select" + owner.getSimpleName() + property.getSimpleName() + "s";
+ } else if (action.equals(ACTION_INSERT)) {
+ queryName = "database.link" + owner.getSimpleName() + property.getSimpleName();
+ } else {
+ queryName = "database.unlink" + owner.getSimpleName() + property.getSimpleName();
+ }
+ String query = config.getString(queryName);
+ if (query == null) {
+ if (generateQueries) {
+ query = constructPermissionQuery(action, owner,
+ property.equals(User.class) ? ManagedUser.class : property);
+ config.setString(queryName, query);
+ } else {
+ Log.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 Introspector.decapitalize(owner.getSimpleName()) + "_" + Introspector.decapitalize(propertyName);
+ }
+
+ private static String getObjectsTableName(Class<?> clazz) {
+ String result = 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 SQLException, LiquibaseException {
if (config.hasKey("database.changelog")) {
@@ -153,7 +298,7 @@ public class DataManager {
public User login(String email, String password) throws SQLException {
User user = QueryBuilder.create(dataSource, getQuery("database.loginUser"))
- .setString("email", email)
+ .setString("email", email.trim())
.executeQuerySingle(User.class);
if (user != null && user.isPasswordValid(password)) {
return user;
@@ -162,124 +307,12 @@ public class DataManager {
}
}
- public Collection<User> getUsers() throws SQLException {
- return QueryBuilder.create(dataSource, getQuery("database.selectUsersAll"))
- .executeQuery(User.class);
- }
-
- public void addUser(User user) throws SQLException {
- user.setId(QueryBuilder.create(dataSource, getQuery("database.insertUser"), true)
- .setObject(user)
- .executeUpdate());
- }
-
- public void updateUser(User user) throws SQLException {
- QueryBuilder.create(dataSource, getQuery("database.updateUser"))
- .setObject(user)
- .executeUpdate();
- if (user.getHashedPassword() != null) {
- QueryBuilder.create(dataSource, getQuery("database.updateUserPassword"))
- .setObject(user)
- .executeUpdate();
- }
- }
-
- public void removeUser(long userId) throws SQLException {
- QueryBuilder.create(dataSource, getQuery("database.deleteUser"))
- .setLong("id", userId)
- .executeUpdate();
- }
-
- public Collection<DevicePermission> getDevicePermissions() throws SQLException {
- return QueryBuilder.create(dataSource, getQuery("database.selectDevicePermissions"))
- .executeQuery(DevicePermission.class);
- }
-
- public Collection<GroupPermission> getGroupPermissions() throws SQLException {
- return QueryBuilder.create(dataSource, getQuery("database.selectGroupPermissions"))
- .executeQuery(GroupPermission.class);
- }
-
- public Collection<Device> getAllDevices() throws SQLException {
- return QueryBuilder.create(dataSource, getQuery("database.selectDevicesAll"))
- .executeQuery(Device.class);
- }
-
- public void addDevice(Device device) throws SQLException {
- device.setId(QueryBuilder.create(dataSource, getQuery("database.insertDevice"), true)
- .setObject(device)
- .executeUpdate());
- }
-
- public void updateDevice(Device device) throws SQLException {
- QueryBuilder.create(dataSource, getQuery("database.updateDevice"))
- .setObject(device)
- .executeUpdate();
- }
-
public void updateDeviceStatus(Device device) throws SQLException {
- QueryBuilder.create(dataSource, getQuery("database.updateDeviceStatus"))
+ QueryBuilder.create(dataSource, getQuery(ACTION_UPDATE, Device.class, true))
.setObject(device)
.executeUpdate();
}
- public void removeDevice(long deviceId) throws SQLException {
- QueryBuilder.create(dataSource, getQuery("database.deleteDevice"))
- .setLong("id", deviceId)
- .executeUpdate();
- }
-
- public void linkDevice(long userId, long deviceId) throws SQLException {
- QueryBuilder.create(dataSource, getQuery("database.linkDevice"))
- .setLong("userId", userId)
- .setLong("deviceId", deviceId)
- .executeUpdate();
- }
-
- public void unlinkDevice(long userId, long deviceId) throws SQLException {
- QueryBuilder.create(dataSource, getQuery("database.unlinkDevice"))
- .setLong("userId", userId)
- .setLong("deviceId", deviceId)
- .executeUpdate();
- }
-
- public Collection<Group> getAllGroups() throws SQLException {
- return QueryBuilder.create(dataSource, getQuery("database.selectGroupsAll"))
- .executeQuery(Group.class);
- }
-
- public void addGroup(Group group) throws SQLException {
- group.setId(QueryBuilder.create(dataSource, getQuery("database.insertGroup"), true)
- .setObject(group)
- .executeUpdate());
- }
-
- public void updateGroup(Group group) throws SQLException {
- QueryBuilder.create(dataSource, getQuery("database.updateGroup"))
- .setObject(group)
- .executeUpdate();
- }
-
- public void removeGroup(long groupId) throws SQLException {
- QueryBuilder.create(dataSource, getQuery("database.deleteGroup"))
- .setLong("id", groupId)
- .executeUpdate();
- }
-
- public void linkGroup(long userId, long groupId) throws SQLException {
- QueryBuilder.create(dataSource, getQuery("database.linkGroup"))
- .setLong("userId", userId)
- .setLong("groupId", groupId)
- .executeUpdate();
- }
-
- public void unlinkGroup(long userId, long groupId) throws SQLException {
- QueryBuilder.create(dataSource, getQuery("database.unlinkGroup"))
- .setLong("userId", userId)
- .setLong("groupId", groupId)
- .executeUpdate();
- }
-
public Collection<Position> getPositions(long deviceId, Date from, Date to) throws SQLException {
return QueryBuilder.create(dataSource, getQuery("database.selectPositions"))
.setLong("deviceId", deviceId)
@@ -288,16 +321,10 @@ public class DataManager {
.executeQuery(Position.class);
}
- public Position getPosition(long positionId) throws SQLException {
- return QueryBuilder.create(dataSource, getQuery("database.selectPosition"))
- .setLong("id", positionId)
- .executeQuerySingle(Position.class);
- }
-
public void addPosition(Position position) throws SQLException {
- position.setId(QueryBuilder.create(dataSource, getQuery("database.insertPosition"), true)
- .setDate("now", new Date())
+ position.setId(QueryBuilder.create(dataSource, getQuery(ACTION_INSERT, Position.class), true)
.setObject(position)
+ .setDate("serverTime", new Date())
.executeUpdate());
}
@@ -328,28 +355,10 @@ public class DataManager {
}
public Server getServer() throws SQLException {
- return QueryBuilder.create(dataSource, getQuery("database.selectServers"))
+ return QueryBuilder.create(dataSource, getQuery(ACTION_SELECT_ALL, Server.class))
.executeQuerySingle(Server.class);
}
- public void updateServer(Server server) throws SQLException {
- QueryBuilder.create(dataSource, getQuery("database.updateServer"))
- .setObject(server)
- .executeUpdate();
- }
-
- public Event getEvent(long eventId) throws SQLException {
- return QueryBuilder.create(dataSource, getQuery("database.selectEvent"))
- .setLong("id", eventId)
- .executeQuerySingle(Event.class);
- }
-
- public void addEvent(Event event) throws SQLException {
- event.setId(QueryBuilder.create(dataSource, getQuery("database.insertEvent"), true)
- .setObject(event)
- .executeUpdate());
- }
-
public Collection<Event> getEvents(long deviceId, Date from, Date to) throws SQLException {
return QueryBuilder.create(dataSource, getQuery("database.selectEvents"))
.setLong("deviceId", deviceId)
@@ -358,132 +367,6 @@ public class DataManager {
.executeQuery(Event.class);
}
- public Collection<Geofence> getGeofences() throws SQLException {
- return QueryBuilder.create(dataSource, getQuery("database.selectGeofencesAll"))
- .executeQuery(Geofence.class);
- }
-
- public void addGeofence(Geofence geofence) throws SQLException {
- geofence.setId(QueryBuilder.create(dataSource, getQuery("database.insertGeofence"), true)
- .setObject(geofence)
- .executeUpdate());
- }
-
- public void updateGeofence(Geofence geofence) throws SQLException {
- QueryBuilder.create(dataSource, getQuery("database.updateGeofence"))
- .setObject(geofence)
- .executeUpdate();
- }
-
- public void removeGeofence(long geofenceId) throws SQLException {
- QueryBuilder.create(dataSource, getQuery("database.deleteGeofence"))
- .setLong("id", geofenceId)
- .executeUpdate();
- }
-
- public Collection<GeofencePermission> getGeofencePermissions() throws SQLException {
- return QueryBuilder.create(dataSource, getQuery("database.selectGeofencePermissions"))
- .executeQuery(GeofencePermission.class);
- }
-
- public void linkGeofence(long userId, long geofenceId) throws SQLException {
- QueryBuilder.create(dataSource, getQuery("database.linkGeofence"))
- .setLong("userId", userId)
- .setLong("geofenceId", geofenceId)
- .executeUpdate();
- }
-
- public void unlinkGeofence(long userId, long geofenceId) throws SQLException {
- QueryBuilder.create(dataSource, getQuery("database.unlinkGeofence"))
- .setLong("userId", userId)
- .setLong("geofenceId", geofenceId)
- .executeUpdate();
- }
-
- public Collection<GroupGeofence> getGroupGeofences() throws SQLException {
- return QueryBuilder.create(dataSource, getQuery("database.selectGroupGeofences"))
- .executeQuery(GroupGeofence.class);
- }
-
- public void linkGroupGeofence(long groupId, long geofenceId) throws SQLException {
- QueryBuilder.create(dataSource, getQuery("database.linkGroupGeofence"))
- .setLong("groupId", groupId)
- .setLong("geofenceId", geofenceId)
- .executeUpdate();
- }
-
- public void unlinkGroupGeofence(long groupId, long geofenceId) throws SQLException {
- QueryBuilder.create(dataSource, getQuery("database.unlinkGroupGeofence"))
- .setLong("groupId", groupId)
- .setLong("geofenceId", geofenceId)
- .executeUpdate();
- }
-
- public Collection<DeviceGeofence> getDeviceGeofences() throws SQLException {
- return QueryBuilder.create(dataSource, getQuery("database.selectDeviceGeofences"))
- .executeQuery(DeviceGeofence.class);
- }
-
- public void linkDeviceGeofence(long deviceId, long geofenceId) throws SQLException {
- QueryBuilder.create(dataSource, getQuery("database.linkDeviceGeofence"))
- .setLong("deviceId", deviceId)
- .setLong("geofenceId", geofenceId)
- .executeUpdate();
- }
-
- public void unlinkDeviceGeofence(long deviceId, long geofenceId) throws SQLException {
- QueryBuilder.create(dataSource, getQuery("database.unlinkDeviceGeofence"))
- .setLong("deviceId", deviceId)
- .setLong("geofenceId", geofenceId)
- .executeUpdate();
- }
-
- public Collection<Notification> getNotifications() throws SQLException {
- return QueryBuilder.create(dataSource, getQuery("database.selectNotifications"))
- .executeQuery(Notification.class);
- }
-
- public void addNotification(Notification notification) throws SQLException {
- notification.setId(QueryBuilder.create(dataSource, getQuery("database.insertNotification"), true)
- .setObject(notification)
- .executeUpdate());
- }
-
- public void updateNotification(Notification notification) throws SQLException {
- QueryBuilder.create(dataSource, getQuery("database.updateNotification"))
- .setObject(notification)
- .executeUpdate();
- }
-
- public void removeNotification(Notification notification) throws SQLException {
- QueryBuilder.create(dataSource, getQuery("database.deleteNotification"))
- .setLong("id", notification.getId())
- .executeUpdate();
- }
-
- public Collection<AttributeAlias> getAttributeAliases() throws SQLException {
- return QueryBuilder.create(dataSource, getQuery("database.selectAttributeAliases"))
- .executeQuery(AttributeAlias.class);
- }
-
- public void addAttributeAlias(AttributeAlias attributeAlias) throws SQLException {
- attributeAlias.setId(QueryBuilder.create(dataSource, getQuery("database.insertAttributeAlias"), true)
- .setObject(attributeAlias)
- .executeUpdate());
- }
-
- public void updateAttributeAlias(AttributeAlias attributeAlias) throws SQLException {
- QueryBuilder.create(dataSource, getQuery("database.updateAttributeAlias"))
- .setObject(attributeAlias)
- .executeUpdate();
- }
-
- public void removeAttributeAlias(long attributeAliasId) throws SQLException {
- QueryBuilder.create(dataSource, getQuery("database.deleteAttributeAlias"))
- .setLong("id", attributeAliasId)
- .executeUpdate();
- }
-
public Collection<Statistics> getStatistics(Date from, Date to) throws SQLException {
return QueryBuilder.create(dataSource, getQuery("database.selectStatistics"))
.setDate("from", from)
@@ -491,150 +374,83 @@ public class DataManager {
.executeQuery(Statistics.class);
}
- public void addStatistics(Statistics statistics) throws SQLException {
- statistics.setId(QueryBuilder.create(dataSource, getQuery("database.insertStatistics"), true)
- .setObject(statistics)
- .executeUpdate());
- }
-
- public Collection<Calendar> getCalendars() throws SQLException {
- return QueryBuilder.create(dataSource, getQuery("database.selectCalendarsAll"))
- .executeQuery(Calendar.class);
- }
-
- public void addCalendar(Calendar calendar) throws SQLException {
- calendar.setId(QueryBuilder.create(dataSource, getQuery("database.insertCalendar"), true)
- .setObject(calendar)
- .executeUpdate());
- }
-
- public void updateCalendar(Calendar calendar) throws SQLException {
- QueryBuilder.create(dataSource, getQuery("database.updateCalendar"))
- .setObject(calendar)
- .executeUpdate();
- }
-
- public void removeCalendar(long calendarId) throws SQLException {
- QueryBuilder.create(dataSource, getQuery("database.deleteCalendar"))
- .setLong("id", calendarId)
- .executeUpdate();
- }
-
- public Collection<CalendarPermission> getCalendarPermissions() throws SQLException {
- return QueryBuilder.create(dataSource, getQuery("database.selectCalendarPermissions"))
- .executeQuery(CalendarPermission.class);
- }
-
- public void linkCalendar(long userId, long calendarId) throws SQLException {
- QueryBuilder.create(dataSource, getQuery("database.linkCalendar"))
- .setLong("userId", userId)
- .setLong("calendarId", calendarId)
- .executeUpdate();
+ 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 "notification":
+ return Notification.class;
+ default:
+ throw new ClassNotFoundException();
+ }
}
- public void unlinkCalendar(long userId, long calendarId) throws SQLException {
- QueryBuilder.create(dataSource, getQuery("database.unlinkCalendar"))
- .setLong("userId", userId)
- .setLong("calendarId", calendarId)
- .executeUpdate();
+ private static String makeNameId(Class<?> clazz) {
+ String name = clazz.getSimpleName();
+ return Introspector.decapitalize(name) + (!name.contains("Id") ? "Id" : "");
}
- public Collection<UserPermission> getUserPermissions() throws SQLException {
- return QueryBuilder.create(dataSource, getQuery("database.selectUserPermissions"))
- .executeQuery(UserPermission.class);
+ 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 linkUser(long userId, long managedUserId) throws SQLException {
- QueryBuilder.create(dataSource, getQuery("database.linkUser"))
- .setLong("userId", userId)
- .setLong("managedUserId", managedUserId)
+ 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 void unlinkUser(long userId, long managedUserId) throws SQLException {
- QueryBuilder.create(dataSource, getQuery("database.unlinkUser"))
- .setLong("userId", userId)
- .setLong("managedUserId", managedUserId)
- .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 Collection<Attribute> getAttributes() throws SQLException {
- return QueryBuilder.create(dataSource, getQuery("database.selectAttributes"))
- .executeQuery(Attribute.class);
+ 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 addAttribute(Attribute attribute) throws SQLException {
- attribute.setId(QueryBuilder.create(dataSource, getQuery("database.insertAttribute"), true)
- .setObject(attribute)
+ public void addObject(BaseModel entity) throws SQLException {
+ entity.setId(QueryBuilder.create(dataSource, getQuery(ACTION_INSERT, entity.getClass()), true)
+ .setObject(entity)
.executeUpdate());
}
- public void updateAttribute(Attribute attribute) throws SQLException {
- QueryBuilder.create(dataSource, getQuery("database.updateAttribute"))
- .setObject(attribute)
- .executeUpdate();
- }
-
- public void removeAttribute(long computedAttributeId) throws SQLException {
- QueryBuilder.create(dataSource, getQuery("database.deleteAttribute"))
- .setLong("id", computedAttributeId)
- .executeUpdate();
- }
-
- public Collection<AttributePermission> getAttributePermissions() throws SQLException {
- return QueryBuilder.create(dataSource, getQuery("database.selectAttributePermissions"))
- .executeQuery(AttributePermission.class);
- }
-
- public void linkAttribute(long userId, long attributeId) throws SQLException {
- QueryBuilder.create(dataSource, getQuery("database.linkAttribute"))
- .setLong("userId", userId)
- .setLong("attributeId", attributeId)
- .executeUpdate();
- }
-
- public void unlinkAttribute(long userId, long attributeId) throws SQLException {
- QueryBuilder.create(dataSource, getQuery("database.unlinkAttribute"))
- .setLong("userId", userId)
- .setLong("attributeId", attributeId)
- .executeUpdate();
- }
-
- public Collection<GroupAttribute> getGroupAttributes() throws SQLException {
- return QueryBuilder.create(dataSource, getQuery("database.selectGroupAttributes"))
- .executeQuery(GroupAttribute.class);
- }
-
- public void linkGroupAttribute(long groupId, long attributeId) throws SQLException {
- QueryBuilder.create(dataSource, getQuery("database.linkGroupAttribute"))
- .setLong("groupId", groupId)
- .setLong("attributeId", attributeId)
- .executeUpdate();
- }
-
- public void unlinkGroupAttribute(long groupId, long attributeId) throws SQLException {
- QueryBuilder.create(dataSource, getQuery("database.unlinkGroupAttribute"))
- .setLong("groupId", groupId)
- .setLong("attributeId", attributeId)
- .executeUpdate();
- }
-
- public Collection<DeviceAttribute> getDeviceAttributes() throws SQLException {
- return QueryBuilder.create(dataSource, getQuery("database.selectDeviceAttributes"))
- .executeQuery(DeviceAttribute.class);
- }
-
- public void linkDeviceAttribute(long deviceId, long attributeId) throws SQLException {
- QueryBuilder.create(dataSource, getQuery("database.linkDeviceAttribute"))
- .setLong("deviceId", deviceId)
- .setLong("attributeId", attributeId)
+ 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 unlinkDeviceAttribute(long deviceId, long attributeId) throws SQLException {
- QueryBuilder.create(dataSource, getQuery("database.unlinkDeviceAttribute"))
- .setLong("deviceId", deviceId)
- .setLong("attributeId", attributeId)
+ 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/org/traccar/database/DeviceManager.java b/src/org/traccar/database/DeviceManager.java
index f2a2dd565..1eb90b7eb 100644
--- a/src/org/traccar/database/DeviceManager.java
+++ b/src/org/traccar/database/DeviceManager.java
@@ -16,10 +16,8 @@
package org.traccar.database;
import java.sql.SQLException;
-import java.util.ArrayList;
import java.util.Collection;
import java.util.HashSet;
-import java.util.Iterator;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
@@ -27,137 +25,56 @@ import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.atomic.AtomicLong;
-import org.traccar.BaseProtocol;
import org.traccar.Config;
import org.traccar.Context;
import org.traccar.helper.Log;
-import org.traccar.model.Command;
-import org.traccar.model.CommandType;
import org.traccar.model.Device;
+import org.traccar.model.DeviceState;
import org.traccar.model.DeviceTotalDistance;
import org.traccar.model.Group;
import org.traccar.model.Position;
import org.traccar.model.Server;
-public class DeviceManager implements IdentityManager {
+public class DeviceManager extends BaseObjectManager<Device> implements IdentityManager, ManagableObjects {
public static final long DEFAULT_REFRESH_DELAY = 300;
private final Config config;
- private final DataManager dataManager;
private final long dataRefreshDelay;
private boolean lookupGroupsAttribute;
- private Map<Long, Device> devicesById;
private Map<String, Device> devicesByUniqueId;
private Map<String, Device> devicesByPhone;
private AtomicLong devicesLastUpdate = new AtomicLong();
- private Map<Long, Group> groupsById;
- private AtomicLong groupsLastUpdate = new AtomicLong();
-
private final Map<Long, Position> positions = new ConcurrentHashMap<>();
- private boolean fallbackToText;
+ private final Map<Long, DeviceState> deviceStates = new ConcurrentHashMap<>();
public DeviceManager(DataManager dataManager) {
- this.dataManager = dataManager;
+ super(dataManager, Device.class);
this.config = Context.getConfig();
+ if (devicesByPhone == null) {
+ devicesByPhone = new ConcurrentHashMap<>();
+ }
+ if (devicesByUniqueId == null) {
+ devicesByUniqueId = new ConcurrentHashMap<>();
+ }
dataRefreshDelay = config.getLong("database.refreshDelay", DEFAULT_REFRESH_DELAY) * 1000;
lookupGroupsAttribute = config.getBoolean("deviceManager.lookupGroupsAttribute");
- fallbackToText = config.getBoolean("command.fallbackToSms");
- if (dataManager != null) {
- try {
- updateGroupCache(true);
- updateDeviceCache(true);
- for (Position position : dataManager.getLatestPositions()) {
- positions.put(position.getDeviceId(), position);
- }
- } catch (SQLException error) {
- Log.warning(error);
- }
- }
+ refreshLastPositions();
}
private void updateDeviceCache(boolean force) throws SQLException {
-
long lastUpdate = devicesLastUpdate.get();
if ((force || System.currentTimeMillis() - lastUpdate > dataRefreshDelay)
&& devicesLastUpdate.compareAndSet(lastUpdate, System.currentTimeMillis())) {
- GeofenceManager geofenceManager = Context.getGeofenceManager();
- Collection<Device> databaseDevices = dataManager.getAllDevices();
- if (devicesById == null) {
- devicesById = new ConcurrentHashMap<>(databaseDevices.size());
- }
- if (devicesByUniqueId == null) {
- devicesByUniqueId = new ConcurrentHashMap<>(databaseDevices.size());
- }
- if (devicesByPhone == null) {
- devicesByPhone = new ConcurrentHashMap<>(databaseDevices.size());
- }
- Set<Long> databaseDevicesIds = new HashSet<>();
- Set<String> databaseDevicesUniqueIds = new HashSet<>();
- Set<String> databaseDevicesPhones = new HashSet<>();
- for (Device device : databaseDevices) {
- databaseDevicesIds.add(device.getId());
- databaseDevicesUniqueIds.add(device.getUniqueId());
- databaseDevicesPhones.add(device.getPhone());
- if (devicesById.containsKey(device.getId())) {
- Device cachedDevice = devicesById.get(device.getId());
- cachedDevice.setName(device.getName());
- cachedDevice.setGroupId(device.getGroupId());
- cachedDevice.setCategory(device.getCategory());
- cachedDevice.setContact(device.getContact());
- cachedDevice.setModel(device.getModel());
- cachedDevice.setAttributes(device.getAttributes());
- if (!device.getUniqueId().equals(cachedDevice.getUniqueId())) {
- devicesByUniqueId.put(device.getUniqueId(), cachedDevice);
- }
- cachedDevice.setUniqueId(device.getUniqueId());
- if (device.getPhone() != null && !device.getPhone().isEmpty()
- && !device.getPhone().equals(cachedDevice.getPhone())) {
- devicesByPhone.put(device.getPhone(), cachedDevice);
- }
- cachedDevice.setPhone(device.getPhone());
- } else {
- devicesById.put(device.getId(), device);
- devicesByUniqueId.put(device.getUniqueId(), device);
- if (device.getPhone() != null && !device.getPhone().isEmpty()) {
- devicesByPhone.put(device.getPhone(), device);
- }
- if (geofenceManager != null) {
- Position lastPosition = getLastPosition(device.getId());
- if (lastPosition != null) {
- device.setGeofenceIds(geofenceManager.getCurrentDeviceGeofences(lastPosition));
- }
- }
- }
- }
- for (Iterator<Long> iterator = devicesById.keySet().iterator(); iterator.hasNext();) {
- if (!databaseDevicesIds.contains(iterator.next())) {
- iterator.remove();
- }
- }
- for (Iterator<String> iterator = devicesByUniqueId.keySet().iterator(); iterator.hasNext();) {
- if (!databaseDevicesUniqueIds.contains(iterator.next())) {
- iterator.remove();
- }
- }
- for (Iterator<String> iterator = devicesByPhone.keySet().iterator(); iterator.hasNext();) {
- if (!databaseDevicesPhones.contains(iterator.next())) {
- iterator.remove();
- }
- }
+ refreshItems();
}
}
@Override
- public Device getDeviceById(long id) {
- return devicesById.get(id);
- }
-
- @Override
- public Device getDeviceByUniqueId(String uniqueId) throws SQLException {
+ public Device getByUniqueId(String uniqueId) throws SQLException {
boolean forceUpdate = !devicesByUniqueId.containsKey(uniqueId) && !config.getBoolean("database.ignoreUnknown");
updateDeviceCache(forceUpdate);
@@ -169,76 +86,127 @@ public class DeviceManager implements IdentityManager {
return devicesByPhone.get(phone);
}
+ @Override
+ public Set<Long> getAllItems() {
+ Set<Long> result = super.getAllItems();
+ if (result.isEmpty()) {
+ try {
+ updateDeviceCache(true);
+ } catch (SQLException e) {
+ Log.warning(e);
+ }
+ result = super.getAllItems();
+ }
+ return result;
+ }
+
public Collection<Device> getAllDevices() {
- boolean forceUpdate = devicesById.isEmpty();
+ return getItems(getAllItems());
+ }
- try {
- updateDeviceCache(forceUpdate);
- } catch (SQLException e) {
- Log.warning(e);
+ @Override
+ public Set<Long> getUserItems(long userId) {
+ if (Context.getPermissionsManager() != null) {
+ return Context.getPermissionsManager().getDevicePermissions(userId);
+ } else {
+ return new HashSet<>();
}
-
- return devicesById.values();
}
- public Collection<Device> getDevices(long userId) throws SQLException {
- Collection<Device> devices = new ArrayList<>();
- for (long id : Context.getPermissionsManager().getDevicePermissions(userId)) {
- devices.add(devicesById.get(id));
+ @Override
+ public Set<Long> getManagedItems(long userId) {
+ Set<Long> result = new HashSet<>();
+ result.addAll(getUserItems(userId));
+ for (long managedUserId : Context.getUsersManager().getUserItems(userId)) {
+ result.addAll(getUserItems(managedUserId));
}
- return devices;
+ return result;
}
- public Collection<Device> getManagedDevices(long userId) throws SQLException {
- Collection<Device> devices = new HashSet<>();
- devices.addAll(getDevices(userId));
- for (long managedUserId : Context.getPermissionsManager().getUserPermissions(userId)) {
- devices.addAll(getDevices(managedUserId));
+ private void putUniqueDeviceId(Device device) {
+ if (devicesByUniqueId == null) {
+ devicesByUniqueId = new ConcurrentHashMap<>(getAllItems().size());
}
- return devices;
+ devicesByUniqueId.put(device.getUniqueId(), device);
}
- public void addDevice(Device device) throws SQLException {
- dataManager.addDevice(device);
+ private void putPhone(Device device) {
+ if (devicesByPhone == null) {
+ devicesByPhone = new ConcurrentHashMap<>(getAllItems().size());
+ }
+ devicesByPhone.put(device.getPhone(), device);
+ }
- devicesById.put(device.getId(), device);
- devicesByUniqueId.put(device.getUniqueId(), device);
+ @Override
+ protected void addNewItem(Device device) {
+ super.addNewItem(device);
+ putUniqueDeviceId(device);
if (device.getPhone() != null && !device.getPhone().isEmpty()) {
- devicesByPhone.put(device.getPhone(), device);
+ putPhone(device);
+ }
+ if (Context.getGeofenceManager() != null) {
+ Position lastPosition = getLastPosition(device.getId());
+ if (lastPosition != null) {
+ device.setGeofenceIds(Context.getGeofenceManager().getCurrentDeviceGeofences(lastPosition));
+ }
}
}
- public void updateDevice(Device device) throws SQLException {
- dataManager.updateDevice(device);
+ @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.setAttributes(device.getAttributes());
+ if (!device.getUniqueId().equals(cachedDevice.getUniqueId())) {
+ devicesByUniqueId.remove(cachedDevice.getUniqueId());
+ cachedDevice.setUniqueId(device.getUniqueId());
+ putUniqueDeviceId(cachedDevice);
+ }
+ if (device.getPhone() != null && !device.getPhone().isEmpty()
+ && !device.getPhone().equals(cachedDevice.getPhone())) {
+ devicesByPhone.remove(cachedDevice.getPhone());
+ cachedDevice.setPhone(device.getPhone());
+ putPhone(cachedDevice);
+ }
+ }
- devicesById.put(device.getId(), device);
- devicesByUniqueId.put(device.getUniqueId(), device);
- if (device.getPhone() != null && !device.getPhone().isEmpty()) {
- devicesByPhone.put(device.getPhone(), device);
+ @Override
+ protected void removeCachedItem(long deviceId) {
+ Device cachedDevice = getById(deviceId);
+ if (cachedDevice != null) {
+ String deviceUniqueId = cachedDevice.getUniqueId();
+ String phone = cachedDevice.getPhone();
+ super.removeCachedItem(deviceId);
+ devicesByUniqueId.remove(deviceUniqueId);
+ if (phone != null && !phone.isEmpty()) {
+ devicesByPhone.remove(phone);
+ }
}
+ positions.remove(deviceId);
}
public void updateDeviceStatus(Device device) throws SQLException {
- dataManager.updateDeviceStatus(device);
- if (devicesById.containsKey(device.getId())) {
- Device cachedDevice = devicesById.get(device.getId());
+ getDataManager().updateDeviceStatus(device);
+ Device cachedDevice = getById(device.getId());
+ if (cachedDevice != null) {
cachedDevice.setStatus(device.getStatus());
}
}
- public void removeDevice(long deviceId) throws SQLException {
- dataManager.removeDevice(deviceId);
-
- if (devicesById.containsKey(deviceId)) {
- String deviceUniqueId = devicesById.get(deviceId).getUniqueId();
- String phone = devicesById.get(deviceId).getPhone();
- devicesById.remove(deviceId);
- devicesByUniqueId.remove(deviceUniqueId);
- if (phone != null && !phone.isEmpty()) {
- devicesByPhone.remove(phone);
+ private void refreshLastPositions() {
+ if (getDataManager() != null) {
+ try {
+ for (Position position : getDataManager().getLatestPositions()) {
+ positions.put(position.getDeviceId(), position);
+ }
+ } catch (SQLException error) {
+ Log.warning(error);
}
}
- positions.remove(deviceId);
}
public boolean isLatestPosition(Position position) {
@@ -250,10 +218,11 @@ public class DeviceManager implements IdentityManager {
if (isLatestPosition(position)) {
- dataManager.updateLatestPosition(position);
+ getDataManager().updateLatestPosition(position);
- if (devicesById.containsKey(position.getDeviceId())) {
- devicesById.get(position.getDeviceId()).setPositionId(position.getId());
+ Device device = getById(position.getDeviceId());
+ if (device != null) {
+ device.setPositionId(position.getId());
}
positions.put(position.getDeviceId(), position);
@@ -274,7 +243,7 @@ public class DeviceManager implements IdentityManager {
List<Position> result = new LinkedList<>();
if (Context.getPermissionsManager() != null) {
- for (long deviceId : Context.getPermissionsManager().getDevicePermissions(userId)) {
+ for (long deviceId : getUserItems(userId)) {
if (positions.containsKey(deviceId)) {
result.add(positions.get(deviceId));
}
@@ -284,154 +253,62 @@ public class DeviceManager implements IdentityManager {
return result;
}
- private void updateGroupCache(boolean force) throws SQLException {
-
- long lastUpdate = groupsLastUpdate.get();
- if ((force || System.currentTimeMillis() - lastUpdate > dataRefreshDelay)
- && groupsLastUpdate.compareAndSet(lastUpdate, System.currentTimeMillis())) {
- Collection<Group> databaseGroups = dataManager.getAllGroups();
- if (groupsById == null) {
- groupsById = new ConcurrentHashMap<>(databaseGroups.size());
- }
- Set<Long> databaseGroupsIds = new HashSet<>();
- for (Group group : databaseGroups) {
- databaseGroupsIds.add(group.getId());
- if (groupsById.containsKey(group.getId())) {
- Group cachedGroup = groupsById.get(group.getId());
- cachedGroup.setName(group.getName());
- cachedGroup.setGroupId(group.getGroupId());
- } else {
- groupsById.put(group.getId(), group);
- }
- }
- for (Long cachedGroupId : groupsById.keySet()) {
- if (!databaseGroupsIds.contains(cachedGroupId)) {
- devicesById.remove(cachedGroupId);
- }
- }
- databaseGroupsIds.clear();
- }
- }
-
- public Group getGroupById(long id) {
- return groupsById.get(id);
- }
-
- public Collection<Group> getAllGroups() {
- boolean forceUpdate = groupsById.isEmpty();
-
- try {
- updateGroupCache(forceUpdate);
- } catch (SQLException e) {
- Log.warning(e);
- }
-
- return groupsById.values();
- }
-
- public Collection<Group> getGroups(long userId) throws SQLException {
- Collection<Group> groups = new ArrayList<>();
- for (long id : Context.getPermissionsManager().getGroupPermissions(userId)) {
- groups.add(getGroupById(id));
- }
- return groups;
- }
-
- public Collection<Group> getManagedGroups(long userId) throws SQLException {
- Collection<Group> groups = new ArrayList<>();
- groups.addAll(getGroups(userId));
- for (long managedUserId : Context.getPermissionsManager().getUserPermissions(userId)) {
- groups.addAll(getGroups(managedUserId));
- }
- return groups;
- }
-
- 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 = groupsById.get(group.getGroupId());
- }
- }
-
- public void addGroup(Group group) throws SQLException {
- checkGroupCycles(group);
- dataManager.addGroup(group);
- groupsById.put(group.getId(), group);
- }
-
- public void updateGroup(Group group) throws SQLException {
- checkGroupCycles(group);
- dataManager.updateGroup(group);
- groupsById.put(group.getId(), group);
- }
-
- public void removeGroup(long groupId) throws SQLException {
- dataManager.removeGroup(groupId);
- groupsById.remove(groupId);
- }
-
public boolean lookupAttributeBoolean(
long deviceId, String attributeName, boolean defaultValue, boolean lookupConfig) {
- String result = lookupAttribute(deviceId, attributeName, lookupConfig);
+ Object result = lookupAttribute(deviceId, attributeName, lookupConfig);
if (result != null) {
- return Boolean.parseBoolean(result);
+ return result instanceof String ? Boolean.parseBoolean((String) result) : (Boolean) result;
}
return defaultValue;
}
public String lookupAttributeString(
long deviceId, String attributeName, String defaultValue, boolean lookupConfig) {
- String result = lookupAttribute(deviceId, attributeName, lookupConfig);
- if (result != null) {
- return result;
- }
- return defaultValue;
+ Object result = lookupAttribute(deviceId, attributeName, lookupConfig);
+ return result != null ? (String) result : defaultValue;
}
public int lookupAttributeInteger(long deviceId, String attributeName, int defaultValue, boolean lookupConfig) {
- String result = lookupAttribute(deviceId, attributeName, lookupConfig);
+ Object result = lookupAttribute(deviceId, attributeName, lookupConfig);
if (result != null) {
- return Integer.parseInt(result);
+ return result instanceof String ? Integer.parseInt((String) result) : ((Number) result).intValue();
}
return defaultValue;
}
public long lookupAttributeLong(
long deviceId, String attributeName, long defaultValue, boolean lookupConfig) {
- String result = lookupAttribute(deviceId, attributeName, lookupConfig);
+ Object result = lookupAttribute(deviceId, attributeName, lookupConfig);
if (result != null) {
- return Long.parseLong(result);
+ return result instanceof String ? Long.parseLong((String) result) : ((Number) result).longValue();
}
return defaultValue;
}
public double lookupAttributeDouble(
long deviceId, String attributeName, double defaultValue, boolean lookupConfig) {
- String result = lookupAttribute(deviceId, attributeName, lookupConfig);
+ Object result = lookupAttribute(deviceId, attributeName, lookupConfig);
if (result != null) {
- return Double.parseDouble(result);
+ return result instanceof String ? Double.parseDouble((String) result) : ((Number) result).doubleValue();
}
return defaultValue;
}
- private String lookupAttribute(long deviceId, String attributeName, boolean lookupConfig) {
- String result = null;
- Device device = getDeviceById(deviceId);
+ private Object lookupAttribute(long deviceId, String attributeName, boolean lookupConfig) {
+ Object result = null;
+ Device device = getById(deviceId);
if (device != null) {
- result = device.getString(attributeName);
+ result = device.getAttributes().get(attributeName);
if (result == null && lookupGroupsAttribute) {
long groupId = device.getGroupId();
while (groupId != 0) {
- if (getGroupById(groupId) != null) {
- result = getGroupById(groupId).getString(attributeName);
+ Group group = Context.getGroupsManager().getById(groupId);
+ if (group != null) {
+ result = group.getAttributes().get(attributeName);
if (result != null) {
break;
}
- groupId = getGroupById(groupId).getGroupId();
+ groupId = group.getGroupId();
} else {
groupId = 0;
}
@@ -442,7 +319,7 @@ public class DeviceManager implements IdentityManager {
result = Context.getConfig().getString(attributeName);
} else {
Server server = Context.getPermissionsManager().getServer();
- result = server.getString(attributeName);
+ result = server.getAttributes().get(attributeName);
}
}
}
@@ -453,54 +330,24 @@ public class DeviceManager implements IdentityManager {
Position last = positions.get(deviceTotalDistance.getDeviceId());
if (last != null) {
last.getAttributes().put(Position.KEY_TOTAL_DISTANCE, deviceTotalDistance.getTotalDistance());
- dataManager.addPosition(last);
+ getDataManager().addPosition(last);
updateLatestPosition(last);
} else {
throw new IllegalArgumentException();
}
}
- public void sendCommand(Command command) throws Exception {
- long deviceId = command.getDeviceId();
- if (command.getTextChannel()) {
- Position lastPosition = getLastPosition(deviceId);
- if (lastPosition != null) {
- BaseProtocol protocol = Context.getServerManager().getProtocol(lastPosition.getProtocol());
- protocol.sendTextCommand(devicesById.get(deviceId).getPhone(), command);
- } else if (command.getType().equals(Command.TYPE_CUSTOM)) {
- Context.getSmppManager().sendMessageSync(devicesById.get(deviceId).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) {
- activeDevice.sendCommand(command);
- } else {
- if (fallbackToText) {
- command.setTextChannel(true);
- sendCommand(command);
- } else {
- throw new RuntimeException("Device is not online");
- }
- }
+ public DeviceState getDeviceState(long deviceId) {
+ DeviceState deviceState = deviceStates.get(deviceId);
+ if (deviceState == null) {
+ deviceState = new DeviceState();
+ deviceStates.put(deviceId, deviceState);
}
+ return deviceState;
}
- public Collection<CommandType> getCommandTypes(long deviceId, boolean textChannel) {
- List<CommandType> result = new ArrayList<>();
- Position lastPosition = Context.getDeviceManager().getLastPosition(deviceId);
- if (lastPosition != null) {
- BaseProtocol protocol = Context.getServerManager().getProtocol(lastPosition.getProtocol());
- Collection<String> commands;
- commands = textChannel ? protocol.getSupportedTextCommands() : protocol.getSupportedDataCommands();
- for (String commandKey : commands) {
- result.add(new CommandType(commandKey));
- }
- } else {
- result.add(new CommandType(Command.TYPE_CUSTOM));
- }
- return result;
+ public void setDeviceState(long deviceId, DeviceState deviceState) {
+ deviceStates.put(deviceId, deviceState);
}
+
}
diff --git a/src/org/traccar/database/DriversManager.java b/src/org/traccar/database/DriversManager.java
new file mode 100644
index 000000000..930951460
--- /dev/null
+++ b/src/org/traccar/database/DriversManager.java
@@ -0,0 +1,73 @@
+/*
+ * 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.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);
+ if (driversByUniqueId == null) {
+ driversByUniqueId = new ConcurrentHashMap<>();
+ }
+ }
+
+ private void putUniqueDriverId(Driver driver) {
+ if (driversByUniqueId == null) {
+ driversByUniqueId = new ConcurrentHashMap<>(getAllItems().size());
+ }
+ driversByUniqueId.put(driver.getUniqueId(), driver);
+ }
+
+ @Override
+ protected void addNewItem(Driver driver) {
+ super.addNewItem(driver);
+ putUniqueDriverId(driver);
+ }
+
+ @Override
+ protected void updateCachedItem(Driver driver) {
+ Driver cachedDriver = getById(driver.getId());
+ cachedDriver.setName(driver.getName());
+ if (!driver.getUniqueId().equals(cachedDriver.getUniqueId())) {
+ driversByUniqueId.remove(cachedDriver.getUniqueId());
+ cachedDriver.setUniqueId(driver.getUniqueId());
+ putUniqueDriverId(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);
+ driversByUniqueId.remove(driverUniqueId);
+ }
+ }
+
+ public Driver getDriverByUniqueId(String uniqueId) {
+ return driversByUniqueId.get(uniqueId);
+ }
+}
diff --git a/src/org/traccar/database/ExtendedObjectManager.java b/src/org/traccar/database/ExtendedObjectManager.java
new file mode 100644
index 000000000..16785cb37
--- /dev/null
+++ b/src/org/traccar/database/ExtendedObjectManager.java
@@ -0,0 +1,112 @@
+/*
+ * 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.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.traccar.Context;
+import org.traccar.helper.Log;
+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 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) {
+ if (!groupItems.containsKey(groupId)) {
+ groupItems.put(groupId, new HashSet<Long>());
+ }
+ return groupItems.get(groupId);
+ }
+
+ public final Set<Long> getDeviceItems(long deviceId) {
+ if (!deviceItems.containsKey(deviceId)) {
+ deviceItems.put(deviceId, new HashSet<Long>());
+ }
+ return deviceItems.get(deviceId);
+ }
+
+ public Set<Long> getAllDeviceItems(long deviceId) {
+ if (!deviceItemsWithGroups.containsKey(deviceId)) {
+ deviceItemsWithGroups.put(deviceId, new HashSet<Long>());
+ }
+ return deviceItemsWithGroups.get(deviceId);
+ }
+
+ @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());
+
+ groupItems.clear();
+ for (Permission groupPermission : databaseGroupPermissions) {
+ getGroupItems(groupPermission.getOwnerId()).add(groupPermission.getPropertyId());
+ }
+
+ Collection<Permission> databaseDevicePermissions =
+ getDataManager().getPermissions(Device.class, getBaseClass());
+
+ deviceItems.clear();
+ deviceItemsWithGroups.clear();
+
+ for (Permission devicePermission : databaseDevicePermissions) {
+ getDeviceItems(devicePermission.getOwnerId()).add(devicePermission.getPropertyId());
+ getAllDeviceItems(devicePermission.getOwnerId()).add(devicePermission.getPropertyId());
+ }
+
+ for (Device device : Context.getDeviceManager().getAllDevices()) {
+ long groupId = device.getGroupId();
+ while (groupId != 0) {
+ getAllDeviceItems(device.getId()).addAll(getGroupItems(groupId));
+ Group group = (Group) Context.getGroupsManager().getById(groupId);
+ if (group != null) {
+ groupId = group.getGroupId();
+ } else {
+ groupId = 0;
+ }
+ }
+ }
+
+ } catch (SQLException | ClassNotFoundException error) {
+ Log.warning(error);
+ }
+ }
+ }
+}
diff --git a/src/org/traccar/database/GeofenceManager.java b/src/org/traccar/database/GeofenceManager.java
index b8e6a5d73..a32847cf9 100644
--- a/src/org/traccar/database/GeofenceManager.java
+++ b/src/org/traccar/database/GeofenceManager.java
@@ -15,290 +15,52 @@
*/
package org.traccar.database;
-import java.sql.SQLException;
import java.util.ArrayList;
-import java.util.Collection;
-import java.util.HashMap;
-import java.util.HashSet;
-import java.util.LinkedList;
import java.util.List;
-import java.util.Map;
-import java.util.Set;
-import java.util.concurrent.locks.ReadWriteLock;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
import org.traccar.Context;
-import org.traccar.helper.Log;
import org.traccar.model.Device;
-import org.traccar.model.DeviceGeofence;
import org.traccar.model.Geofence;
-import org.traccar.model.GeofencePermission;
-import org.traccar.model.GroupGeofence;
import org.traccar.model.Position;
-public class GeofenceManager {
-
- private final DataManager dataManager;
-
- private final Map<Long, Geofence> geofences = new HashMap<>();
- private final Map<Long, Set<Long>> userGeofences = new HashMap<>();
- private final Map<Long, Set<Long>> groupGeofences = new HashMap<>();
-
- private final Map<Long, Set<Long>> deviceGeofencesWithGroups = new HashMap<>();
- private final Map<Long, Set<Long>> deviceGeofences = new HashMap<>();
-
- private final ReadWriteLock deviceGeofencesLock = new ReentrantReadWriteLock();
- private final ReadWriteLock geofencesLock = new ReentrantReadWriteLock();
- private final ReadWriteLock groupGeofencesLock = new ReentrantReadWriteLock();
- private final ReadWriteLock userGeofencesLock = new ReentrantReadWriteLock();
+public class GeofenceManager extends ExtendedObjectManager<Geofence> {
public GeofenceManager(DataManager dataManager) {
- this.dataManager = dataManager;
- refreshGeofences();
- }
-
- private Set<Long> getUserGeofences(long userId) {
- if (!userGeofences.containsKey(userId)) {
- userGeofences.put(userId, new HashSet<Long>());
- }
- return userGeofences.get(userId);
- }
-
- public Set<Long> getUserGeofencesIds(long userId) {
- userGeofencesLock.readLock().lock();
- try {
- return getUserGeofences(userId);
- } finally {
- userGeofencesLock.readLock().unlock();
- }
- }
-
- private Set<Long> getGroupGeofences(long groupId) {
- if (!groupGeofences.containsKey(groupId)) {
- groupGeofences.put(groupId, new HashSet<Long>());
- }
- return groupGeofences.get(groupId);
- }
-
- public Set<Long> getGroupGeofencesIds(long groupId) {
- groupGeofencesLock.readLock().lock();
- try {
- return getGroupGeofences(groupId);
- } finally {
- groupGeofencesLock.readLock().unlock();
- }
- }
-
- public Set<Long> getAllDeviceGeofences(long deviceId) {
- deviceGeofencesLock.readLock().lock();
- try {
- return getDeviceGeofences(deviceGeofencesWithGroups, deviceId);
- } finally {
- deviceGeofencesLock.readLock().unlock();
- }
+ super(dataManager, Geofence.class);
}
- public Set<Long> getDeviceGeofencesIds(long deviceId) {
- deviceGeofencesLock.readLock().lock();
- try {
- return getDeviceGeofences(deviceGeofences, deviceId);
- } finally {
- deviceGeofencesLock.readLock().unlock();
- }
+ @Override
+ public final void refreshExtendedPermissions() {
+ super.refreshExtendedPermissions();
+ recalculateDevicesGeofences();
}
- private Set<Long> getDeviceGeofences(Map<Long, Set<Long>> deviceGeofences, long deviceId) {
- if (!deviceGeofences.containsKey(deviceId)) {
- deviceGeofences.put(deviceId, new HashSet<Long>());
- }
- return deviceGeofences.get(deviceId);
- }
-
- public final void refreshGeofences() {
- if (dataManager != null) {
- try {
- geofencesLock.writeLock().lock();
- try {
- geofences.clear();
- for (Geofence geofence : dataManager.getGeofences()) {
- geofences.put(geofence.getId(), geofence);
- }
- } finally {
- geofencesLock.writeLock().unlock();
- }
- } catch (SQLException error) {
- Log.warning(error);
- }
- }
- refreshUserGeofences();
- refresh();
- }
-
- public final void refreshUserGeofences() {
- if (dataManager != null) {
- try {
- userGeofencesLock.writeLock().lock();
- try {
- userGeofences.clear();
- for (GeofencePermission geofencePermission : dataManager.getGeofencePermissions()) {
- getUserGeofences(geofencePermission.getUserId()).add(geofencePermission.getGeofenceId());
- }
- } finally {
- userGeofencesLock.writeLock().unlock();
- }
- } catch (SQLException error) {
- Log.warning(error);
- }
- }
- }
-
- public final void refresh() {
- if (dataManager != null) {
- try {
-
- Collection<GroupGeofence> databaseGroupGeofences = dataManager.getGroupGeofences();
- groupGeofencesLock.writeLock().lock();
- try {
- groupGeofences.clear();
- for (GroupGeofence groupGeofence : databaseGroupGeofences) {
- getGroupGeofences(groupGeofence.getGroupId()).add(groupGeofence.getGeofenceId());
- }
- } finally {
- groupGeofencesLock.writeLock().unlock();
- }
-
- Collection<DeviceGeofence> databaseDeviceGeofences = dataManager.getDeviceGeofences();
- Collection<Device> allDevices = Context.getDeviceManager().getAllDevices();
-
- groupGeofencesLock.readLock().lock();
- deviceGeofencesLock.writeLock().lock();
- try {
- deviceGeofences.clear();
- deviceGeofencesWithGroups.clear();
-
- for (DeviceGeofence deviceGeofence : databaseDeviceGeofences) {
- getDeviceGeofences(deviceGeofences, deviceGeofence.getDeviceId())
- .add(deviceGeofence.getGeofenceId());
- getDeviceGeofences(deviceGeofencesWithGroups, deviceGeofence.getDeviceId())
- .add(deviceGeofence.getGeofenceId());
- }
-
- for (Device device : allDevices) {
- long groupId = device.getGroupId();
- while (groupId != 0) {
- getDeviceGeofences(deviceGeofencesWithGroups,
- device.getId()).addAll(getGroupGeofences(groupId));
- if (Context.getDeviceManager().getGroupById(groupId) != null) {
- groupId = Context.getDeviceManager().getGroupById(groupId).getGroupId();
- } else {
- groupId = 0;
- }
- }
- List<Long> deviceGeofenceIds = device.getGeofenceIds();
- if (deviceGeofenceIds == null) {
- deviceGeofenceIds = new ArrayList<>();
- } else {
- deviceGeofenceIds.clear();
- }
- Position lastPosition = Context.getIdentityManager().getLastPosition(device.getId());
- if (lastPosition != null && deviceGeofencesWithGroups.containsKey(device.getId())) {
- for (long geofenceId : deviceGeofencesWithGroups.get(device.getId())) {
- Geofence geofence = getGeofence(geofenceId);
- if (geofence != null && geofence.getGeometry()
- .containsPoint(lastPosition.getLatitude(), lastPosition.getLongitude())) {
- deviceGeofenceIds.add(geofenceId);
- }
- }
- }
- device.setGeofenceIds(deviceGeofenceIds);
- }
-
- } finally {
- deviceGeofencesLock.writeLock().unlock();
- groupGeofencesLock.readLock().unlock();
- }
-
- } catch (SQLException error) {
- Log.warning(error);
+ 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 final Collection<Geofence> getAllGeofences() {
- geofencesLock.readLock().lock();
- try {
- return geofences.values();
- } finally {
- geofencesLock.readLock().unlock();
- }
- }
-
- public final Set<Long> getAllGeofencesIds() {
- geofencesLock.readLock().lock();
- try {
- return geofences.keySet();
- } finally {
- geofencesLock.readLock().unlock();
- }
- }
-
- public final Set<Long> getManagedGeofencesIds(long userId) {
- Set<Long> geofences = new HashSet<>();
- geofences.addAll(getUserGeofencesIds(userId));
- for (long managedUserId : Context.getPermissionsManager().getUserPermissions(userId)) {
- geofences.addAll(getUserGeofencesIds(managedUserId));
- }
- return geofences;
- }
-
- public final Collection<Geofence> getGeofences(Set<Long> geofencesIds) {
- geofencesLock.readLock().lock();
- try {
- Collection<Geofence> result = new LinkedList<>();
- for (long geofenceId : geofencesIds) {
- result.add(getGeofence(geofenceId));
+ public void recalculateDevicesGeofences() {
+ for (Device device : Context.getDeviceManager().getAllDevices()) {
+ List<Long> deviceGeofenceIds = device.getGeofenceIds();
+ if (deviceGeofenceIds == null) {
+ deviceGeofenceIds = new ArrayList<>();
+ } else {
+ deviceGeofenceIds.clear();
}
- return result;
- } finally {
- geofencesLock.readLock().unlock();
- }
- }
-
- public final Geofence getGeofence(long geofenceId) {
- geofencesLock.readLock().lock();
- try {
- return geofences.get(geofenceId);
- } finally {
- geofencesLock.readLock().unlock();
- }
- }
-
- public final void updateGeofence(Geofence geofence) {
- geofencesLock.writeLock().lock();
- try {
- geofences.put(geofence.getId(), geofence);
- } finally {
- geofencesLock.writeLock().unlock();
- }
- try {
- dataManager.updateGeofence(geofence);
- } catch (SQLException error) {
- Log.warning(error);
- }
- }
-
- public boolean checkGeofence(long userId, long geofenceId) {
- return getUserGeofencesIds(userId).contains(geofenceId);
- }
-
- public List<Long> getCurrentDeviceGeofences(Position position) {
- List<Long> result = new ArrayList<>();
- for (long geofenceId : getAllDeviceGeofences(position.getDeviceId())) {
- if (getGeofence(geofenceId).getGeometry().containsPoint(position.getLatitude(), position.getLongitude())) {
- result.add(geofenceId);
+ Position lastPosition = Context.getIdentityManager().getLastPosition(device.getId());
+ if (lastPosition != null && getAllDeviceItems(device.getId()) != null) {
+ deviceGeofenceIds.addAll(getCurrentDeviceGeofences(lastPosition));
}
+ device.setGeofenceIds(deviceGeofenceIds);
}
- return result;
}
}
diff --git a/src/org/traccar/database/GroupsManager.java b/src/org/traccar/database/GroupsManager.java
new file mode 100644
index 000000000..c0456085b
--- /dev/null
+++ b/src/org/traccar/database/GroupsManager.java
@@ -0,0 +1,103 @@
+/*
+ * 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.sql.SQLException;
+import java.util.HashSet;
+import java.util.Set;
+import java.util.concurrent.atomic.AtomicLong;
+
+import org.traccar.Context;
+import org.traccar.helper.Log;
+import org.traccar.model.Group;
+
+public class GroupsManager extends BaseObjectManager<Group> implements ManagableObjects {
+
+ private AtomicLong groupsLastUpdate = new AtomicLong();
+ private final long dataRefreshDelay;
+
+ public GroupsManager(DataManager dataManager) {
+ super(dataManager, Group.class);
+ dataRefreshDelay = Context.getConfig().getLong("database.refreshDelay",
+ DeviceManager.DEFAULT_REFRESH_DELAY) * 1000;
+ }
+
+ 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());
+ }
+ }
+
+ private void updateGroupCache(boolean force) throws SQLException {
+ long lastUpdate = groupsLastUpdate.get();
+ if ((force || System.currentTimeMillis() - lastUpdate > dataRefreshDelay)
+ && groupsLastUpdate.compareAndSet(lastUpdate, System.currentTimeMillis())) {
+ refreshItems();
+ }
+ }
+
+ @Override
+ public Set<Long> getAllItems() {
+ Set<Long> result = super.getAllItems();
+ if (result.isEmpty()) {
+ try {
+ updateGroupCache(true);
+ } catch (SQLException e) {
+ Log.warning(e);
+ }
+ result = super.getAllItems();
+ }
+ return result;
+ }
+
+ @Override
+ protected void addNewItem(Group group) {
+ checkGroupCycles(group);
+ super.addNewItem(group);
+ }
+
+ @Override
+ protected void updateCachedItem(Group group) {
+ checkGroupCycles(group);
+ super.updateCachedItem(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 = new HashSet<>();
+ result.addAll(getUserItems(userId));
+ for (long managedUserId : Context.getUsersManager().getUserItems(userId)) {
+ result.addAll(getUserItems(managedUserId));
+ }
+ return result;
+ }
+
+}
diff --git a/src/org/traccar/database/IdentityManager.java b/src/org/traccar/database/IdentityManager.java
index c8c593a54..82d905963 100644
--- a/src/org/traccar/database/IdentityManager.java
+++ b/src/org/traccar/database/IdentityManager.java
@@ -20,9 +20,9 @@ import org.traccar.model.Position;
public interface IdentityManager {
- Device getDeviceById(long id);
+ Device getById(long id);
- Device getDeviceByUniqueId(String uniqueId) throws Exception;
+ Device getByUniqueId(String uniqueId) throws Exception;
Position getLastPosition(long deviceId);
diff --git a/src/org/traccar/database/ManagableObjects.java b/src/org/traccar/database/ManagableObjects.java
new file mode 100644
index 000000000..ec9549493
--- /dev/null
+++ b/src/org/traccar/database/ManagableObjects.java
@@ -0,0 +1,27 @@
+/*
+ * 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/org/traccar/database/NotificationManager.java b/src/org/traccar/database/NotificationManager.java
index 48caa615c..73041a23f 100644
--- a/src/org/traccar/database/NotificationManager.java
+++ b/src/org/traccar/database/NotificationManager.java
@@ -1,5 +1,6 @@
/*
* 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.
@@ -18,56 +19,70 @@ package org.traccar.database;
import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
import java.sql.SQLException;
-import java.util.Collection;
-import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
+import java.util.Map.Entry;
import java.util.Set;
-import java.util.concurrent.locks.ReadWriteLock;
-import java.util.concurrent.locks.ReentrantReadWriteLock;
import org.traccar.Context;
import org.traccar.helper.Log;
import org.traccar.model.Event;
import org.traccar.model.Notification;
import org.traccar.model.Position;
+import org.traccar.model.Typed;
import org.traccar.notification.NotificationMail;
import org.traccar.notification.NotificationSms;
-public class NotificationManager {
-
- private final DataManager dataManager;
-
- private final Map<Long, Set<Notification>> userNotifications = new HashMap<>();
-
- private final ReadWriteLock notificationsLock = new ReentrantReadWriteLock();
+public class NotificationManager extends ExtendedObjectManager<Notification> {
public NotificationManager(DataManager dataManager) {
- this.dataManager = dataManager;
- refresh();
+ super(dataManager, Notification.class);
+ }
+
+ private Set<Long> getEffectiveNotifications(long userId, long deviceId) {
+ Set<Long> result = new HashSet<>();
+ Set<Long> deviceNotifications = getAllDeviceItems(deviceId);
+ for (long itemId : getUserItems(userId)) {
+ if (getById(itemId).getAlways() || deviceNotifications.contains(itemId)) {
+ result.add(itemId);
+ }
+ }
+ return result;
}
public void updateEvent(Event event, Position position) {
try {
- dataManager.addEvent(event);
+ getDataManager().addObject(event);
} catch (SQLException error) {
Log.warning(error);
}
- Set<Long> users = Context.getPermissionsManager().getDeviceUsers(event.getDeviceId());
+ long deviceId = event.getDeviceId();
+ Set<Long> users = Context.getPermissionsManager().getDeviceUsers(deviceId);
for (long userId : users) {
if (event.getGeofenceId() == 0 || Context.getGeofenceManager() != null
- && Context.getGeofenceManager().checkGeofence(userId, event.getGeofenceId())) {
- Notification notification = getUserNotificationByType(userId, event.getType());
- if (notification != null) {
- if (notification.getWeb()) {
- Context.getConnectionManager().updateEvent(userId, event);
- }
- if (notification.getMail()) {
- NotificationMail.sendMailAsync(userId, event, position);
+ && Context.getGeofenceManager().checkItemPermission(userId, event.getGeofenceId())) {
+ boolean sentWeb = false;
+ boolean sentMail = false;
+ boolean sentSms = Context.getSmppManager() == null;
+ for (long notificationId : getEffectiveNotifications(userId, deviceId)) {
+ Notification notification = getById(notificationId);
+ if (getById(notificationId).getType().equals(event.getType())) {
+ if (!sentWeb && notification.getWeb()) {
+ Context.getConnectionManager().updateEvent(userId, event);
+ sentWeb = true;
+ }
+ if (!sentMail && notification.getMail()) {
+ NotificationMail.sendMailAsync(userId, event, position);
+ sentMail = true;
+ }
+ if (!sentSms && notification.getSms()) {
+ NotificationSms.sendSmsAsync(userId, event, position);
+ sentSms = true;
+ }
}
- if (notification.getSms()) {
- NotificationSms.sendSmsAsync(userId, event, position);
+ if (sentWeb && sentMail && sentSms) {
+ break;
}
}
}
@@ -77,141 +92,24 @@ public class NotificationManager {
}
}
- public void updateEvents(Collection<Event> events, Position position) {
- for (Event event : events) {
- updateEvent(event, position);
- }
- }
-
- private Set<Notification> getUserNotificationsUnsafe(long userId) {
- if (!userNotifications.containsKey(userId)) {
- userNotifications.put(userId, new HashSet<Notification>());
- }
- return userNotifications.get(userId);
- }
-
- public Set<Notification> getUserNotifications(long userId) {
- notificationsLock.readLock().lock();
- try {
- return getUserNotificationsUnsafe(userId);
- } finally {
- notificationsLock.readLock().unlock();
- }
- }
-
- public final void refresh() {
- if (dataManager != null) {
- try {
- notificationsLock.writeLock().lock();
- try {
- userNotifications.clear();
- for (Notification notification : dataManager.getNotifications()) {
- getUserNotificationsUnsafe(notification.getUserId()).add(notification);
- }
- } finally {
- notificationsLock.writeLock().unlock();
- }
- } catch (SQLException error) {
- Log.warning(error);
- }
- }
- }
-
- public Notification getUserNotificationByType(long userId, String type) {
- notificationsLock.readLock().lock();
- try {
- for (Notification notification : getUserNotificationsUnsafe(userId)) {
- if (notification.getType().equals(type)) {
- return notification;
- }
- }
- } finally {
- notificationsLock.readLock().unlock();
- }
- return null;
- }
-
- public void updateNotification(Notification notification) {
- Notification cachedNotification = getUserNotificationByType(notification.getUserId(), notification.getType());
- if (cachedNotification != null) {
- if (cachedNotification.getWeb() != notification.getWeb()
- || cachedNotification.getMail() != notification.getMail()
- || cachedNotification.getSms() != notification.getSms()) {
- if (!notification.getWeb() && !notification.getMail() && !notification.getSms()) {
- try {
- dataManager.removeNotification(cachedNotification);
- } catch (SQLException error) {
- Log.warning(error);
- }
- notificationsLock.writeLock().lock();
- try {
- getUserNotificationsUnsafe(notification.getUserId()).remove(cachedNotification);
- } finally {
- notificationsLock.writeLock().unlock();
- }
- } else {
- notificationsLock.writeLock().lock();
- try {
- cachedNotification.setWeb(notification.getWeb());
- cachedNotification.setMail(notification.getMail());
- cachedNotification.setSms(notification.getSms());
- cachedNotification.setAttributes(notification.getAttributes());
- } finally {
- notificationsLock.writeLock().unlock();
- }
- try {
- dataManager.updateNotification(cachedNotification);
- } catch (SQLException error) {
- Log.warning(error);
- }
- }
- } else {
- notification.setId(cachedNotification.getId());
- }
- } else if (notification.getWeb() || notification.getMail() || notification.getSms()) {
- try {
- dataManager.addNotification(notification);
- } catch (SQLException error) {
- Log.warning(error);
- }
- notificationsLock.writeLock().lock();
- try {
- getUserNotificationsUnsafe(notification.getUserId()).add(notification);
- } finally {
- notificationsLock.writeLock().unlock();
- }
+ public void updateEvents(Map<Event, Position> events) {
+ for (Entry<Event, Position> event : events.entrySet()) {
+ updateEvent(event.getKey(), event.getValue());
}
}
- public Set<Notification> getAllNotifications() {
- Set<Notification> notifications = new HashSet<>();
- long id = 1;
+ 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 {
- Notification notification = new Notification();
- notification.setType(field.get(null).toString());
- notification.setId(id++);
- notifications.add(notification);
+ types.add(new Typed(field.get(null).toString()));
} catch (IllegalArgumentException | IllegalAccessException error) {
Log.warning(error);
}
}
}
- return notifications;
+ return types;
}
-
- public Collection<Notification> getAllUserNotifications(long userId) {
- Map<String, Notification> notifications = new HashMap<>();
- for (Notification notification : getAllNotifications()) {
- notification.setUserId(userId);
- notifications.put(notification.getType(), notification);
- }
- for (Notification notification : getUserNotifications(userId)) {
- notifications.put(notification.getType(), notification);
- }
- return notifications.values();
- }
-
}
diff --git a/src/org/traccar/database/PermissionsManager.java b/src/org/traccar/database/PermissionsManager.java
index 9a82efd48..07b60ba58 100644
--- a/src/org/traccar/database/PermissionsManager.java
+++ b/src/org/traccar/database/PermissionsManager.java
@@ -17,39 +17,48 @@ package org.traccar.database;
import org.traccar.Context;
import org.traccar.helper.Log;
+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.DevicePermission;
+import org.traccar.model.Driver;
+import org.traccar.model.Geofence;
import org.traccar.model.Group;
-import org.traccar.model.GroupPermission;
+import org.traccar.model.ManagedUser;
+import org.traccar.model.Notification;
+import org.traccar.model.Permission;
import org.traccar.model.Server;
import org.traccar.model.User;
-import org.traccar.model.UserPermission;
-import java.lang.reflect.Method;
import java.sql.SQLException;
-import java.util.ArrayList;
-import java.util.Collection;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
-import java.util.concurrent.ConcurrentHashMap;
public class PermissionsManager {
private final DataManager dataManager;
+ private final UsersManager usersManager;
private volatile Server server;
- private final Map<Long, User> users = new ConcurrentHashMap<>();
- private final Map<String, Long> usersTokens = new HashMap<>();
-
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<>();
- private final Map<Long, Set<Long>> userPermissions = new HashMap<>();
+ public PermissionsManager(DataManager dataManager, UsersManager usersManager) {
+ this.dataManager = dataManager;
+ this.usersManager = usersManager;
+ refreshServer();
+ refreshDeviceAndGroupPermissions();
+ }
+
+ public User getUser(long userId) {
+ return (User) usersManager.getById(userId);
+ }
public Set<Long> getGroupPermissions(long userId) {
if (!groupPermissions.containsKey(userId)) {
@@ -79,76 +88,45 @@ public class PermissionsManager {
return groupDevices.get(groupId);
}
- public Set<Long> getUserPermissions(long userId) {
- if (!userPermissions.containsKey(userId)) {
- userPermissions.put(userId, new HashSet<Long>());
- }
- return userPermissions.get(userId);
- }
-
- public PermissionsManager(DataManager dataManager) {
- this.dataManager = dataManager;
- refreshUsers();
- refreshPermissions();
- refreshUserPermissions();
- }
-
- public final void refreshUsers() {
- users.clear();
- usersTokens.clear();
+ public void refreshServer() {
try {
server = dataManager.getServer();
- for (User user : dataManager.getUsers()) {
- users.put(user.getId(), user);
- if (user.getToken() != null) {
- usersTokens.put(user.getToken(), user.getId());
- }
- }
- } catch (SQLException error) {
- Log.warning(error);
- }
- }
-
- public final void refreshUserPermissions() {
- userPermissions.clear();
- try {
- for (UserPermission permission : dataManager.getUserPermissions()) {
- getUserPermissions(permission.getUserId()).add(permission.getManagedUserId());
- }
} catch (SQLException error) {
Log.warning(error);
}
}
- public final void refreshPermissions() {
+ public final void refreshDeviceAndGroupPermissions() {
groupPermissions.clear();
devicePermissions.clear();
try {
- GroupTree groupTree = new GroupTree(Context.getDeviceManager().getAllGroups(),
+ GroupTree groupTree = new GroupTree(Context.getGroupsManager().getItems(
+ Context.getGroupsManager().getAllItems()),
Context.getDeviceManager().getAllDevices());
- for (GroupPermission permission : dataManager.getGroupPermissions()) {
- Set<Long> userGroupPermissions = getGroupPermissions(permission.getUserId());
- Set<Long> userDevicePermissions = getDevicePermissions(permission.getUserId());
- userGroupPermissions.add(permission.getGroupId());
- for (Group group : groupTree.getGroups(permission.getGroupId())) {
+ 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(permission.getGroupId())) {
+ for (Device device : groupTree.getDevices(groupPermission.getPropertyId())) {
userDevicePermissions.add(device.getId());
}
}
- for (DevicePermission permission : dataManager.getDevicePermissions()) {
- getDevicePermissions(permission.getUserId()).add(permission.getDeviceId());
+
+ for (Permission devicePermission : dataManager.getPermissions(User.class, Device.class)) {
+ getDevicePermissions(devicePermission.getOwnerId()).add(devicePermission.getPropertyId());
}
groupDevices.clear();
- for (Group group : Context.getDeviceManager().getAllGroups()) {
- for (Device device : groupTree.getDevices(group.getId())) {
- getGroupDevices(group.getId()).add(device.getId());
+ for (long groupId : Context.getGroupsManager().getAllItems()) {
+ for (Device device : groupTree.getDevices(groupId)) {
+ getGroupDevices(groupId).add(device.getId());
}
}
- } catch (SQLException error) {
+ } catch (SQLException | ClassNotFoundException error) {
Log.warning(error);
}
@@ -160,48 +138,50 @@ public class PermissionsManager {
}
}
- public boolean isAdmin(long userId) {
- return users.containsKey(userId) && users.get(userId).getAdmin();
+ public boolean getUserAdmin(long userId) {
+ User user = getUser(userId);
+ return user != null && user.getAdmin();
}
public void checkAdmin(long userId) throws SecurityException {
- if (!isAdmin(userId)) {
+ if (!getUserAdmin(userId)) {
throw new SecurityException("Admin access required");
}
}
- public boolean isManager(long userId) {
- return users.containsKey(userId) && users.get(userId).getUserLimit() != 0;
+ public boolean getUserManager(long userId) {
+ User user = getUser(userId);
+ return user != null && user.getUserLimit() != 0;
}
public void checkManager(long userId) throws SecurityException {
- if (!isManager(userId)) {
+ if (!getUserManager(userId)) {
throw new SecurityException("Manager access required");
}
}
public void checkManager(long userId, long managedUserId) throws SecurityException {
checkManager(userId);
- if (!getUserPermissions(userId).contains(managedUserId)) {
+ if (!usersManager.getUserItems(userId).contains(managedUserId)) {
throw new SecurityException("User access denied");
}
}
public void checkUserLimit(long userId) throws SecurityException {
- int userLimit = users.get(userId).getUserLimit();
- if (userLimit != -1 && getUserPermissions(userId).size() >= userLimit) {
+ 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, SQLException {
- int deviceLimit = users.get(userId).getDeviceLimit();
+ int deviceLimit = getUser(userId).getDeviceLimit();
if (deviceLimit != -1) {
int deviceCount = 0;
- if (isManager(userId)) {
- deviceCount = Context.getDeviceManager().getManagedDevices(userId).size();
+ if (getUserManager(userId)) {
+ deviceCount = Context.getDeviceManager().getManagedItems(userId).size();
} else {
- deviceCount = getDevicePermissions(userId).size();
+ deviceCount = Context.getDeviceManager().getUserItems(userId).size();
}
if (deviceCount >= deviceLimit) {
throw new SecurityException("User device limit reached");
@@ -209,28 +189,50 @@ public class PermissionsManager {
}
}
- public boolean isReadonly(long userId) {
- return users.containsKey(userId) && users.get(userId).getReadonly();
+ public boolean getUserReadonly(long userId) {
+ User user = getUser(userId);
+ return user != null && user.getReadonly();
}
- public boolean isDeviceReadonly(long userId) {
- return users.containsKey(userId) && users.get(userId).getDeviceReadonly();
+ 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 (!isAdmin(userId) && (server.getReadonly() || isReadonly(userId))) {
+ if (!getUserAdmin(userId) && (server.getReadonly() || getUserReadonly(userId))) {
throw new SecurityException("Account is readonly");
}
}
public void checkDeviceReadonly(long userId) throws SecurityException {
- if (!isAdmin(userId) && (server.getDeviceReadonly() || isDeviceReadonly(userId))) {
+ 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");
}
@@ -245,9 +247,10 @@ public class PermissionsManager {
|| before.getUserLimit() != after.getUserLimit()) {
checkAdmin(userId);
}
- if (users.containsKey(userId) && users.get(userId).getExpirationTime() != null
+ User user = getUser(userId);
+ if (user != null && user.getExpirationTime() != null
&& (after.getExpirationTime() == null
- || users.get(userId).getExpirationTime().compareTo(after.getExpirationTime()) < 0)) {
+ || user.getExpirationTime().compareTo(after.getExpirationTime()) < 0)) {
checkAdmin(userId);
}
if (before.getReadonly() != after.getReadonly()
@@ -256,22 +259,22 @@ public class PermissionsManager {
if (userId == after.getId()) {
checkAdmin(userId);
}
- if (!isAdmin(userId)) {
+ if (!getUserAdmin(userId)) {
checkManager(userId);
}
}
}
public void checkUser(long userId, long managedUserId) throws SecurityException {
- if (userId != managedUserId && !isAdmin(userId)) {
+ if (userId != managedUserId && !getUserAdmin(userId)) {
checkManager(userId, managedUserId);
}
}
public void checkGroup(long userId, long groupId) throws SecurityException {
- if (!getGroupPermissions(userId).contains(groupId) && !isAdmin(userId)) {
+ if (!getGroupPermissions(userId).contains(groupId) && !getUserAdmin(userId)) {
checkManager(userId);
- for (long managedUserId : getUserPermissions(userId)) {
+ for (long managedUserId : usersManager.getUserItems(userId)) {
if (getGroupPermissions(managedUserId).contains(groupId)) {
return;
}
@@ -281,10 +284,10 @@ public class PermissionsManager {
}
public void checkDevice(long userId, long deviceId) throws SecurityException {
- if (!getDevicePermissions(userId).contains(deviceId) && !isAdmin(userId)) {
+ if (!Context.getDeviceManager().getUserItems(userId).contains(deviceId) && !getUserAdmin(userId)) {
checkManager(userId);
- for (long managedUserId : getUserPermissions(userId)) {
- if (getDevicePermissions(managedUserId).contains(deviceId)) {
+ for (long managedUserId : usersManager.getUserItems(userId)) {
+ if (Context.getDeviceManager().getUserItems(managedUserId).contains(deviceId)) {
return;
}
}
@@ -293,44 +296,105 @@ public class PermissionsManager {
}
public void checkRegistration(long userId) {
- if (!server.getRegistration() && !isAdmin(userId)) {
+ if (!server.getRegistration() && !getUserAdmin(userId)) {
throw new SecurityException("Registration disabled");
}
}
- public void checkGeofence(long userId, long geofenceId) throws SecurityException {
- if (!Context.getGeofenceManager().checkGeofence(userId, geofenceId) && !isAdmin(userId)) {
- checkManager(userId);
- for (long managedUserId : getUserPermissions(userId)) {
- if (Context.getGeofenceManager().checkGeofence(managedUserId, geofenceId)) {
- return;
- }
- }
- throw new SecurityException("Geofence access denied");
+ 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(Notification.class)) {
+ manager = Context.getNotificationManager();
+ } else {
+ throw new IllegalArgumentException("Unknown object type");
}
- }
- public void checkAttribute(long userId, long attributeId) throws SecurityException {
- if (!Context.getAttributesManager().checkAttribute(userId, attributeId) && !isAdmin(userId)) {
+ if (manager != null && !manager.checkItemPermission(userId, objectId) && !getUserAdmin(userId)) {
checkManager(userId);
- for (long managedUserId : getUserPermissions(userId)) {
- if (Context.getAttributesManager().checkAttribute(managedUserId, attributeId)) {
+ for (long managedUserId : usersManager.getManagedItems(userId)) {
+ if (manager.checkItemPermission(managedUserId, objectId)) {
return;
}
}
- throw new SecurityException("Attribute access denied");
- }
- }
-
- public void checkCalendar(long userId, long calendarId) throws SecurityException {
- if (!Context.getCalendarManager().checkCalendar(userId, calendarId) && !isAdmin(userId)) {
- checkManager(userId);
- for (long managedUserId : getUserPermissions(userId)) {
- if (Context.getCalendarManager().checkCalendar(managedUserId, calendarId)) {
- 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();
+ 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();
+ }
+
+ 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(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(Notification.class)
+ && Context.getNotificationManager() != null) {
+ Context.getNotificationManager().refreshExtendedPermissions();
}
- throw new SecurityException("Calendar access denied");
}
}
@@ -339,94 +403,23 @@ public class PermissionsManager {
}
public void updateServer(Server server) throws SQLException {
- dataManager.updateServer(server);
+ dataManager.updateObject(server);
this.server = server;
}
- public Collection<User> getAllUsers() {
- return users.values();
- }
-
- public Collection<User> getUsers(long userId) {
- Collection<User> result = new ArrayList<>();
- for (long managedUserId : getUserPermissions(userId)) {
- result.add(users.get(managedUserId));
- }
- return result;
- }
-
- public Collection<User> getManagedUsers(long userId) {
- Collection<User> result = getUsers(userId);
- result.add(users.get(userId));
- return result;
- }
-
- public User getUser(long userId) {
- return users.get(userId);
- }
-
- public void addUser(User user) throws SQLException {
- dataManager.addUser(user);
- users.put(user.getId(), user);
- if (user.getToken() != null) {
- usersTokens.put(user.getToken(), user.getId());
- }
- refreshPermissions();
- }
-
- public void updateUser(User user) throws SQLException {
- dataManager.updateUser(user);
- User old = users.get(user.getId());
- users.put(user.getId(), user);
- if (user.getToken() != null) {
- usersTokens.put(user.getToken(), user.getId());
- }
- if (old.getToken() != null && !old.getToken().equals(user.getToken())) {
- usersTokens.remove(old.getToken());
- }
- refreshPermissions();
- }
-
- public void removeUser(long userId) throws SQLException {
- dataManager.removeUser(userId);
- usersTokens.remove(users.get(userId).getToken());
- users.remove(userId);
- refreshPermissions();
- refreshUserPermissions();
- }
-
public User login(String email, String password) throws SQLException {
User user = dataManager.login(email, password);
if (user != null) {
checkUserEnabled(user.getId());
- return users.get(user.getId());
+ return getUser(user.getId());
}
return null;
}
- public User getUserByToken(String token) {
- return users.get(usersTokens.get(token));
- }
-
- public Object lookupPreference(long userId, String key, Object defaultValue) {
- String methodName = "get" + key.substring(0, 1).toUpperCase() + key.substring(1);
+ public Object lookupAttribute(long userId, String key, Object defaultValue) {
Object preference;
- Object serverPreference = null;
- Object userPreference = null;
- try {
- Method method = null;
- method = User.class.getMethod(methodName, (Class<?>[]) null);
- if (method != null) {
- userPreference = method.invoke(users.get(userId), (Object[]) null);
- }
- method = null;
- method = Server.class.getMethod(methodName, (Class<?>[]) null);
- if (method != null) {
- serverPreference = method.invoke(server, (Object[]) null);
- }
- } catch (ReflectiveOperationException | SecurityException | IllegalArgumentException exception) {
- return defaultValue;
- }
+ Object serverPreference = server.getAttributes().get(key);
+ Object userPreference = getUser(userId).getAttributes().get(key);
if (server.getForceSettings()) {
preference = serverPreference != null ? serverPreference : userPreference;
} else {
diff --git a/src/org/traccar/database/QueryBuilder.java b/src/org/traccar/database/QueryBuilder.java
index a24e6f0bf..af33458a8 100644
--- a/src/org/traccar/database/QueryBuilder.java
+++ b/src/org/traccar/database/QueryBuilder.java
@@ -19,6 +19,7 @@ import com.fasterxml.jackson.core.JsonProcessingException;
import org.traccar.Context;
import org.traccar.helper.Log;
import org.traccar.model.MiscFormatter;
+import org.traccar.model.Permission;
import javax.sql.DataSource;
import java.io.IOException;
@@ -35,6 +36,7 @@ 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;
@@ -487,4 +489,28 @@ public final class QueryBuilder {
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/org/traccar/database/QueryExtended.java b/src/org/traccar/database/QueryExtended.java
new file mode 100644
index 000000000..07bc2c211
--- /dev/null
+++ b/src/org/traccar/database/QueryExtended.java
@@ -0,0 +1,27 @@
+/*
+ * 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/org/traccar/database/SimpleObjectManager.java b/src/org/traccar/database/SimpleObjectManager.java
new file mode 100644
index 000000000..0b4d11378
--- /dev/null
+++ b/src/org/traccar/database/SimpleObjectManager.java
@@ -0,0 +1,91 @@
+/*
+ * 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.sql.SQLException;
+import java.util.HashSet;
+import java.util.Map;
+import java.util.Set;
+import java.util.concurrent.ConcurrentHashMap;
+
+import org.traccar.Context;
+import org.traccar.helper.Log;
+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 Map<Long, Set<Long>> userItems;
+
+ protected SimpleObjectManager(DataManager dataManager, Class<T> baseClass) {
+ super(dataManager, baseClass);
+ }
+
+ @Override
+ public final Set<Long> getUserItems(long userId) {
+ if (!userItems.containsKey(userId)) {
+ userItems.put(userId, new HashSet<Long>());
+ }
+ return userItems.get(userId);
+ }
+
+ @Override
+ public Set<Long> getManagedItems(long userId) {
+ Set<Long> result = new HashSet<>();
+ result.addAll(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 {
+ if (userItems != null) {
+ userItems.clear();
+ } else {
+ userItems = new ConcurrentHashMap<>();
+ }
+ for (Permission permission : getDataManager().getPermissions(User.class, getBaseClass())) {
+ getUserItems(permission.getOwnerId()).add(permission.getPropertyId());
+ }
+ } catch (SQLException | ClassNotFoundException error) {
+ Log.warning(error);
+ }
+ }
+ }
+
+ @Override
+ public void removeItem(long itemId) throws SQLException {
+ super.removeItem(itemId);
+ refreshUserItems();
+ }
+
+}
diff --git a/src/org/traccar/database/StatisticsManager.java b/src/org/traccar/database/StatisticsManager.java
index 5b42416ad..06a3e7b35 100644
--- a/src/org/traccar/database/StatisticsManager.java
+++ b/src/org/traccar/database/StatisticsManager.java
@@ -61,7 +61,7 @@ public class StatisticsManager {
statistics.setGeolocationRequests(geolocationRequests);
try {
- Context.getDataManager().addStatistics(statistics);
+ Context.getDataManager().addObject(statistics);
} catch (SQLException e) {
Log.warning(e);
}
diff --git a/src/org/traccar/database/UsersManager.java b/src/org/traccar/database/UsersManager.java
new file mode 100644
index 000000000..576a9e6c7
--- /dev/null
+++ b/src/org/traccar/database/UsersManager.java
@@ -0,0 +1,86 @@
+/*
+ * 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.HashSet;
+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 = new HashSet<>();
+ result.addAll(getUserItems(userId));
+ result.add(userId);
+ return result;
+ }
+
+ public User getUserByToken(String token) {
+ return usersTokens.get(token);
+ }
+
+}