My problem is that when i want to respond to an arriveng message i dont get the delivery token back from broker but the message is arrived at the broker. i can see it in the logs. So my question is how to respond with a publish to an incoming message?
This is the way i do and it does not work...
public void setMqttCallback() {
mqttClient.setCallback(new MqttCallback() {
#Override
public void connectionLost(final Throwable throwable) {
System.out.println("Lost connection to Broker because of: " + throwable.getMessage());
}
#Override
public void messageArrived(final String topic, final MqttMessage mqttMessage) throws Exception {
System.out.println("Received on " + topic + ": " + new String(mqttMessage.getPayload()));
topics = new Topics();
//Answer to arriving messages (Logic)
if (topic.equals(topics.getVehicleNavLandmarkInfo(Mqtt.VIN_ID))) {
landmarks = new Landmarks();
MqttMessage message = new MqttMessage(landmarks.getLandmarks().getBytes());
message.setQos(2);
System.out.println("Sending on " + topic + ": " + landmarks.getLandmarks());
mqttClient.publish(topics.getBackendNavLandsmarks(Mqtt.VIN_ID), message);
}
if (topic.equals(topics.getVehicleNavDestination(Mqtt.VIN_ID))) {
routing = new Routing(49.0000, 8.0000, "A");
MqttMessage message = new MqttMessage(routing.getShortestPath().getBytes());
message.setQos(2);
System.out.println("Sending on " + topic + ": " + routing.getShortestPath());
mqttClient.publish(topics.getBackendNavRoute(Mqtt.VIN_ID), message);
}
}
#Override
public void deliveryComplete(final IMqttDeliveryToken iMqttDeliveryToken) {
System.out.println("Delivered Message: " + iMqttDeliveryToken.toString());
}
});
}
The messageArrived method is blocking, so you cannot then try and publish a message using the same mqttClient connection. You need to use another thread that has its own connection to the broker.
If it is a one-off situation then you can start a new thread and do everything in it but if your application will be constantly publishing messages to arriving messages then it would be better to start a thread, connect to broker then wait for information to be passed from the messageArrived method.
Related
I have subscription VIEW_TOPIC with pull strategy. Why I cannot see any message although have 7 delay messages? I cannot figure out what am I missing. By the way, I'm running subscriber on k8s GCP. I was also add GOOGLE_APPLICATION_CREDENTIALS variable environment.
Subscriber configuration
private Subscriber buildSubscriber() {
try (SubscriptionAdminClient subscriptionAdminClient = SubscriptionAdminClient.create()) {
TopicName topicName = TopicName.of(projectId, topic);
ProjectSubscriptionName subscriptionName =
ProjectSubscriptionName.of(projectId, subscriptionId);
// Create a pull subscription with default acknowledgement deadline of 10 seconds.
// Messages not successfully acknowledged within 10 seconds will get resent by the server.
Subscription subscription =
subscriptionAdminClient.createSubscription(
subscriptionName, topicName, PushConfig.getDefaultInstance(), 10);
System.out.println("Created pull subscription: " + subscription.getName());
} catch (IOException e) {
LOGGER.error("Cannot create pull subscription");
} catch (AlreadyExistsException existsException) {
LOGGER.warn("Subscription already created");
}
ProjectSubscriptionName subscriptionName = ProjectSubscriptionName.of(projectId, subscriptionId);
LOGGER.info("Subscribe topic: " + topic + " | SubscriptionId: " + subscriptionId);
// default is 4 * num of processor
ExecutorProvider executorProvider = InstantiatingExecutorProvider.newBuilder().build();
Subscriber.Builder subscriberBuilder = Subscriber.newBuilder(subscriptionName, new MessageReceiverImpl())
.setExecutorProvider(executorProvider);
// The subscriber will pause the message stream and stop receiving more messages from the
// server if any one of the conditions is met.
FlowControlSettings flowControlSettings =
FlowControlSettings.newBuilder()
.setMaxOutstandingElementCount(100)
// the maximum size of messages the subscriber
// receives before pausing the message stream.
// 10Mib
.setMaxOutstandingRequestBytes(10L * 1024L * 1024L)
.build();
subscriberBuilder.setFlowControlSettings(flowControlSettings);
Subscriber subscriber = subscriberBuilder.build();
subscriber.addListener(new ApiService.Listener() {
#Override
public void failed(ApiService.State from, Throwable failure) {
LOGGER.error(from, failure);
}
}, MoreExecutors.directExecutor());
return subscriber;
}
Subscriber
public void startSubscribeMessage() {
LOGGER.info("Begin subscribe topic " + topic);
this.subscriber.startAsync().awaitRunning();
LOGGER.info("Subscriber start successfully!!!");
}
public class MessageReceiverImpl implements MessageReceiver {
private static final Logger LOGGER = Logger.getLogger(MessageReceiverImpl.class);
private final LogSave logSave = MatchSave.getInstance();
#Override
public void receiveMessage(PubsubMessage message, AckReplyConsumer consumer) {
ByteString data = message.getData();
// Get the schema encoding type.
String encoding = message.getAttributesMap().get("googclient_schemaencoding");
Req.LogReq logReqMsg = null;
try {
switch (encoding) {
case "BINARY":
logReqMsg = Req.LogReq.parseFrom(data);
break;
case "JSON":
Req.LogReq.Builder msgBuilder = Req.LogReq.newBuilder();
JsonFormat.parser().merge(data.toStringUtf8(), msgBuilder);
logReqMsg = msgBuilder.build();
break;
}
LOGGER.info((JsonFormat.printer().omittingInsignificantWhitespace().print(logReqMsg)));
logSave.addLogMsg(battleLogMsg);
} catch (InvalidProtocolBufferException e) {
e.printStackTrace();
}
consumer.ack();
}
}
With Req.LogReq is a proto message. My dependency:
// google cloud
implementation platform('com.google.cloud:libraries-bom:22.0.0')
implementation 'com.google.cloud:google-cloud-pubsub'
implementation group: 'com.google.protobuf', name: 'protobuf-java-util', version: '3.17.2'
And the call function logSave.addLogMsg(battleLogMsg); is add message to CopyOnWriteArrayList
I am trying to create multiple worker threads for the undertow server so that multiple threads are available to process the request from the client concurrently.
I tried setting them at the server level using UndertowOptions and Options. Tried creating custom XnioWorker and assigned to Undertow Server.
Nothing seems to work here, with all attempts to configure worker threads.
Xnio xnio = Xnio.getInstance();
XnioWorker worker = null;
try {
worker = xnio.createWorker(
OptionMap.builder().set(Options.WORKER_IO_THREADS, 50).set(Options.WORKER_TASK_CORE_THREADS, 50)
.set(Options.WORKER_TASK_MAX_THREADS, 50).set(Options.TCP_NODELAY, true).getMap());
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
// OptionMap socketOptions = OptionMap.builder().set(Options.WORKER_IO_THREADS, 10).set(Options.TCP_NODELAY, true)
// .set(Options.REUSE_ADDRESSES, true).getMap();
Undertow server = Undertow.builder().setServerOption(UndertowOptions.ENABLE_HTTP2, true)
.setServerOption(UndertowOptions.HTTP2_SETTINGS_MAX_CONCURRENT_STREAMS,
UndertowHttp2ServerEpLevel.maxReqPerConn)
.setServerOption(UndertowOptions.MAX_CONCURRENT_REQUESTS_PER_CONNECTION,
UndertowHttp2ServerEpLevel.maxReqPerConn)
.addHttpListener(port, host)
.setWorkerOption(Options.WORKER_IO_THREADS, 10)
.setWorkerOption(Options.WORKER_TASK_CORE_THREADS, 10)
.setWorkerThreads(UndertowHttp2ServerEpLevel.iotheads)
.setIoThreads(UndertowHttp2ServerEpLevel.iotheads)
.setWorker(worker)
.setHandler(exchange -> {
Thread.sleep(responseDelayInMs);
DateFormat dateFormat = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss");
Date date = new Date();
System.out.print(dateFormat.format(date) + ", **Thread name: " + Thread.currentThread().getName());**
System.out.println(
": " + port + ", Client address is: " + exchange.getConnection().getPeerAddress().toString()
+ " TotalMsgReceived: " + ++msgCounter);
exchange.getResponseHeaders().put(Headers.CONTENT_TYPE, "application/json");
exchange.setStatusCode(returnCode);
// exchange.getResponseSender().send("Undertow Hi");
}).build();
server.start();
With the above code i see handler code is always executed by same thread. And with one thread with n/w latency assumed 100ms i am able process only 9 request per second. Thats why i want more number of threads to process request concurrently so that high rate can be achieved.
Console output:
*2021/07/29 09:22:46, Thread name: XNIO-1 I/O-12: 8081, Client address is: /127.0.0.1:16002 TotalMsgReceived: 534
2021/07/29 09:22:47, Thread name: XNIO-1 I/O-12: 8081, Client address is: /127.0.0.1:16002 TotalMsgReceived: 535*
Now from JMX i see thread pool size is updated to 50 but still no improvement in perfromance and no multi worker threads seen in console:
Any view on this will help. Thanks!
From the documentation
Dispatching to a worker thread
public void handleRequest(final HttpServerExchange exchange) throws Exception{
if (exchange.isInIoThread()) {
exchange.dispatch(this);
return;
}
//handler code
}
You seem to be missing this part, because everything in your case is running on IO thread.
There are multiple overloads of dispatch method that you can choose from depending on your use case.
Following code does the job.
Undertow server = Undertow.builder().setServerOption(UndertowOptions.ENABLE_HTTP2, true)
.setServerOption(UndertowOptions.HTTP2_SETTINGS_MAX_CONCURRENT_STREAMS,
UndertowHttp2ServerEpLevelMT.maxReqPerConn)
.setServerOption(UndertowOptions.MAX_CONCURRENT_REQUESTS_PER_CONNECTION,
UndertowHttp2ServerEpLevelMT.maxReqPerConn)
.addHttpListener(port, host)
.setWorkerOption(Options.WORKER_IO_THREADS, UndertowHttp2ServerEpLevelMT.iotheads)
.setWorkerOption(Options.WORKER_TASK_CORE_THREADS, UndertowHttp2ServerEpLevelMT.iotheads)
.setWorkerOption(Options.WORKER_TASK_MAX_THREADS, UndertowHttp2ServerEpLevelMT.iotheads)
.setWorkerThreads(UndertowHttp2ServerEpLevelMT.iotheads)
.setIoThreads(UndertowHttp2ServerEpLevelMT.iotheads)
.setHandler(new HttpHandler() {
#Override
public void handleRequest(final HttpServerExchange exchange) throws Exception {
if (exchange.isInIoThread()) {
exchange.dispatch(this);
return;
}
System.out.println("Port: " + port + ", Client address is: "
+ exchange.getConnection().getPeerAddress().toString());
exchange.setStatusCode(returnCode);
}
}).build();
server.start();
I'm trying to send push message using the emulator of pubsub, I'm using spring boot too, this is my configuration:
Dependency:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-gcp-starter-pubsub</artifactId>
</dependency>
My bean:
#Configuration
#AutoConfigureBefore(value= GcpPubSubAutoConfiguration.class)
#EnableConfigurationProperties(value= GcpPubSubProperties.class)
public class EmulatorPubSubConfiguration {
#Value("${spring.gcp.pubsub.projectid}")
private String projectId;
#Value("${spring.gcp.pubsub.subscriptorid}")
private String subscriptorId;
#Value("${spring.gcp.pubsub.topicid}")
private String topicId;
#Bean
public Publisher pubsubEmulator() throws IOException {
String hostport = System.getenv("PUBSUB_EMULATOR_HOST");
ManagedChannel channel = ManagedChannelBuilder.forTarget(hostport).usePlaintext().build();
try {
TransportChannelProvider channelProvider =
FixedTransportChannelProvider.create(GrpcTransportChannel.create(channel));
CredentialsProvider credentialsProvider = NoCredentialsProvider.create();
// Set the channel and credentials provider when creating a `TopicAdminClient`.
// Similarly for SubscriptionAdminClient
TopicAdminClient topicClient =
TopicAdminClient.create(
TopicAdminSettings.newBuilder()
.setTransportChannelProvider(channelProvider)
.setCredentialsProvider(credentialsProvider)
.build());
ProjectTopicName topicName = ProjectTopicName.of(projectId, topicId);
// Set the channel and credentials provider when creating a `Publisher`.
// Similarly for Subscriber
return Publisher.newBuilder(topicName)
.setChannelProvider(channelProvider)
.setCredentialsProvider(credentialsProvider)
.build();
} finally {
channel.shutdown();
}
}
}
Of course, I have set PUBSUB_EMULATOR_HOST system variable to localhost:8085, where is the emulator running
I created a rest controller for testing:
for send push message
#Autowired
private Publisher pubsubPublisher;
#PostMapping("/send1")
public String publishMessage(#RequestParam("message") String message) throws InterruptedException, IOException {
Publisher pubsubPublisher = this.getPublisher();
ByteString data = ByteString.copyFromUtf8(message);
PubsubMessage pubsubMessage = PubsubMessage.newBuilder().setData(data).build();
ApiFuture<String> future = pubsubPublisher.publish(pubsubMessage);
//pubsubPublisher.publishAllOutstanding();
try {
// Add an asynchronous callback to handle success / failure
ApiFutures.addCallback(future,
new ApiFutureCallback<String>() {
#Override
public void onFailure(Throwable throwable) {
if (throwable instanceof ApiException) {
ApiException apiException = ((ApiException) throwable);
// details on the API exception
System.out.println(apiException.getStatusCode().getCode());
System.out.println(apiException.isRetryable());
}
System.out.println("Error publishing message : " + message);
System.out.println("Error publishing error : " + throwable.getMessage());
System.out.println("Error publishing cause : " + throwable.getCause());
}
#Override
public void onSuccess(String messageId) {
// Once published, returns server-assigned message ids (unique within the topic)
System.out.println(messageId);
}
},
MoreExecutors.directExecutor());
}
finally {
if (pubsubPublisher != null) {
// When finished with the publisher, shutdown to free up resources.
pubsubPublisher.shutdown();
pubsubPublisher.awaitTermination(1, TimeUnit.MINUTES);
}
}
return "ok";
for get message:
#PostMapping("/pushtest")
public String pushTest(#RequestBody CloudPubSubPushMessage request) {
System.out.println( "------> message received: " + decode(request.getMessage().getData()) );
return request.toString();
}
I have created my topic and subscription in the emulator, I followed this tutorial:
https://cloud.google.com/pubsub/docs/emulator
I'm set the endpoint "pushtest" for get push message in the emulator, with this command:
python subscriber.py PUBSUB_PROJECT_ID create-push TOPIC_ID SUBSCRIPTION_ID PUSH_ENDPOINT
But when I run the test, doesn't reach "/pushtest" endpoint and I'm getting this error:
Task java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask#265d5d05
[Not completed, task = java.util.concurrent.Executors$RunnableAdapter#a8c8be3
[Wrapped task = com.google.common.util.concurrent.TrustedListenableFutureTask#1a53c57c
[status=PENDING, info=[task=[running=[NOT STARTED YET], com.google.api.gax.rpc.AttemptCallable#3866e1d0]]]]]
rejected from java.util.concurrent.ScheduledThreadPoolExecutor#3f34809a
[Terminated, pool size = 0, active threads = 0, queued tasks = 0, completed tasks = 1]
for assurance that the emulator is running ok, I'm run the test in python with the following command:
python publisher.py PUBSUB_PROJECT_ID publish TOPIC_ID
And I'm getting messages correctly in "pushtest" endpoint.
I don't know why sorry for my hazing.
Thanks for your help.
I found the problem.
Only comment this line in the bean
channel.shutdown();
HAHA very simple.
I want use multiple gateway to send messages with SMSLIB.
I have 4 HSPA modems and for each one a different operator, how to detect the name of operator and from there using a specific SMS to be sent.
Here my code:
// SendMessage.java - Sample application.
//
// This application shows you the basic procedure for sending messages.
// You will find how to send synchronous and asynchronous messages.
//
// For asynchronous dispatch, the example application sets a callback
// notification, to see what's happened with messages.
package sms;
import org.smslib.AGateway;
import org.smslib.IOutboundMessageNotification;
import org.smslib.Library;
import org.smslib.OutboundMessage;
import org.smslib.Service;
import org.smslib.modem.SerialModemGateway;
public class SendMessage
{
public void doIt() throws Exception
{
OutboundNotification outboundNotification = new OutboundNotification();
System.out.println("Example: Send message from a serial gsm modem.");
System.out.println(Library.getLibraryDescription());
System.out.println("Version: " + Library.getLibraryVersion());
SerialModemGateway gateway = new SerialModemGateway("modem.com3", "COM3", 115200, "Huawei", "");
gateway.setInbound(true);
gateway.setOutbound(true);
gateway.setSimPin("0000");
// Explicit SMSC address set is required for some modems.
// Below is for VODAFONE GREECE - be sure to set your own!
gateway.setSmscNumber("+947500001");
Service.getInstance().setOutboundMessageNotification(outboundNotification);
Service.getInstance().addGateway(gateway);
Service.getInstance().startService();
System.out.println();
System.out.println("Modem Information:");
System.out.println(" Manufacturer: " + gateway.getManufacturer());
System.out.println(" Model: " + gateway.getModel());
System.out.println(" Serial No: " + gateway.getSerialNo());
System.out.println(" SIM IMSI: " + gateway.getImsi());
System.out.println(" Signal Level: " + gateway.getSignalLevel() + " dBm");
System.out.println(" Battery Level: " + gateway.getBatteryLevel() + "%");
System.out.println();
// Send a message synchronously.
OutboundMessage msg = new OutboundMessage("0094757599108", "Hello from SMSLib!");
Service.getInstance().sendMessage(msg);
System.out.println(msg);
// Or, send out a WAP SI message.
//OutboundWapSIMessage wapMsg = new OutboundWapSIMessage("306974000000", new URL("http://www.smslib.org/"), "Visit SMSLib now!");
//Service.getInstance().sendMessage(wapMsg);
//System.out.println(wapMsg);
// You can also queue some asynchronous messages to see how the callbacks
// are called...
//msg = new OutboundMessage("309999999999", "Wrong number!");
//srv.queueMessage(msg, gateway.getGatewayId());
//msg = new OutboundMessage("308888888888", "Wrong number!");
//srv.queueMessage(msg, gateway.getGatewayId());
System.out.println("Now Sleeping - Hit <enter> to terminate.");
System.in.read();
Service.getInstance().stopService();
}
public class OutboundNotification implements IOutboundMessageNotification
{
public void process(AGateway gateway, OutboundMessage msg)
{
System.out.println("Outbound handler called from Gateway: " + gateway.getGatewayId());
System.out.println(msg);
}
}
public static void main(String args[])
{
SendMessage app = new SendMessage();
try
{
app.doIt();
}
catch (Exception e)
{
e.printStackTrace();
}
}
}
This one detect only one gateway from COM3, but i have a USB SWITCHER in COM3 and 4 modems on it.
What is the method to use to get them detected (I want a method to do it), thank you so much.
I have downloaded the source from github from this link: https://github.com/twitter/cloudhopper-smpp
Assuming I want to test receiving message between clients so I create a server and 2 clients. To run server, I used the command "make server". Then in other machine, a client connected to my server and send 1 message to other client which has phone number "123456" using following code
submit0.setSourceAddress(new Address((byte)0x03, (byte)0x00, "654321"));
submit0.setDestAddress(new Address((byte)0x01, (byte)0x01, "123456"));
submit0.setShortMessage(textBytes);
SubmitSmResp submitResp = session0.submit(submit0, 10000);
How can the client which has phone number "123456" get message content from phone number "654321"?
Thanks!
When you are creating sessionHandler like this,
DefaultSmppSessionHandler sessionHandler = new ClientSmppSessionHandler();
This ClientSmppSessionHandler should be extended to DefaultSmppSessionHandler.
There are 2 listeners.
Please see below example.
public class ClientSmppSessionHandler extends DefaultSmppSessionHandler {
private static final Logger logger = LoggerFactory.getLogger(ClientSmppSessionHandler.class);
public ClientSmppSessionHandler() {
super(logger);
}
#Override
public void firePduRequestExpired(PduRequest pduRequest) {
logger.warn("PDU request expired: {}", pduRequest);
}
#Override
public PduResponse firePduRequestReceived(PduRequest pduRequest) {
PduResponse response = pduRequest.createResponse();
logger.info("SMS Received: {}", pduRequest);
if (pduRequest.getCommandId() == SmppConstants.CMD_ID_DELIVER_SM) {
DeliverSm mo = (DeliverSm) pduRequest;
int length = mo.getShortMessageLength();
Address source_address = mo.getSourceAddress();
Address dest_address = mo.getDestAddress();
byte[] shortMessage = mo.getShortMessage();
String SMS= new String(shortMessage);
logger.info(source_address + ", " + dest_address + ", " + SMS);
}
return response;
}
}