From 1c73bae2e23242673e0a07cdbc2493700f134ceb Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sun, 13 Feb 2022 23:34:25 -0800 Subject: New storage implementation --- src/main/java/org/traccar/MainEventHandler.java | 4 +- .../java/org/traccar/api/BaseObjectResource.java | 7 +- .../org/traccar/api/SecurityRequestFilter.java | 4 +- .../traccar/api/resource/AttributeResource.java | 9 +- .../org/traccar/api/resource/DeviceResource.java | 3 +- .../org/traccar/api/resource/EventResource.java | 6 +- .../org/traccar/api/resource/PasswordResource.java | 6 +- .../traccar/api/resource/PermissionsResource.java | 10 +- .../org/traccar/api/resource/PositionResource.java | 4 +- .../org/traccar/api/resource/ReportResource.java | 28 +-- .../org/traccar/api/resource/ServerResource.java | 6 +- .../org/traccar/api/resource/SessionResource.java | 6 +- .../traccar/api/resource/StatisticsResource.java | 4 +- .../org/traccar/api/resource/UserResource.java | 3 +- .../org/traccar/database/BaseObjectManager.java | 10 +- .../org/traccar/database/ConnectionManager.java | 6 +- .../java/org/traccar/database/DataManager.java | 265 ++++++++------------- .../java/org/traccar/database/DeviceManager.java | 28 +-- .../traccar/database/ExtendedObjectManager.java | 6 +- .../java/org/traccar/database/GroupsManager.java | 4 +- .../org/traccar/database/NotificationManager.java | 4 +- .../org/traccar/database/PermissionsManager.java | 10 +- .../org/traccar/database/SimpleObjectManager.java | 6 +- .../org/traccar/database/StatisticsManager.java | 4 +- .../java/org/traccar/database/UsersManager.java | 9 + .../java/org/traccar/handler/FilterHandler.java | 4 +- src/main/java/org/traccar/model/Attribute.java | 3 + src/main/java/org/traccar/model/Calendar.java | 2 + src/main/java/org/traccar/model/Command.java | 8 + src/main/java/org/traccar/model/Device.java | 7 +- src/main/java/org/traccar/model/Driver.java | 4 + src/main/java/org/traccar/model/Event.java | 3 + src/main/java/org/traccar/model/Geofence.java | 2 + src/main/java/org/traccar/model/Group.java | 3 + src/main/java/org/traccar/model/Maintenance.java | 3 + src/main/java/org/traccar/model/Notification.java | 4 +- src/main/java/org/traccar/model/Order.java | 3 + src/main/java/org/traccar/model/Position.java | 15 +- src/main/java/org/traccar/model/Server.java | 2 + src/main/java/org/traccar/model/Statistics.java | 3 + src/main/java/org/traccar/model/User.java | 2 + src/main/java/org/traccar/reports/Events.java | 6 +- src/main/java/org/traccar/reports/Route.java | 6 +- src/main/java/org/traccar/reports/Stops.java | 8 +- src/main/java/org/traccar/reports/Summary.java | 8 +- src/main/java/org/traccar/reports/Trips.java | 8 +- .../java/org/traccar/storage/DatabaseStorage.java | 71 ++++-- .../java/org/traccar/storage/QueryBuilder.java | 6 +- src/main/java/org/traccar/storage/Storage.java | 15 +- .../java/org/traccar/storage/query/Columns.java | 22 +- .../java/org/traccar/storage/query/Condition.java | 42 +++- src/main/java/org/traccar/storage/query/Limit.java | 15 ++ .../java/org/traccar/storage/query/Request.java | 22 ++ .../java/org/traccar/database/DataManagerTest.java | 81 ------- 54 files changed, 420 insertions(+), 410 deletions(-) create mode 100644 src/main/java/org/traccar/storage/query/Limit.java delete mode 100644 src/test/java/org/traccar/database/DataManagerTest.java (limited to 'src') diff --git a/src/main/java/org/traccar/MainEventHandler.java b/src/main/java/org/traccar/MainEventHandler.java index 4889f6a2e..a3f6f4105 100644 --- a/src/main/java/org/traccar/MainEventHandler.java +++ b/src/main/java/org/traccar/MainEventHandler.java @@ -27,8 +27,8 @@ import org.traccar.config.Keys; import org.traccar.database.StatisticsManager; import org.traccar.helper.DateUtil; import org.traccar.model.Position; +import org.traccar.storage.StorageException; -import java.sql.SQLException; import java.util.Arrays; import java.util.HashSet; import java.util.LinkedHashSet; @@ -57,7 +57,7 @@ public class MainEventHandler extends ChannelInboundHandlerAdapter { Position position = (Position) msg; try { Context.getDeviceManager().updateLatestPosition(position); - } catch (SQLException error) { + } catch (StorageException error) { LOGGER.warn("Failed to update device", error); } diff --git a/src/main/java/org/traccar/api/BaseObjectResource.java b/src/main/java/org/traccar/api/BaseObjectResource.java index 71f3939cb..22756f62a 100644 --- a/src/main/java/org/traccar/api/BaseObjectResource.java +++ b/src/main/java/org/traccar/api/BaseObjectResource.java @@ -41,6 +41,7 @@ import org.traccar.model.Group; import org.traccar.model.GroupedModel; import org.traccar.model.ScheduledModel; import org.traccar.model.User; +import org.traccar.storage.StorageException; public abstract class BaseObjectResource extends BaseResource { @@ -87,7 +88,7 @@ public abstract class BaseObjectResource extends BaseResour } @POST - public Response add(T entity) throws SQLException { + public Response add(T entity) throws StorageException { Context.getPermissionsManager().checkReadonly(getUserId()); if (baseClass.equals(Device.class)) { Context.getPermissionsManager().checkDeviceReadonly(getUserId()); @@ -120,7 +121,7 @@ public abstract class BaseObjectResource extends BaseResour @Path("{id}") @PUT - public Response update(T entity) throws SQLException { + public Response update(T entity) throws StorageException { Context.getPermissionsManager().checkReadonly(getUserId()); if (baseClass.equals(Device.class)) { Context.getPermissionsManager().checkDeviceReadonly(getUserId()); @@ -150,7 +151,7 @@ public abstract class BaseObjectResource extends BaseResour @Path("{id}") @DELETE - public Response remove(@PathParam("id") long id) throws SQLException { + public Response remove(@PathParam("id") long id) throws StorageException { Context.getPermissionsManager().checkReadonly(getUserId()); if (baseClass.equals(Device.class)) { Context.getPermissionsManager().checkDeviceReadonly(getUserId()); diff --git a/src/main/java/org/traccar/api/SecurityRequestFilter.java b/src/main/java/org/traccar/api/SecurityRequestFilter.java index 33b6b37df..6b190be9f 100644 --- a/src/main/java/org/traccar/api/SecurityRequestFilter.java +++ b/src/main/java/org/traccar/api/SecurityRequestFilter.java @@ -23,6 +23,7 @@ import org.traccar.api.resource.SessionResource; import org.traccar.database.StatisticsManager; import org.traccar.helper.DataConverter; import org.traccar.model.User; +import org.traccar.storage.StorageException; import javax.annotation.security.PermitAll; import javax.servlet.http.HttpServletRequest; @@ -34,7 +35,6 @@ import javax.ws.rs.core.Response; import javax.ws.rs.core.SecurityContext; import java.lang.reflect.Method; import java.nio.charset.StandardCharsets; -import java.sql.SQLException; public class SecurityRequestFilter implements ContainerRequestFilter { @@ -82,7 +82,7 @@ public class SecurityRequestFilter implements ContainerRequestFilter { Main.getInjector().getInstance(StatisticsManager.class).registerRequest(user.getId()); securityContext = new UserSecurityContext(new UserPrincipal(user.getId())); } - } catch (SQLException e) { + } catch (StorageException e) { throw new WebApplicationException(e); } diff --git a/src/main/java/org/traccar/api/resource/AttributeResource.java b/src/main/java/org/traccar/api/resource/AttributeResource.java index de69d871c..d2dc28903 100644 --- a/src/main/java/org/traccar/api/resource/AttributeResource.java +++ b/src/main/java/org/traccar/api/resource/AttributeResource.java @@ -16,8 +16,6 @@ */ package org.traccar.api.resource; -import java.sql.SQLException; - import javax.ws.rs.Consumes; import javax.ws.rs.DELETE; import javax.ws.rs.POST; @@ -34,6 +32,7 @@ import org.traccar.api.ExtendedObjectResource; import org.traccar.model.Attribute; import org.traccar.model.Position; import org.traccar.handler.ComputedAttributesHandler; +import org.traccar.storage.StorageException; @Path("attributes/computed") @Produces(MediaType.APPLICATION_JSON) @@ -75,21 +74,21 @@ public class AttributeResource extends ExtendedObjectResource { } @POST - public Response add(Attribute entity) throws SQLException { + public Response add(Attribute entity) throws StorageException { Context.getPermissionsManager().checkAdmin(getUserId()); return super.add(entity); } @Path("{id}") @PUT - public Response update(Attribute entity) throws SQLException { + public Response update(Attribute entity) throws StorageException { Context.getPermissionsManager().checkAdmin(getUserId()); return super.update(entity); } @Path("{id}") @DELETE - public Response remove(@PathParam("id") long id) throws SQLException { + public Response remove(@PathParam("id") long id) throws StorageException { Context.getPermissionsManager().checkAdmin(getUserId()); return super.remove(id); } diff --git a/src/main/java/org/traccar/api/resource/DeviceResource.java b/src/main/java/org/traccar/api/resource/DeviceResource.java index 7006cdb84..9436b59f6 100644 --- a/src/main/java/org/traccar/api/resource/DeviceResource.java +++ b/src/main/java/org/traccar/api/resource/DeviceResource.java @@ -21,6 +21,7 @@ import org.traccar.database.DeviceManager; import org.traccar.helper.LogAction; import org.traccar.model.Device; import org.traccar.model.DeviceAccumulators; +import org.traccar.storage.StorageException; import javax.ws.rs.Consumes; import javax.ws.rs.GET; @@ -87,7 +88,7 @@ public class DeviceResource extends BaseObjectResource { @Path("{id}/accumulators") @PUT - public Response updateAccumulators(DeviceAccumulators entity) throws SQLException { + public Response updateAccumulators(DeviceAccumulators entity) throws StorageException { if (!Context.getPermissionsManager().getUserAdmin(getUserId())) { Context.getPermissionsManager().checkManager(getUserId()); Context.getPermissionsManager().checkPermission(Device.class, getUserId(), entity.getDeviceId()); diff --git a/src/main/java/org/traccar/api/resource/EventResource.java b/src/main/java/org/traccar/api/resource/EventResource.java index 34e4a94ce..354d96e4f 100644 --- a/src/main/java/org/traccar/api/resource/EventResource.java +++ b/src/main/java/org/traccar/api/resource/EventResource.java @@ -15,8 +15,6 @@ */ package org.traccar.api.resource; -import java.sql.SQLException; - import javax.ws.rs.Consumes; import javax.ws.rs.GET; import javax.ws.rs.Path; @@ -31,16 +29,16 @@ import org.traccar.api.BaseResource; import org.traccar.model.Event; import org.traccar.model.Geofence; import org.traccar.model.Maintenance; +import org.traccar.storage.StorageException; @Path("events") @Produces(MediaType.APPLICATION_JSON) @Consumes(MediaType.APPLICATION_JSON) - public class EventResource extends BaseResource { @Path("{id}") @GET - public Event get(@PathParam("id") long id) throws SQLException { + public Event get(@PathParam("id") long id) throws StorageException { Event event = Context.getDataManager().getObject(Event.class, id); if (event == null) { throw new WebApplicationException(Response.status(Response.Status.NOT_FOUND).build()); diff --git a/src/main/java/org/traccar/api/resource/PasswordResource.java b/src/main/java/org/traccar/api/resource/PasswordResource.java index 1868a6191..0642ff3cc 100644 --- a/src/main/java/org/traccar/api/resource/PasswordResource.java +++ b/src/main/java/org/traccar/api/resource/PasswordResource.java @@ -21,6 +21,7 @@ import org.traccar.api.BaseResource; import org.traccar.model.User; import org.traccar.notification.NotificationMessage; import org.traccar.notification.TextTemplateFormatter; +import org.traccar.storage.StorageException; import javax.annotation.security.PermitAll; import javax.mail.MessagingException; @@ -31,7 +32,6 @@ import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; -import java.sql.SQLException; import java.util.UUID; @Path("password") @@ -44,7 +44,7 @@ public class PasswordResource extends BaseResource { @Path("reset") @PermitAll @POST - public Response reset(@FormParam("email") String email) throws SQLException, MessagingException { + public Response reset(@FormParam("email") String email) throws StorageException, MessagingException { for (long userId : Context.getUsersManager().getAllItems()) { User user = Context.getUsersManager().getById(userId); if (email.equals(user.getEmail())) { @@ -66,7 +66,7 @@ public class PasswordResource extends BaseResource { @PermitAll @POST public Response update( - @FormParam("token") String token, @FormParam("password") String password) throws SQLException { + @FormParam("token") String token, @FormParam("password") String password) throws StorageException { for (long userId : Context.getUsersManager().getAllItems()) { User user = Context.getUsersManager().getById(userId); if (token.equals(user.getString(PASSWORD_RESET_TOKEN))) { diff --git a/src/main/java/org/traccar/api/resource/PermissionsResource.java b/src/main/java/org/traccar/api/resource/PermissionsResource.java index 54d3964b6..7def38919 100644 --- a/src/main/java/org/traccar/api/resource/PermissionsResource.java +++ b/src/main/java/org/traccar/api/resource/PermissionsResource.java @@ -16,7 +16,6 @@ */ package org.traccar.api.resource; -import java.sql.SQLException; import java.util.Collections; import java.util.LinkedHashMap; import java.util.List; @@ -37,6 +36,7 @@ import org.traccar.helper.LogAction; import org.traccar.model.Device; import org.traccar.model.Permission; import org.traccar.model.User; +import org.traccar.storage.StorageException; @Path("permissions") @Produces(MediaType.APPLICATION_JSON) @@ -71,7 +71,7 @@ public class PermissionsResource extends BaseResource { @Path("bulk") @POST - public Response add(List> entities) throws SQLException, ClassNotFoundException { + public Response add(List> entities) throws StorageException, ClassNotFoundException { Context.getPermissionsManager().checkReadonly(getUserId()); checkPermissionTypes(entities); for (LinkedHashMap entity: entities) { @@ -89,13 +89,13 @@ public class PermissionsResource extends BaseResource { } @POST - public Response add(LinkedHashMap entity) throws SQLException, ClassNotFoundException { + public Response add(LinkedHashMap entity) throws StorageException, ClassNotFoundException { return add(Collections.singletonList(entity)); } @DELETE @Path("bulk") - public Response remove(List> entities) throws SQLException, ClassNotFoundException { + public Response remove(List> entities) throws StorageException, ClassNotFoundException { Context.getPermissionsManager().checkReadonly(getUserId()); checkPermissionTypes(entities); for (LinkedHashMap entity: entities) { @@ -113,7 +113,7 @@ public class PermissionsResource extends BaseResource { } @DELETE - public Response remove(LinkedHashMap entity) throws SQLException, ClassNotFoundException { + public Response remove(LinkedHashMap entity) throws StorageException, ClassNotFoundException { return remove(Collections.singletonList(entity)); } diff --git a/src/main/java/org/traccar/api/resource/PositionResource.java b/src/main/java/org/traccar/api/resource/PositionResource.java index 53157197b..511032402 100644 --- a/src/main/java/org/traccar/api/resource/PositionResource.java +++ b/src/main/java/org/traccar/api/resource/PositionResource.java @@ -18,6 +18,7 @@ package org.traccar.api.resource; import org.traccar.Context; import org.traccar.api.BaseResource; import org.traccar.model.Position; +import org.traccar.storage.StorageException; import javax.ws.rs.Consumes; import javax.ws.rs.GET; @@ -25,7 +26,6 @@ import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; import javax.ws.rs.core.MediaType; -import java.sql.SQLException; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; @@ -41,7 +41,7 @@ public class PositionResource extends BaseResource { public Collection getJson( @QueryParam("deviceId") long deviceId, @QueryParam("id") List positionIds, @QueryParam("from") Date from, @QueryParam("to") Date to) - throws SQLException { + throws StorageException { if (!positionIds.isEmpty()) { ArrayList positions = new ArrayList<>(); for (Long positionId : positionIds) { diff --git a/src/main/java/org/traccar/api/resource/ReportResource.java b/src/main/java/org/traccar/api/resource/ReportResource.java index 23ffaf54c..03df0d03a 100644 --- a/src/main/java/org/traccar/api/resource/ReportResource.java +++ b/src/main/java/org/traccar/api/resource/ReportResource.java @@ -18,7 +18,6 @@ package org.traccar.api.resource; import java.io.ByteArrayOutputStream; import java.io.IOException; -import java.sql.SQLException; import java.util.Collection; import java.util.Date; import java.util.List; @@ -51,6 +50,7 @@ import org.traccar.reports.model.SummaryReport; import org.traccar.reports.model.TripReport; import org.traccar.reports.Route; import org.traccar.reports.Stops; +import org.traccar.storage.StorageException; @Path("reports") @Produces(MediaType.APPLICATION_JSON) @@ -63,11 +63,11 @@ public class ReportResource extends BaseResource { private static final String CONTENT_DISPOSITION_VALUE_XLSX = "attachment; filename=report.xlsx"; private interface ReportExecutor { - void execute(ByteArrayOutputStream stream) throws SQLException, IOException; + void execute(ByteArrayOutputStream stream) throws StorageException, IOException; } private Response executeReport( - long userId, boolean mail, ReportExecutor executor) throws SQLException, IOException { + long userId, boolean mail, ReportExecutor executor) throws StorageException, IOException { final ByteArrayOutputStream stream = new ByteArrayOutputStream(); if (mail) { new Thread(() -> { @@ -82,7 +82,7 @@ public class ReportResource extends BaseResource { Context.getMailManager().sendMessage( userId, "Report", "The report is in the attachment.", attachment); - } catch (SQLException | IOException | MessagingException e) { + } catch (StorageException | IOException | MessagingException e) { LOGGER.warn("Report failed", e); } }).start(); @@ -98,7 +98,7 @@ public class ReportResource extends BaseResource { @GET public Collection getRoute( @QueryParam("deviceId") final List deviceIds, @QueryParam("groupId") final List groupIds, - @QueryParam("from") Date from, @QueryParam("to") Date to) throws SQLException { + @QueryParam("from") Date from, @QueryParam("to") Date to) throws StorageException { Context.getPermissionsManager().checkDisableReports(getUserId()); LogAction.logReport(getUserId(), "route", from, to, deviceIds, groupIds); return Route.getObjects(getUserId(), deviceIds, groupIds, from, to); @@ -110,7 +110,7 @@ public class ReportResource extends BaseResource { public Response getRouteExcel( @QueryParam("deviceId") final List deviceIds, @QueryParam("groupId") final List groupIds, @QueryParam("from") Date from, @QueryParam("to") Date to, @QueryParam("mail") boolean mail) - throws SQLException, IOException { + throws StorageException, IOException { Context.getPermissionsManager().checkDisableReports(getUserId()); return executeReport(getUserId(), mail, stream -> { LogAction.logReport(getUserId(), "route", from, to, deviceIds, groupIds); @@ -123,7 +123,7 @@ public class ReportResource extends BaseResource { public Collection getEvents( @QueryParam("deviceId") final List deviceIds, @QueryParam("groupId") final List groupIds, @QueryParam("type") final List types, - @QueryParam("from") Date from, @QueryParam("to") Date to) throws SQLException { + @QueryParam("from") Date from, @QueryParam("to") Date to) throws StorageException { Context.getPermissionsManager().checkDisableReports(getUserId()); LogAction.logReport(getUserId(), "events", from, to, deviceIds, groupIds); return Events.getObjects(getUserId(), deviceIds, groupIds, types, from, to); @@ -136,7 +136,7 @@ public class ReportResource extends BaseResource { @QueryParam("deviceId") final List deviceIds, @QueryParam("groupId") final List groupIds, @QueryParam("type") final List types, @QueryParam("from") Date from, @QueryParam("to") Date to, @QueryParam("mail") boolean mail) - throws SQLException, IOException { + throws StorageException, IOException { Context.getPermissionsManager().checkDisableReports(getUserId()); return executeReport(getUserId(), mail, stream -> { LogAction.logReport(getUserId(), "events", from, to, deviceIds, groupIds); @@ -149,7 +149,7 @@ public class ReportResource extends BaseResource { public Collection getSummary( @QueryParam("deviceId") final List deviceIds, @QueryParam("groupId") final List groupIds, @QueryParam("from") Date from, @QueryParam("to") Date to, @QueryParam("daily") boolean daily) - throws SQLException { + throws StorageException { Context.getPermissionsManager().checkDisableReports(getUserId()); LogAction.logReport(getUserId(), "summary", from, to, deviceIds, groupIds); return Summary.getObjects(getUserId(), deviceIds, groupIds, from, to, daily); @@ -162,7 +162,7 @@ public class ReportResource extends BaseResource { @QueryParam("deviceId") final List deviceIds, @QueryParam("groupId") final List groupIds, @QueryParam("from") Date from, @QueryParam("to") Date to, @QueryParam("daily") boolean daily, @QueryParam("mail") boolean mail) - throws SQLException, IOException { + throws StorageException, IOException { Context.getPermissionsManager().checkDisableReports(getUserId()); return executeReport(getUserId(), mail, stream -> { LogAction.logReport(getUserId(), "summary", from, to, deviceIds, groupIds); @@ -175,7 +175,7 @@ public class ReportResource extends BaseResource { @Produces(MediaType.APPLICATION_JSON) public Collection getTrips( @QueryParam("deviceId") final List deviceIds, @QueryParam("groupId") final List groupIds, - @QueryParam("from") Date from, @QueryParam("to") Date to) throws SQLException { + @QueryParam("from") Date from, @QueryParam("to") Date to) throws StorageException { Context.getPermissionsManager().checkDisableReports(getUserId()); LogAction.logReport(getUserId(), "trips", from, to, deviceIds, groupIds); return Trips.getObjects(getUserId(), deviceIds, groupIds, from, to); @@ -187,7 +187,7 @@ public class ReportResource extends BaseResource { public Response getTripsExcel( @QueryParam("deviceId") final List deviceIds, @QueryParam("groupId") final List groupIds, @QueryParam("from") Date from, @QueryParam("to") Date to, @QueryParam("mail") boolean mail) - throws SQLException, IOException { + throws StorageException, IOException { Context.getPermissionsManager().checkDisableReports(getUserId()); return executeReport(getUserId(), mail, stream -> { LogAction.logReport(getUserId(), "trips", from, to, deviceIds, groupIds); @@ -200,7 +200,7 @@ public class ReportResource extends BaseResource { @Produces(MediaType.APPLICATION_JSON) public Collection getStops( @QueryParam("deviceId") final List deviceIds, @QueryParam("groupId") final List groupIds, - @QueryParam("from") Date from, @QueryParam("to") Date to) throws SQLException { + @QueryParam("from") Date from, @QueryParam("to") Date to) throws StorageException { Context.getPermissionsManager().checkDisableReports(getUserId()); LogAction.logReport(getUserId(), "stops", from, to, deviceIds, groupIds); return Stops.getObjects(getUserId(), deviceIds, groupIds, from, to); @@ -212,7 +212,7 @@ public class ReportResource extends BaseResource { public Response getStopsExcel( @QueryParam("deviceId") final List deviceIds, @QueryParam("groupId") final List groupIds, @QueryParam("from") Date from, @QueryParam("to") Date to, @QueryParam("mail") boolean mail) - throws SQLException, IOException { + throws StorageException, IOException { Context.getPermissionsManager().checkDisableReports(getUserId()); return executeReport(getUserId(), mail, stream -> { LogAction.logReport(getUserId(), "stops", from, to, deviceIds, groupIds); diff --git a/src/main/java/org/traccar/api/resource/ServerResource.java b/src/main/java/org/traccar/api/resource/ServerResource.java index 91488afff..8096c66fa 100644 --- a/src/main/java/org/traccar/api/resource/ServerResource.java +++ b/src/main/java/org/traccar/api/resource/ServerResource.java @@ -19,6 +19,7 @@ import org.traccar.Context; import org.traccar.api.BaseResource; import org.traccar.helper.LogAction; import org.traccar.model.Server; +import org.traccar.storage.StorageException; import javax.annotation.security.PermitAll; import javax.ws.rs.Consumes; @@ -29,7 +30,6 @@ import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; -import java.sql.SQLException; @Path("server") @Produces(MediaType.APPLICATION_JSON) @@ -38,7 +38,7 @@ public class ServerResource extends BaseResource { @PermitAll @GET - public Server get(@QueryParam("force") boolean force) throws SQLException { + public Server get(@QueryParam("force") boolean force) throws StorageException { if (force) { return Context.getDataManager().getServer(); } else { @@ -47,7 +47,7 @@ public class ServerResource extends BaseResource { } @PUT - public Response update(Server entity) throws SQLException { + public Response update(Server entity) throws StorageException { Context.getPermissionsManager().checkAdmin(getUserId()); Context.getPermissionsManager().updateServer(entity); LogAction.edit(getUserId(), entity); diff --git a/src/main/java/org/traccar/api/resource/SessionResource.java b/src/main/java/org/traccar/api/resource/SessionResource.java index 60ce5490a..8422e0b49 100644 --- a/src/main/java/org/traccar/api/resource/SessionResource.java +++ b/src/main/java/org/traccar/api/resource/SessionResource.java @@ -21,6 +21,7 @@ import org.traccar.helper.DataConverter; import org.traccar.helper.ServletHelper; import org.traccar.helper.LogAction; import org.traccar.model.User; +import org.traccar.storage.StorageException; import javax.annotation.security.PermitAll; import javax.servlet.http.Cookie; @@ -40,7 +41,6 @@ import javax.ws.rs.core.Response; import java.io.UnsupportedEncodingException; import java.net.URLDecoder; import java.nio.charset.StandardCharsets; -import java.sql.SQLException; @Path("session") @Produces(MediaType.APPLICATION_JSON) @@ -56,7 +56,7 @@ public class SessionResource extends BaseResource { @PermitAll @GET - public User get(@QueryParam("token") String token) throws SQLException, UnsupportedEncodingException { + public User get(@QueryParam("token") String token) throws StorageException, UnsupportedEncodingException { if (token != null) { User user = Context.getUsersManager().getUserByToken(token); @@ -107,7 +107,7 @@ public class SessionResource extends BaseResource { @PermitAll @POST public User add( - @FormParam("email") String email, @FormParam("password") String password) throws SQLException { + @FormParam("email") String email, @FormParam("password") String password) throws StorageException { User user = Context.getPermissionsManager().login(email, password); if (user != null) { request.getSession().setAttribute(USER_ID_KEY, user.getId()); diff --git a/src/main/java/org/traccar/api/resource/StatisticsResource.java b/src/main/java/org/traccar/api/resource/StatisticsResource.java index 58073e7d1..5c0734877 100644 --- a/src/main/java/org/traccar/api/resource/StatisticsResource.java +++ b/src/main/java/org/traccar/api/resource/StatisticsResource.java @@ -18,6 +18,7 @@ package org.traccar.api.resource; import org.traccar.Context; import org.traccar.api.BaseResource; import org.traccar.model.Statistics; +import org.traccar.storage.StorageException; import javax.ws.rs.Consumes; import javax.ws.rs.GET; @@ -25,7 +26,6 @@ import javax.ws.rs.Path; import javax.ws.rs.Produces; import javax.ws.rs.QueryParam; import javax.ws.rs.core.MediaType; -import java.sql.SQLException; import java.util.Collection; import java.util.Date; @@ -36,7 +36,7 @@ public class StatisticsResource extends BaseResource { @GET public Collection get( - @QueryParam("from") Date from, @QueryParam("to") Date to) throws SQLException { + @QueryParam("from") Date from, @QueryParam("to") Date to) throws StorageException { Context.getPermissionsManager().checkAdmin(getUserId()); return Context.getDataManager().getStatistics(from, to); } diff --git a/src/main/java/org/traccar/api/resource/UserResource.java b/src/main/java/org/traccar/api/resource/UserResource.java index d54cc2382..83bb8fd0b 100644 --- a/src/main/java/org/traccar/api/resource/UserResource.java +++ b/src/main/java/org/traccar/api/resource/UserResource.java @@ -22,6 +22,7 @@ import org.traccar.database.UsersManager; import org.traccar.helper.LogAction; import org.traccar.model.ManagedUser; import org.traccar.model.User; +import org.traccar.storage.StorageException; import javax.annotation.security.PermitAll; import javax.ws.rs.Consumes; @@ -67,7 +68,7 @@ public class UserResource extends BaseObjectResource { @Override @PermitAll @POST - public Response add(User entity) throws SQLException { + public Response add(User entity) throws StorageException { if (!Context.getPermissionsManager().getUserAdmin(getUserId())) { Context.getPermissionsManager().checkUserUpdate(getUserId(), new User(), entity); if (Context.getPermissionsManager().getUserManager(getUserId())) { diff --git a/src/main/java/org/traccar/database/BaseObjectManager.java b/src/main/java/org/traccar/database/BaseObjectManager.java index be6310033..dd8b3bae4 100644 --- a/src/main/java/org/traccar/database/BaseObjectManager.java +++ b/src/main/java/org/traccar/database/BaseObjectManager.java @@ -16,7 +16,6 @@ */ package org.traccar.database; -import java.sql.SQLException; import java.util.Collection; import java.util.HashSet; import java.util.LinkedList; @@ -29,6 +28,7 @@ import java.util.concurrent.locks.ReentrantReadWriteLock; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.traccar.model.BaseModel; +import org.traccar.storage.StorageException; public class BaseObjectManager { @@ -102,7 +102,7 @@ public class BaseObjectManager { removeCachedItem(cachedItemId); } } - } catch (SQLException error) { + } catch (StorageException error) { LOGGER.warn("Error refreshing items", error); } finally { writeUnlock(); @@ -119,7 +119,7 @@ public class BaseObjectManager { } } - public void addItem(T item) throws SQLException { + public void addItem(T item) throws StorageException { dataManager.addObject(item); addNewItem(item); } @@ -133,7 +133,7 @@ public class BaseObjectManager { } } - public void updateItem(T item) throws SQLException { + public void updateItem(T item) throws StorageException { dataManager.updateObject(item); updateCachedItem(item); } @@ -147,7 +147,7 @@ public class BaseObjectManager { } } - public void removeItem(long itemId) throws SQLException { + public void removeItem(long itemId) throws StorageException { BaseModel item = getById(itemId); if (item != null) { dataManager.removeObject(baseClass, itemId); diff --git a/src/main/java/org/traccar/database/ConnectionManager.java b/src/main/java/org/traccar/database/ConnectionManager.java index e12d44612..359061f00 100644 --- a/src/main/java/org/traccar/database/ConnectionManager.java +++ b/src/main/java/org/traccar/database/ConnectionManager.java @@ -30,9 +30,9 @@ import org.traccar.model.Device; import org.traccar.model.DeviceState; import org.traccar.model.Event; import org.traccar.model.Position; +import org.traccar.storage.StorageException; import java.net.SocketAddress; -import java.sql.SQLException; import java.util.Date; import java.util.HashMap; import java.util.HashSet; @@ -127,8 +127,8 @@ public class ConnectionManager { try { Context.getDeviceManager().updateDeviceStatus(device); - } catch (SQLException error) { - LOGGER.warn("Update device status error", error); + } catch (StorageException e) { + LOGGER.warn("Update device status error", e); } updateDevice(device); diff --git a/src/main/java/org/traccar/database/DataManager.java b/src/main/java/org/traccar/database/DataManager.java index 199167419..303b8e033 100644 --- a/src/main/java/org/traccar/database/DataManager.java +++ b/src/main/java/org/traccar/database/DataManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2012 - 2021 Anton Tananaev (anton@traccar.org) + * Copyright 2012 - 2022 Anton Tananaev (anton@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -41,15 +41,20 @@ import org.traccar.model.Group; import org.traccar.model.Maintenance; import org.traccar.model.ManagedUser; import org.traccar.model.Notification; -import org.traccar.model.Order; import org.traccar.model.Permission; import org.traccar.model.Position; import org.traccar.model.Server; import org.traccar.model.Statistics; import org.traccar.model.User; +import org.traccar.storage.DatabaseStorage; import org.traccar.storage.QueryBuilder; -import org.traccar.storage.QueryExtended; -import org.traccar.storage.QueryIgnore; +import org.traccar.storage.Storage; +import org.traccar.storage.StorageException; +import org.traccar.storage.query.Columns; +import org.traccar.storage.query.Condition; +import org.traccar.storage.query.Limit; +import org.traccar.storage.query.Order; +import org.traccar.storage.query.Request; import javax.sql.DataSource; import java.beans.Introspector; @@ -57,11 +62,10 @@ import java.io.File; import java.lang.reflect.Method; import java.net.URL; import java.sql.SQLException; -import java.util.Arrays; import java.util.Collection; import java.util.Date; -import java.util.HashSet; -import java.util.Set; +import java.util.LinkedList; +import java.util.List; public class DataManager { @@ -81,6 +85,8 @@ public class DataManager { return dataSource; } + private final Storage storage; + private boolean generateQueries; private final boolean forceLdap; @@ -92,6 +98,8 @@ public class DataManager { initDatabase(); initDatabaseSchema(); + + storage = new DatabaseStorage(dataSource); } private void initDatabase() throws Exception { @@ -134,58 +142,6 @@ public class DataManager { 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 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: @@ -204,39 +160,6 @@ public class DataManager { } } - private String getQuery(String key) { - String query = config.getString(key); - if (query == null) { - LOGGER.info("Query not provided: " + key); - } - return query; - } - - public String getQuery(String action, Class clazz) { - return getQuery(action, clazz, false); - } - - public String getQuery(String action, Class clazz, boolean extended) { - String queryName; - if (action.equals(ACTION_SELECT_ALL)) { - queryName = "database.select" + clazz.getSimpleName() + "s"; - } else { - queryName = "database." + action.toLowerCase() + clazz.getSimpleName(); - if (extended) { - queryName += "Extended"; - } - } - String query = config.getString(queryName); - if (query == null) { - if (generateQueries) { - query = constructObjectQuery(action, clazz, extended); - } else { - LOGGER.info("Query not provided: " + queryName); - } - } - return query; - } - public String getQuery(String action, Class owner, Class property) { String queryName; switch (action) { @@ -302,10 +225,12 @@ public class DataManager { } } - public User login(String email, String password) throws SQLException { - User user = QueryBuilder.create(dataSource, getQuery("database.loginUser")) - .setString("email", email.trim()) - .executeQuerySingle(User.class); + public User login(String email, String password) throws StorageException { + User user = storage.getObject(User.class, new Request( + new Columns.Include("id", "login", "hashedPassword", "salt"), + new Condition.Or( + new Condition.Equals("email", "email", email.trim()), + new Condition.Equals("login", "email")))); LdapProvider ldapProvider = Context.getLdapProvider(); if (user != null) { if (ldapProvider != null && user.getLogin() != null && ldapProvider.login(user.getLogin(), password) @@ -322,57 +247,75 @@ public class DataManager { return null; } - public void updateDeviceStatus(Device device) throws SQLException { - QueryBuilder.create(dataSource, getQuery(ACTION_UPDATE, Device.class, true)) - .setObject(device) - .executeUpdate(); + public void updateUserPassword(User user) throws StorageException { + storage.updateObject(user, new Request( + new Columns.Include("hashedPassword", "salt"), + new Condition.Equals("id", "id"))); } - public Collection getPositions(long deviceId, Date from, Date to) throws SQLException { - return QueryBuilder.create(dataSource, getQuery("database.selectPositions")) - .setLong("deviceId", deviceId) - .setDate("from", from) - .setDate("to", to) - .executeQuery(Position.class); + public void updateDeviceStatus(Device device) throws StorageException { + storage.updateObject(device, new Request( + new Columns.Include("lastUpdate"), + new Condition.Equals("id", "id"))); } - public Position getPrecedingPosition(long deviceId, Date date) throws SQLException { - return QueryBuilder.create(dataSource, getQuery("database.selectPrecedingPosition")) - .setLong("deviceId", deviceId) - .setDate("time", date) - .executeQuerySingle(Position.class); + public Collection getPositions(long deviceId, Date from, Date to) throws StorageException { + return storage.getObjects(Position.class, new Request( + new Columns.All(), + new Condition.And( + new Condition.Equals("deviceId", "deviceId", deviceId), + new Condition.Between("fixTime", "from", from, "to", to)), + new Order("fixTime"))); } - public void updateLatestPosition(Position position) throws SQLException { - QueryBuilder.create(dataSource, getQuery("database.updateLatestPosition")) - .setDate("now", new Date()) - .setObject(position) - .executeUpdate(); + public Position getPrecedingPosition(long deviceId, Date date) throws StorageException { + return storage.getObject(Position.class, new Request( + new Columns.All(), + new Condition.And( + new Condition.Equals("deviceId", "deviceId", deviceId), + new Condition.Compare("fixTime", "<=", "time", date)), + new Order(true, "fixTime"), + new Limit(1))); } - public Collection getLatestPositions() throws SQLException { - return QueryBuilder.create(dataSource, getQuery("database.selectLatestPositions")) - .executeQuery(Position.class); + public void updateLatestPosition(Position position) throws StorageException { + Device device = new Device(); + device.setId(position.getDeviceId()); + device.setPositionId(position.getId()); + storage.updateObject(device, new Request( + new Columns.Include("positionId"), + new Condition.Equals("id", "id"))); + } + + public Collection getLatestPositions() throws StorageException { + List positions = new LinkedList<>(); + List devices = storage.getObjects(Device.class, new Request(new Columns.Include("positionId"))); + for (Device device : devices) { + positions.addAll(storage.getObjects(Position.class, new Request( + new Columns.All(), + new Condition.Equals("id", "id", device.getPositionId())))); + } + return positions; } - public Server getServer() throws SQLException { - return QueryBuilder.create(dataSource, getQuery(ACTION_SELECT_ALL, Server.class)) - .executeQuerySingle(Server.class); + public Server getServer() throws StorageException { + return storage.getObject(Server.class, new Request(new Columns.All())); } - public Collection getEvents(long deviceId, Date from, Date to) throws SQLException { - return QueryBuilder.create(dataSource, getQuery("database.selectEvents")) - .setLong("deviceId", deviceId) - .setDate("from", from) - .setDate("to", to) - .executeQuery(Event.class); + public Collection getEvents(long deviceId, Date from, Date to) throws StorageException { + return storage.getObjects(Event.class, new Request( + new Columns.All(), + new Condition.And( + new Condition.Equals("deviceId", "deviceId", deviceId), + new Condition.Between("eventTime", "from", from, "to", to)), + new Order("eventTime"))); } - public Collection getStatistics(Date from, Date to) throws SQLException { - return QueryBuilder.create(dataSource, getQuery("database.selectStatistics")) - .setDate("from", from) - .setDate("to", to) - .executeQuery(Statistics.class); + public Collection getStatistics(Date from, Date to) throws StorageException { + return storage.getObjects(Statistics.class, new Request( + new Columns.All(), + new Condition.Between("captureTime", "from", from, "to", to), + new Order("captureTime"))); } public static Class getClassByName(String name) throws ClassNotFoundException { @@ -400,7 +343,7 @@ public class DataManager { case "notification": return Notification.class; case "order": - return Order.class; + return org.traccar.model.Order.class; default: throw new ClassNotFoundException(); } @@ -412,51 +355,49 @@ public class DataManager { } public Collection getPermissions(Class owner, Class property) - throws SQLException, ClassNotFoundException { - return QueryBuilder.create(dataSource, getQuery(ACTION_SELECT_ALL, owner, property)) - .executePermissionsQuery(); + throws StorageException, ClassNotFoundException { + try { + return QueryBuilder.create(dataSource, getQuery(ACTION_SELECT_ALL, owner, property)) + .executePermissionsQuery(); + } catch (SQLException e) { + throw new StorageException(e); + } } public void linkObject(Class owner, long ownerId, Class property, long propertyId, boolean link) - throws SQLException { + throws StorageException { + try { QueryBuilder.create(dataSource, getQuery(link ? ACTION_INSERT : ACTION_DELETE, owner, property)) .setLong(makeNameId(owner), ownerId) .setLong(makeNameId(property), propertyId) .executeUpdate(); + } catch (SQLException e) { + throw new StorageException(e); + } } - public T getObject(Class clazz, long entityId) throws SQLException { - return QueryBuilder.create(dataSource, getQuery(ACTION_SELECT, clazz)) - .setLong("id", entityId) - .executeQuerySingle(clazz); + public T getObject(Class clazz, long entityId) throws StorageException { + return storage.getObject(clazz, new Request( + new Columns.All(), + new Condition.Equals("id", "id", entityId))); } - public Collection getObjects(Class clazz) throws SQLException { - return QueryBuilder.create(dataSource, getQuery(ACTION_SELECT_ALL, clazz)) - .executeQuery(clazz); + public Collection getObjects(Class clazz) throws StorageException { + return storage.getObjects(clazz, new Request(new Columns.All())); } - public void addObject(BaseModel entity) throws SQLException { - entity.setId(QueryBuilder.create(dataSource, getQuery(ACTION_INSERT, entity.getClass()), true) - .setObject(entity) - .executeUpdate()); + public void addObject(BaseModel entity) throws StorageException { + entity.setId(storage.addObject(entity, new Request(new Columns.Exclude("id")))); } - 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 updateObject(BaseModel entity) throws StorageException { + storage.updateObject(entity, new Request( + new Columns.Exclude("id"), + new Condition.Equals("id", "id"))); } - public void removeObject(Class clazz, long entityId) throws SQLException { - QueryBuilder.create(dataSource, getQuery(ACTION_DELETE, clazz)) - .setLong("id", entityId) - .executeUpdate(); + public void removeObject(Class clazz, long entityId) throws StorageException { + storage.removeObject(clazz, new Request(new Condition.Equals("id", "id", entityId))); } } diff --git a/src/main/java/org/traccar/database/DeviceManager.java b/src/main/java/org/traccar/database/DeviceManager.java index c8a99274c..40591e869 100644 --- a/src/main/java/org/traccar/database/DeviceManager.java +++ b/src/main/java/org/traccar/database/DeviceManager.java @@ -37,6 +37,7 @@ import org.traccar.model.DeviceAccumulators; import org.traccar.model.Group; import org.traccar.model.Position; import org.traccar.model.Server; +import org.traccar.storage.StorageException; public class DeviceManager extends BaseObjectManager implements IdentityManager, ManagableObjects { @@ -94,13 +95,13 @@ public class DeviceManager extends BaseObjectManager implements Identity } return device.getId(); - } catch (SQLException e) { + } catch (StorageException e) { LOGGER.warn("Automatic device registration error", e); return 0; } } - public void updateDeviceCache(boolean force) throws SQLException { + public void updateDeviceCache(boolean force) { long lastUpdate = devicesLastUpdate.get(); if ((force || System.currentTimeMillis() - lastUpdate > dataRefreshDelay) && devicesLastUpdate.compareAndSet(lastUpdate, System.currentTimeMillis())) { @@ -144,24 +145,11 @@ public class DeviceManager extends BaseObjectManager implements Identity return defaultPassword; } - public Device getDeviceByPhone(String phone) { - try { - readLock(); - return devicesByPhone.get(phone); - } finally { - readUnlock(); - } - } - @Override public Set getAllItems() { Set result = super.getAllItems(); if (result.isEmpty()) { - try { - updateDeviceCache(true); - } catch (SQLException e) { - LOGGER.warn("Update device cache error", e); - } + updateDeviceCache(true); result = super.getAllItems(); } return result; @@ -309,7 +297,7 @@ public class DeviceManager extends BaseObjectManager implements Identity positions.remove(deviceId); } - public void updateDeviceStatus(Device device) throws SQLException { + public void updateDeviceStatus(Device device) throws StorageException { getDataManager().updateDeviceStatus(device); Device cachedDevice = getById(device.getId()); if (cachedDevice != null) { @@ -323,7 +311,7 @@ public class DeviceManager extends BaseObjectManager implements Identity for (Position position : getDataManager().getLatestPositions()) { positions.put(position.getDeviceId(), position); } - } catch (SQLException error) { + } catch (StorageException error) { LOGGER.warn("Load latest positions error", error); } } @@ -334,7 +322,7 @@ public class DeviceManager extends BaseObjectManager implements Identity return lastPosition == null || position.getFixTime().compareTo(lastPosition.getFixTime()) >= 0; } - public void updateLatestPosition(Position position) throws SQLException { + public void updateLatestPosition(Position position) throws StorageException { if (isLatestPosition(position)) { @@ -451,7 +439,7 @@ public class DeviceManager extends BaseObjectManager implements Identity return result; } - public void resetDeviceAccumulators(DeviceAccumulators deviceAccumulators) throws SQLException { + public void resetDeviceAccumulators(DeviceAccumulators deviceAccumulators) throws StorageException { Position last = positions.get(deviceAccumulators.getDeviceId()); if (last != null) { if (deviceAccumulators.getTotalDistance() != null) { diff --git a/src/main/java/org/traccar/database/ExtendedObjectManager.java b/src/main/java/org/traccar/database/ExtendedObjectManager.java index 93e5820fb..006ed47b2 100644 --- a/src/main/java/org/traccar/database/ExtendedObjectManager.java +++ b/src/main/java/org/traccar/database/ExtendedObjectManager.java @@ -16,7 +16,6 @@ */ package org.traccar.database; -import java.sql.SQLException; import java.util.Collection; import java.util.HashSet; import java.util.Map; @@ -30,6 +29,7 @@ import org.traccar.model.Device; import org.traccar.model.Group; import org.traccar.model.Permission; import org.traccar.model.BaseModel; +import org.traccar.storage.StorageException; public abstract class ExtendedObjectManager extends SimpleObjectManager { @@ -87,7 +87,7 @@ public abstract class ExtendedObjectManager extends SimpleO } @Override - public void removeItem(long itemId) throws SQLException { + public void removeItem(long itemId) throws StorageException { super.removeItem(itemId); refreshExtendedPermissions(); } @@ -133,7 +133,7 @@ public abstract class ExtendedObjectManager extends SimpleO } } - } catch (SQLException | ClassNotFoundException error) { + } catch (StorageException | ClassNotFoundException error) { LOGGER.warn("Refresh permissions error", error); } finally { writeUnlock(); diff --git a/src/main/java/org/traccar/database/GroupsManager.java b/src/main/java/org/traccar/database/GroupsManager.java index c35f35f93..dafddc0cc 100644 --- a/src/main/java/org/traccar/database/GroupsManager.java +++ b/src/main/java/org/traccar/database/GroupsManager.java @@ -16,12 +16,12 @@ */ package org.traccar.database; -import java.sql.SQLException; import java.util.HashSet; import java.util.Set; import org.traccar.Context; import org.traccar.model.Group; +import org.traccar.storage.StorageException; public class GroupsManager extends BaseObjectManager implements ManagableObjects { @@ -57,7 +57,7 @@ public class GroupsManager extends BaseObjectManager implements Managable } @Override - public void updateItem(Group group) throws SQLException { + public void updateItem(Group group) throws StorageException { checkGroupCycles(group); super.updateItem(group); } diff --git a/src/main/java/org/traccar/database/NotificationManager.java b/src/main/java/org/traccar/database/NotificationManager.java index 9f9a83cd2..f358b1d4d 100644 --- a/src/main/java/org/traccar/database/NotificationManager.java +++ b/src/main/java/org/traccar/database/NotificationManager.java @@ -18,7 +18,6 @@ package org.traccar.database; import java.lang.reflect.Field; import java.lang.reflect.Modifier; -import java.sql.SQLException; import java.util.Arrays; import java.util.Date; import java.util.HashSet; @@ -36,6 +35,7 @@ import org.traccar.model.Event; import org.traccar.model.Notification; import org.traccar.model.Position; import org.traccar.model.Typed; +import org.traccar.storage.StorageException; public class NotificationManager extends ExtendedObjectManager { @@ -66,7 +66,7 @@ public class NotificationManager extends ExtendedObjectManager { public void updateEvent(Event event, Position position) { try { getDataManager().addObject(event); - } catch (SQLException error) { + } catch (StorageException error) { LOGGER.warn("Event save error", error); } diff --git a/src/main/java/org/traccar/database/PermissionsManager.java b/src/main/java/org/traccar/database/PermissionsManager.java index ab841a521..2bb808033 100644 --- a/src/main/java/org/traccar/database/PermissionsManager.java +++ b/src/main/java/org/traccar/database/PermissionsManager.java @@ -33,8 +33,8 @@ import org.traccar.model.Order; import org.traccar.model.Permission; import org.traccar.model.Server; import org.traccar.model.User; +import org.traccar.storage.StorageException; -import java.sql.SQLException; import java.util.HashMap; import java.util.HashSet; import java.util.Map; @@ -156,7 +156,7 @@ public class PermissionsManager { public void refreshServer() { try { server = dataManager.getServer(); - } catch (SQLException error) { + } catch (StorageException error) { LOGGER.warn("Refresh server config error", error); } } @@ -193,7 +193,7 @@ public class PermissionsManager { } } - } catch (SQLException | ClassNotFoundException error) { + } catch (StorageException | ClassNotFoundException error) { LOGGER.warn("Refresh device permissions error", error); } @@ -499,12 +499,12 @@ public class PermissionsManager { return server; } - public void updateServer(Server server) throws SQLException { + public void updateServer(Server server) throws StorageException { dataManager.updateObject(server); this.server = server; } - public User login(String email, String password) throws SQLException { + public User login(String email, String password) throws StorageException { User user = dataManager.login(email, password); if (user != null) { checkUserEnabled(user.getId()); diff --git a/src/main/java/org/traccar/database/SimpleObjectManager.java b/src/main/java/org/traccar/database/SimpleObjectManager.java index eb8284d4e..78701720f 100644 --- a/src/main/java/org/traccar/database/SimpleObjectManager.java +++ b/src/main/java/org/traccar/database/SimpleObjectManager.java @@ -16,7 +16,6 @@ */ package org.traccar.database; -import java.sql.SQLException; import java.util.HashSet; import java.util.Map; import java.util.Set; @@ -28,6 +27,7 @@ import org.traccar.Context; import org.traccar.model.BaseModel; import org.traccar.model.Permission; import org.traccar.model.User; +import org.traccar.storage.StorageException; public abstract class SimpleObjectManager extends BaseObjectManager implements ManagableObjects { @@ -83,7 +83,7 @@ public abstract class SimpleObjectManager extends BaseObjec Set items = userItems.computeIfAbsent(permission.getOwnerId(), key -> new HashSet<>()); items.add(permission.getPropertyId()); } - } catch (SQLException | ClassNotFoundException error) { + } catch (StorageException | ClassNotFoundException error) { LOGGER.warn("Error getting permissions", error); } finally { writeUnlock(); @@ -92,7 +92,7 @@ public abstract class SimpleObjectManager extends BaseObjec } @Override - public void removeItem(long itemId) throws SQLException { + public void removeItem(long itemId) throws StorageException { super.removeItem(itemId); refreshUserItems(); } diff --git a/src/main/java/org/traccar/database/StatisticsManager.java b/src/main/java/org/traccar/database/StatisticsManager.java index 4ad6d9d5c..3579ce7a5 100644 --- a/src/main/java/org/traccar/database/StatisticsManager.java +++ b/src/main/java/org/traccar/database/StatisticsManager.java @@ -23,12 +23,12 @@ import org.traccar.config.Config; import org.traccar.config.Keys; import org.traccar.helper.DateUtil; import org.traccar.model.Statistics; +import org.traccar.storage.StorageException; import javax.inject.Inject; import javax.ws.rs.client.Client; import javax.ws.rs.client.Entity; import javax.ws.rs.core.Form; -import java.sql.SQLException; import java.util.Calendar; import java.util.Date; import java.util.HashMap; @@ -106,7 +106,7 @@ public class StatisticsManager { try { dataManager.addObject(statistics); - } catch (SQLException e) { + } catch (StorageException e) { LOGGER.warn("Error saving statistics", e); } diff --git a/src/main/java/org/traccar/database/UsersManager.java b/src/main/java/org/traccar/database/UsersManager.java index b741a85b6..31759dc8b 100644 --- a/src/main/java/org/traccar/database/UsersManager.java +++ b/src/main/java/org/traccar/database/UsersManager.java @@ -21,6 +21,7 @@ import java.util.Set; import java.util.concurrent.ConcurrentHashMap; import org.traccar.model.User; +import org.traccar.storage.StorageException; public class UsersManager extends SimpleObjectManager { @@ -58,6 +59,14 @@ public class UsersManager extends SimpleObjectManager { } } + @Override + public void updateItem(User user) throws StorageException { + if (user.getHashedPassword() != null) { + getDataManager().updateUserPassword(user); + } + super.updateItem(user); + } + @Override protected void removeCachedItem(long userId) { User cachedUser = getById(userId); diff --git a/src/main/java/org/traccar/handler/FilterHandler.java b/src/main/java/org/traccar/handler/FilterHandler.java index 2b850c755..e576a26b8 100644 --- a/src/main/java/org/traccar/handler/FilterHandler.java +++ b/src/main/java/org/traccar/handler/FilterHandler.java @@ -24,8 +24,8 @@ import org.traccar.config.Config; import org.traccar.config.Keys; import org.traccar.helper.UnitsConverter; import org.traccar.model.Position; +import org.traccar.storage.StorageException; -import java.sql.SQLException; import java.util.Date; @ChannelHandler.Sharable @@ -174,7 +174,7 @@ public class FilterHandler extends BaseDataHandler { try { Date newFixTime = position.getFixTime(); preceding = Context.getDataManager().getPrecedingPosition(deviceId, newFixTime); - } catch (SQLException e) { + } catch (StorageException e) { LOGGER.warn("Error retrieving preceding position; fallbacking to last received position.", e); preceding = getLastReceivedPosition(deviceId); } diff --git a/src/main/java/org/traccar/model/Attribute.java b/src/main/java/org/traccar/model/Attribute.java index 45d40b3ec..65f2e3881 100644 --- a/src/main/java/org/traccar/model/Attribute.java +++ b/src/main/java/org/traccar/model/Attribute.java @@ -16,6 +16,9 @@ */ package org.traccar.model; +import org.traccar.storage.StorageName; + +@StorageName("tc_attributes") public class Attribute extends BaseModel { private String description; diff --git a/src/main/java/org/traccar/model/Calendar.java b/src/main/java/org/traccar/model/Calendar.java index af6364626..102c0be52 100644 --- a/src/main/java/org/traccar/model/Calendar.java +++ b/src/main/java/org/traccar/model/Calendar.java @@ -25,6 +25,7 @@ import net.fortuna.ical4j.model.DateTime; import net.fortuna.ical4j.model.Period; import net.fortuna.ical4j.model.component.CalendarComponent; import org.traccar.storage.QueryIgnore; +import org.traccar.storage.StorageName; import java.io.ByteArrayInputStream; import java.io.IOException; @@ -32,6 +33,7 @@ import java.time.Duration; import java.util.Collection; import java.util.Date; +@StorageName("tc_calendars") public class Calendar extends ExtendedModel { private String name; diff --git a/src/main/java/org/traccar/model/Command.java b/src/main/java/org/traccar/model/Command.java index 71bc232e9..03961c7b2 100644 --- a/src/main/java/org/traccar/model/Command.java +++ b/src/main/java/org/traccar/model/Command.java @@ -18,7 +18,9 @@ package org.traccar.model; import org.traccar.storage.QueryIgnore; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import org.traccar.storage.StorageName; +@StorageName("tc_commands") @JsonIgnoreProperties(ignoreUnknown = true) public class Command extends Message implements Cloneable { @@ -104,6 +106,12 @@ public class Command extends Message implements Cloneable { return super.getDeviceId(); } + @QueryIgnore + @Override + public void setDeviceId(long deviceId) { + super.setDeviceId(deviceId); + } + private String description; public String getDescription() { diff --git a/src/main/java/org/traccar/model/Device.java b/src/main/java/org/traccar/model/Device.java index 46de8003d..836a6709c 100644 --- a/src/main/java/org/traccar/model/Device.java +++ b/src/main/java/org/traccar/model/Device.java @@ -20,7 +20,9 @@ import java.util.List; import org.traccar.storage.QueryExtended; import org.traccar.storage.QueryIgnore; +import org.traccar.storage.StorageName; +@StorageName("tc_devices") public class Device extends GroupedModel { private String name; @@ -54,13 +56,13 @@ public class Device extends GroupedModel { return status != null ? status : STATUS_OFFLINE; } + @QueryIgnore public void setStatus(String status) { this.status = status; } private Date lastUpdate; - @QueryExtended public Date getLastUpdate() { if (lastUpdate != null) { return new Date(lastUpdate.getTime()); @@ -69,6 +71,7 @@ public class Device extends GroupedModel { } } + @QueryExtended public void setLastUpdate(Date lastUpdate) { if (lastUpdate != null) { this.lastUpdate = new Date(lastUpdate.getTime()); @@ -84,6 +87,7 @@ public class Device extends GroupedModel { return positionId; } + @QueryIgnore public void setPositionId(long positionId) { this.positionId = positionId; } @@ -95,6 +99,7 @@ public class Device extends GroupedModel { return geofenceIds; } + @QueryIgnore public void setGeofenceIds(List geofenceIds) { this.geofenceIds = geofenceIds; } diff --git a/src/main/java/org/traccar/model/Driver.java b/src/main/java/org/traccar/model/Driver.java index 05f52fd4d..b9e023088 100644 --- a/src/main/java/org/traccar/model/Driver.java +++ b/src/main/java/org/traccar/model/Driver.java @@ -16,6 +16,9 @@ */ package org.traccar.model; +import org.traccar.storage.StorageName; + +@StorageName("tc_drivers") public class Driver extends ExtendedModel { private String name; @@ -37,4 +40,5 @@ public class Driver extends ExtendedModel { public void setUniqueId(String uniqueId) { this.uniqueId = uniqueId; } + } diff --git a/src/main/java/org/traccar/model/Event.java b/src/main/java/org/traccar/model/Event.java index a7a134ecf..6e3953fda 100644 --- a/src/main/java/org/traccar/model/Event.java +++ b/src/main/java/org/traccar/model/Event.java @@ -15,8 +15,11 @@ */ package org.traccar.model; +import org.traccar.storage.StorageName; + import java.util.Date; +@StorageName("tc_events") public class Event extends Message { public Event(String type, Position position) { diff --git a/src/main/java/org/traccar/model/Geofence.java b/src/main/java/org/traccar/model/Geofence.java index a451da9f5..5b857580d 100644 --- a/src/main/java/org/traccar/model/Geofence.java +++ b/src/main/java/org/traccar/model/Geofence.java @@ -26,7 +26,9 @@ import org.traccar.geofence.GeofencePolygon; import org.traccar.geofence.GeofencePolyline; import com.fasterxml.jackson.annotation.JsonIgnore; +import org.traccar.storage.StorageName; +@StorageName("tc_geofences") public class Geofence extends ScheduledModel { public static final String TYPE_GEOFENCE_CILCLE = "geofenceCircle"; diff --git a/src/main/java/org/traccar/model/Group.java b/src/main/java/org/traccar/model/Group.java index 91ea2319d..ff69f61fa 100644 --- a/src/main/java/org/traccar/model/Group.java +++ b/src/main/java/org/traccar/model/Group.java @@ -15,6 +15,9 @@ */ package org.traccar.model; +import org.traccar.storage.StorageName; + +@StorageName("tc_groups") public class Group extends GroupedModel { private String name; diff --git a/src/main/java/org/traccar/model/Maintenance.java b/src/main/java/org/traccar/model/Maintenance.java index 73f67ea96..cad100a3a 100644 --- a/src/main/java/org/traccar/model/Maintenance.java +++ b/src/main/java/org/traccar/model/Maintenance.java @@ -16,6 +16,9 @@ */ package org.traccar.model; +import org.traccar.storage.StorageName; + +@StorageName("tc_maintenances") public class Maintenance extends ExtendedModel { private String name; diff --git a/src/main/java/org/traccar/model/Notification.java b/src/main/java/org/traccar/model/Notification.java index 01ca2711c..95e446132 100644 --- a/src/main/java/org/traccar/model/Notification.java +++ b/src/main/java/org/traccar/model/Notification.java @@ -21,7 +21,9 @@ import java.util.Set; import org.traccar.storage.QueryIgnore; import com.fasterxml.jackson.annotation.JsonIgnore; +import org.traccar.storage.StorageName; +@StorageName("tc_notifications") public class Notification extends ScheduledModel { private boolean always; @@ -44,7 +46,6 @@ public class Notification extends ScheduledModel { this.type = type; } - private String notificators; public String getNotificators() { @@ -55,7 +56,6 @@ public class Notification extends ScheduledModel { this.notificators = transports; } - @JsonIgnore @QueryIgnore public Set getNotificatorsTypes() { diff --git a/src/main/java/org/traccar/model/Order.java b/src/main/java/org/traccar/model/Order.java index fe6d926b8..7d09b0a47 100644 --- a/src/main/java/org/traccar/model/Order.java +++ b/src/main/java/org/traccar/model/Order.java @@ -15,6 +15,9 @@ */ package org.traccar.model; +import org.traccar.storage.StorageName; + +@StorageName("tc_orders") public class Order extends ExtendedModel { private String uniqueId; diff --git a/src/main/java/org/traccar/model/Position.java b/src/main/java/org/traccar/model/Position.java index bbea58901..348370e2c 100644 --- a/src/main/java/org/traccar/model/Position.java +++ b/src/main/java/org/traccar/model/Position.java @@ -17,8 +17,11 @@ package org.traccar.model; import java.util.Date; +import com.fasterxml.jackson.annotation.JsonIgnore; import org.traccar.storage.QueryIgnore; +import org.traccar.storage.StorageName; +@StorageName("tc_positions") public class Position extends Message { public static final String KEY_ORIGINAL = "raw"; @@ -190,6 +193,7 @@ public class Position extends Message { this.fixTime = fixTime; } + @QueryIgnore public void setTime(Date time) { setDeviceTime(time); setFixTime(time); @@ -202,6 +206,7 @@ public class Position extends Message { return outdated; } + @QueryIgnore public void setOutdated(boolean outdated) { this.outdated = outdated; } @@ -296,10 +301,18 @@ public class Position extends Message { this.network = network; } - @Override + @JsonIgnore @QueryIgnore + @Override public String getType() { return super.getType(); } + @JsonIgnore + @QueryIgnore + @Override + public void setType(String type) { + super.setType(type); + } + } diff --git a/src/main/java/org/traccar/model/Server.java b/src/main/java/org/traccar/model/Server.java index fdb071a18..b48e84939 100644 --- a/src/main/java/org/traccar/model/Server.java +++ b/src/main/java/org/traccar/model/Server.java @@ -18,7 +18,9 @@ package org.traccar.model; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import org.traccar.Context; import org.traccar.storage.QueryIgnore; +import org.traccar.storage.StorageName; +@StorageName("tc_servers") @JsonIgnoreProperties(ignoreUnknown = true) public class Server extends ExtendedModel { diff --git a/src/main/java/org/traccar/model/Statistics.java b/src/main/java/org/traccar/model/Statistics.java index a9a117aef..0dc1b98e8 100644 --- a/src/main/java/org/traccar/model/Statistics.java +++ b/src/main/java/org/traccar/model/Statistics.java @@ -15,9 +15,12 @@ */ package org.traccar.model; +import org.traccar.storage.StorageName; + import java.util.Date; import java.util.Map; +@StorageName("tc_statistics") public class Statistics extends ExtendedModel { private Date captureTime; diff --git a/src/main/java/org/traccar/model/User.java b/src/main/java/org/traccar/model/User.java index 447cf691c..94828ab95 100644 --- a/src/main/java/org/traccar/model/User.java +++ b/src/main/java/org/traccar/model/User.java @@ -20,9 +20,11 @@ import com.fasterxml.jackson.annotation.JsonIgnore; import org.traccar.storage.QueryExtended; import org.traccar.storage.QueryIgnore; import org.traccar.helper.Hashing; +import org.traccar.storage.StorageName; import java.util.Date; +@StorageName("tc_users") public class User extends ExtendedModel { private String name; diff --git a/src/main/java/org/traccar/reports/Events.java b/src/main/java/org/traccar/reports/Events.java index 66d9e708d..e4b905702 100644 --- a/src/main/java/org/traccar/reports/Events.java +++ b/src/main/java/org/traccar/reports/Events.java @@ -20,7 +20,6 @@ import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.sql.SQLException; import java.util.ArrayList; import java.util.Collection; import java.util.Date; @@ -35,6 +34,7 @@ import org.traccar.model.Geofence; import org.traccar.model.Group; import org.traccar.model.Maintenance; import org.traccar.reports.model.DeviceReport; +import org.traccar.storage.StorageException; public final class Events { @@ -42,7 +42,7 @@ public final class Events { } public static Collection getObjects(long userId, Collection deviceIds, Collection groupIds, - Collection types, Date from, Date to) throws SQLException { + Collection types, Date from, Date to) throws StorageException { ReportUtils.checkPeriodLimit(from, to); ArrayList result = new ArrayList<>(); for (long deviceId: ReportUtils.getDeviceList(deviceIds, groupIds)) { @@ -66,7 +66,7 @@ public final class Events { public static void getExcel(OutputStream outputStream, long userId, Collection deviceIds, Collection groupIds, - Collection types, Date from, Date to) throws SQLException, IOException { + Collection types, Date from, Date to) throws StorageException, IOException { ReportUtils.checkPeriodLimit(from, to); ArrayList devicesEvents = new ArrayList<>(); ArrayList sheetNames = new ArrayList<>(); diff --git a/src/main/java/org/traccar/reports/Route.java b/src/main/java/org/traccar/reports/Route.java index 6adb00aae..4a5edd295 100644 --- a/src/main/java/org/traccar/reports/Route.java +++ b/src/main/java/org/traccar/reports/Route.java @@ -20,7 +20,6 @@ import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.sql.SQLException; import java.util.ArrayList; import java.util.Collection; import java.util.Date; @@ -31,6 +30,7 @@ import org.traccar.model.Device; import org.traccar.model.Group; import org.traccar.model.Position; import org.traccar.reports.model.DeviceReport; +import org.traccar.storage.StorageException; public final class Route { @@ -38,7 +38,7 @@ public final class Route { } public static Collection getObjects(long userId, Collection deviceIds, Collection groupIds, - Date from, Date to) throws SQLException { + Date from, Date to) throws StorageException { ReportUtils.checkPeriodLimit(from, to); ArrayList result = new ArrayList<>(); for (long deviceId: ReportUtils.getDeviceList(deviceIds, groupIds)) { @@ -50,7 +50,7 @@ public final class Route { public static void getExcel(OutputStream outputStream, long userId, Collection deviceIds, Collection groupIds, - Date from, Date to) throws SQLException, IOException { + Date from, Date to) throws StorageException, IOException { ReportUtils.checkPeriodLimit(from, to); ArrayList devicesRoutes = new ArrayList<>(); ArrayList sheetNames = new ArrayList<>(); diff --git a/src/main/java/org/traccar/reports/Stops.java b/src/main/java/org/traccar/reports/Stops.java index 2036b0641..36a4a7549 100644 --- a/src/main/java/org/traccar/reports/Stops.java +++ b/src/main/java/org/traccar/reports/Stops.java @@ -21,7 +21,6 @@ import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.sql.SQLException; import java.util.ArrayList; import java.util.Collection; import java.util.Date; @@ -35,13 +34,14 @@ import org.traccar.model.Device; import org.traccar.model.Group; import org.traccar.reports.model.DeviceReport; import org.traccar.reports.model.StopReport; +import org.traccar.storage.StorageException; public final class Stops { private Stops() { } - private static Collection detectStops(long deviceId, Date from, Date to) throws SQLException { + private static Collection detectStops(long deviceId, Date from, Date to) throws StorageException { boolean ignoreOdometer = Context.getDeviceManager() .lookupAttributeBoolean(deviceId, "report.ignoreOdometer", false, false, true); @@ -55,7 +55,7 @@ public final class Stops { public static Collection getObjects( long userId, Collection deviceIds, Collection groupIds, - Date from, Date to) throws SQLException { + Date from, Date to) throws StorageException { ReportUtils.checkPeriodLimit(from, to); ArrayList result = new ArrayList<>(); for (long deviceId: ReportUtils.getDeviceList(deviceIds, groupIds)) { @@ -67,7 +67,7 @@ public final class Stops { public static void getExcel( OutputStream outputStream, long userId, Collection deviceIds, Collection groupIds, - Date from, Date to) throws SQLException, IOException { + Date from, Date to) throws StorageException, IOException { ReportUtils.checkPeriodLimit(from, to); ArrayList devicesStops = new ArrayList<>(); ArrayList sheetNames = new ArrayList<>(); diff --git a/src/main/java/org/traccar/reports/Summary.java b/src/main/java/org/traccar/reports/Summary.java index d576ac1e6..4924af062 100644 --- a/src/main/java/org/traccar/reports/Summary.java +++ b/src/main/java/org/traccar/reports/Summary.java @@ -20,7 +20,6 @@ import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.sql.SQLException; import java.util.ArrayList; import java.util.Calendar; import java.util.Collection; @@ -31,6 +30,7 @@ import org.traccar.Context; import org.traccar.helper.UnitsConverter; import org.traccar.model.Position; import org.traccar.reports.model.SummaryReport; +import org.traccar.storage.StorageException; public final class Summary { @@ -97,7 +97,7 @@ public final class Summary { } private static Collection calculateSummaryResults( - long userId, long deviceId, Date from, Date to, boolean daily) throws SQLException { + long userId, long deviceId, Date from, Date to, boolean daily) throws StorageException { ArrayList positions = new ArrayList<>(Context.getDataManager().getPositions(deviceId, from, to)); @@ -122,7 +122,7 @@ public final class Summary { } public static Collection getObjects(long userId, Collection deviceIds, - Collection groupIds, Date from, Date to, boolean daily) throws SQLException { + Collection groupIds, Date from, Date to, boolean daily) throws StorageException { ReportUtils.checkPeriodLimit(from, to); ArrayList result = new ArrayList<>(); for (long deviceId: ReportUtils.getDeviceList(deviceIds, groupIds)) { @@ -134,7 +134,7 @@ public final class Summary { public static void getExcel(OutputStream outputStream, long userId, Collection deviceIds, Collection groupIds, - Date from, Date to, boolean daily) throws SQLException, IOException { + Date from, Date to, boolean daily) throws StorageException, IOException { ReportUtils.checkPeriodLimit(from, to); Collection summaries = getObjects(userId, deviceIds, groupIds, from, to, daily); String templatePath = Context.getConfig().getString("report.templatesPath", diff --git a/src/main/java/org/traccar/reports/Trips.java b/src/main/java/org/traccar/reports/Trips.java index 7c0cd6921..1461b869e 100644 --- a/src/main/java/org/traccar/reports/Trips.java +++ b/src/main/java/org/traccar/reports/Trips.java @@ -20,7 +20,6 @@ import java.io.FileInputStream; import java.io.IOException; import java.io.InputStream; import java.io.OutputStream; -import java.sql.SQLException; import java.util.ArrayList; import java.util.Collection; import java.util.Date; @@ -34,13 +33,14 @@ import org.traccar.model.Device; import org.traccar.model.Group; import org.traccar.reports.model.DeviceReport; import org.traccar.reports.model.TripReport; +import org.traccar.storage.StorageException; public final class Trips { private Trips() { } - private static Collection detectTrips(long deviceId, Date from, Date to) throws SQLException { + private static Collection detectTrips(long deviceId, Date from, Date to) throws StorageException { boolean ignoreOdometer = Context.getDeviceManager() .lookupAttributeBoolean(deviceId, "report.ignoreOdometer", false, false, true); @@ -53,7 +53,7 @@ public final class Trips { } public static Collection getObjects(long userId, Collection deviceIds, Collection groupIds, - Date from, Date to) throws SQLException { + Date from, Date to) throws StorageException { ReportUtils.checkPeriodLimit(from, to); ArrayList result = new ArrayList<>(); for (long deviceId: ReportUtils.getDeviceList(deviceIds, groupIds)) { @@ -65,7 +65,7 @@ public final class Trips { public static void getExcel(OutputStream outputStream, long userId, Collection deviceIds, Collection groupIds, - Date from, Date to) throws SQLException, IOException { + Date from, Date to) throws StorageException, IOException { ReportUtils.checkPeriodLimit(from, to); ArrayList devicesTrips = new ArrayList<>(); ArrayList sheetNames = new ArrayList<>(); diff --git a/src/main/java/org/traccar/storage/DatabaseStorage.java b/src/main/java/org/traccar/storage/DatabaseStorage.java index 0bcab7d20..2c893ebbc 100644 --- a/src/main/java/org/traccar/storage/DatabaseStorage.java +++ b/src/main/java/org/traccar/storage/DatabaseStorage.java @@ -2,6 +2,7 @@ package org.traccar.storage; import org.traccar.storage.query.Columns; import org.traccar.storage.query.Condition; +import org.traccar.storage.query.Limit; import org.traccar.storage.query.Order; import org.traccar.storage.query.Request; @@ -24,7 +25,7 @@ public class DatabaseStorage extends Storage { @Override public List getObjects(Class clazz, Request request) throws StorageException { StringBuilder query = new StringBuilder("SELECT "); - query.append(formatColumns(request.getColumns(), clazz, c -> c)); + query.append(formatColumns(request.getColumns(), clazz, "get", c -> c)); query.append(" FROM ").append(getTableName(clazz)); query.append(formatCondition(request.getCondition())); query.append(formatOrder(request.getOrder())); @@ -44,9 +45,9 @@ public class DatabaseStorage extends Storage { StringBuilder query = new StringBuilder("INSERT INTO "); query.append(getTableName(entity.getClass())); query.append("("); - query.append(formatColumns(request.getColumns(), entity.getClass(), c -> c)); + query.append(formatColumns(request.getColumns(), entity.getClass(), "set", c -> c)); query.append(") VALUES ("); - query.append(formatColumns(request.getColumns(), entity.getClass(), c -> ':' + c)); + query.append(formatColumns(request.getColumns(), entity.getClass(), "set", c -> ':' + c)); query.append(")"); try { QueryBuilder builder = QueryBuilder.create(dataSource, query.toString(), true); @@ -62,7 +63,7 @@ public class DatabaseStorage extends Storage { StringBuilder query = new StringBuilder("UPDATE "); query.append(getTableName(entity.getClass())); query.append(" SET "); - query.append(formatColumns(request.getColumns(), entity.getClass(), c -> c + " = :" + c)); + query.append(formatColumns(request.getColumns(), entity.getClass(), "set", c -> c + " = :" + c)); query.append(formatCondition(request.getCondition())); try { QueryBuilder builder = QueryBuilder.create(dataSource, query.toString()); @@ -101,31 +102,46 @@ public class DatabaseStorage extends Storage { } private Map getConditionVariables(Condition genericCondition) { - Map result = new HashMap<>(); - if (genericCondition instanceof Condition.Equals) { - Condition.Equals condition = (Condition.Equals) genericCondition; - result.put(condition.getVariable(), condition.getValue()); + Map results = new HashMap<>(); + if (genericCondition instanceof Condition.Compare) { + Condition.Compare condition = (Condition.Compare) genericCondition; + if (condition.getValue() != null) { + results.put(condition.getVariable(), condition.getValue()); + } } else if (genericCondition instanceof Condition.Between) { Condition.Between condition = (Condition.Between) genericCondition; - result.put(condition.getFromVariable(), condition.getFromValue()); - result.put(condition.getToVariable(), condition.getToValue()); + results.put(condition.getFromVariable(), condition.getFromValue()); + results.put(condition.getToVariable(), condition.getToValue()); + } else if (genericCondition instanceof Condition.Binary) { + Condition.Binary condition = (Condition.Binary) genericCondition; + results.putAll(getConditionVariables(condition.getFirst())); + results.putAll(getConditionVariables(condition.getSecond())); } - return result; + return results; } - private String formatColumns(Columns columns, Class clazz, Function mapper) { - return columns.getColumns(clazz).stream().map(mapper).collect(Collectors.joining(", ")); + private String formatColumns( + Columns columns, Class clazz, String type, Function mapper) { + return columns.getColumns(clazz, type).stream().map(mapper).collect(Collectors.joining(", ")); } private String formatCondition(Condition genericCondition) { + return formatCondition(genericCondition, true); + } + + private String formatCondition(Condition genericCondition, boolean appendWhere) { StringBuilder result = new StringBuilder(); if (genericCondition != null) { - result.append(" WHERE "); - if (genericCondition instanceof Condition.Equals) { + if (appendWhere) { + result.append(" WHERE "); + } + if (genericCondition instanceof Condition.Compare) { - Condition.Equals condition = (Condition.Equals) genericCondition; + Condition.Compare condition = (Condition.Compare) genericCondition; result.append(condition.getColumn()); - result.append(" == :"); + result.append(" "); + result.append(condition.getOperator()); + result.append(" :"); result.append(condition.getVariable()); } else if (genericCondition instanceof Condition.Between) { @@ -137,12 +153,14 @@ public class DatabaseStorage extends Storage { result.append(" AND :"); result.append(condition.getToVariable()); - } else if (genericCondition instanceof Condition.And) { + } else if (genericCondition instanceof Condition.Binary) { - Condition.And condition = (Condition.And) genericCondition; - result.append(formatCondition(condition.getFirst())); - result.append(" AND "); - result.append(formatCondition(condition.getSecond())); + Condition.Binary condition = (Condition.Binary) genericCondition; + result.append(formatCondition(condition.getFirst(), false)); + result.append(" "); + result.append(condition.getOperator()); + result.append(" "); + result.append(formatCondition(condition.getSecond(), false)); } } @@ -161,4 +179,13 @@ public class DatabaseStorage extends Storage { return result.toString(); } + private String formatLimit(Limit limit) { + StringBuilder result = new StringBuilder(); + if (limit != null) { + result.append(" LIMIT "); + result.append(limit.getValue()); + } + return result.toString(); + } + } diff --git a/src/main/java/org/traccar/storage/QueryBuilder.java b/src/main/java/org/traccar/storage/QueryBuilder.java index 838472c8b..edaacb74d 100644 --- a/src/main/java/org/traccar/storage/QueryBuilder.java +++ b/src/main/java/org/traccar/storage/QueryBuilder.java @@ -276,8 +276,7 @@ public final class QueryBuilder { Method[] methods = object.getClass().getMethods(); for (Method method : methods) { - if (method.getName().startsWith("get") && method.getParameterTypes().length == 0 - && !method.isAnnotationPresent(QueryIgnore.class)) { + if (method.getName().startsWith("get") && method.getParameterTypes().length == 0) { String name = method.getName().substring(3); try { if (method.getReturnType().equals(boolean.class)) { @@ -412,8 +411,7 @@ public final class QueryBuilder { Method[] methods = clazz.getMethods(); for (final Method method : methods) { - if (method.getName().startsWith("set") && method.getParameterTypes().length == 1 - && !method.isAnnotationPresent(QueryIgnore.class)) { + if (method.getName().startsWith("set") && method.getParameterTypes().length == 1) { final String name = method.getName().substring(3); diff --git a/src/main/java/org/traccar/storage/Storage.java b/src/main/java/org/traccar/storage/Storage.java index b95ce9505..3726fbf50 100644 --- a/src/main/java/org/traccar/storage/Storage.java +++ b/src/main/java/org/traccar/storage/Storage.java @@ -6,20 +6,17 @@ import java.util.List; public abstract class Storage { - abstract List getObjects(Class clazz, Request request) throws StorageException; + public abstract List getObjects(Class clazz, Request request) throws StorageException; - abstract long addObject(T entity, Request request) throws StorageException; + public abstract long addObject(T entity, Request request) throws StorageException; - abstract void updateObject(T entity, Request request) throws StorageException; + public abstract void updateObject(T entity, Request request) throws StorageException; - abstract void removeObject(Class clazz, Request request) throws StorageException; + public abstract void removeObject(Class clazz, Request request) throws StorageException; - T getObject(Class clazz, Request request) throws StorageException { + public T getObject(Class clazz, Request request) throws StorageException { var objects = getObjects(clazz, request); - if (objects.isEmpty()) { - throw new StorageException("No objects found"); - } - return objects.get(0); + return objects.isEmpty() ? null : objects.get(0); } } diff --git a/src/main/java/org/traccar/storage/query/Columns.java b/src/main/java/org/traccar/storage/query/Columns.java index 1a13665ee..196d2281c 100644 --- a/src/main/java/org/traccar/storage/query/Columns.java +++ b/src/main/java/org/traccar/storage/query/Columns.java @@ -1,5 +1,6 @@ package org.traccar.storage.query; +import org.traccar.storage.QueryExtended; import org.traccar.storage.QueryIgnore; import java.lang.reflect.Method; @@ -11,14 +12,17 @@ import java.util.stream.Collectors; public abstract class Columns { - public abstract List getColumns(Class clazz); + public abstract List getColumns(Class clazz, String type); - protected List getAllColumns(Class clazz) { + protected List getAllColumns(Class clazz, String type) { List columns = new LinkedList<>(); Method[] methods = clazz.getMethods(); for (Method method : methods) { - if (method.getName().startsWith("set") && method.getParameterTypes().length == 1 - && !method.isAnnotationPresent(QueryIgnore.class)) { + int parameterCount = type.equals("set") ? 1 : 0; + if (method.getName().startsWith(type) && method.getParameterTypes().length == parameterCount + && !method.isAnnotationPresent(QueryIgnore.class) + && !method.isAnnotationPresent(QueryExtended.class) + && !method.getName().equals("getClass")) { columns.add(method.getName().substring(3).toLowerCase()); } } @@ -27,8 +31,8 @@ public abstract class Columns { public static class All extends Columns { @Override - public List getColumns(Class clazz) { - return getAllColumns(clazz); + public List getColumns(Class clazz, String type) { + return getAllColumns(clazz, type); } } @@ -40,7 +44,7 @@ public abstract class Columns { } @Override - public List getColumns(Class clazz) { + public List getColumns(Class clazz, String type) { return columns; } } @@ -53,8 +57,8 @@ public abstract class Columns { } @Override - public List getColumns(Class clazz) { - return getAllColumns(clazz).stream() + public List getColumns(Class clazz, String type) { + return getAllColumns(clazz, type).stream() .filter(column -> !columns.contains(column)) .collect(Collectors.toList()); } diff --git a/src/main/java/org/traccar/storage/query/Condition.java b/src/main/java/org/traccar/storage/query/Condition.java index 50d520bc7..82c8e8479 100644 --- a/src/main/java/org/traccar/storage/query/Condition.java +++ b/src/main/java/org/traccar/storage/query/Condition.java @@ -2,13 +2,25 @@ package org.traccar.storage.query; public interface Condition { - class Equals implements Condition { + class Equals extends Compare { + public Equals(String column, String variable) { + this(column, variable, null); + } + + public Equals(String column, String variable, Object value) { + super(column, "=", variable, value); + } + } + + class Compare implements Condition { private final String column; + private final String operator; private final String variable; private final Object value; - public Equals(String column, String variable, Object value) { + public Compare(String column, String operator, String variable, Object value) { this.column = column; + this.operator = operator; this.variable = variable; this.value = value; } @@ -17,6 +29,10 @@ public interface Condition { return column; } + public String getOperator() { + return operator; + } + public String getVariable() { return variable; } @@ -62,13 +78,27 @@ public interface Condition { } } - class And implements Condition { + class Or extends Binary { + public Or(Condition first, Condition second) { + super(first, second, "OR"); + } + } + + class And extends Binary { + public And(Condition first, Condition second) { + super(first, second, "AND"); + } + } + + class Binary implements Condition { private final Condition first; private final Condition second; + private final String operator; - public And(Condition first, Condition second) { + public Binary(Condition first, Condition second, String operator) { this.first = first; this.second = second; + this.operator = operator; } public Condition getFirst() { @@ -78,6 +108,10 @@ public interface Condition { public Condition getSecond() { return second; } + + public String getOperator() { + return operator; + } } } diff --git a/src/main/java/org/traccar/storage/query/Limit.java b/src/main/java/org/traccar/storage/query/Limit.java new file mode 100644 index 000000000..4a20f0ce2 --- /dev/null +++ b/src/main/java/org/traccar/storage/query/Limit.java @@ -0,0 +1,15 @@ +package org.traccar.storage.query; + +public class Limit { + + private final int value; + + public Limit(int value) { + this.value = value; + } + + public int getValue() { + return value; + } + +} diff --git a/src/main/java/org/traccar/storage/query/Request.java b/src/main/java/org/traccar/storage/query/Request.java index 8536cafd0..a98dd48f7 100644 --- a/src/main/java/org/traccar/storage/query/Request.java +++ b/src/main/java/org/traccar/storage/query/Request.java @@ -5,11 +5,29 @@ public class Request { private final Columns columns; private final Condition condition; private final Order order; + private final Limit limit; + + public Request(Columns columns) { + this(columns, null, null); + } + + public Request(Condition condition) { + this(null, condition, null); + } + + public Request(Columns columns, Condition condition) { + this(columns, condition, null); + } public Request(Columns columns, Condition condition, Order order) { + this(columns, condition, order, null); + } + + public Request(Columns columns, Condition condition, Order order, Limit limit) { this.columns = columns; this.condition = condition; this.order = order; + this.limit = limit; } public Columns getColumns() { @@ -24,4 +42,8 @@ public class Request { return order; } + public Limit getLimit() { + return limit; + } + } diff --git a/src/test/java/org/traccar/database/DataManagerTest.java b/src/test/java/org/traccar/database/DataManagerTest.java deleted file mode 100644 index 23043e96e..000000000 --- a/src/test/java/org/traccar/database/DataManagerTest.java +++ /dev/null @@ -1,81 +0,0 @@ -package org.traccar.database; - -import org.junit.Test; -import org.traccar.model.Attribute; -import org.traccar.model.Device; -import org.traccar.model.Driver; -import org.traccar.model.Geofence; -import org.traccar.model.Group; -import org.traccar.model.ManagedUser; -import org.traccar.model.Position; -import org.traccar.model.User; - -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertFalse; -import static org.junit.Assert.assertTrue; - -public class DataManagerTest { - - @Test - public void constructObjectQuery() { - assertEquals("SELECT * FROM tc_users", - DataManager.constructObjectQuery(DataManager.ACTION_SELECT_ALL, User.class, false)); - assertEquals("DELETE FROM tc_groups WHERE id = :id", - DataManager.constructObjectQuery(DataManager.ACTION_DELETE, Group.class, false)); - assertEquals("SELECT * FROM tc_positions WHERE id = :id", - DataManager.constructObjectQuery(DataManager.ACTION_SELECT, Position.class, false)); - - String insertDevice = DataManager.constructObjectQuery(DataManager.ACTION_INSERT, Device.class, false); - assertFalse(insertDevice.contains("class")); - assertFalse(insertDevice.contains("id")); - assertFalse(insertDevice.contains("status")); - assertFalse(insertDevice.contains("geofenceIds")); - - String updateDeviceStatus = DataManager.constructObjectQuery("update", Device.class, true); - assertTrue(updateDeviceStatus.contains("lastUpdate")); - - String updateUser = DataManager.constructObjectQuery(DataManager.ACTION_UPDATE, User.class, false); - assertFalse(updateUser.contains("class")); - assertFalse(updateUser.contains("password")); - assertFalse(updateUser.contains("salt")); - - String updateUserPassword = DataManager.constructObjectQuery(DataManager.ACTION_UPDATE, User.class, true); - assertFalse(updateUserPassword.contains("name")); - assertTrue(updateUserPassword.contains("hashedPassword")); - assertTrue(updateUserPassword.contains("salt")); - - String insertPosition = DataManager.constructObjectQuery(DataManager.ACTION_INSERT, Position.class, false); - assertFalse(insertPosition.contains("type")); - assertFalse(insertPosition.contains("outdated")); - - } - - @Test - public void constructPermissionsQuery() { - assertEquals("SELECT userId, deviceId FROM tc_user_device", - DataManager.constructPermissionQuery(DataManager.ACTION_SELECT_ALL, User.class, Device.class)); - - assertEquals("SELECT userId, managedUserId FROM tc_user_user", - DataManager.constructPermissionQuery(DataManager.ACTION_SELECT_ALL, User.class, ManagedUser.class)); - - assertEquals("SELECT deviceId, driverId FROM tc_device_driver", - DataManager.constructPermissionQuery(DataManager.ACTION_SELECT_ALL, Device.class, Driver.class)); - - assertEquals("SELECT groupId, geofenceId FROM tc_group_geofence", - DataManager.constructPermissionQuery(DataManager.ACTION_SELECT_ALL, Group.class, Geofence.class)); - - assertEquals("INSERT INTO tc_user_device (userId, deviceId) VALUES (:userId, :deviceId)", - DataManager.constructPermissionQuery(DataManager.ACTION_INSERT, User.class, Device.class)); - - assertEquals("DELETE FROM tc_user_user WHERE userId = :userId AND managedUserId = :managedUserId", - DataManager.constructPermissionQuery(DataManager.ACTION_DELETE, User.class, ManagedUser.class)); - - assertEquals("INSERT INTO tc_device_geofence (deviceId, geofenceId) VALUES (:deviceId, :geofenceId)", - DataManager.constructPermissionQuery(DataManager.ACTION_INSERT, Device.class, Geofence.class)); - - assertEquals("DELETE FROM tc_group_attribute WHERE groupId = :groupId AND attributeId = :attributeId", - DataManager.constructPermissionQuery(DataManager.ACTION_DELETE, Group.class, Attribute.class)); - - } - -} -- cgit v1.2.3