Hi Anton,
I want to use Rabbitmq to publish position from Traccar.
I know that there is a forward url feature in Traccar, but the protocol is HTTP, while what I need is AMQP.
This my code:
build.gradle
...
implementation "com.rabbitmq:amqp-client:5.15.0"
...
config/keys.java
...
public static final ConfigKey<String> RABBIT_URL = new StringConfigKey(
"rabbit.url",
List.of(KeyType.CONFIG));
...
database/RabbitManager.java
package org.traccar.database;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.rabbitmq.client.AMQP;
import com.rabbitmq.client.Channel;
import com.rabbitmq.client.Connection;
import com.rabbitmq.client.ConnectionFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.traccar.config.Config;
import org.traccar.config.Keys;
import org.traccar.model.Device;
import org.traccar.model.Position;
import org.traccar.session.cache.CacheManager;
import javax.inject.Inject;
import java.io.IOException;
import java.net.URISyntaxException;
import java.security.KeyManagementException;
import java.security.NoSuchAlgorithmException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeoutException;
public class RabbitManager {
private final Config config;
private ConnectionFactory factory;
private Connection connection;
private Channel channel;
private String url;
private static final String QUEUE_NAME = "traccar";
private static final String KEY_POSITION = "position";
private static final String KEY_DEVICE = "device";
@Inject
private ObjectMapper objectMapper;
@Inject
private CacheManager cacheManager;
private static final Logger LOGGER = LoggerFactory.getLogger(RabbitManager.class);
public RabbitManager(Config config) {
this.config = config;
initConnection();
}
public void initConnection() {
factory = new ConnectionFactory();
url = config.getString(Keys.RABBIT_URL);
try {
factory.setUri(url);
} catch (URISyntaxException e) {
e.printStackTrace();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
} catch (KeyManagementException e) {
e.printStackTrace();
}
try {
connection = factory.newConnection();
} catch (IOException e) {
e.printStackTrace();
} catch (TimeoutException e) {
e.printStackTrace();
}
try {
channel = connection.createChannel();
} catch (IOException e) {
e.printStackTrace();
}
}
public void publish(Position position) {
try {
channel.queueDeclare(QUEUE_NAME, true, false, false, null);
} catch (IOException e) {
e.printStackTrace();
}
Map<String, Object> data = new HashMap<>();
Device device = cacheManager.getObject(Device.class, position.getDeviceId());
data.put(KEY_POSITION, position);
if (device != null) {
data.put(KEY_DEVICE, device);
}
String json = null;
try {
json = objectMapper.writeValueAsString(data);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
try {
channel.basicPublish("", QUEUE_NAME, new AMQP.BasicProperties.Builder()
.deliveryMode(2).build(), json.getBytes("UTF-8"));
} catch (IOException e) {
e.printStackTrace();
}
LOGGER.debug(json);
}
}
RabbitDataHandler.java
package org.traccar;
import io.netty.channel.ChannelHandler;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.traccar.database.RabbitManager;
import org.traccar.model.Position;
import javax.inject.Inject;
@ChannelHandler.Sharable
public class RabbitDataHandler extends BaseDataHandler {
private static final Logger LOGGER = LoggerFactory.getLogger(RabbitDataHandler.class);
@Inject
private RabbitManager rabbitManager;
@Override
protected Position handlePosition(Position position) {
try {
rabbitManager.publish(position);
} catch (Exception error) {
LOGGER.error("error forward position to Rabbit", error);
}
return position;
}
}
BasePipelineFactory.java
...
DriverEventHandler.class,
MainEventHandler.class,
RabbitDataHandler.class);
...
MainModule.java
...
@Singleton
@Provides
public static RabbitManager provideRabbitManager(Config config) {
if (config.hasKey(Keys.RABBIT_URL)) {
return new RabbitManager(config);
}
return null;
}
...
I was build from the latest commit on Traccar Master (v5.3)
Edit: /opt/traccar/conf/traccar.xml
<entry key='rabbit.url'>amqp://[USERNAME]:[PASSWORD]@[IPADDRESS]:5672</entry>
Pull from Github:
git pull https://github.com/traccar/traccar.git
Then, I do:
sudo systemctl stop traccar
./gradlew assemble
sudo cp target/tracker-server.jar /opt/traccar
sudo systemctl start traccar
When I checked on /opt/traccar/logs/tracker-server.log, I found:
2022-08-13 22:16:17 INFO: Successfully acquired change log lock
2022-08-13 22:16:17 INFO: Cannot load service: liquibase.parser.ChangeLogParser: liquibase.parser.core.json.JsonChangeLogParser Unable to get public no-arg constructor
2022-08-13 22:16:17 INFO: Cannot load service: liquibase.parser.ChangeLogParser: liquibase.parser.core.yaml.YamlChangeLogParser Unable to get public no-arg constructor
2022-08-13 22:16:17 INFO: Reading from traccar.DATABASECHANGELOG
2022-08-13 22:16:21 INFO: Reading from traccar.DATABASECHANGELOG
2022-08-13 22:16:21 INFO: Cannot load service: liquibase.hub.HubService: Provider liquibase.hub.core.StandardHubService could not be instantiated
2022-08-13 22:16:21 INFO: Successfully released change log lock
2022-08-13 22:16:22 INFO: Your platform does not provide complete low-level API for accessing direct buffers reliably. Unless explicitly requested, heap buffer will always be preferred to avoid potential system instability.
2022-08-13 22:16:22 WARN: Failed to initialize a channel. Closing: [id: 0x9c990ba0] - com.rabbitmq.client.ConnectionFactory - ClassNotFoundException (... < RabbitManager:54 < *:50 < MainModule:345 < < gener:-1 < ...)
2022-08-13 22:16:22 ERROR: Main method error - StacklessClosedChannelException (...)
I've read the documentation of Build Traccar. It says: It will automatically download all dependencies and generate tracker-server.jar in the target subfolder
But, why it cannot found my dependency (com.rabbit.client).
Thank you
Hi Anton,
I want to use Rabbitmq to publish position from Traccar.
I know that there is a forward url feature in Traccar, but the protocol is HTTP, while what I need is AMQP.
This my code:
build.gradle
config/keys.java
database/RabbitManager.java
package org.traccar.database; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.rabbitmq.client.AMQP; import com.rabbitmq.client.Channel; import com.rabbitmq.client.Connection; import com.rabbitmq.client.ConnectionFactory; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.traccar.config.Config; import org.traccar.config.Keys; import org.traccar.model.Device; import org.traccar.model.Position; import org.traccar.session.cache.CacheManager; import javax.inject.Inject; import java.io.IOException; import java.net.URISyntaxException; import java.security.KeyManagementException; import java.security.NoSuchAlgorithmException; import java.util.HashMap; import java.util.Map; import java.util.concurrent.TimeoutException; public class RabbitManager { private final Config config; private ConnectionFactory factory; private Connection connection; private Channel channel; private String url; private static final String QUEUE_NAME = "traccar"; private static final String KEY_POSITION = "position"; private static final String KEY_DEVICE = "device"; @Inject private ObjectMapper objectMapper; @Inject private CacheManager cacheManager; private static final Logger LOGGER = LoggerFactory.getLogger(RabbitManager.class); public RabbitManager(Config config) { this.config = config; initConnection(); } public void initConnection() { factory = new ConnectionFactory(); url = config.getString(Keys.RABBIT_URL); try { factory.setUri(url); } catch (URISyntaxException e) { e.printStackTrace(); } catch (NoSuchAlgorithmException e) { e.printStackTrace(); } catch (KeyManagementException e) { e.printStackTrace(); } try { connection = factory.newConnection(); } catch (IOException e) { e.printStackTrace(); } catch (TimeoutException e) { e.printStackTrace(); } try { channel = connection.createChannel(); } catch (IOException e) { e.printStackTrace(); } } public void publish(Position position) { try { channel.queueDeclare(QUEUE_NAME, true, false, false, null); } catch (IOException e) { e.printStackTrace(); } Map<String, Object> data = new HashMap<>(); Device device = cacheManager.getObject(Device.class, position.getDeviceId()); data.put(KEY_POSITION, position); if (device != null) { data.put(KEY_DEVICE, device); } String json = null; try { json = objectMapper.writeValueAsString(data); } catch (JsonProcessingException e) { e.printStackTrace(); } try { channel.basicPublish("", QUEUE_NAME, new AMQP.BasicProperties.Builder() .deliveryMode(2).build(), json.getBytes("UTF-8")); } catch (IOException e) { e.printStackTrace(); } LOGGER.debug(json); } }
RabbitDataHandler.java
package org.traccar; import io.netty.channel.ChannelHandler; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.traccar.database.RabbitManager; import org.traccar.model.Position; import javax.inject.Inject; @ChannelHandler.Sharable public class RabbitDataHandler extends BaseDataHandler { private static final Logger LOGGER = LoggerFactory.getLogger(RabbitDataHandler.class); @Inject private RabbitManager rabbitManager; @Override protected Position handlePosition(Position position) { try { rabbitManager.publish(position); } catch (Exception error) { LOGGER.error("error forward position to Rabbit", error); } return position; } }
BasePipelineFactory.java
MainModule.java
... @Singleton @Provides public static RabbitManager provideRabbitManager(Config config) { if (config.hasKey(Keys.RABBIT_URL)) { return new RabbitManager(config); } return null; } ...
I was build from the latest commit on Traccar Master (v5.3)
Edit: /opt/traccar/conf/traccar.xml
Pull from Github:
Then, I do:
When I checked on /opt/traccar/logs/tracker-server.log, I found:
I've read the documentation of Build Traccar. It says: It will automatically download all dependencies and generate tracker-server.jar in the target subfolder
But, why it cannot found my dependency (com.rabbit.client).
Thank you