All Downloads are FREE. Search and download functionalities are using the official Maven repository.

fr.mines_stetienne.ci.sparql_generate.mqtt.ITER_MQTTSubscribe Maven / Gradle / Ivy

There is a newer version: 2.1.0
Show newest version
/*
 * Copyright 2020 MINES Saint-Étienne
 *
 * 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 fr.mines_stetienne.ci.sparql_generate.mqtt;

import fr.mines_stetienne.ci.sparql_generate.utils.LogUtils;
import fr.mines_stetienne.ci.sparql_generate.SPARQLExt;
import fr.mines_stetienne.ci.sparql_generate.iterator.IteratorStreamFunctionBase;
import fr.mines_stetienne.ci.sparql_generate.utils.ContextUtils;
import java.io.IOException;
import java.nio.charset.StandardCharsets;
import org.apache.jena.sparql.expr.ExprEvalException;
import org.apache.jena.sparql.expr.ExprList;
import org.apache.jena.sparql.expr.NodeValue;
import org.eclipse.paho.client.mqttv3.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.ArrayList;

import java.util.Collections;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Executor;
import java.util.function.Consumer;
import java.util.function.Function;
import org.apache.commons.io.IOUtils;
import org.apache.jena.sparql.expr.nodevalue.NodeValueString;
import org.apache.jena.sparql.util.Context;

/**
 * Iterator function
 * iter:MQTTSubscribe
 * connects to a MQTT server, subscribes to some topics, and issues bindings for
 * the topic (first variable) and the message (second variable) when they are
 * received.
 *
 * 

* See * Live * example

* *
    *
  • Param 1: (a String or URL) the MQTT server. Two types of connection are * supported tcp:// for a TCP connection and ssl:// for a TCP connection secured * by SSL/TLS;
  • *
  • Param 2 .. n (optional, Strings): topics to subscribe to.
  • *
* *

* For SSL configuration (programmatic or using JVM arguments), see * the * constructor of MqttClient. *

* Additional connection OPTIONS configuration can be programmatically set using * the MqttConnectOptions returned by {@link #getOptions}. *

*

* The MQTT message (byte[]) is assumed to be a UTF-8 string. This behaviour may * may changed using {@link #setParser} static method. *

* * @author Maxime Lefrançois * * @since 2018-10-02 */ public class ITER_MQTTSubscribe extends IteratorStreamFunctionBase { private static final Logger LOG = LoggerFactory.getLogger(ITER_MQTTSubscribe.class); public static final String URI = SPARQLExt.ITER + "MQTTSubscribe"; public static final MqttConnectOptions OPTIONS = new MqttConnectOptions(); static { OPTIONS.setAutomaticReconnect(true); OPTIONS.setCleanSession(true); OPTIONS.setConnectionTimeout(10); } public static Function PARSER = (message) -> { try { String messageString = IOUtils.toString(message, StandardCharsets.UTF_8.name()); return new NodeValueString(messageString); } catch (IOException ex) { LOG.warn("Exception while parsing message " + new String(message), ex); return null; } }; public static void setParser(Function parser) { PARSER = parser; } public static MqttConnectOptions getOptions() { return OPTIONS; } @Override public void checkBuild(ExprList args) { if (args.size() < 1) { LOG.debug("Expecting at least one argument"); throw new ExprEvalException("Expecting at least one argument"); } } @Override public void exec( final List args, final Consumer>> listListNodeValue) { final CompletableFuture semaphore = new CompletableFuture(); if(args.get(0) == null) { String msg = "First argument must be a string or a URI"; LOG.debug(msg); throw new ExprEvalException(msg); } if (!args.get(0).isString() && !args.get(0).isIRI()) { LOG.debug("First argument must be a string or a URI, got: " + args.get(0)); throw new ExprEvalException("First argument must be a string, got: " + args.get(0)); } final String url_s = args.get(0).isString() ? args.get(0).asString() : args.get(0).asNode().getURI(); if (args.size() > 1) { for (int i = 1; i < args.size(); i++) { if(args.get(i) == null) { String msg = "Argument " + i + " is null"; LOG.debug(msg); throw new ExprEvalException(msg); } if (!args.get(i).isString()) { LOG.debug("Argument " + i + " must be a string, got: " + args.get(i)); throw new ExprEvalException("Argument " + i + " must be a string, got: " + args.get(i)); } } } final Executor executor = ContextUtils.getExecutor(getContext()); try { IMqttClient mqttClient = new MqttClient(url_s, MqttClient.generateClientId()); mqttClient.setCallback(new MqttCallback() { @Override public void connectionLost(Throwable cause) { LOG.debug("MQTT Connection is lost", cause); executor.execute(() -> { LOG.debug("MQTT Connection is lost", cause); }); semaphore.complete(null); } @Override public void messageArrived(String topic, MqttMessage message) throws Exception { LOG.debug("MQTT message arrived"); executor.execute(() -> { LOG.debug("MQTT message arrived " + topic); if (LOG.isTraceEnabled()) { LOG.trace("MQTT message arrived " + topic + " -> " + LogUtils.compress(PARSER.apply(message.getPayload()).asNode())); } List nv = new ArrayList<>(); nv.add(new NodeValueString(topic)); nv.add(PARSER.apply(message.getPayload())); listListNodeValue.accept(Collections.singletonList(nv)); }); } @Override public void deliveryComplete(IMqttDeliveryToken token) { } }); mqttClient.connect(OPTIONS); if (args.size() > 1) { for (int i = 1; i < args.size(); i++) { mqttClient.subscribe(args.get(i).asString()); } } ContextUtils.addTaskOnClose(getContext(), () -> { try { mqttClient.close(); } catch (MqttException ex) { LOG.debug("Error while trying to close mqttClient ", ex); } }); } catch (MqttException e) { if (e.getCause() instanceof InterruptedException) { LOG.debug("Execution interrupted"); } else { LOG.debug("A MqttException occurred", e); throw new ExprEvalException("A MqttException occurred", e); } } try { semaphore.get(); } catch (InterruptedException ex) { LOG.debug("Execution interrupted"); throw new ExprEvalException("A MqttException occurred", ex); } catch (ExecutionException ex) { LOG.debug("An Exception occurred"); throw new ExprEvalException("An Exception occurred", ex); } } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy