diff options
Diffstat (limited to 'src/main/java/org/traccar/notification')
7 files changed, 463 insertions, 0 deletions
diff --git a/src/main/java/org/traccar/notification/EventForwarder.java b/src/main/java/org/traccar/notification/EventForwarder.java new file mode 100644 index 000000000..c0010ebbd --- /dev/null +++ b/src/main/java/org/traccar/notification/EventForwarder.java @@ -0,0 +1,91 @@ +/* + * Copyright 2016 - 2019 Anton Tananaev (anton@traccar.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.traccar.notification; + +import org.traccar.Context; +import org.traccar.model.Device; +import org.traccar.model.Event; +import org.traccar.model.Geofence; +import org.traccar.model.Maintenance; +import org.traccar.model.Position; + +import javax.ws.rs.client.AsyncInvoker; +import javax.ws.rs.client.Invocation; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; + +public abstract class EventForwarder { + + private final String url; + private final String header; + + public EventForwarder() { + url = Context.getConfig().getString("event.forward.url", "http://localhost/"); + header = Context.getConfig().getString("event.forward.header"); + } + + private static final String KEY_POSITION = "position"; + private static final String KEY_EVENT = "event"; + private static final String KEY_GEOFENCE = "geofence"; + private static final String KEY_DEVICE = "device"; + private static final String KEY_MAINTENANCE = "maintenance"; + private static final String KEY_USERS = "users"; + + public final void forwardEvent(Event event, Position position, Set<Long> users) { + + Invocation.Builder requestBuilder = Context.getClient().target(url).request(); + + if (header != null && !header.isEmpty()) { + for (String line: header.split("\\r?\\n")) { + String[] values = line.split(":", 2); + requestBuilder.header(values[0].trim(), values[1].trim()); + } + } + + executeRequest(event, position, users, requestBuilder.async()); + } + + protected Map<String, Object> preparePayload(Event event, Position position, Set<Long> users) { + Map<String, Object> data = new HashMap<>(); + data.put(KEY_EVENT, event); + if (position != null) { + data.put(KEY_POSITION, position); + } + Device device = Context.getIdentityManager().getById(event.getDeviceId()); + if (device != null) { + data.put(KEY_DEVICE, device); + } + if (event.getGeofenceId() != 0) { + Geofence geofence = Context.getGeofenceManager().getById(event.getGeofenceId()); + if (geofence != null) { + data.put(KEY_GEOFENCE, geofence); + } + } + if (event.getMaintenanceId() != 0) { + Maintenance maintenance = Context.getMaintenancesManager().getById(event.getMaintenanceId()); + if (maintenance != null) { + data.put(KEY_MAINTENANCE, maintenance); + } + } + data.put(KEY_USERS, Context.getUsersManager().getItems(users)); + return data; + } + + protected abstract void executeRequest( + Event event, Position position, Set<Long> users, AsyncInvoker invoker); + +} diff --git a/src/main/java/org/traccar/notification/FullMessage.java b/src/main/java/org/traccar/notification/FullMessage.java new file mode 100644 index 000000000..f66537c6e --- /dev/null +++ b/src/main/java/org/traccar/notification/FullMessage.java @@ -0,0 +1,36 @@ +/* + * Copyright 2016 Anton Tananaev (anton@traccar.org) + * Copyright 2016 Andrey Kunitsyn (andrey@traccar.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.traccar.notification; + +public class FullMessage { + + private String subject; + private String body; + + public FullMessage(String subject, String body) { + this.subject = subject; + this.body = body; + } + + public String getSubject() { + return subject; + } + + public String getBody() { + return body; + } +} diff --git a/src/main/java/org/traccar/notification/JsonTypeEventForwarder.java b/src/main/java/org/traccar/notification/JsonTypeEventForwarder.java new file mode 100644 index 000000000..55d926fc8 --- /dev/null +++ b/src/main/java/org/traccar/notification/JsonTypeEventForwarder.java @@ -0,0 +1,18 @@ +package org.traccar.notification; + +import java.util.Set; + +import org.traccar.model.Event; +import org.traccar.model.Position; + +import javax.ws.rs.client.AsyncInvoker; +import javax.ws.rs.client.Entity; + +public class JsonTypeEventForwarder extends EventForwarder { + + @Override + protected void executeRequest(Event event, Position position, Set<Long> users, AsyncInvoker invoker) { + invoker.post(Entity.json(preparePayload(event, position, users))); + } + +} diff --git a/src/main/java/org/traccar/notification/MessageException.java b/src/main/java/org/traccar/notification/MessageException.java new file mode 100644 index 000000000..710b927b0 --- /dev/null +++ b/src/main/java/org/traccar/notification/MessageException.java @@ -0,0 +1,29 @@ +/* + * Copyright 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2018 Andrey Kunitsyn (andrey@traccar.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.traccar.notification; + +public class MessageException extends Exception { + + public MessageException(Throwable cause) { + super(cause); + } + + public MessageException(String message) { + super(message); + } + +} diff --git a/src/main/java/org/traccar/notification/NotificationFormatter.java b/src/main/java/org/traccar/notification/NotificationFormatter.java new file mode 100644 index 000000000..2f8100226 --- /dev/null +++ b/src/main/java/org/traccar/notification/NotificationFormatter.java @@ -0,0 +1,118 @@ +/* + * Copyright 2016 - 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2017 - 2018 Andrey Kunitsyn (andrey@traccar.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.traccar.notification; + +import java.io.StringWriter; +import java.nio.charset.StandardCharsets; +import java.nio.file.Paths; +import java.util.Locale; + +import org.apache.velocity.Template; +import org.apache.velocity.VelocityContext; +import org.apache.velocity.exception.ResourceNotFoundException; +import org.apache.velocity.tools.generic.DateTool; +import org.apache.velocity.tools.generic.NumberTool; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.traccar.Context; +import org.traccar.model.Device; +import org.traccar.model.Event; +import org.traccar.model.Position; +import org.traccar.model.User; +import org.traccar.reports.ReportUtils; + +public final class NotificationFormatter { + + private static final Logger LOGGER = LoggerFactory.getLogger(NotificationFormatter.class); + + private NotificationFormatter() { + } + + public static VelocityContext prepareContext(long userId, Event event, Position position) { + + User user = Context.getPermissionsManager().getUser(userId); + Device device = Context.getIdentityManager().getById(event.getDeviceId()); + + VelocityContext velocityContext = new VelocityContext(); + velocityContext.put("user", user); + velocityContext.put("device", device); + velocityContext.put("event", event); + if (position != null) { + velocityContext.put("position", position); + velocityContext.put("speedUnit", ReportUtils.getSpeedUnit(userId)); + velocityContext.put("distanceUnit", ReportUtils.getDistanceUnit(userId)); + velocityContext.put("volumeUnit", ReportUtils.getVolumeUnit(userId)); + } + if (event.getGeofenceId() != 0) { + velocityContext.put("geofence", Context.getGeofenceManager().getById(event.getGeofenceId())); + } + if (event.getMaintenanceId() != 0) { + velocityContext.put("maintenance", Context.getMaintenancesManager().getById(event.getMaintenanceId())); + } + String driverUniqueId = event.getString(Position.KEY_DRIVER_UNIQUE_ID); + if (driverUniqueId != null) { + velocityContext.put("driver", Context.getDriversManager().getDriverByUniqueId(driverUniqueId)); + } + velocityContext.put("webUrl", Context.getVelocityEngine().getProperty("web.url")); + velocityContext.put("dateTool", new DateTool()); + velocityContext.put("numberTool", new NumberTool()); + velocityContext.put("timezone", ReportUtils.getTimezone(userId)); + velocityContext.put("locale", Locale.getDefault()); + return velocityContext; + } + + public static Template getTemplate(Event event, String path) { + + String templateFilePath; + Template template; + + try { + templateFilePath = Paths.get(path, event.getType() + ".vm").toString(); + template = Context.getVelocityEngine().getTemplate(templateFilePath, StandardCharsets.UTF_8.name()); + } catch (ResourceNotFoundException error) { + LOGGER.warn("Notification template error", error); + templateFilePath = Paths.get(path, "unknown.vm").toString(); + template = Context.getVelocityEngine().getTemplate(templateFilePath, StandardCharsets.UTF_8.name()); + } + return template; + } + + public static FullMessage formatFullMessage(long userId, Event event, Position position) { + VelocityContext velocityContext = prepareContext(userId, event, position); + String formattedMessage = formatMessage(velocityContext, userId, event, position, "full"); + + return new FullMessage((String) velocityContext.get("subject"), formattedMessage); + } + + public static String formatShortMessage(long userId, Event event, Position position) { + return formatMessage(null, userId, event, position, "short"); + } + + private static String formatMessage(VelocityContext vc, Long userId, Event event, Position position, + String templatePath) { + + VelocityContext velocityContext = vc; + if (velocityContext == null) { + velocityContext = prepareContext(userId, event, position); + } + StringWriter writer = new StringWriter(); + getTemplate(event, templatePath).merge(velocityContext, writer); + + return writer.toString(); + } + +} diff --git a/src/main/java/org/traccar/notification/NotificatorManager.java b/src/main/java/org/traccar/notification/NotificatorManager.java new file mode 100644 index 000000000..a4080a38d --- /dev/null +++ b/src/main/java/org/traccar/notification/NotificatorManager.java @@ -0,0 +1,90 @@ +/* + * Copyright 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2018 Andrey Kunitsyn (andrey@traccar.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.traccar.notification; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.traccar.Context; +import org.traccar.model.Typed; +import org.traccar.notificators.NotificatorFirebase; +import org.traccar.notificators.NotificatorMail; +import org.traccar.notificators.NotificatorNull; +import org.traccar.notificators.Notificator; +import org.traccar.notificators.NotificatorSms; +import org.traccar.notificators.NotificatorWeb; + +public final class NotificatorManager { + + private static final Logger LOGGER = LoggerFactory.getLogger(NotificatorManager.class); + + private static final Notificator NULL_NOTIFICATOR = new NotificatorNull(); + + private final Map<String, Notificator> notificators = new HashMap<>(); + + public NotificatorManager() { + final String[] types = Context.getConfig().getString("notificator.types", "").split(","); + for (String type : types) { + String defaultNotificator = ""; + switch (type) { + case "web": + defaultNotificator = NotificatorWeb.class.getCanonicalName(); + break; + case "mail": + defaultNotificator = NotificatorMail.class.getCanonicalName(); + break; + case "sms": + defaultNotificator = NotificatorSms.class.getCanonicalName(); + break; + case "firebase": + defaultNotificator = NotificatorFirebase.class.getCanonicalName(); + break; + default: + break; + } + final String className = Context.getConfig() + .getString("notificator." + type + ".class", defaultNotificator); + try { + notificators.put(type, (Notificator) Class.forName(className).newInstance()); + } catch (ClassNotFoundException | InstantiationException | IllegalAccessException e) { + LOGGER.warn("Unable to load notificator class for " + type + " " + className + " " + e.getMessage()); + } + } + } + + public Notificator getNotificator(String type) { + final Notificator notificator = notificators.get(type); + if (notificator == null) { + LOGGER.warn("No notificator configured for type : " + type); + return NULL_NOTIFICATOR; + } + return notificator; + } + + public Set<Typed> getAllNotificatorTypes() { + Set<Typed> result = new HashSet<>(); + for (String notificator : notificators.keySet()) { + result.add(new Typed(notificator)); + } + return result; + } + +} diff --git a/src/main/java/org/traccar/notification/PropertiesProvider.java b/src/main/java/org/traccar/notification/PropertiesProvider.java new file mode 100644 index 000000000..f0078feef --- /dev/null +++ b/src/main/java/org/traccar/notification/PropertiesProvider.java @@ -0,0 +1,81 @@ +/* + * Copyright 2016 Anton Tananaev (anton@traccar.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.traccar.notification; + +import org.traccar.config.Config; +import org.traccar.model.ExtendedModel; + +public class PropertiesProvider { + + private Config config; + + private ExtendedModel extendedModel; + + public PropertiesProvider(Config config) { + this.config = config; + } + + public PropertiesProvider(ExtendedModel extendedModel) { + this.extendedModel = extendedModel; + } + + public String getString(String key) { + if (config != null) { + return config.getString(key); + } else { + return extendedModel.getString(key); + } + } + + public String getString(String key, String defaultValue) { + String value = getString(key); + if (value == null) { + value = defaultValue; + } + return value; + } + + public int getInteger(String key, int defaultValue) { + if (config != null) { + return config.getInteger(key, defaultValue); + } else { + Object result = extendedModel.getAttributes().get(key); + if (result != null) { + return result instanceof String ? Integer.parseInt((String) result) : (Integer) result; + } else { + return defaultValue; + } + } + } + + public Boolean getBoolean(String key) { + if (config != null) { + if (config.hasKey(key)) { + return config.getBoolean(key); + } else { + return null; + } + } else { + Object result = extendedModel.getAttributes().get(key); + if (result != null) { + return result instanceof String ? Boolean.valueOf((String) result) : (Boolean) result; + } else { + return null; + } + } + } + +} |