From c1121777969fc5f183e325ad672b581cbe881895 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Tue, 28 Dec 2021 23:09:40 -0800 Subject: Extract connector interface --- src/main/java/org/traccar/BaseProtocol.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) (limited to 'src/main/java/org/traccar/BaseProtocol.java') diff --git a/src/main/java/org/traccar/BaseProtocol.java b/src/main/java/org/traccar/BaseProtocol.java index bd3391822..2fca9432e 100644 --- a/src/main/java/org/traccar/BaseProtocol.java +++ b/src/main/java/org/traccar/BaseProtocol.java @@ -35,7 +35,7 @@ public abstract class BaseProtocol implements Protocol { private final String name; private final Set supportedDataCommands = new HashSet<>(); private final Set supportedTextCommands = new HashSet<>(); - private final List serverList = new LinkedList<>(); + private final List connectorList = new LinkedList<>(); private StringProtocolEncoder textCommandEncoder = null; @@ -54,12 +54,14 @@ public abstract class BaseProtocol implements Protocol { } protected void addServer(TrackerServer server) { - serverList.add(server); + connectorList.add(server); } + // TODO addClient + @Override - public Collection getServerList() { - return serverList; + public Collection getConnectorList() { + return connectorList; } public void setSupportedDataCommands(String... commands) { -- cgit v1.2.3 From 0ce163ba62cc991fee56d9c05fca41c9f7a28143 Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Sat, 15 Jan 2022 23:19:23 -0800 Subject: Finish initial implementation --- src/main/java/org/traccar/BasePipelineFactory.java | 4 ++ src/main/java/org/traccar/BaseProtocol.java | 4 +- src/main/java/org/traccar/BaseProtocolPoller.java | 56 ++++++++++++++++++ src/main/java/org/traccar/ServerManager.java | 5 +- src/main/java/org/traccar/TrackerClient.java | 66 +++++++++++++++++---- src/main/java/org/traccar/TrackerConnector.java | 4 +- src/main/java/org/traccar/TrackerServer.java | 24 +++++++- src/main/java/org/traccar/config/Keys.java | 31 +++++++++- .../java/org/traccar/protocol/OrbcommProtocol.java | 40 +++++++++++++ .../traccar/protocol/OrbcommProtocolDecoder.java | 57 ++++++++++++++++++ .../traccar/protocol/OrbcommProtocolPoller.java | 69 ++++++++++++++++++++++ src/test/java/org/traccar/ProtocolTest.java | 6 ++ .../protocol/OrbcommProtocolDecoderTest.java | 18 ++++++ 13 files changed, 366 insertions(+), 18 deletions(-) create mode 100644 src/main/java/org/traccar/BaseProtocolPoller.java create mode 100644 src/main/java/org/traccar/protocol/OrbcommProtocol.java create mode 100644 src/main/java/org/traccar/protocol/OrbcommProtocolDecoder.java create mode 100644 src/main/java/org/traccar/protocol/OrbcommProtocolPoller.java create mode 100644 src/test/java/org/traccar/protocol/OrbcommProtocolDecoderTest.java (limited to 'src/main/java/org/traccar/BaseProtocol.java') diff --git a/src/main/java/org/traccar/BasePipelineFactory.java b/src/main/java/org/traccar/BasePipelineFactory.java index d50852649..89ef76a80 100644 --- a/src/main/java/org/traccar/BasePipelineFactory.java +++ b/src/main/java/org/traccar/BasePipelineFactory.java @@ -67,6 +67,8 @@ public abstract class BasePipelineFactory extends ChannelInitializer { } } + protected abstract void addTransportHandlers(PipelineBuilder pipeline); + protected abstract void addProtocolHandlers(PipelineBuilder pipeline); @SafeVarargs @@ -97,6 +99,8 @@ public abstract class BasePipelineFactory extends ChannelInitializer { protected void initChannel(Channel channel) { final ChannelPipeline pipeline = channel.pipeline(); + addTransportHandlers(pipeline::addLast); + if (timeout > 0 && !connector.isDatagram()) { pipeline.addLast(new IdleStateHandler(timeout, 0, 0)); } diff --git a/src/main/java/org/traccar/BaseProtocol.java b/src/main/java/org/traccar/BaseProtocol.java index 2fca9432e..52d34dc44 100644 --- a/src/main/java/org/traccar/BaseProtocol.java +++ b/src/main/java/org/traccar/BaseProtocol.java @@ -57,7 +57,9 @@ public abstract class BaseProtocol implements Protocol { connectorList.add(server); } - // TODO addClient + protected void addClient(TrackerClient client) { + connectorList.add(client); + } @Override public Collection getConnectorList() { diff --git a/src/main/java/org/traccar/BaseProtocolPoller.java b/src/main/java/org/traccar/BaseProtocolPoller.java new file mode 100644 index 000000000..88138577c --- /dev/null +++ b/src/main/java/org/traccar/BaseProtocolPoller.java @@ -0,0 +1,56 @@ +/* + * Copyright 2022 Anton Tananaev (anton@traccar.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.traccar; + +import io.netty.channel.Channel; +import io.netty.channel.ChannelDuplexHandler; +import io.netty.channel.ChannelHandlerContext; +import io.netty.util.concurrent.Future; +import org.traccar.config.Keys; + +import java.net.SocketAddress; +import java.util.concurrent.TimeUnit; + +public abstract class BaseProtocolPoller extends ChannelDuplexHandler { + + private final long interval; + private Future timeout; + + public BaseProtocolPoller(Protocol protocol) { + interval = Context.getConfig().getLong(Keys.PROTOCOL_INTERVAL.withPrefix(protocol.getName())); + } + + protected abstract void sendRequest(Channel channel, SocketAddress remoteAddress); + + @Override + public void channelActive(ChannelHandlerContext ctx) throws Exception { + super.channelActive(ctx); + if (interval > 0) { + timeout = ctx.executor().scheduleAtFixedRate( + () -> sendRequest(ctx.channel(), ctx.channel().remoteAddress()), 0, interval, TimeUnit.SECONDS); + } + } + + @Override + public void channelInactive(ChannelHandlerContext ctx) throws Exception { + super.channelInactive(ctx); + if (timeout != null) { + timeout.cancel(false); + timeout = null; + } + } + +} diff --git a/src/main/java/org/traccar/ServerManager.java b/src/main/java/org/traccar/ServerManager.java index 45ac656f3..0db786bdb 100644 --- a/src/main/java/org/traccar/ServerManager.java +++ b/src/main/java/org/traccar/ServerManager.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. @@ -22,6 +22,7 @@ import org.traccar.config.Keys; import java.io.File; import java.io.IOException; import java.net.BindException; +import java.net.ConnectException; import java.net.URI; import java.net.URISyntaxException; import java.net.URL; @@ -95,6 +96,8 @@ public class ServerManager { connector.start(); } catch (BindException e) { LOGGER.warn("Port disabled due to conflict", e); + } catch (ConnectException e) { + LOGGER.warn("Connection failed", e); } } } diff --git a/src/main/java/org/traccar/TrackerClient.java b/src/main/java/org/traccar/TrackerClient.java index d86dc43e1..dda02f909 100644 --- a/src/main/java/org/traccar/TrackerClient.java +++ b/src/main/java/org/traccar/TrackerClient.java @@ -16,18 +16,24 @@ package org.traccar; import io.netty.bootstrap.Bootstrap; -import io.netty.channel.ChannelInitializer; import io.netty.channel.group.ChannelGroup; import io.netty.channel.group.DefaultChannelGroup; -import io.netty.channel.socket.SocketChannel; import io.netty.channel.socket.nio.NioSocketChannel; +import io.netty.handler.ssl.SslHandler; +import io.netty.util.concurrent.Future; +import io.netty.util.concurrent.GenericFutureListener; import io.netty.util.concurrent.GlobalEventExecutor; import org.traccar.config.Keys; -import java.util.List; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLEngine; +import java.util.concurrent.TimeUnit; public abstract class TrackerClient implements TrackerConnector { + private final boolean secure; + private final long interval; + private final Bootstrap bootstrap; private final int port; @@ -41,31 +47,54 @@ public abstract class TrackerClient implements TrackerConnector { return false; } + @Override + public boolean isSecure() { + return secure; + } + public TrackerClient(String protocol) { + secure = Context.getConfig().getBoolean(Keys.PROTOCOL_SSL.withPrefix(protocol)); + interval = Context.getConfig().getLong(Keys.PROTOCOL_INTERVAL.withPrefix(protocol)); address = Context.getConfig().getString(Keys.PROTOCOL_ADDRESS.withPrefix(protocol)); - port = Context.getConfig().getInteger(Keys.PROTOCOL_PORT.withPrefix(protocol)); + port = Context.getConfig().getInteger(Keys.PROTOCOL_PORT.withPrefix(protocol), secure ? 443 : 80); devices = Context.getConfig().getString(Keys.PROTOCOL_DEVICES.withPrefix(protocol)).split("[, ]"); BasePipelineFactory pipelineFactory = new BasePipelineFactory(this, protocol) { + @Override + protected void addTransportHandlers(PipelineBuilder pipeline) { + try { + if (isSecure()) { + SSLEngine engine = SSLContext.getDefault().createSSLEngine(); + engine.setUseClientMode(true); + pipeline.addLast(new SslHandler(engine)); + } + } catch (Exception e) { + throw new RuntimeException(e); + } + } + @Override protected void addProtocolHandlers(PipelineBuilder pipeline) { - TrackerClient.this.addProtocolHandlers(pipeline); + try { + TrackerClient.this.addProtocolHandlers(pipeline); + } catch (Exception e) { + throw new RuntimeException(e); + } } }; bootstrap = new Bootstrap() .group(EventLoopGroupFactory.getWorkerGroup()) .channel(NioSocketChannel.class) - .handler(new ChannelInitializer() { - @Override - protected void initChannel(SocketChannel channel) { - pipelineFactory.initChannel(channel); - } - }); + .handler(pipelineFactory); } - protected abstract void addProtocolHandlers(PipelineBuilder pipeline); + protected abstract void addProtocolHandlers(PipelineBuilder pipeline) throws Exception; + + public String[] getDevices() { + return devices; + } @Override public ChannelGroup getChannelGroup() { @@ -74,7 +103,18 @@ public abstract class TrackerClient implements TrackerConnector { @Override public void start() throws Exception { - bootstrap.connect(address, port).sync(); + bootstrap.connect(address, port) + .syncUninterruptibly().channel().closeFuture().addListener(new GenericFutureListener<>() { + @Override + public void operationComplete(Future future) { + if (interval > 0) { + GlobalEventExecutor.INSTANCE.schedule(() -> { + bootstrap.connect(address, port) + .syncUninterruptibly().channel().closeFuture().addListener(this); + }, interval, TimeUnit.SECONDS); + } + } + }); } @Override diff --git a/src/main/java/org/traccar/TrackerConnector.java b/src/main/java/org/traccar/TrackerConnector.java index 9fc5e0f62..9e2d27ae5 100644 --- a/src/main/java/org/traccar/TrackerConnector.java +++ b/src/main/java/org/traccar/TrackerConnector.java @@ -1,5 +1,5 @@ /* - * Copyright 2021 Anton Tananaev (anton@traccar.org) + * Copyright 2021 - 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. @@ -21,6 +21,8 @@ public interface TrackerConnector { boolean isDatagram(); + boolean isSecure(); + ChannelGroup getChannelGroup(); void start() throws Exception; diff --git a/src/main/java/org/traccar/TrackerServer.java b/src/main/java/org/traccar/TrackerServer.java index caae6c585..8e2fce616 100644 --- a/src/main/java/org/traccar/TrackerServer.java +++ b/src/main/java/org/traccar/TrackerServer.java @@ -23,14 +23,18 @@ import io.netty.channel.group.ChannelGroup; import io.netty.channel.group.DefaultChannelGroup; import io.netty.channel.socket.nio.NioDatagramChannel; import io.netty.channel.socket.nio.NioServerSocketChannel; +import io.netty.handler.ssl.SslHandler; import io.netty.util.concurrent.GlobalEventExecutor; import org.traccar.config.Keys; +import javax.net.ssl.SSLContext; +import javax.net.ssl.SSLEngine; import java.net.InetSocketAddress; public abstract class TrackerServer implements TrackerConnector { private final boolean datagram; + private final boolean secure; @SuppressWarnings("rawtypes") private final AbstractBootstrap bootstrap; @@ -45,13 +49,31 @@ public abstract class TrackerServer implements TrackerConnector { return datagram; } + @Override + public boolean isSecure() { + return secure; + } + public TrackerServer(boolean datagram, String protocol) { this.datagram = datagram; + secure = Context.getConfig().getBoolean(Keys.PROTOCOL_SSL.withPrefix(protocol)); address = Context.getConfig().getString(Keys.PROTOCOL_ADDRESS.withPrefix(protocol)); port = Context.getConfig().getInteger(Keys.PROTOCOL_PORT.withPrefix(protocol)); BasePipelineFactory pipelineFactory = new BasePipelineFactory(this, protocol) { + @Override + protected void addTransportHandlers(PipelineBuilder pipeline) { + try { + if (isSecure()) { + SSLEngine engine = SSLContext.getDefault().createSSLEngine(); + pipeline.addLast(new SslHandler(engine)); + } + } catch (Exception e) { + throw new RuntimeException(e); + } + } + @Override protected void addProtocolHandlers(PipelineBuilder pipeline) { TrackerServer.this.addProtocolHandlers(pipeline); @@ -99,7 +121,7 @@ public abstract class TrackerServer implements TrackerConnector { endpoint = new InetSocketAddress(address, port); } - Channel channel = bootstrap.bind(endpoint).sync().channel(); + Channel channel = bootstrap.bind(endpoint).syncUninterruptibly().channel(); if (channel != null) { getChannelGroup().add(channel); } diff --git a/src/main/java/org/traccar/config/Keys.java b/src/main/java/org/traccar/config/Keys.java index 8f93b21c1..cb3bd4de8 100644 --- a/src/main/java/org/traccar/config/Keys.java +++ b/src/main/java/org/traccar/config/Keys.java @@ -38,12 +38,27 @@ public final class Keys { Collections.singletonList(KeyType.GLOBAL)); /** - * List of devices for polling protocols. List should contain unique ids separated by commas. + * List of devices for polling protocols. List should contain unique ids separated by commas. Used only for polling + * protocols. */ public static final ConfigSuffix PROTOCOL_DEVICES = new ConfigSuffix<>( ".devices", Collections.singletonList(KeyType.GLOBAL)); + /** + * Polling interval in seconds. Used only for polling protocols. + */ + public static final ConfigSuffix PROTOCOL_INTERVAL = new ConfigSuffix<>( + ".interval", + Collections.singletonList(KeyType.GLOBAL)); + + /** + * Enable SSL support for the protocol. Not all protocols support this. + */ + public static final ConfigSuffix PROTOCOL_SSL = new ConfigSuffix<>( + ".ssl", + Collections.singletonList(KeyType.GLOBAL)); + /** * Connection timeout value in seconds. Because sometimes there is no way to detect lost TCP connection old * connections stay in open state. On most systems there is a limit on number of open connection, so this leads to @@ -182,6 +197,20 @@ public final class Keys { ".ignoreSessionCache", Collections.singletonList(KeyType.GLOBAL)); + /** + * ORBCOMM API access id. + */ + public static final ConfigKey ORBCOMM_ACCESS_ID = new ConfigKey<>( + "orbcomm.accessId", + Collections.singletonList(KeyType.GLOBAL)); + + /** + * ORBCOMM API password. + */ + public static final ConfigKey ORBCOMM_PASSWORD = new ConfigKey<>( + "orbcomm.password", + Collections.singletonList(KeyType.GLOBAL)); + /** * Skip device connection session cache. Global configuration. */ diff --git a/src/main/java/org/traccar/protocol/OrbcommProtocol.java b/src/main/java/org/traccar/protocol/OrbcommProtocol.java new file mode 100644 index 000000000..bdfce3b1e --- /dev/null +++ b/src/main/java/org/traccar/protocol/OrbcommProtocol.java @@ -0,0 +1,40 @@ +/* + * Copyright 2022 Anton Tananaev (anton@traccar.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.traccar.protocol; + +import io.netty.handler.codec.http.HttpObjectAggregator; +import io.netty.handler.codec.http.HttpRequestEncoder; +import io.netty.handler.codec.http.HttpResponseDecoder; +import org.traccar.BaseProtocol; +import org.traccar.PipelineBuilder; +import org.traccar.TrackerClient; + +public class OrbcommProtocol extends BaseProtocol { + + public OrbcommProtocol() { + addClient(new TrackerClient(getName()) { + @Override + protected void addProtocolHandlers(PipelineBuilder pipeline) { + pipeline.addLast(new HttpRequestEncoder()); + pipeline.addLast(new HttpResponseDecoder()); + pipeline.addLast(new HttpObjectAggregator(65535)); + pipeline.addLast(new OrbcommProtocolDecoder(OrbcommProtocol.this)); + pipeline.addLast(new OrbcommProtocolPoller(OrbcommProtocol.this)); + } + }); + } + +} diff --git a/src/main/java/org/traccar/protocol/OrbcommProtocolDecoder.java b/src/main/java/org/traccar/protocol/OrbcommProtocolDecoder.java new file mode 100644 index 000000000..8f828beff --- /dev/null +++ b/src/main/java/org/traccar/protocol/OrbcommProtocolDecoder.java @@ -0,0 +1,57 @@ +/* + * Copyright 2022 Anton Tananaev (anton@traccar.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.traccar.protocol; + +import io.netty.channel.Channel; +import io.netty.handler.codec.http.FullHttpResponse; +import org.traccar.BasePipelineFactory; +import org.traccar.BaseProtocolDecoder; +import org.traccar.Protocol; + +import javax.json.Json; +import javax.json.JsonObject; +import java.io.StringReader; +import java.net.SocketAddress; +import java.nio.charset.StandardCharsets; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.TimeZone; + +public class OrbcommProtocolDecoder extends BaseProtocolDecoder { + + public OrbcommProtocolDecoder(Protocol protocol) { + super(protocol); + } + + @Override + protected Object decode( + Channel channel, SocketAddress remoteAddress, Object msg) throws Exception { + + FullHttpResponse response = (FullHttpResponse) msg; + String content = response.content().toString(StandardCharsets.UTF_8); + JsonObject json = Json.createReader(new StringReader(content)).readObject(); + + OrbcommProtocolPoller poller = BasePipelineFactory.getHandler(channel.pipeline(), OrbcommProtocolPoller.class); + if (poller != null) { + DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); + poller.setStartTime(dateFormat.parse(json.getString("NextStartUTC"))); + } + + return null; + } + +} diff --git a/src/main/java/org/traccar/protocol/OrbcommProtocolPoller.java b/src/main/java/org/traccar/protocol/OrbcommProtocolPoller.java new file mode 100644 index 000000000..87fa039e1 --- /dev/null +++ b/src/main/java/org/traccar/protocol/OrbcommProtocolPoller.java @@ -0,0 +1,69 @@ +/* + * Copyright 2022 Anton Tananaev (anton@traccar.org) + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package org.traccar.protocol; + +import io.netty.buffer.Unpooled; +import io.netty.channel.Channel; +import io.netty.handler.codec.http.DefaultFullHttpRequest; +import io.netty.handler.codec.http.HttpMethod; +import io.netty.handler.codec.http.HttpRequest; +import io.netty.handler.codec.http.HttpVersion; +import io.netty.handler.codec.http.QueryStringEncoder; +import org.traccar.BaseProtocolPoller; +import org.traccar.Context; +import org.traccar.Protocol; +import org.traccar.config.Keys; + +import java.net.SocketAddress; +import java.text.DateFormat; +import java.text.SimpleDateFormat; +import java.util.Date; +import java.util.TimeZone; + +public class OrbcommProtocolPoller extends BaseProtocolPoller { + + private final String accessId; + private final String password; + + private Date startTime = new Date(); + + public void setStartTime(Date startTime) { + this.startTime = startTime; + } + + public OrbcommProtocolPoller(Protocol protocol) { + super(protocol); + accessId = Context.getConfig().getString(Keys.ORBCOMM_ACCESS_ID); + password = Context.getConfig().getString(Keys.ORBCOMM_PASSWORD); + } + + @Override + protected void sendRequest(Channel channel, SocketAddress remoteAddress) { + + QueryStringEncoder encoder = new QueryStringEncoder("/GLGW/2/RestMessages.svc/JSON/get_return_messages/"); + encoder.addParam("access_id", accessId); + encoder.addParam("password", password); + + DateFormat dateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + dateFormat.setTimeZone(TimeZone.getTimeZone("UTC")); + encoder.addParam("start_utc", dateFormat.format(startTime)); + + HttpRequest request = new DefaultFullHttpRequest( + HttpVersion.HTTP_1_1, HttpMethod.POST, encoder.toString(), Unpooled.buffer()); + channel.writeAndFlush(request); + } + +} diff --git a/src/test/java/org/traccar/ProtocolTest.java b/src/test/java/org/traccar/ProtocolTest.java index c40a15dcc..353593c29 100644 --- a/src/test/java/org/traccar/ProtocolTest.java +++ b/src/test/java/org/traccar/ProtocolTest.java @@ -4,9 +4,11 @@ import io.netty.buffer.ByteBuf; import io.netty.buffer.ByteBufUtil; import io.netty.buffer.Unpooled; import io.netty.handler.codec.http.DefaultFullHttpRequest; +import io.netty.handler.codec.http.DefaultFullHttpResponse; import io.netty.handler.codec.http.DefaultHttpHeaders; import io.netty.handler.codec.http.HttpHeaders; import io.netty.handler.codec.http.HttpMethod; +import io.netty.handler.codec.http.HttpResponseStatus; import io.netty.handler.codec.http.HttpVersion; import org.traccar.helper.DataConverter; import org.traccar.model.CellTower; @@ -89,6 +91,10 @@ public class ProtocolTest extends BaseTest { return new DefaultFullHttpRequest(HttpVersion.HTTP_1_1, method, url, Unpooled.buffer(), headers, new DefaultHttpHeaders()); } + protected DefaultFullHttpResponse response(ByteBuf data) { + return new DefaultFullHttpResponse(HttpVersion.HTTP_1_1, HttpResponseStatus.OK, data); + } + protected void verifyNotNull(BaseProtocolDecoder decoder, Object object) throws Exception { assertNotNull(decoder.decode(null, null, object)); } diff --git a/src/test/java/org/traccar/protocol/OrbcommProtocolDecoderTest.java b/src/test/java/org/traccar/protocol/OrbcommProtocolDecoderTest.java new file mode 100644 index 000000000..fe84c1af4 --- /dev/null +++ b/src/test/java/org/traccar/protocol/OrbcommProtocolDecoderTest.java @@ -0,0 +1,18 @@ +package org.traccar.protocol; + +import org.junit.Test; +import org.traccar.ProtocolTest; + +public class OrbcommProtocolDecoderTest extends ProtocolTest { + + @Test + public void testDecode() throws Exception { + + var decoder = new OrbcommProtocolDecoder(null); + + verifyNull(decoder, response( + buffer("{\"ErrorID\":0,\"NextStartUTC\":\"2016-10-13 15:19:59\",\"Messages\":[{\"ID\":120213064,\"MessageUTC\":\"2016-10-12 12:42:01\",\"ReceiveUTC\":\"2016-10-12 12:42:01\",\"SIN\":0,\"MobileID\":\"01173096SKY0E45\",\"Payload\":{\"Name\":\"modemRegistration\",\"SIN\":0,\"MIN\":0,\"Fields\":[{\"Name\":\"hardwareMajorVersion\",\"Value\":\"4\"},{\"Name\":\"hardwareMinorVersion\",\"Value\":\"2\"},{\"Name\":\"softwareMajorVersion\",\"Value\":\"13\"},{\"Name\":\"softwareMinorVersion\",\"Value\":\"1\"},{\"Name\":\"product\",\"Value\":\"4\"},{\"Name\":\"wakeupPeriod\",\"Value\":\"None\"},{\"Name\":\"lastResetReason\",\"Value\":\"Software\"},{\"Name\":\"virtualCarrier\",\"Value\":\"6\"},{\"Name\":\"beam\",\"Value\":\"1\"},{\"Name\":\"vain\",\"Value\":\"0\"},{\"Name\":\"reserved\",\"Value\":\"0\"},{\"Name\":\"operatorTxState\",\"Value\":\"0\"},{\"Name\":\"userTxState\",\"Value\":\"0\"},{\"Name\":\"broadcastIDCount\",\"Value\":\"0\"}}],\"RegionName\":\"AMERRB11\",\"OTAMessageSize\":15,\"CustomerID\":0}]}"))); + + } + +} -- cgit v1.2.3 From 65f9e253171dc6805127e5279b97fad05f8c4b9f Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Tue, 7 Jun 2022 07:07:25 -0700 Subject: Remove async methods --- src/main/java/org/traccar/BaseProtocol.java | 4 +-- .../traccar/api/resource/NotificationResource.java | 4 +-- .../java/org/traccar/database/CommandsManager.java | 2 +- .../org/traccar/database/NotificationManager.java | 13 +++++++-- .../java/org/traccar/notificators/Notificator.java | 19 ++----------- .../traccar/notificators/NotificatorFirebase.java | 9 ++---- .../org/traccar/notificators/NotificatorMail.java | 4 +-- .../org/traccar/notificators/NotificatorNull.java | 9 ++---- .../traccar/notificators/NotificatorPushover.java | 9 ++---- .../org/traccar/notificators/NotificatorSms.java | 18 ++---------- .../traccar/notificators/NotificatorTelegram.java | 9 ++---- .../org/traccar/notificators/NotificatorWeb.java | 4 +-- src/main/java/org/traccar/sms/HttpSmsClient.java | 32 +++++----------------- src/main/java/org/traccar/sms/SmsManager.java | 7 ++--- src/main/java/org/traccar/sms/SnsSmsClient.java | 9 ++---- 15 files changed, 43 insertions(+), 109 deletions(-) (limited to 'src/main/java/org/traccar/BaseProtocol.java') diff --git a/src/main/java/org/traccar/BaseProtocol.java b/src/main/java/org/traccar/BaseProtocol.java index 52d34dc44..ec1933dc8 100644 --- a/src/main/java/org/traccar/BaseProtocol.java +++ b/src/main/java/org/traccar/BaseProtocol.java @@ -113,11 +113,11 @@ public abstract class BaseProtocol implements Protocol { public void sendTextCommand(String destAddress, Command command) throws Exception { if (Context.getSmsManager() != null) { if (command.getType().equals(Command.TYPE_CUSTOM)) { - Context.getSmsManager().sendMessageSync(destAddress, command.getString(Command.KEY_DATA), true); + Context.getSmsManager().sendMessage(destAddress, command.getString(Command.KEY_DATA), true); } else if (supportedTextCommands.contains(command.getType()) && textCommandEncoder != null) { String encodedCommand = (String) textCommandEncoder.encodeCommand(command); if (encodedCommand != null) { - Context.getSmsManager().sendMessageSync(destAddress, encodedCommand, true); + Context.getSmsManager().sendMessage(destAddress, encodedCommand, true); } else { throw new RuntimeException("Failed to encode command"); } diff --git a/src/main/java/org/traccar/api/resource/NotificationResource.java b/src/main/java/org/traccar/api/resource/NotificationResource.java index 2fc103e20..9ea811473 100644 --- a/src/main/java/org/traccar/api/resource/NotificationResource.java +++ b/src/main/java/org/traccar/api/resource/NotificationResource.java @@ -62,7 +62,7 @@ public class NotificationResource extends ExtendedObjectResource { User user = permissionsService.getUser(getUserId()); for (Typed method : Context.getNotificatorManager().getAllNotificatorTypes()) { Context.getNotificatorManager() - .getNotificator(method.getType()).sendSync(user, new Event("test", 0), null); + .getNotificator(method.getType()).send(user, new Event("test", 0), null); } return Response.noContent().build(); } @@ -72,7 +72,7 @@ public class NotificationResource extends ExtendedObjectResource { public Response testMessage(@PathParam("notificator") String notificator) throws MessageException, InterruptedException, StorageException { User user = permissionsService.getUser(getUserId()); - Context.getNotificatorManager().getNotificator(notificator).sendSync(user, new Event("test", 0), null); + Context.getNotificatorManager().getNotificator(notificator).send(user, new Event("test", 0), null); return Response.noContent().build(); } diff --git a/src/main/java/org/traccar/database/CommandsManager.java b/src/main/java/org/traccar/database/CommandsManager.java index d440755f7..8dd2ba8b7 100644 --- a/src/main/java/org/traccar/database/CommandsManager.java +++ b/src/main/java/org/traccar/database/CommandsManager.java @@ -79,7 +79,7 @@ public class CommandsManager { BaseProtocol protocol = serverManager.getProtocol(position.getProtocol()); protocol.sendTextCommand(device.getPhone(), command); } else if (command.getType().equals(Command.TYPE_CUSTOM)) { - smsManager.sendMessageSync(device.getPhone(), command.getString(Command.KEY_DATA), true); + smsManager.sendMessage(device.getPhone(), command.getString(Command.KEY_DATA), true); } else { throw new RuntimeException("Command " + command.getType() + " is not supported"); } diff --git a/src/main/java/org/traccar/database/NotificationManager.java b/src/main/java/org/traccar/database/NotificationManager.java index f88b3b18c..2f912fff1 100644 --- a/src/main/java/org/traccar/database/NotificationManager.java +++ b/src/main/java/org/traccar/database/NotificationManager.java @@ -36,6 +36,7 @@ import org.traccar.model.Notification; import org.traccar.model.Position; import org.traccar.model.Typed; import org.traccar.model.User; +import org.traccar.notification.MessageException; import org.traccar.storage.StorageException; public class NotificationManager extends ExtendedObjectManager { @@ -108,9 +109,15 @@ public class NotificationManager extends ExtendedObjectManager { } User user = Context.getUsersManager().getById(userId); - for (String notificator : notificators) { - Context.getNotificatorManager().getNotificator(notificator).sendAsync(user, event, position); - } + new Thread(() -> { + for (String notificator : notificators) { + try { + Context.getNotificatorManager().getNotificator(notificator).send(user, event, position); + } catch (MessageException | InterruptedException exception) { + LOGGER.warn("Notification failed", exception); + } + } + }).start(); } if (Context.getEventForwarder() != null) { Context.getEventForwarder().forwardEvent(event, position, usersToForward); diff --git a/src/main/java/org/traccar/notificators/Notificator.java b/src/main/java/org/traccar/notificators/Notificator.java index 3903f3008..052365c7a 100644 --- a/src/main/java/org/traccar/notificators/Notificator.java +++ b/src/main/java/org/traccar/notificators/Notificator.java @@ -16,28 +16,13 @@ */ package org.traccar.notificators; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.traccar.model.Event; import org.traccar.model.Position; import org.traccar.model.User; import org.traccar.notification.MessageException; -public abstract class Notificator { +public interface Notificator { - private static final Logger LOGGER = LoggerFactory.getLogger(Notificator.class); - - public void sendAsync(User user, Event event, Position position) { - new Thread(() -> { - try { - sendSync(user, event, position); - } catch (MessageException | InterruptedException error) { - LOGGER.warn("Event send error", error); - } - }).start(); - } - - public abstract void sendSync(User user, Event event, Position position) - throws MessageException, InterruptedException; + void send(User user, Event event, Position position) throws MessageException, InterruptedException; } diff --git a/src/main/java/org/traccar/notificators/NotificatorFirebase.java b/src/main/java/org/traccar/notificators/NotificatorFirebase.java index ee22b3a22..cafd2237d 100644 --- a/src/main/java/org/traccar/notificators/NotificatorFirebase.java +++ b/src/main/java/org/traccar/notificators/NotificatorFirebase.java @@ -32,7 +32,7 @@ import org.traccar.session.cache.CacheManager; import javax.ws.rs.client.Entity; import javax.ws.rs.client.InvocationCallback; -public class NotificatorFirebase extends Notificator { +public class NotificatorFirebase implements Notificator { private static final Logger LOGGER = LoggerFactory.getLogger(NotificatorFirebase.class); @@ -67,7 +67,7 @@ public class NotificatorFirebase extends Notificator { } @Override - public void sendSync(User user, Event event, Position position) { + public void send(User user, Event event, Position position) { if (user.getAttributes().containsKey("notificationTokens")) { NotificationMessage shortMessage = NotificationFormatter.formatMessage( @@ -97,9 +97,4 @@ public class NotificatorFirebase extends Notificator { } } - @Override - public void sendAsync(User user, Event event, Position position) { - sendSync(user, event, position); - } - } diff --git a/src/main/java/org/traccar/notificators/NotificatorMail.java b/src/main/java/org/traccar/notificators/NotificatorMail.java index 7b85254be..fd7cae7c3 100644 --- a/src/main/java/org/traccar/notificators/NotificatorMail.java +++ b/src/main/java/org/traccar/notificators/NotificatorMail.java @@ -28,10 +28,10 @@ import org.traccar.session.cache.CacheManager; import javax.mail.MessagingException; -public final class NotificatorMail extends Notificator { +public final class NotificatorMail implements Notificator { @Override - public void sendSync(User user, Event event, Position position) throws MessageException { + public void send(User user, Event event, Position position) throws MessageException { try { NotificationMessage fullMessage = NotificationFormatter.formatMessage( Main.getInjector().getInstance(CacheManager.class), user, event, position, "full"); diff --git a/src/main/java/org/traccar/notificators/NotificatorNull.java b/src/main/java/org/traccar/notificators/NotificatorNull.java index a03a6e2c9..ba9ade9c6 100644 --- a/src/main/java/org/traccar/notificators/NotificatorNull.java +++ b/src/main/java/org/traccar/notificators/NotificatorNull.java @@ -22,17 +22,12 @@ import org.traccar.model.Event; import org.traccar.model.Position; import org.traccar.model.User; -public final class NotificatorNull extends Notificator { +public class NotificatorNull implements Notificator { private static final Logger LOGGER = LoggerFactory.getLogger(NotificatorNull.class); @Override - public void sendAsync(User user, Event event, Position position) { - LOGGER.warn("You are using null notificatior, please check your configuration, notification not sent"); - } - - @Override - public void sendSync(User user, Event event, Position position) { + public void send(User user, Event event, Position position) { LOGGER.warn("You are using null notificatior, please check your configuration, notification not sent"); } diff --git a/src/main/java/org/traccar/notificators/NotificatorPushover.java b/src/main/java/org/traccar/notificators/NotificatorPushover.java index ffd9b426f..70c1a6cdc 100644 --- a/src/main/java/org/traccar/notificators/NotificatorPushover.java +++ b/src/main/java/org/traccar/notificators/NotificatorPushover.java @@ -31,7 +31,7 @@ import org.traccar.session.cache.CacheManager; import javax.ws.rs.client.Entity; import javax.ws.rs.client.InvocationCallback; -public class NotificatorPushover extends Notificator { +public class NotificatorPushover implements Notificator { private static final Logger LOGGER = LoggerFactory.getLogger(NotificatorPushover.class); @@ -59,7 +59,7 @@ public class NotificatorPushover extends Notificator { } @Override - public void sendSync(User user, Event event, Position position) { + public void send(User user, Event event, Position position) { String device = ""; @@ -100,9 +100,4 @@ public class NotificatorPushover extends Notificator { }); } - @Override - public void sendAsync(User user, Event event, Position position) { - sendSync(user, event, position); - } - } diff --git a/src/main/java/org/traccar/notificators/NotificatorSms.java b/src/main/java/org/traccar/notificators/NotificatorSms.java index ae409c558..f35b797cd 100644 --- a/src/main/java/org/traccar/notificators/NotificatorSms.java +++ b/src/main/java/org/traccar/notificators/NotificatorSms.java @@ -27,27 +27,15 @@ import org.traccar.notification.NotificationFormatter; import org.traccar.notification.NotificationMessage; import org.traccar.session.cache.CacheManager; -public final class NotificatorSms extends Notificator { +public final class NotificatorSms implements Notificator { @Override - public void sendAsync(User user, Event event, Position position) { + public void send(User user, Event event, Position position) throws MessageException, InterruptedException { if (user.getPhone() != null) { NotificationMessage shortMessage = NotificationFormatter.formatMessage( Main.getInjector().getInstance(CacheManager.class), user, event, position, "short"); Main.getInjector().getInstance(StatisticsManager.class).registerSms(); - Context.getSmsManager().sendMessageAsync(user.getPhone(), - shortMessage.getBody(), false); - } - } - - @Override - public void sendSync(User user, Event event, Position position) throws MessageException, InterruptedException { - if (user.getPhone() != null) { - NotificationMessage shortMessage = NotificationFormatter.formatMessage( - Main.getInjector().getInstance(CacheManager.class), user, event, position, "short"); - Main.getInjector().getInstance(StatisticsManager.class).registerSms(); - Context.getSmsManager().sendMessageSync(user.getPhone(), - shortMessage.getBody(), false); + Context.getSmsManager().sendMessage(user.getPhone(), shortMessage.getBody(), false); } } diff --git a/src/main/java/org/traccar/notificators/NotificatorTelegram.java b/src/main/java/org/traccar/notificators/NotificatorTelegram.java index 46e29559d..0ed53ac4c 100644 --- a/src/main/java/org/traccar/notificators/NotificatorTelegram.java +++ b/src/main/java/org/traccar/notificators/NotificatorTelegram.java @@ -32,7 +32,7 @@ import org.traccar.session.cache.CacheManager; import javax.ws.rs.client.Entity; import javax.ws.rs.client.InvocationCallback; -public class NotificatorTelegram extends Notificator { +public class NotificatorTelegram implements Notificator { private static final Logger LOGGER = LoggerFactory.getLogger(NotificatorTelegram.class); @@ -99,7 +99,7 @@ public class NotificatorTelegram extends Notificator { } @Override - public void sendSync(User user, Event event, Position position) { + public void send(User user, Event event, Position position) { NotificationMessage shortMessage = NotificationFormatter.formatMessage( Main.getInjector().getInstance(CacheManager.class), user, event, position, "short"); @@ -115,9 +115,4 @@ public class NotificatorTelegram extends Notificator { } } - @Override - public void sendAsync(User user, Event event, Position position) { - sendSync(user, event, position); - } - } diff --git a/src/main/java/org/traccar/notificators/NotificatorWeb.java b/src/main/java/org/traccar/notificators/NotificatorWeb.java index c9ab93b6d..023cb04af 100644 --- a/src/main/java/org/traccar/notificators/NotificatorWeb.java +++ b/src/main/java/org/traccar/notificators/NotificatorWeb.java @@ -21,10 +21,10 @@ import org.traccar.model.Event; import org.traccar.model.Position; import org.traccar.model.User; -public final class NotificatorWeb extends Notificator { +public final class NotificatorWeb implements Notificator { @Override - public void sendSync(User user, Event event, Position position) { + public void send(User user, Event event, Position position) { Context.getConnectionManager().updateEvent(user.getId(), event); } diff --git a/src/main/java/org/traccar/sms/HttpSmsClient.java b/src/main/java/org/traccar/sms/HttpSmsClient.java index 6234eabb8..5c3cef747 100644 --- a/src/main/java/org/traccar/sms/HttpSmsClient.java +++ b/src/main/java/org/traccar/sms/HttpSmsClient.java @@ -1,5 +1,5 @@ /* - * Copyright 2018 - 2020 Anton Tananaev (anton@traccar.org) + * Copyright 2018 - 2022 Anton Tananaev (anton@traccar.org) * Copyright 2018 Andrey Kunitsyn (andrey@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -16,8 +16,6 @@ */ package org.traccar.sms; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; import org.traccar.Context; import org.traccar.config.Keys; import org.traccar.helper.DataConverter; @@ -25,7 +23,6 @@ import org.traccar.notification.MessageException; import javax.ws.rs.client.Entity; import javax.ws.rs.client.Invocation; -import javax.ws.rs.client.InvocationCallback; import javax.ws.rs.core.MediaType; import javax.ws.rs.core.Response; import java.io.UnsupportedEncodingException; @@ -34,8 +31,6 @@ import java.nio.charset.StandardCharsets; public class HttpSmsClient implements SmsManager { - private static final Logger LOGGER = LoggerFactory.getLogger(HttpSmsClient.class); - private final String url; private final String authorizationHeader; private final String authorization; @@ -91,26 +86,13 @@ public class HttpSmsClient implements SmsManager { } @Override - public void sendMessageSync(String destAddress, String message, boolean command) throws MessageException { - Response response = getRequestBuilder().post(Entity.entity(preparePayload(destAddress, message), mediaType)); - if (response.getStatus() / 100 != 2) { - throw new MessageException(response.readEntity(String.class)); - } - } - - @Override - public void sendMessageAsync(final String destAddress, final String message, final boolean command) { - getRequestBuilder().async().post( - Entity.entity(preparePayload(destAddress, message), mediaType), new InvocationCallback() { - @Override - public void completed(String s) { - } - - @Override - public void failed(Throwable throwable) { - LOGGER.warn("SMS send failed", throwable); + public void sendMessage(String destAddress, String message, boolean command) throws MessageException { + try (Response response = getRequestBuilder() + .post(Entity.entity(preparePayload(destAddress, message), mediaType))) { + if (response.getStatus() / 100 != 2) { + throw new MessageException(response.readEntity(String.class)); } - }); + } } } diff --git a/src/main/java/org/traccar/sms/SmsManager.java b/src/main/java/org/traccar/sms/SmsManager.java index 3b0cbda7f..9ab25d9cb 100644 --- a/src/main/java/org/traccar/sms/SmsManager.java +++ b/src/main/java/org/traccar/sms/SmsManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2018 Anton Tananaev (anton@traccar.org) + * Copyright 2018 - 2022 Anton Tananaev (anton@traccar.org) * Copyright 2018 Andrey Kunitsyn (andrey@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -20,10 +20,7 @@ import org.traccar.notification.MessageException; public interface SmsManager { - void sendMessageSync( + void sendMessage( String destAddress, String message, boolean command) throws InterruptedException, MessageException; - void sendMessageAsync( - String destAddress, String message, boolean command); - } diff --git a/src/main/java/org/traccar/sms/SnsSmsClient.java b/src/main/java/org/traccar/sms/SnsSmsClient.java index bdd4104f5..49889ac89 100644 --- a/src/main/java/org/traccar/sms/SnsSmsClient.java +++ b/src/main/java/org/traccar/sms/SnsSmsClient.java @@ -1,5 +1,5 @@ /* - * Copyright 2021 Anton Tananaev (anton@traccar.org) + * Copyright 2021 - 2022 Anton Tananaev (anton@traccar.org) * Copyright 2021 Subodh Ranadive (subodhranadive3103@gmail.com) * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -54,7 +54,7 @@ public class SnsSmsClient implements SmsManager { } @Override - public void sendMessageSync(String destAddress, String message, boolean command) { + public void sendMessage(String destAddress, String message, boolean command) { Map smsAttributes = new HashMap<>(); smsAttributes.put("AWS.SNS.SMS.SenderID", new MessageAttributeValue().withStringValue("SNS").withDataType("String")); @@ -74,9 +74,4 @@ public class SnsSmsClient implements SmsManager { } }); } - - @Override - public void sendMessageAsync(String destAddress, String message, boolean command) { - sendMessageSync(destAddress, message, command); - } } -- cgit v1.2.3 From adafc5f6130854dd88c191dd04489073419ee41d Mon Sep 17 00:00:00 2001 From: Anton Tananaev Date: Thu, 9 Jun 2022 17:56:37 -0700 Subject: Remove SMS from context --- src/main/java/org/traccar/BaseProtocol.java | 18 +++++-- src/main/java/org/traccar/Context.java | 15 ------ src/main/java/org/traccar/MainModule.java | 12 ++++- src/main/java/org/traccar/ServerManager.java | 6 ++- src/main/java/org/traccar/config/Keys.java | 8 ++++ .../traccar/notification/NotificatorManager.java | 56 ++++++++-------------- .../org/traccar/notificators/NotificatorSms.java | 24 +++++++--- 7 files changed, 74 insertions(+), 65 deletions(-) (limited to 'src/main/java/org/traccar/BaseProtocol.java') diff --git a/src/main/java/org/traccar/BaseProtocol.java b/src/main/java/org/traccar/BaseProtocol.java index ec1933dc8..d19fc307e 100644 --- a/src/main/java/org/traccar/BaseProtocol.java +++ b/src/main/java/org/traccar/BaseProtocol.java @@ -1,5 +1,5 @@ /* - * Copyright 2015 - 2020 Anton Tananaev (anton@traccar.org) + * Copyright 2015 - 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. @@ -21,7 +21,10 @@ import io.netty.channel.Channel; import io.netty.handler.codec.string.StringEncoder; import org.traccar.helper.DataConverter; import org.traccar.model.Command; +import org.traccar.sms.SmsManager; +import javax.annotation.Nullable; +import javax.inject.Inject; import java.net.SocketAddress; import java.util.Arrays; import java.util.Collection; @@ -37,6 +40,8 @@ public abstract class BaseProtocol implements Protocol { private final Set supportedTextCommands = new HashSet<>(); private final List connectorList = new LinkedList<>(); + private SmsManager smsManager; + private StringProtocolEncoder textCommandEncoder = null; public static String nameFromClass(Class clazz) { @@ -48,6 +53,11 @@ public abstract class BaseProtocol implements Protocol { name = nameFromClass(getClass()); } + @Inject + public void setSmsManager(@Nullable SmsManager smsManager) { + this.smsManager = smsManager; + } + @Override public String getName() { return name; @@ -111,13 +121,13 @@ public abstract class BaseProtocol implements Protocol { @Override public void sendTextCommand(String destAddress, Command command) throws Exception { - if (Context.getSmsManager() != null) { + if (smsManager != null) { if (command.getType().equals(Command.TYPE_CUSTOM)) { - Context.getSmsManager().sendMessage(destAddress, command.getString(Command.KEY_DATA), true); + smsManager.sendMessage(destAddress, command.getString(Command.KEY_DATA), true); } else if (supportedTextCommands.contains(command.getType()) && textCommandEncoder != null) { String encodedCommand = (String) textCommandEncoder.encodeCommand(command); if (encodedCommand != null) { - Context.getSmsManager().sendMessage(destAddress, encodedCommand, true); + smsManager.sendMessage(destAddress, encodedCommand, true); } else { throw new RuntimeException("Failed to encode command"); } diff --git a/src/main/java/org/traccar/Context.java b/src/main/java/org/traccar/Context.java index 3e4cc1bb9..5011764c6 100644 --- a/src/main/java/org/traccar/Context.java +++ b/src/main/java/org/traccar/Context.java @@ -43,9 +43,6 @@ import org.traccar.notification.EventForwarder; import org.traccar.notification.NotificatorManager; import org.traccar.session.ConnectionManager; import org.traccar.session.cache.CacheManager; -import org.traccar.sms.HttpSmsClient; -import org.traccar.sms.SmsManager; -import org.traccar.sms.SnsSmsClient; import javax.ws.rs.client.Client; import javax.ws.rs.client.ClientBuilder; @@ -153,12 +150,6 @@ public final class Context { return eventForwarder; } - private static SmsManager smsManager; - - public static SmsManager getSmsManager() { - return smsManager; - } - private static class ObjectMapperContextResolver implements ContextResolver { @Override @@ -207,12 +198,6 @@ public final class Context { connectionManager = new ConnectionManager(); - if (config.hasKey(Keys.SMS_HTTP_URL)) { - smsManager = new HttpSmsClient(); - } else if (config.hasKey(Keys.SMS_AWS_REGION)) { - smsManager = new SnsSmsClient(); - } - initEventsModule(); if (config.hasKey(Keys.EVENT_FORWARD_URL)) { diff --git a/src/main/java/org/traccar/MainModule.java b/src/main/java/org/traccar/MainModule.java index 9ec73d819..f6621a18e 100644 --- a/src/main/java/org/traccar/MainModule.java +++ b/src/main/java/org/traccar/MainModule.java @@ -57,7 +57,9 @@ import org.traccar.geolocation.UnwiredGeolocationProvider; import org.traccar.handler.GeocoderHandler; import org.traccar.handler.GeolocationHandler; import org.traccar.handler.SpeedLimitHandler; +import org.traccar.sms.HttpSmsClient; import org.traccar.sms.SmsManager; +import org.traccar.sms.SnsSmsClient; import org.traccar.speedlimit.OverpassSpeedLimitProvider; import org.traccar.speedlimit.SpeedLimitProvider; import org.traccar.storage.Storage; @@ -115,9 +117,15 @@ public class MainModule extends AbstractModule { return Context.getDeviceManager(); } + @Singleton @Provides - public static SmsManager provideSmsManager() { - return Context.getSmsManager(); + public static SmsManager provideSmsManager(Config config) { + if (config.hasKey(Keys.SMS_HTTP_URL)) { + return new HttpSmsClient(); + } else if (config.hasKey(Keys.SMS_AWS_REGION)) { + return new SnsSmsClient(); + } + return null; } @Singleton diff --git a/src/main/java/org/traccar/ServerManager.java b/src/main/java/org/traccar/ServerManager.java index a6bb6888c..f4f6e1ba4 100644 --- a/src/main/java/org/traccar/ServerManager.java +++ b/src/main/java/org/traccar/ServerManager.java @@ -15,11 +15,13 @@ */ package org.traccar; +import com.google.inject.Injector; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.traccar.config.Keys; import org.traccar.helper.ClassScanner; +import javax.inject.Inject; import javax.inject.Singleton; import java.io.IOException; import java.net.BindException; @@ -38,10 +40,12 @@ public class ServerManager implements LifecycleObject { private final List connectorList = new LinkedList<>(); private final Map protocolList = new ConcurrentHashMap<>(); - public ServerManager() throws IOException, URISyntaxException, ReflectiveOperationException { + @Inject + public ServerManager(Injector injector) throws IOException, URISyntaxException, ReflectiveOperationException { for (Class protocolClass : ClassScanner.findSubclasses(BaseProtocol.class, "org.traccar.protocol")) { if (Context.getConfig().hasKey(Keys.PROTOCOL_PORT.withPrefix(BaseProtocol.nameFromClass(protocolClass)))) { BaseProtocol protocol = (BaseProtocol) protocolClass.getDeclaredConstructor().newInstance(); + injector.injectMembers(protocol); connectorList.addAll(protocol.getConnectorList()); protocolList.put(protocol.getName(), protocol); } diff --git a/src/main/java/org/traccar/config/Keys.java b/src/main/java/org/traccar/config/Keys.java index ba576397b..d53245c65 100644 --- a/src/main/java/org/traccar/config/Keys.java +++ b/src/main/java/org/traccar/config/Keys.java @@ -753,6 +753,14 @@ public final class Keys { "sms.aws.region", Collections.singletonList(KeyType.GLOBAL)); + /** + * Enabled notification options. Comma-separated string is expected. + * Example: web,mail,sms + */ + public static final ConfigKey NOTIFICATOR_TYPES = new ConfigKey<>( + "notificator.types", + Collections.singletonList(KeyType.GLOBAL)); + /** * Traccar notification API key. */ diff --git a/src/main/java/org/traccar/notification/NotificatorManager.java b/src/main/java/org/traccar/notification/NotificatorManager.java index dfd8cd3d6..9705377b4 100644 --- a/src/main/java/org/traccar/notification/NotificatorManager.java +++ b/src/main/java/org/traccar/notification/NotificatorManager.java @@ -1,5 +1,5 @@ /* - * Copyright 2018 - 2020 Anton Tananaev (anton@traccar.org) + * Copyright 2018 - 2022 Anton Tananaev (anton@traccar.org) * Copyright 2018 Andrey Kunitsyn (andrey@traccar.org) * * Licensed under the Apache License, Version 2.0 (the "License"); @@ -24,6 +24,8 @@ import java.util.Set; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.traccar.Context; +import org.traccar.Main; +import org.traccar.config.Keys; import org.traccar.model.Typed; import org.traccar.notificators.NotificatorFirebase; import org.traccar.notificators.NotificatorMail; @@ -39,45 +41,25 @@ public final class NotificatorManager { private static final Logger LOGGER = LoggerFactory.getLogger(NotificatorManager.class); - private static final Notificator NULL_NOTIFICATOR = new NotificatorNull(); + private static final Map> NOTIFICATORS_ALL = Map.of( + "web", NotificatorWeb.class, + "mail", NotificatorMail.class, + "sms", NotificatorSms.class, + "firebase", NotificatorFirebase.class, + "traccar", NotificatorTraccar.class, + "telegram", NotificatorTelegram.class, + "pushover", NotificatorPushover.class); private final Map 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; - case "traccar": - defaultNotificator = NotificatorTraccar.class.getCanonicalName(); - break; - case "telegram": - defaultNotificator = NotificatorTelegram.class.getCanonicalName(); - break; - case "pushover": - defaultNotificator = NotificatorPushover.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()); + String types = Context.getConfig().getString(Keys.NOTIFICATOR_TYPES); + if (types != null) { + for (String type : types.split(",")) { + var notificatorClass = NOTIFICATORS_ALL.get(type); + if (notificatorClass != null) { + notificators.put(type, Main.getInjector().getInstance(notificatorClass)); + } } } } @@ -86,7 +68,7 @@ public final class NotificatorManager { final Notificator notificator = notificators.get(type); if (notificator == null) { LOGGER.warn("No notificator configured for type : " + type); - return NULL_NOTIFICATOR; + return new NotificatorNull(); } return notificator; } diff --git a/src/main/java/org/traccar/notificators/NotificatorSms.java b/src/main/java/org/traccar/notificators/NotificatorSms.java index f35b797cd..f4d1de0cb 100644 --- a/src/main/java/org/traccar/notificators/NotificatorSms.java +++ b/src/main/java/org/traccar/notificators/NotificatorSms.java @@ -16,8 +16,6 @@ */ package org.traccar.notificators; -import org.traccar.Context; -import org.traccar.Main; import org.traccar.database.StatisticsManager; import org.traccar.model.Event; import org.traccar.model.Position; @@ -26,16 +24,30 @@ import org.traccar.notification.MessageException; import org.traccar.notification.NotificationFormatter; import org.traccar.notification.NotificationMessage; import org.traccar.session.cache.CacheManager; +import org.traccar.sms.SmsManager; -public final class NotificatorSms implements Notificator { +import javax.inject.Inject; + +public class NotificatorSms implements Notificator { + + private final SmsManager smsManager; + private final CacheManager cacheManager; + private final StatisticsManager statisticsManager; + + @Inject + public NotificatorSms(SmsManager smsManager, CacheManager cacheManager, StatisticsManager statisticsManager) { + this.smsManager = smsManager; + this.cacheManager = cacheManager; + this.statisticsManager = statisticsManager; + } @Override public void send(User user, Event event, Position position) throws MessageException, InterruptedException { if (user.getPhone() != null) { NotificationMessage shortMessage = NotificationFormatter.formatMessage( - Main.getInjector().getInstance(CacheManager.class), user, event, position, "short"); - Main.getInjector().getInstance(StatisticsManager.class).registerSms(); - Context.getSmsManager().sendMessage(user.getPhone(), shortMessage.getBody(), false); + cacheManager, user, event, position, "short"); + statisticsManager.registerSms(); + smsManager.sendMessage(user.getPhone(), shortMessage.getBody(), false); } } -- cgit v1.2.3