This is an automated email from the ASF dual-hosted git repository.

glcj pushed a commit to branch feature/merlot
in repository https://gitbox.apache.org/repos/asf/plc4x-extras.git


The following commit(s) were added to refs/heads/feature/merlot by this push:
     new 0405018  Local Buffer PVHtc-Archiver (#682)
0405018 is described below

commit 0405018540fa6e31a1fc3e61156ac61179db9a9e
Author: Lerb123 <[email protected]>
AuthorDate: Fri May 29 16:51:09 2026 -0400

    Local Buffer PVHtc-Archiver (#682)
    
    * feat: Implement Loki appender for Karaf event bus
    
    * fix: Implement Loki appender for Karaf event bus, added comments.
    
    * feat: Functional test for Loki Appender using WireMock
    
    * feat: CI Pipeline for MerlotLokiAppender
    
    * Correction to the Maven configuration to prevent tests from being 
skipped; add .mvn
    
    * Correction to Maven configuration: local cache is disabled
    
    * feat:Kafka collector for topics on the Phoebus alarm server
    
    * feat:Local data persistence for PVHtc
---
 .../impl/MerlotDataBrowserSupportImpl.java         |   5 +-
 .../archiver/impl/MerlotPvHtcCollectorImpl.java    | 358 ++++++++++++++++++---
 .../archiver/impl/MerlotPvRtCollectorImpl.java     |  61 +++-
 .../OSGI-INF/blueprint/archiver-service.xml        |   6 +-
 .../src/main/feature/feature.xml                   |   2 +-
 .../impl/MerlotKafkaDecanterCollectorImpl.java     |   2 +-
 6 files changed, 375 insertions(+), 59 deletions(-)

diff --git 
a/plc4j/tools/merlot/org.apache.plc4x.merlot.archiver/src/main/java/org/apache/plc4x/merlot/archiver/impl/MerlotDataBrowserSupportImpl.java
 
b/plc4j/tools/merlot/org.apache.plc4x.merlot.archiver/src/main/java/org/apache/plc4x/merlot/archiver/impl/MerlotDataBrowserSupportImpl.java
index 4678e39..a38eed0 100644
--- 
a/plc4j/tools/merlot/org.apache.plc4x.merlot.archiver/src/main/java/org/apache/plc4x/merlot/archiver/impl/MerlotDataBrowserSupportImpl.java
+++ 
b/plc4j/tools/merlot/org.apache.plc4x.merlot.archiver/src/main/java/org/apache/plc4x/merlot/archiver/impl/MerlotDataBrowserSupportImpl.java
@@ -26,6 +26,7 @@ import java.util.Dictionary;
 import org.apache.plc4x.merlot.archiver.api.MerlotGPClient;
 import org.osgi.service.cm.ManagedServiceFactory;
 import org.apache.plc4x.merlot.scheduler.api.Scheduler;
+import org.osgi.framework.BundleContext;
 import org.osgi.service.cm.ConfigurationException;
 import org.osgi.service.event.EventAdmin;
 import org.slf4j.LoggerFactory;
@@ -42,8 +43,8 @@ public class MerlotDataBrowserSupportImpl extends 
MerlotPvHtcCollectorImpl  {
 //    private HttpServer server;
 
     
-    public MerlotDataBrowserSupportImpl(Scheduler scheduler, MerlotGPClient 
gpClient) {
-        super(scheduler, gpClient);
+    public MerlotDataBrowserSupportImpl(Scheduler scheduler, MerlotGPClient 
gpClient, BundleContext ctx ) {
+        super(scheduler, gpClient, ctx);
     }
 
     @Override
diff --git 
a/plc4j/tools/merlot/org.apache.plc4x.merlot.archiver/src/main/java/org/apache/plc4x/merlot/archiver/impl/MerlotPvHtcCollectorImpl.java
 
b/plc4j/tools/merlot/org.apache.plc4x.merlot.archiver/src/main/java/org/apache/plc4x/merlot/archiver/impl/MerlotPvHtcCollectorImpl.java
index f2a8634..d7f4760 100644
--- 
a/plc4j/tools/merlot/org.apache.plc4x.merlot.archiver/src/main/java/org/apache/plc4x/merlot/archiver/impl/MerlotPvHtcCollectorImpl.java
+++ 
b/plc4j/tools/merlot/org.apache.plc4x.merlot.archiver/src/main/java/org/apache/plc4x/merlot/archiver/impl/MerlotPvHtcCollectorImpl.java
@@ -16,25 +16,60 @@
  */
 package org.apache.plc4x.merlot.archiver.impl;
 
+import com.fasterxml.jackson.databind.ObjectMapper;
+import java.io.File;
+import java.io.IOException;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.Path;
+import java.nio.file.Paths;
 import java.time.Instant;
+import java.util.ArrayList;
 import java.util.Date;
 import java.util.Dictionary;
 import java.util.Enumeration;
 import java.util.HashMap;
 import java.util.Hashtable;
+import java.util.List;
 import java.util.Map;
+import java.util.Set;
 import java.util.concurrent.ConcurrentHashMap;
+import java.util.concurrent.TimeUnit;
 import java.util.function.BiConsumer;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 import org.apache.commons.lang3.tuple.MutablePair;
+import org.apache.iotdb.rpc.IoTDBConnectionException;
+import org.apache.iotdb.rpc.StatementExecutionException;
+import org.apache.iotdb.session.Session;
 import org.apache.plc4x.merlot.archiver.api.MerlotCollector;
 import org.apache.plc4x.merlot.archiver.api.MerlotGPClient;
 import org.apache.plc4x.merlot.scheduler.api.Job;
 import org.apache.plc4x.merlot.scheduler.api.JobContext;
 import org.apache.plc4x.merlot.scheduler.api.ScheduleOptions;
 import org.apache.plc4x.merlot.scheduler.api.Scheduler;
+
+import org.apache.tsfile.enums.TSDataType;
+import org.apache.tsfile.exception.write.WriteProcessException;
+import org.apache.tsfile.file.metadata.IDeviceID;
 import static org.apache.tsfile.file.metadata.IDeviceID.LOGGER;
+import org.apache.tsfile.file.metadata.enums.CompressionType;
+import org.apache.tsfile.file.metadata.enums.TSEncoding;
+import org.apache.tsfile.read.TsFileReader;
+import org.apache.tsfile.read.TsFileSequenceReader;
+import org.apache.tsfile.read.common.Field;
+import org.apache.tsfile.read.common.RowRecord;
+import org.apache.tsfile.read.expression.QueryExpression;
+import org.apache.tsfile.read.query.dataset.QueryDataSet;
+import org.apache.tsfile.write.TsFileWriter;
+import org.apache.tsfile.write.record.TSRecord;
+import org.apache.tsfile.write.record.datapoint.DataPoint;
+import org.apache.tsfile.write.record.datapoint.DoubleDataPoint;
+import org.apache.tsfile.write.record.datapoint.LongDataPoint;
+import org.apache.tsfile.write.schema.MeasurementSchema;
+import org.eclipse.paho.client.mqttv3.IMqttDeliveryToken;
+import org.eclipse.paho.client.mqttv3.MqttAsyncClient;
+import org.eclipse.paho.client.mqttv3.MqttCallback;
+import org.eclipse.paho.client.mqttv3.MqttCallbackExtended;
 import org.eclipse.paho.client.mqttv3.MqttClient;
 import org.eclipse.paho.client.mqttv3.MqttConnectOptions;
 import org.eclipse.paho.client.mqttv3.MqttException;
@@ -42,19 +77,17 @@ import org.eclipse.paho.client.mqttv3.MqttMessage;
 import org.eclipse.paho.client.mqttv3.persist.MemoryPersistence;
 import org.epics.gpclient.GPClientInstance;
 import org.epics.gpclient.PVEvent;
-import org.epics.gpclient.PVEventRecorder;
 import org.epics.gpclient.PVReader;
 import org.epics.gpclient.PVReaderListener;
 import org.epics.vtype.VNumber;
 import org.epics.vtype.VType;
+import org.osgi.framework.BundleContext;
+import org.osgi.framework.FrameworkUtil;
 import org.osgi.service.cm.ConfigurationException;
 import org.osgi.service.cm.ManagedServiceFactory;
-import org.osgi.service.event.Event;
-import org.osgi.service.event.EventAdmin;
-import org.osgi.service.event.EventProperties;
 import org.slf4j.LoggerFactory;
 
-public class MerlotPvHtcCollectorImpl implements MerlotCollector, 
ManagedServiceFactory, PVReaderListener {
+public class MerlotPvHtcCollectorImpl implements MerlotCollector, 
ManagedServiceFactory, PVReaderListener, MqttCallbackExtended {
 
     private static final org.slf4j.Logger LOGGER = 
LoggerFactory.getLogger(MerlotPvHtcCollectorImpl.class);
 
@@ -70,15 +103,20 @@ public class MerlotPvHtcCollectorImpl implements 
MerlotCollector, ManagedService
     private final Map<String, SchedulerGroup> groups = new 
ConcurrentHashMap<>();
     private final Map<String, MutablePair<SchedulerGroup, PVReader<VType>>> 
pvs = new ConcurrentHashMap<>();
 
-    /*
-    Parameter Broker MQTT IoTDB
-     */
-    private volatile MqttClient mqttClient = null;
-    //
+    //Buffer IoTDB fail connection (Local Buffer)
+    private volatile TsFileWriter tsFileWriter;
+    private final BundleContext ctx;
+    private File file;
+    private final String MERLOT_DATA_DIRECTORY = "karaf.data";
+    private static final Set<String> timeSeries = 
java.util.concurrent.ConcurrentHashMap.newKeySet();
+
+    //Parameter Broker MQTT IoTDB
+    private volatile MqttAsyncClient mqttClient = null;
 
-    public MerlotPvHtcCollectorImpl(Scheduler scheduler, MerlotGPClient 
gpMerlotClient) {
+    public MerlotPvHtcCollectorImpl(Scheduler scheduler, MerlotGPClient 
gpMerlotClient, BundleContext ctx) {
         this.scheduler = scheduler;
         this.gpClient = gpMerlotClient.gpClientFactory("MerlotPvHtc");
+        this.ctx = ctx;
     }
 
     @Override
@@ -86,20 +124,28 @@ public class MerlotPvHtcCollectorImpl implements 
MerlotCollector, ManagedService
         LOGGER.info("Starting the PV Collector");
     }
 
-    public MqttClient getMqttClient() {
+    public MqttAsyncClient getMqttClient() {
         return mqttClient;
     }
 
     private void createConnection(String mqttUrl, String username, String 
password) {
 
         try {
-            mqttClient = new MqttClient(mqttUrl, "Merlot-HTC-IoTDB" + 
System.currentTimeMillis(), new MemoryPersistence());
+            mqttClient = new MqttAsyncClient(mqttUrl, "Merlot-HTC-IoTDB" + 
System.currentTimeMillis(), new MemoryPersistence());
+            mqttClient.setCallback(this);
+
+            /*Note: Set a property in IoTDB (Server): File 
/config/iotdb-system.properties: 
+            dn_session_timeout_threshold=0; To prevent information from being 
deleted from open channels
+             */
             MqttConnectOptions connOpts = new MqttConnectOptions();
             connOpts.setUserName(username);
             connOpts.setPassword(password.toCharArray());
-            connOpts.setCleanSession(true);
-            connOpts.setAutomaticReconnect(true);
 
+            connOpts.setCleanSession(false);
+            connOpts.setKeepAliveInterval(30);
+            connOpts.setConnectionTimeout(30);
+            connOpts.setMaxInflight(1000);
+            connOpts.setAutomaticReconnect(true);
             mqttClient.connect(connOpts);
             LOGGER.info("Connection made successfully");
         } catch (MqttException e) {
@@ -155,22 +201,32 @@ public class MerlotPvHtcCollectorImpl implements 
MerlotCollector, ManagedService
         groups.clear();
 
         if (this.mqttClient != null) {
-            try {
 
-                if (this.mqttClient.isConnected()) {
-                    this.mqttClient.disconnectForcibly();
+            while (this.mqttClient != null) {
+                try {
+                    this.mqttClient.disconnectForcibly(0, 0, true);
+                    if (!this.mqttClient.isConnected()) {
+                        this.mqttClient.close(true);
+                        this.mqttClient = null;
+                    }
+                    Thread.sleep(1000);
+                } catch (InterruptedException ex) {
+                    LOGGER.info(ex.getMessage());
+                } catch (MqttException ex) {
+                    LOGGER.info(ex.getMessage());
                 }
-                this.mqttClient.close();
-                LOGGER.info("MQTT connection released.");
-            } catch (MqttException ex) {
-                LOGGER.warn("Error closing previous MQTT connection: {}", 
ex.getMessage());
             }
         }
-        createConnection((String) properties.get("broker"), (String) 
properties.get("useriotdb"), (String) properties.get("passwordiotdb"));
+
+        //Make sure that too many MQTT connections aren't created. There 
should only be one.
+        if (this.mqttClient == null) {
+            createConnection((String) properties.get("broker"), (String) 
properties.get("useriotdb"), (String) properties.get("passwordiotdb"));
+        }
 
         if (null == properties) {
             return;
         }
+
         //Group Section
         Enumeration<String> enumKeys = properties.keys();
         while (enumKeys.hasMoreElements()) {
@@ -201,7 +257,15 @@ public class MerlotPvHtcCollectorImpl implements 
MerlotCollector, ManagedService
 
                     String channel = getChannel(pvInfo.strPv);
                     String fieldQuery = getField(pvInfo.strPv);
-                    PVReader<VType> pvr = 
gpClient.read(String.format("pva://%s?request=field(%s)", channel, fieldQuery))
+
+                    String pathPV = "";
+                    if (fieldQuery == null) {
+                        pathPV = String.format("pva://%s", channel);
+                    } else {
+
+                        pathPV = String.format("pva://%s?request=field(%s)", 
channel, fieldQuery);
+                    }
+                    PVReader<VType> pvr = gpClient.read(pathPV)
                             .addReadListener((event, pv) -> {
                             })
                             .start();
@@ -213,21 +277,47 @@ public class MerlotPvHtcCollectorImpl implements 
MerlotCollector, ManagedService
             };
         }
     }
+
     private String getChannel(String pvName) {
-        Matcher matcher = Pattern.compile("//([^/]+)/").matcher(pvName);
+        if (pvName == null || pvName.isEmpty()) {
+            return null;
+        }
+
+        int startIndex = pvName.indexOf("://");
+        if (startIndex == -1) {
+            return null;
+        }
+
+        startIndex += 3;
+
+        int endIndex = pvName.indexOf("/", (startIndex));
 
-        if (matcher.find()) {
-            return matcher.group(1);
+        if (endIndex != -1) {
+            return pvName.substring(startIndex, endIndex);
+        } else {
+            return pvName.substring(startIndex);
         }
-        return null;
     }
 
     private String getField(String pvName) {
-        Matcher matcher = Pattern.compile("([^/]+)$").matcher(pvName);
-        if (matcher.find()) {
-            return matcher.group(1);
+        if (pvName == null || pvName.isEmpty()) {
+            return null;
+        }
+
+        int protocolIndex = pvName.indexOf("://");
+        if (protocolIndex == -1) {
+            return null;
+        }
+
+        String withoutProtocol = pvName.substring(protocolIndex + 3);
+
+        int lastSlashIndex = withoutProtocol.lastIndexOf("/");
+
+        if (lastSlashIndex != -1) {
+            return withoutProtocol.substring(lastSlashIndex + 1);
+        } else {
+            return null;
         }
-        return null;
     }
 
     @Override
@@ -294,6 +384,158 @@ public class MerlotPvHtcCollectorImpl implements 
MerlotCollector, ManagedService
 
     }
 
+    @Override
+    public void connectionLost(Throwable cause) {
+
+        LOGGER.info("The connection to the IoTDB broker has been lost: {}", 
cause.getMessage());
+        String karafDataDir = ctx.getProperty(MERLOT_DATA_DIRECTORY);
+
+        if (file == null) {
+            file = new File(karafDataDir, "buffer.tsfile");
+        }
+
+        if (!file.exists()) {
+            try {
+
+                LOGGER.info("The buffer file did not exist; it is being 
created");
+                file.createNewFile();
+            } catch (IOException ex) {
+                LOGGER.info("The file could not be created in the /data 
directory of Merlot");
+            }
+        }
+
+        if (file.exists() && tsFileWriter == null) {
+            try {
+                LOGGER.info("The file already exists; create the writer and 
assign the file");
+
+                tsFileWriter = new TsFileWriter(file);
+            } catch (Exception ex) {
+                LOGGER.error("Error assigning tsfilewriter: {}", 
ex.getMessage());
+            }
+        }
+    }
+
+    @Override
+    public void messageArrived(String topic, MqttMessage message) throws 
Exception {
+        //Not in use
+    }
+
+    @Override
+    public void deliveryComplete(IMqttDeliveryToken token) {
+        //Not in use
+    }
+
+    @Override
+    public void connectComplete(boolean reconnect, String serverURI) {
+        if (reconnect) {
+            LOGGER.info("Successful reconnection detected automatically");
+
+            new Thread(() -> {
+                try {
+                    if (this.tsFileWriter != null) {
+                        LOGGER.info("Closing the file writer");
+                        this.tsFileWriter.close();
+
+                        LOGGER.info("Sending a buffer to the IoTDB broker");
+                        sendBufferToIoTDB();
+
+                        LOGGER.info("Removing the reference to the current 
writer");
+                        this.tsFileWriter = null;
+                    }
+                    this.timeSeries.clear();
+                } catch (IOException e) {
+                    LOGGER.error("Error processing the buffer after 
reconnection: " + e.getMessage(), e);
+                }
+            }).start();
+
+        } else {
+            LOGGER.info("Initial connection established with the broker: " + 
serverURI);
+        }
+
+    }
+
+    public void sendBufferToIoTDB() {
+
+        List<String> measurements = new ArrayList<>();
+        List<Object> values = new ArrayList<>();
+        List<String> messages = new ArrayList<>();
+        String device = "";
+
+        try {
+            String filePath = 
this.tsFileWriter.getIOWriter().getFile().toString();
+
+            try (TsFileSequenceReader reader = new 
TsFileSequenceReader(filePath)) {
+                List<org.apache.tsfile.read.common.Path> paths = 
reader.getAllPaths();
+
+                try (TsFileReader tsReader = new TsFileReader(reader)) {
+                    QueryExpression expr = QueryExpression.create(paths, null);
+                    QueryDataSet dataSet = tsReader.query(expr);
+
+                    while (dataSet.hasNext()) {
+                        RowRecord row = dataSet.next();
+                        long timestamp = row.getTimestamp();
+
+                        List<Field> fields = row.getFields();
+
+                        for (int i = 0; i < fields.size(); i++) {
+                            Field field = fields.get(i);
+
+                            //Device
+                            device = 
dataSet.getPaths().get(i).getDeviceString();
+
+                            //Measurements and Values
+                            if (field != null) {
+                                
measurements.add(dataSet.getPaths().get(i).getMeasurement());
+                                values.add(field.getDoubleV());
+                            }
+
+                        }
+
+                        //Constructing JSON messages for the batch to IoTDB
+                        String jsonMeasurements = 
measurements.toString().replace("[", "[\"").replace("]", "\"]").replace(", ", 
"\",\"");
+                        String jsonValues = values.toString();
+
+                        //Added to the JSON message list
+                        messages.add(
+                                String.format(java.util.Locale.US, "{\n"
+                                        + "  \"device\":\"%s\",\n"
+                                        + "  \"timestamp\":%d,\n"
+                                        + "  \"measurements\":%s,\n"
+                                        + "  \"values\":%s\n"
+                                        + "}",
+                                        device,
+                                        timestamp,
+                                        jsonMeasurements,
+                                        jsonValues)
+                        );
+
+                        measurements.clear();
+                        values.clear();
+
+                    }
+
+                    try {
+                        //Converts a JSON message list into a string
+                        String convertedMessage = messages.toString();
+                        //Serialize the string. Then the MQTT message is 
constructed.
+                        MqttMessage message = new 
MqttMessage(convertedMessage.getBytes());
+                        message.setQos(0);
+
+                        //A message is sent to the IoTDB MQTT broker
+                        getMqttClient().publish("iotdb/insert", message);
+
+                    } catch (MqttException e) {
+                        LOGGER.error("Error posting to MQTT: " + 
e.getMessage());
+                    }
+                }
+
+            }
+        } catch (Exception e) {
+            System.err.println("Error reading the buffer.tsfile file " + 
e.getMessage());
+        }
+
+    }
+
     private class PVInfo {
 
         public PVReader<VType> pvr;
@@ -321,6 +563,7 @@ public class MerlotPvHtcCollectorImpl implements 
MerlotCollector, ManagedService
 
         @Override
         public void execute(JobContext context) {
+
             pvs.forEach(new BiConsumer<String, PVInfo>() {
                 @Override
                 public void accept(String s, PVInfo pv) {
@@ -329,14 +572,14 @@ public class MerlotPvHtcCollectorImpl implements 
MerlotCollector, ManagedService
                             && mqttClient != null && 
mqttClient.isConnected())) {
 
                         value = (VNumber) pv.pvr.getValue();
-                        if ((null == pv.lastValue) || 
!value.equals(pv.lastValue)) {
+                        if (value != null && ((null == pv.lastValue) || 
!value.equals(pv.lastValue))) {
 
                             Double actualValue = 
value.getValue().doubleValue();
                             Double lastValue = (null == pv.lastValue) ? 0 : 
pv.lastValue.getValue().doubleValue();
 
                             if ((Math.abs(actualValue - lastValue)) > 
Math.abs(lastValue * (pv.delta / 100))) {
                                 pv.lastValue = value;
-                                long timeEpoch = 
value.getTime().getTimestamp().toEpochMilli();
+                                long timeEpoch = Instant.now().toEpochMilli();
 
                                 String strValue = 
String.format(java.util.Locale.US, "{\n"
                                         + "\"device\":\"%s\",\n"
@@ -357,17 +600,58 @@ public class MerlotPvHtcCollectorImpl implements 
MerlotCollector, ManagedService
                                     MqttMessage message = new 
MqttMessage(strValue.getBytes());
                                     message.setQos(0);
 
-                                    getMqttClient().publish(pv.strDevice, 
message);
+                                    getMqttClient().publish("iotdb/insert", 
message);
 
                                 } catch (MqttException e) {
                                     LOGGER.error("Error posting to MQTT: " + 
e.getMessage());
                                 }
                             }
+                        }
+                    } else if (!mqttClient.isConnected() && 
pv.pvr.isConnected()) {
+
+                        VNumber valueT = (VNumber) pv.pvr.getValue();
+                        if (valueT != null && ((null == pv.lastValue) || 
!valueT.equals(pv.lastValue))) {
+
+                            Double actualValue = 
valueT.getValue().doubleValue();
+                            Double lastValue = (null == pv.lastValue) ? 0 : 
pv.lastValue.getValue().doubleValue();
+
+                            if ((Math.abs(actualValue - lastValue)) > 
Math.abs(lastValue * (pv.delta / 100))) {
+                                pv.lastValue = valueT;
+                                long timeEpoch = Instant.now().toEpochMilli();
+//                                LOGGER.info("PV: {} Value: {} Timestamp: {}",
+//                                        pv.strTag, 
valueT.getValue().doubleValue(), timeEpoch);
+
+                                try {
+                                    if (timeSeries != null && 
!timeSeries.contains(pv.strDevice + "." + pv.strTag)) {
+                                        
tsFileWriter.registerTimeseries(pv.strDevice,
+                                                new MeasurementSchema(
+                                                        pv.strTag,
+                                                        TSDataType.DOUBLE,
+                                                        TSEncoding.GORILLA,
+                                                        
CompressionType.LZMA2));
+
+                                        timeSeries.add(pv.strDevice + "." + 
pv.strTag);
+
+                                    }
+                                    TSRecord tsRecord = new 
TSRecord(pv.strDevice, timeEpoch);
+
+                                    DataPoint dataPoint = new 
DoubleDataPoint(pv.strTag, valueT.getValue().doubleValue());
+                                    tsRecord.addTuple(dataPoint);
+
+                                    if (tsFileWriter.writeRecord(tsRecord)) {
+                                        LOGGER.debug("A write operation was 
performed to the buffer file");
+                                    }
+
+                                } catch (Exception e) {
+                                    LOGGER.info("Error processing device: {} 
", pv.strDevice);
+                                }
+
+                            }
 
                         }
-                    } else {
-                        LOGGER.info("PVReader not connected or MQTT connection 
not established");
+
                     }
+
                 }
             });
 
diff --git 
a/plc4j/tools/merlot/org.apache.plc4x.merlot.archiver/src/main/java/org/apache/plc4x/merlot/archiver/impl/MerlotPvRtCollectorImpl.java
 
b/plc4j/tools/merlot/org.apache.plc4x.merlot.archiver/src/main/java/org/apache/plc4x/merlot/archiver/impl/MerlotPvRtCollectorImpl.java
index 8fab49c..c2cf5a0 100644
--- 
a/plc4j/tools/merlot/org.apache.plc4x.merlot.archiver/src/main/java/org/apache/plc4x/merlot/archiver/impl/MerlotPvRtCollectorImpl.java
+++ 
b/plc4j/tools/merlot/org.apache.plc4x.merlot.archiver/src/main/java/org/apache/plc4x/merlot/archiver/impl/MerlotPvRtCollectorImpl.java
@@ -186,12 +186,17 @@ public class MerlotPvRtCollectorImpl implements 
MerlotCollector, ManagedServiceF
                     pvInfo.delta = Double.parseDouble(fields[2]);
                     pvInfo.strTag = fields[3];
 
-                    
                     String channel = getChannel(pvInfo.strPv);
                     String fieldQuery = getField(pvInfo.strPv);
-
-
-                    PVReader<VType> pvr = 
gpClient.read(String.format("pva://%s?request=field(%s)", channel, fieldQuery))
+                    
+                    String pathPV = "";
+                    if (fieldQuery == null) {
+                        pathPV = String.format("pva://%s", channel);
+                    } else {
+                        pathPV = String.format("pva://%s?request=field(%s)", 
channel, fieldQuery);
+                    }
+                    
+                    PVReader<VType> pvr = gpClient.read(pathPV)
                             .addReadListener((event, pv) -> {
                             })
                             .start();
@@ -206,20 +211,45 @@ public class MerlotPvRtCollectorImpl implements 
MerlotCollector, ManagedServiceF
     }
 
     private String getChannel(String pvName) {
-        Matcher matcher = Pattern.compile("//([^/]+)/").matcher(pvName);
+        if (pvName == null || pvName.isEmpty()) {
+            return null;
+        }
+
+        int startIndex = pvName.indexOf("://");
+        if (startIndex == -1) {
+            return null;
+        }
 
-        if (matcher.find()) {
-            return matcher.group(1);
+        startIndex += 3;
+
+        int endIndex = pvName.indexOf("/", (startIndex));
+
+        if (endIndex != -1) {
+            return pvName.substring(startIndex, endIndex);
+        } else {
+            return pvName.substring(startIndex);
         }
-        return null;
     }
 
     private String getField(String pvName) {
-        Matcher matcher = Pattern.compile("([^/]+)$").matcher(pvName);
-        if (matcher.find()) {
-            return matcher.group(1);
+        if (pvName == null || pvName.isEmpty()) {
+            return null;
+        }
+
+        int protocolIndex = pvName.indexOf("://");
+        if (protocolIndex == -1) {
+            return null;
+        }
+
+        String withoutProtocol = pvName.substring(protocolIndex + 3);
+
+        int lastSlashIndex = withoutProtocol.lastIndexOf("/");
+
+        if (lastSlashIndex != -1) {
+            return withoutProtocol.substring(lastSlashIndex + 1);
+        } else {
+            return null;
         }
-        return null;
     }
 
     @Override
@@ -315,7 +345,7 @@ public class MerlotPvRtCollectorImpl implements 
MerlotCollector, ManagedServiceF
                 public void accept(String s, PVInfo pv) {
 
                     if ((pv.pvr.isConnected()) && (!pv.pvr.isPaused())) {
-                        
+
                         value = (VNumber) pv.pvr.getValue();
                         if ((null == pv.lastValue) || 
!value.equals(pv.lastValue)) {
 
@@ -329,15 +359,14 @@ public class MerlotPvRtCollectorImpl implements 
MerlotCollector, ManagedServiceF
                             }
 
                         }
-                    } else{
+                    } else {
                         LOGGER.info("PVReader {} offline", pv.pvr);
                     }
                 }
 
-                private void sendDataToGrafanaLive(String strPv, VNumber 
value) { 
+                private void sendDataToGrafanaLive(String strPv, VNumber 
value) {
                     long nanoTime = 
value.getTime().getTimestamp().getEpochSecond() * 1_000_000_000L + 
Instant.now().getNano();
 
-                   
                     String influxLine = String.format(java.util.Locale.US, 
"%s,%s=%s,%s=%s %s=%f %d",
                             configurationChannel.get("measurement"),
                             "area",
diff --git 
a/plc4j/tools/merlot/org.apache.plc4x.merlot.archiver/src/main/resources/OSGI-INF/blueprint/archiver-service.xml
 
b/plc4j/tools/merlot/org.apache.plc4x.merlot.archiver/src/main/resources/OSGI-INF/blueprint/archiver-service.xml
index 4e1e90a..8114b74 100644
--- 
a/plc4j/tools/merlot/org.apache.plc4x.merlot.archiver/src/main/resources/OSGI-INF/blueprint/archiver-service.xml
+++ 
b/plc4j/tools/merlot/org.apache.plc4x.merlot.archiver/src/main/resources/OSGI-INF/blueprint/archiver-service.xml
@@ -82,7 +82,8 @@
           scope="singleton"
           activation="eager">
         <argument ref="refSchedulerService" /> 
-        <argument ref="MerlotGPClientBean" />                        
+        <argument ref="MerlotGPClientBean" />  
+        <argument ref="blueprintBundleContext" />            
     </bean>  
     
     <bean id="MerlotPvRtCollectorImplBean" 
@@ -113,7 +114,8 @@
           activation="eager">
         <argument ref="refSchedulerService" />
         <!--<argument ref="refEventAdminService" />-->   
-        <argument ref="MerlotGPClientBean" />                      
+        <argument ref="MerlotGPClientBean" /> 
+        <argument ref="blueprintBundleContext" />                       
     </bean>
     
     <bean id="MerlotHtcRTBean" 
diff --git 
a/plc4j/tools/merlot/org.apache.plc4x.merlot.features/src/main/feature/feature.xml
 
b/plc4j/tools/merlot/org.apache.plc4x.merlot.features/src/main/feature/feature.xml
index d249b00..cfc10e8 100755
--- 
a/plc4j/tools/merlot/org.apache.plc4x.merlot.features/src/main/feature/feature.xml
+++ 
b/plc4j/tools/merlot/org.apache.plc4x.merlot.features/src/main/feature/feature.xml
@@ -756,7 +756,7 @@
         <bundle 
start-level="30">mvn:org.apache.tsfile/tsfile/${tsfile.version}</bundle> 
         <bundle start-level="30">mvn:net.jpountz.lz4/lz4/1.3.0</bundle> 
         <bundle 
start-level="30">mvn:com.github.luben/zstd-jni/1.5.7-7</bundle> 
-        <bundle start-level="30">mvn:org.antlr/antlr4-runtime/4.13.2</bundle>  
  
+        <bundle start-level="30">mvn:org.antlr/antlr4-runtime/4.9.3</bundle>   
 
         <bundle start-level="30">mvn:org.tukaani/xz/1.10</bundle> 
         <bundle 
start-level="30">mvn:org.xerial.snappy/snappy-java/1.1.10.7</bundle>     
                                                                                
             
diff --git 
a/plc4j/tools/merlot/org.apache.plc4x.merlot.kafka/src/main/java/org/apache/plc4x/merlot/kafka/impl/MerlotKafkaDecanterCollectorImpl.java
 
b/plc4j/tools/merlot/org.apache.plc4x.merlot.kafka/src/main/java/org/apache/plc4x/merlot/kafka/impl/MerlotKafkaDecanterCollectorImpl.java
index c6782c2..7a8a76c 100644
--- 
a/plc4j/tools/merlot/org.apache.plc4x.merlot.kafka/src/main/java/org/apache/plc4x/merlot/kafka/impl/MerlotKafkaDecanterCollectorImpl.java
+++ 
b/plc4j/tools/merlot/org.apache.plc4x.merlot.kafka/src/main/java/org/apache/plc4x/merlot/kafka/impl/MerlotKafkaDecanterCollectorImpl.java
@@ -223,7 +223,7 @@ public class MerlotKafkaDecanterCollectorImpl implements 
MerlotDecanterCollector
             //Alarm values
             String value = record.value();
 
-            LOGGER.info("Key: {} Value: {}", key, value);
+            //LOGGER.info("Key: {} Value: {}", key, value);
 
             String pathPV = getPathPV(key);
 

Reply via email to