From 6c17f85d04b224ff2a09265918765c9f4fc8cf94 Mon Sep 17 00:00:00 2001 From: Abyss777 Date: Wed, 10 May 2017 13:27:49 +0500 Subject: Implement computed attributes --- src/org/traccar/BasePipelineFactory.java | 13 +- src/org/traccar/Context.java | 9 + src/org/traccar/CopyAttributesHandler.java | 45 ----- .../api/resource/AttributePermissionResource.java | 58 ++++++ .../traccar/api/resource/AttributeResource.java | 111 ++++++++++++ .../api/resource/DeviceAttributeResource.java | 58 ++++++ .../api/resource/GroupAttributeResource.java | 58 ++++++ src/org/traccar/database/AttributesManager.java | 199 +++++++++++++++++++++ src/org/traccar/database/DataManager.java | 84 +++++++++ src/org/traccar/database/PermissionsManager.java | 12 ++ src/org/traccar/model/Attribute.java | 71 ++++++++ src/org/traccar/model/AttributePermission.java | 41 +++++ src/org/traccar/model/DeviceAttribute.java | 40 +++++ src/org/traccar/model/GroupAttribute.java | 40 +++++ .../processing/ComputedAttributesHandler.java | 78 ++++++++ .../traccar/processing/CopyAttributesHandler.java | 47 +++++ 16 files changed, 918 insertions(+), 46 deletions(-) delete mode 100644 src/org/traccar/CopyAttributesHandler.java create mode 100644 src/org/traccar/api/resource/AttributePermissionResource.java create mode 100644 src/org/traccar/api/resource/AttributeResource.java create mode 100644 src/org/traccar/api/resource/DeviceAttributeResource.java create mode 100644 src/org/traccar/api/resource/GroupAttributeResource.java create mode 100644 src/org/traccar/database/AttributesManager.java create mode 100644 src/org/traccar/model/Attribute.java create mode 100644 src/org/traccar/model/AttributePermission.java create mode 100644 src/org/traccar/model/DeviceAttribute.java create mode 100644 src/org/traccar/model/GroupAttribute.java create mode 100644 src/org/traccar/processing/ComputedAttributesHandler.java create mode 100644 src/org/traccar/processing/CopyAttributesHandler.java (limited to 'src/org/traccar') diff --git a/src/org/traccar/BasePipelineFactory.java b/src/org/traccar/BasePipelineFactory.java index 620c4729a..11457905d 100644 --- a/src/org/traccar/BasePipelineFactory.java +++ b/src/org/traccar/BasePipelineFactory.java @@ -1,5 +1,5 @@ /* - * Copyright 2012 - 2016 Anton Tananaev (anton@traccar.org) + * Copyright 2012 - 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. @@ -38,6 +38,8 @@ import org.traccar.events.MotionEventHandler; import org.traccar.events.OverspeedEventHandler; import org.traccar.events.AlertEventHandler; import org.traccar.helper.Log; +import org.traccar.processing.ComputedAttributesHandler; +import org.traccar.processing.CopyAttributesHandler; import java.net.InetSocketAddress; @@ -53,6 +55,7 @@ public abstract class BasePipelineFactory implements ChannelPipelineFactory { private GeolocationHandler geolocationHandler; private HemisphereHandler hemisphereHandler; private CopyAttributesHandler copyAttributesHandler; + private ComputedAttributesHandler computedAttributesHandler; private CommandResultEventHandler commandResultEventHandler; private OverspeedEventHandler overspeedEventHandler; @@ -153,6 +156,10 @@ public abstract class BasePipelineFactory implements ChannelPipelineFactory { copyAttributesHandler = new CopyAttributesHandler(); } + if (Context.getConfig().getBoolean("processing.computedAttributes.enable")) { + computedAttributesHandler = new ComputedAttributesHandler(); + } + if (Context.getConfig().getBoolean("event.enable")) { commandResultEventHandler = new CommandResultEventHandler(); overspeedEventHandler = new OverspeedEventHandler(); @@ -209,6 +216,10 @@ public abstract class BasePipelineFactory implements ChannelPipelineFactory { pipeline.addLast("copyAttributes", copyAttributesHandler); } + if (computedAttributesHandler != null) { + pipeline.addLast("computedAttributes", computedAttributesHandler); + } + if (Context.getDataManager() != null) { pipeline.addLast("dataHandler", new DefaultDataHandler()); } diff --git a/src/org/traccar/Context.java b/src/org/traccar/Context.java index bfef3807b..07ede4cad 100644 --- a/src/org/traccar/Context.java +++ b/src/org/traccar/Context.java @@ -27,6 +27,7 @@ import org.apache.velocity.app.VelocityEngine; import org.eclipse.jetty.util.URIUtil; import org.traccar.database.AliasesManager; import org.traccar.database.CalendarManager; +import org.traccar.database.AttributesManager; import org.traccar.database.ConnectionManager; import org.traccar.database.DataManager; import org.traccar.database.DeviceManager; @@ -173,6 +174,12 @@ public final class Context { return aliasesManager; } + private static AttributesManager attributesManager; + + public static AttributesManager getAttributesManager() { + return attributesManager; + } + private static StatisticsManager statisticsManager; public static StatisticsManager getStatisticsManager() { @@ -310,6 +317,8 @@ public final class Context { aliasesManager = new AliasesManager(dataManager); + attributesManager = new AttributesManager(dataManager); + statisticsManager = new StatisticsManager(); if (config.getBoolean("sms.smpp.enable")) { diff --git a/src/org/traccar/CopyAttributesHandler.java b/src/org/traccar/CopyAttributesHandler.java deleted file mode 100644 index 18052d0ea..000000000 --- a/src/org/traccar/CopyAttributesHandler.java +++ /dev/null @@ -1,45 +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; - -import org.traccar.model.Position; - -public class CopyAttributesHandler extends BaseDataHandler { - - private Position getLastPosition(long deviceId) { - if (Context.getIdentityManager() != null) { - return Context.getIdentityManager().getLastPosition(deviceId); - } - return null; - } - - @Override - protected Position handlePosition(Position position) { - String attributesString = Context.getDeviceManager().lookupAttributeString( - position.getDeviceId(), "processing.copyAttributes", null, true); - Position last = getLastPosition(position.getDeviceId()); - if (attributesString != null && last != null) { - for (String attribute : attributesString.split("[ ,]")) { - if (last.getAttributes().containsKey(attribute) && !position.getAttributes().containsKey(attribute)) { - position.getAttributes().put(attribute, last.getAttributes().get(attribute)); - } - } - } - return position; - } - -} diff --git a/src/org/traccar/api/resource/AttributePermissionResource.java b/src/org/traccar/api/resource/AttributePermissionResource.java new file mode 100644 index 000000000..1924bcdf1 --- /dev/null +++ b/src/org/traccar/api/resource/AttributePermissionResource.java @@ -0,0 +1,58 @@ +/* + * 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.api.resource; + +import java.sql.SQLException; + +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +import org.traccar.Context; +import org.traccar.api.BaseResource; +import org.traccar.model.AttributePermission; + +@Path("permissions/attributes") +@Produces(MediaType.APPLICATION_JSON) +@Consumes(MediaType.APPLICATION_JSON) +public class AttributePermissionResource extends BaseResource { + + @POST + public Response add(AttributePermission entity) throws SQLException { + Context.getPermissionsManager().checkReadonly(getUserId()); + Context.getPermissionsManager().checkUser(getUserId(), entity.getUserId()); + Context.getPermissionsManager().checkAttribute(getUserId(), entity.getAttributeId()); + Context.getDataManager().linkAttribute(entity.getUserId(), entity.getAttributeId()); + Context.getAttributesManager().refreshUserAttributes(); + return Response.ok(entity).build(); + } + + @DELETE + public Response remove(AttributePermission entity) throws SQLException { + Context.getPermissionsManager().checkReadonly(getUserId()); + Context.getPermissionsManager().checkUser(getUserId(), entity.getUserId()); + Context.getPermissionsManager().checkAttribute(getUserId(), entity.getAttributeId()); + Context.getDataManager().unlinkAttribute(entity.getUserId(), entity.getAttributeId()); + Context.getAttributesManager().refreshUserAttributes(); + return Response.noContent().build(); + } + +} diff --git a/src/org/traccar/api/resource/AttributeResource.java b/src/org/traccar/api/resource/AttributeResource.java new file mode 100644 index 000000000..7751a9360 --- /dev/null +++ b/src/org/traccar/api/resource/AttributeResource.java @@ -0,0 +1,111 @@ +/* + * 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.api.resource; + +import java.sql.SQLException; +import java.util.Collection; +import java.util.HashSet; +import java.util.Set; + +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.GET; +import javax.ws.rs.POST; +import javax.ws.rs.PUT; +import javax.ws.rs.Path; +import javax.ws.rs.PathParam; +import javax.ws.rs.Produces; +import javax.ws.rs.QueryParam; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +import org.traccar.Context; +import org.traccar.api.BaseResource; +import org.traccar.database.AttributesManager; +import org.traccar.model.Attribute; + +@Path("attributes/computed") +@Produces(MediaType.APPLICATION_JSON) +@Consumes(MediaType.APPLICATION_JSON) +public class AttributeResource extends BaseResource { + + @GET + public Collection get( + @QueryParam("all") boolean all, @QueryParam("userId") long userId, @QueryParam("groupId") long groupId, + @QueryParam("deviceId") long deviceId, @QueryParam("refresh") boolean refresh) throws SQLException { + + AttributesManager attributesManager = Context.getAttributesManager(); + if (refresh) { + attributesManager.refreshAttributes(); + } + + Set result = new HashSet<>(); + if (all) { + if (Context.getPermissionsManager().isAdmin(getUserId())) { + result.addAll(attributesManager.getAllAttributes()); + } else { + Context.getPermissionsManager().checkManager(getUserId()); + result.addAll(attributesManager.getManagedAttributes(getUserId())); + } + } else { + if (userId == 0) { + userId = getUserId(); + } + Context.getPermissionsManager().checkUser(getUserId(), userId); + result.addAll(attributesManager.getUserAttributes(userId)); + } + + if (groupId != 0) { + Context.getPermissionsManager().checkGroup(getUserId(), groupId); + result.retainAll(attributesManager.getGroupAttributes(groupId)); + } + + if (deviceId != 0) { + Context.getPermissionsManager().checkDevice(getUserId(), deviceId); + result.retainAll(attributesManager.getDeviceAttributes(deviceId)); + } + return attributesManager.getAttributes(result); + + } + @POST + public Response add(Attribute entity) throws SQLException { + Context.getPermissionsManager().checkReadonly(getUserId()); + Context.getAttributesManager().addAttribute(entity); + Context.getDataManager().linkAttribute(getUserId(), entity.getId()); + Context.getAttributesManager().refreshUserAttributes(); + return Response.ok(entity).build(); + } + + @Path("{id}") + @PUT + public Response update(Attribute entity) throws SQLException { + Context.getPermissionsManager().checkReadonly(getUserId()); + Context.getPermissionsManager().checkAttribute(getUserId(), entity.getId()); + Context.getAttributesManager().updateAttribute(entity); + return Response.ok(entity).build(); + } + + @Path("{id}") + @DELETE + public Response remove(@PathParam("id") long id) throws SQLException { + Context.getPermissionsManager().checkReadonly(getUserId()); + Context.getPermissionsManager().checkAttribute(getUserId(), id); + Context.getAttributesManager().removeAttribute(id); + return Response.noContent().build(); + } + +} diff --git a/src/org/traccar/api/resource/DeviceAttributeResource.java b/src/org/traccar/api/resource/DeviceAttributeResource.java new file mode 100644 index 000000000..8d80c9235 --- /dev/null +++ b/src/org/traccar/api/resource/DeviceAttributeResource.java @@ -0,0 +1,58 @@ +/* + * 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.api.resource; + +import java.sql.SQLException; + +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +import org.traccar.Context; +import org.traccar.api.BaseResource; +import org.traccar.model.DeviceAttribute; + +@Path("devices/attributes") +@Produces(MediaType.APPLICATION_JSON) +@Consumes(MediaType.APPLICATION_JSON) +public class DeviceAttributeResource extends BaseResource { + + @POST + public Response add(DeviceAttribute entity) throws SQLException { + Context.getPermissionsManager().checkReadonly(getUserId()); + Context.getPermissionsManager().checkDevice(getUserId(), entity.getDeviceId()); + Context.getPermissionsManager().checkAttribute(getUserId(), entity.getAttributeId()); + Context.getDataManager().linkDeviceAttribute(entity.getDeviceId(), entity.getAttributeId()); + Context.getAttributesManager().refresh(); + return Response.ok(entity).build(); + } + + @DELETE + public Response remove(DeviceAttribute entity) throws SQLException { + Context.getPermissionsManager().checkReadonly(getUserId()); + Context.getPermissionsManager().checkDevice(getUserId(), entity.getDeviceId()); + Context.getPermissionsManager().checkGeofence(getUserId(), entity.getAttributeId()); + Context.getDataManager().unlinkDeviceAttribute(entity.getDeviceId(), entity.getAttributeId()); + Context.getAttributesManager().refresh(); + return Response.noContent().build(); + } + +} diff --git a/src/org/traccar/api/resource/GroupAttributeResource.java b/src/org/traccar/api/resource/GroupAttributeResource.java new file mode 100644 index 000000000..84b876d34 --- /dev/null +++ b/src/org/traccar/api/resource/GroupAttributeResource.java @@ -0,0 +1,58 @@ +/* + * 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.api.resource; + +import java.sql.SQLException; + +import javax.ws.rs.Consumes; +import javax.ws.rs.DELETE; +import javax.ws.rs.POST; +import javax.ws.rs.Path; +import javax.ws.rs.Produces; +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +import org.traccar.Context; +import org.traccar.api.BaseResource; +import org.traccar.model.GroupAttribute; + +@Path("groups/attributes") +@Produces(MediaType.APPLICATION_JSON) +@Consumes(MediaType.APPLICATION_JSON) +public class GroupAttributeResource extends BaseResource { + + @POST + public Response add(GroupAttribute entity) throws SQLException { + Context.getPermissionsManager().checkReadonly(getUserId()); + Context.getPermissionsManager().checkGroup(getUserId(), entity.getGroupId()); + Context.getPermissionsManager().checkAttribute(getUserId(), entity.getAttributeId()); + Context.getDataManager().linkGroupAttribute(entity.getGroupId(), entity.getAttributeId()); + Context.getAttributesManager().refresh(); + return Response.ok(entity).build(); + } + + @DELETE + public Response remove(GroupAttribute entity) throws SQLException { + Context.getPermissionsManager().checkReadonly(getUserId()); + Context.getPermissionsManager().checkGroup(getUserId(), entity.getGroupId()); + Context.getPermissionsManager().checkGeofence(getUserId(), entity.getAttributeId()); + Context.getDataManager().unlinkGroupAttribute(entity.getGroupId(), entity.getAttributeId()); + Context.getAttributesManager().refresh(); + return Response.noContent().build(); + } + +} diff --git a/src/org/traccar/database/AttributesManager.java b/src/org/traccar/database/AttributesManager.java new file mode 100644 index 000000000..362d6130f --- /dev/null +++ b/src/org/traccar/database/AttributesManager.java @@ -0,0 +1,199 @@ +/* + * 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.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 attributes = new ConcurrentHashMap<>(); + private final Map> deviceAttributes = new ConcurrentHashMap<>(); + private final Map> deviceAttributesWithGroups = new ConcurrentHashMap<>(); + private final Map> groupAttributes = new ConcurrentHashMap<>(); + private final Map> userAttributes = new ConcurrentHashMap<>(); + + public AttributesManager(DataManager dataManager) { + this.dataManager = dataManager; + refreshAttributes(); + } + + public Set getUserAttributes(long userId) { + if (!userAttributes.containsKey(userId)) { + userAttributes.put(userId, new HashSet()); + } + return userAttributes.get(userId); + } + + public Set getGroupAttributes(long groupId) { + if (!groupAttributes.containsKey(groupId)) { + groupAttributes.put(groupId, new HashSet()); + } + return groupAttributes.get(groupId); + } + + public Set getDeviceAttributes(long deviceId) { + return getDeviceAttributes(deviceAttributes, deviceId); + } + + public Set getAllDeviceAttributes(long deviceId) { + return getDeviceAttributes(deviceAttributesWithGroups, deviceId); + } + + private Set getDeviceAttributes(Map> deviceAttributes, long deviceId) { + if (!deviceAttributes.containsKey(deviceId)) { + deviceAttributes.put(deviceId, new HashSet()); + } + 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 databaseGroupAttributes = dataManager.getGroupAttributes(); + + groupAttributes.clear(); + for (GroupAttribute groupAttribute : databaseGroupAttributes) { + getGroupAttributes(groupAttribute.getGroupId()).add(groupAttribute.getAttributeId()); + } + + Collection databaseDeviceAttributes = dataManager.getDeviceAttributes(); + Collection 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); + } + + public void updateAttribute(Attribute attribute) throws SQLException { + dataManager.updateAttribute(attribute); + Attribute cachedAttribute = attributes.get(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 getAttributes(Set attributeIds) { + Collection result = new LinkedList<>(); + for (long attributeId : attributeIds) { + result.add(getAttribute(attributeId)); + } + return result; + } + + public final Set getAllAttributes() { + return attributes.keySet(); + } + + public final Set getManagedAttributes(long userId) { + Set 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/DataManager.java b/src/org/traccar/database/DataManager.java index 0c5f458a2..acbaac17b 100644 --- a/src/org/traccar/database/DataManager.java +++ b/src/org/traccar/database/DataManager.java @@ -37,13 +37,17 @@ 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.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.Notification; @@ -548,4 +552,84 @@ public class DataManager { .executeUpdate(); } + public Collection getAttributes() throws SQLException { + return QueryBuilder.create(dataSource, getQuery("database.selectAttributes")) + .executeQuery(Attribute.class); + } + + public void addAttribute(Attribute attribute) throws SQLException { + attribute.setId(QueryBuilder.create(dataSource, getQuery("database.insertAttribute"), true) + .setObject(attribute) + .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 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 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 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) + .executeUpdate(); + } + + public void unlinkDeviceAttribute(long deviceId, long attributeId) throws SQLException { + QueryBuilder.create(dataSource, getQuery("database.unlinkDeviceAttribute")) + .setLong("deviceId", deviceId) + .setLong("attributeId", attributeId) + .executeUpdate(); + } + } diff --git a/src/org/traccar/database/PermissionsManager.java b/src/org/traccar/database/PermissionsManager.java index e4bd6f5db..11f147c7c 100644 --- a/src/org/traccar/database/PermissionsManager.java +++ b/src/org/traccar/database/PermissionsManager.java @@ -310,6 +310,18 @@ public class PermissionsManager { } } + public void checkAttribute(long userId, long attributeId) throws SecurityException { + if (!Context.getAttributesManager().checkAttribute(userId, attributeId) && !isAdmin(userId)) { + checkManager(userId); + for (long managedUserId : getUserPermissions(userId)) { + if (Context.getAttributesManager().checkAttribute(managedUserId, attributeId)) { + 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); diff --git a/src/org/traccar/model/Attribute.java b/src/org/traccar/model/Attribute.java new file mode 100644 index 000000000..9c3b5e43b --- /dev/null +++ b/src/org/traccar/model/Attribute.java @@ -0,0 +1,71 @@ +/* + * 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.model; + +public class Attribute { + + private long id; + + public long getId() { + return id; + } + + public void setId(long id) { + this.id = id; + } + + private String description; + + public String getDescription() { + return description; + } + + public void setDescription(String description) { + this.description = description; + } + + private String attribute; + + public String getAttribute() { + return attribute; + } + + public void setAttribute(String attribute) { + this.attribute = attribute; + } + + private String expression; + + public String getExpression() { + return expression; + } + + public void setExpression(String expression) { + this.expression = expression; + } + + private String type; + + public String getType() { + return type; + } + + public void setType(String type) { + this.type = type; + } + +} diff --git a/src/org/traccar/model/AttributePermission.java b/src/org/traccar/model/AttributePermission.java new file mode 100644 index 000000000..fe2fe7b6e --- /dev/null +++ b/src/org/traccar/model/AttributePermission.java @@ -0,0 +1,41 @@ +/* + * 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.model; + +public class AttributePermission { + + private long userId; + + public long getUserId() { + return userId; + } + + public void setUserId(long userId) { + this.userId = userId; + } + + private long attributeId; + + public long getAttributeId() { + return attributeId; + } + + public void setAttributeId(long attributeId) { + this.attributeId = attributeId; + } + +} diff --git a/src/org/traccar/model/DeviceAttribute.java b/src/org/traccar/model/DeviceAttribute.java new file mode 100644 index 000000000..e0ac6dd98 --- /dev/null +++ b/src/org/traccar/model/DeviceAttribute.java @@ -0,0 +1,40 @@ +/* + * 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.model; + +public class DeviceAttribute { + + private long deviceId; + + public long getDeviceId() { + return deviceId; + } + + public void setDeviceId(long deviceId) { + this.deviceId = deviceId; + } + + private long attributeId; + + public long getAttributeId() { + return attributeId; + } + + public void setAttributeId(long attributeId) { + this.attributeId = attributeId; + } +} diff --git a/src/org/traccar/model/GroupAttribute.java b/src/org/traccar/model/GroupAttribute.java new file mode 100644 index 000000000..a7e8a80bc --- /dev/null +++ b/src/org/traccar/model/GroupAttribute.java @@ -0,0 +1,40 @@ +/* + * 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.model; + +public class GroupAttribute { + + private long groupId; + + public long getGroupId() { + return groupId; + } + + public void setGroupId(long groupId) { + this.groupId = groupId; + } + + private long attributeId; + + public long getAttributeId() { + return attributeId; + } + + public void setAttributeId(long attributeId) { + this.attributeId = attributeId; + } +} diff --git a/src/org/traccar/processing/ComputedAttributesHandler.java b/src/org/traccar/processing/ComputedAttributesHandler.java new file mode 100644 index 000000000..ea7c0aa1d --- /dev/null +++ b/src/org/traccar/processing/ComputedAttributesHandler.java @@ -0,0 +1,78 @@ +/* + * 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.processing; + +import java.util.Collection; + +import org.apache.commons.jexl2.JexlEngine; +import org.apache.commons.jexl2.JexlException; +import org.apache.commons.jexl2.MapContext; +import org.traccar.BaseDataHandler; +import org.traccar.Context; +import org.traccar.helper.Log; +import org.traccar.model.Attribute; +import org.traccar.model.Position; + +public class ComputedAttributesHandler extends BaseDataHandler { + + private JexlEngine engine; + + public ComputedAttributesHandler() { + engine = new JexlEngine(); + engine.setStrict(true); + } + + public Object computeAttribute(Attribute attribute, Position position) throws JexlException { + MapContext expressionContext = new MapContext(); + expressionContext.set("position", position); + return engine.createExpression(attribute.getExpression()).evaluate(expressionContext); + } + + @Override + protected Position handlePosition(Position position) { + Collection attributes = Context.getAttributesManager().getAttributes( + Context.getAttributesManager().getAllDeviceAttributes(position.getDeviceId())); + for (Attribute attribute : attributes) { + if (attribute.getAttribute() != null) { + Object result = null; + try { + result = computeAttribute(attribute, position); + } catch (JexlException error) { + Log.warning(error); + } + if (result != null) { + try { + switch (attribute.getType()) { + case "number": + position.getAttributes().put(attribute.getAttribute(), (Number) result); + break; + case "boolean": + position.getAttributes().put(attribute.getAttribute(), (Boolean) result); + break; + default: + position.getAttributes().put(attribute.getAttribute(), result.toString()); + } + } catch (ClassCastException error) { + Log.warning(error); + } + } + } + } + return position; + } + +} diff --git a/src/org/traccar/processing/CopyAttributesHandler.java b/src/org/traccar/processing/CopyAttributesHandler.java new file mode 100644 index 000000000..3a96ca98d --- /dev/null +++ b/src/org/traccar/processing/CopyAttributesHandler.java @@ -0,0 +1,47 @@ +/* + * Copyright 2016 - 2017 Anton Tananaev (anton@traccar.org) + * Copyright 2016 - 2017 Andrey Kunitsyn (andrey@traccar.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.traccar.processing; + +import org.traccar.BaseDataHandler; +import org.traccar.Context; +import org.traccar.model.Position; + +public class CopyAttributesHandler extends BaseDataHandler { + + private Position getLastPosition(long deviceId) { + if (Context.getIdentityManager() != null) { + return Context.getIdentityManager().getLastPosition(deviceId); + } + return null; + } + + @Override + protected Position handlePosition(Position position) { + String attributesString = Context.getDeviceManager().lookupAttributeString( + position.getDeviceId(), "processing.copyAttributes", null, true); + Position last = getLastPosition(position.getDeviceId()); + if (attributesString != null && last != null) { + for (String attribute : attributesString.split("[ ,]")) { + if (last.getAttributes().containsKey(attribute) && !position.getAttributes().containsKey(attribute)) { + position.getAttributes().put(attribute, last.getAttributes().get(attribute)); + } + } + } + return position; + } + +} -- cgit v1.2.3