getConnectionState() as connected /disconnected depending on the device .if it is sending message i should see connected and if it not sending i should get disconnected .But each time i run the below java Program i am getting status as disconnected irrespective of device is sending messages or not
RegistryManager registryManager = RegistryManager.createFromConnectionString(connectionString);
System.out.println(registryManager.getDevices(new Integer(1000)));
while(true){
ArrayList<Device> deviceslist=registryManager.getDevices(new Integer(1000));
for(Device device:deviceslist)
{
/*System.out.println(device.getDeviceId());
System.out.println(device.getPrimaryKey());
System.out.println(device.getSecondaryKey());*/
System.out.println(device.getDeviceId());
System.out.println(device.getConnectionState());
/*System.out.println(device.getConnectionStateUpdatedTime());
System.out.println(device.getLastActivityTime());
System.out.println(device.getStatusReason());
System.out.println(device.getStatusUpdatedTime());
System.out.println(device.getSymmetricKey());
System.out.println(device.geteTag());
*/ }
}
I definitely am seeing otherwise.
I'm creating an simple C# console application using the code below,
static async void QueryDevices()
{
RegistryManager manager = RegistryManager.CreateFromConnectionString(connectionString);
while (true)
{
var devices = await manager.GetDevicesAsync(100);
{
foreach (var item in devices)
{
Console.WriteLine(DateTime.Now + ": " + item.Id + ", " + item.ConnectionState);
System.Threading.Thread.Sleep(100);
}
}
}
}
The git here is to always query the whole device list, because the ConnectionState property somehow looks like "static" memebers of the single device client instance, which is not apt-to change even when the actual state changes.
And my output is like below, the "connected" state is when I'm using an java client sample to send message to the IoT Hub.
Related
I'm writing code in java (using Azure SDK for Java), I have a Service bus queue that contains sessionful messages. I want to receive those messages and process them to another place.
I make a connection to the Queue by using QueueClient, and then I use registerSessionHandler to process through the messages (code below).
The problem is that whenever a message is received, I can print all details about it including the content, but it is printed 10 times and after each time it prints an Exception.
(printing 10 times: I understand that this is because there is a 10 times retry policy before it throws the message to the Dead letter queue and goes to the next message.)
The Exception says
> USERCALLBACK-Receiver not created. Registering a MessageHandler creates a receiver.
The output with the Exception
But I'm sure that the SessionHandler does the same thing as MessageHandler but includes support for sessions, so it should create a receiver since it receives messages. I have tried to use MessageHandler but it won't even work and stops the whole program because it doesn't support sessionful messages, and the ones I receive have sessions.
My problem is understanding what the Exception wants me to do, and how can I fix the code so it won't give me any exceptions? Does anyone have suggestions on how to improve the code? or other methods that do the same thing?
QueueClient qc = new QueueClient(
new ConnectionStringBuilder(connectionString),
ReceiveMode.PEEKLOCK);
qc.registerSessionHandler(
new ISessionHandler() {
#Override
public CompletableFuture<Void> onMessageAsync(IMessageSession messageSession, IMessage message) {
System.out.printf(
"\nMessage received: " +
"\n --> MessageId = %s " +
"\n --> SessionId = %s" +
"\n --> Content Type = %s" +
"\n --> Content = \n\t\t %s",
message.getMessageId(),
messageSession.getSessionId(),
message.getContentType(),
getMessageContent(message)
);
return qc.completeAsync(message.getLockToken());
}
#Override
public CompletableFuture<Void> OnCloseSessionAsync(IMessageSession iMessageSession) {
return CompletableFuture.completedFuture(null);
}
#Override
public void notifyException(Throwable throwable, ExceptionPhase exceptionPhase) {
System.out.println("\n Exception " + exceptionPhase + "-" + throwable.getMessage());
}
},
new SessionHandlerOptions(1, true, Duration.ofMinutes(1)),
Executors.newSingleThreadExecutor()
);
(The getMessageContent(message) method is a separate method, for those interested:)
public String getMessageContent(IMessage message){
List<byte[]> content = message.getMessageBody().getBinaryData();
StringBuilder sb = new StringBuilder();
for (byte[] b : content) {
sb.append(new String(b)
);
}
return sb.toString();
}
For those who wonder, I managed to solve the problem!
It was simply done by using Azure Functions ServiceBusQueueTrigger, it will then listen to the Service bus Queue and process the messages. By setting isSessionsEnabled to true, it will accept sessionful messages as I wanted :)
So instead of writing more than 100 lines of code, the code looks like this now:
public class Function {
#FunctionName("QueueFunction")
public void run(
#ServiceBusQueueTrigger(
name = "TriggerName", //Any name you choose
queueName = "queueName", //QueueName from the portal
connection = "ConnectionString", //ConnectionString from the portal
isSessionsEnabled = true
) String message,
ExecutionContext context
) {
// Write the code you want to do with the message here
// Using the variable messsage which contains the messageContent, messageId, sessionId etc.
}
}
I want to send a message (e.g. Update available) to all users(~15,000). I have implemented App Engine Backend with Google Cloud Messaging to send message.
I have tested on 2 devices. Got message on both. But as google docs says "GCM is support for up to 1,000 recipients for a single message."
My question is how to send same message to remaining 14,000 users in my
case? Or the code below will take care of it?
Below is the code which sends message
import com.google.android.gcm.server.Constants;
import com.google.android.gcm.server.Message;
import com.google.android.gcm.server.Result;
import com.google.android.gcm.server.Sender;
import com.google.api.server.spi.config.Api;
import com.google.api.server.spi.config.ApiNamespace;
import java.io.IOException;
import java.util.List;
import java.util.logging.Logger;
import javax.inject.Named;
import static com.example.shani.myapplication.backend.OfyService.ofy;
/**
* An endpoint to send messages to devices registered with the backend
* <p/>
* For more information, see
* https://developers.google.com/appengine/docs/java/endpoints/
* <p/>
* NOTE: This endpoint does not use any form of authorization or
* authentication! If this app is deployed, anyone can access this endpoint! If
* you'd like to add authentication, take a look at the documentation.
*/
#Api(name = "messaging", version = "v1", namespace = #ApiNamespace(ownerDomain = "backend.myapplication.shani.example.com", ownerName = "backend.myapplication.shani.example.com", packagePath = ""))
public class MessagingEndpoint {
private static final Logger log = Logger.getLogger(MessagingEndpoint.class.getName());
/**
* Api Keys can be obtained from the google cloud console
*/
private static final String API_KEY = System.getProperty("gcm.api.key");
/**
* Send to the first 10 devices (You can modify this to send to any number of devices or a specific device)
*
* #param message The message to send
*/
public void sendMessage(#Named("message") String message) throws IOException {
if (message == null || message.trim().length() == 0) {
log.warning("Not sending message because it is empty");
return;
}
// crop longer messages
if (message.length() > 1000) {
message = message.substring(0, 1000) + "[...]";
}
Sender sender = new Sender(API_KEY);
Message msg = new Message.Builder().addData("message", message).build();
List<RegistrationRecord> records = ofy().load().type(RegistrationRecord.class).limit(1000).list();
for (RegistrationRecord record : records) {
Result result = sender.send(msg, record.getRegId(), 5);
if (result.getMessageId() != null) {
log.info("Message sent to " + record.getRegId());
String canonicalRegId = result.getCanonicalRegistrationId();
if (canonicalRegId != null) {
// if the regId changed, we have to update the datastore
log.info("Registration Id changed for " + record.getRegId() + " updating to " + canonicalRegId);
record.setRegId(canonicalRegId);
ofy().save().entity(record).now();
}
} else {
String error = result.getErrorCodeName();
if (error.equals(Constants.ERROR_NOT_REGISTERED)) {
log.warning("Registration Id " + record.getRegId() + " no longer registered with GCM, removing from datastore");
// if the device is no longer registered with Gcm, remove it from the datastore
ofy().delete().entity(record).now();
} else {
log.warning("Error when sending message : " + error);
}
}
}
}
}
I know there are simillar questions but I am using Java language. I found questions which uses php language at backend. so not helpful to me!
Google Cloud Messaging: Send message to "all" users
Sending Push Notification on multiple devices
Is there anyone who has successfully implemented App Engine+Google Cloud Messaging JAVA language?
In the below code line if I replace 1000 with 15,000 Will it solve my problem?
List<RegistrationRecord> records = ofy().load().type(RegistrationRecord.class).limit(1000).list();
Please please help as soon as possible. And very sorry for my English.. If anyone need other details you are welcome to ask.
Thanks for your time.
A few considerations,
1) Sending notifications to a possibly huge number of users might take significant time, consider using Task Queues to queue that work to be done "offline" outside the 60 sec limit.
2) Now as for the GCM limit, if you need to all your users but GCM allow you 1000 at a time just split them in batches of 1000 and send every batch a message separately.
If you combine both recommendations you should have a fairly scalable process where you query for all your users in 1 request , split that list and just queue sending the message to those users 1000 at a time.
Extension to the #jirungaray answer below is code for sending GCM messages to all registered users,
Here I assume that from android you are registering each mobile-devices for GCM services and storing those device tokens in database.
public class GCM {
private final static Logger LOGGER = Logger.getLogger(GCM.class.getName());
private static final String API_KEY = ConstantUtil.GCM_API_KEY;
public static void doSendViaGcm(List<String> tocken,String message) throws IOException {
Sender sender = new Sender(API_KEY);
// Trim message if needed.
if (message.length() > 1000) {
message = message.substring(0, 1000) + "[...]";
}
Message msg = new Message.Builder().addData("message", message).build();
try{
MulticastResult result = sender.send(msg, tocken, 5);
}catch(Exception ex){
LOGGER.severe("error is"+ex.getMessage());
ex.printStackTrace();
}
}
}
In above code snippet API_KEY can be obtain from google console project ,here I assume that you have already created one google console project and enable GCM api,
you can generate API_KEY as follows
your_google_console_project>> Credentials>> Create New Key >> Server
key >> enter ip address Which you want to allow
access to GCM api[i used 0.0.0.0/0]
Now doSendViaGcm(List tocken,String message) of GCM class performs task of sending messages to all register android mobile devices
here List<String> token is array-list of all device token on which messages will be delivered ,remember this list size should not more than 1000 or else http call will fail.
hope this will help you
thanks
I'm experimenting with java flavored zmq to test the benefits of using PGM over TCP in my project. So I changed the weather example, from the zmq guide, to use the epgm transport.
Everything compiles and runs, but nothing is being sent or received. If I change the transport back to TCP, the server receives the messages sent from the client and I get the console output I'm expecting.
So, what are the requirements for using PGM? I changed the string, that I'm passing to the bind and connect methods, to follow the zmq api for zmq_pgm: "transport://interface;multicast address:port". That didn't work. I get and invalid argument error whenever I attempt to use this format. So, I simplified it by dropping the interface and semicolon which "works", but I'm not getting any results.
I haven't been able to find a jzmq example that uses pgm/epgm and the api documentation for the java binding does not define the appropriate string format for an endpoint passed to bind or connect. So what am I missing here? Do I have to use different hosts for the client and the server?
One thing of note is that I'm running my code on a VirtualBox VM (Ubuntu 14.04/OSX Mavericks host). I'm not sure if that has anything to do with the issue I'm currently facing.
Server:
public class wuserver {
public static void main (String[] args) throws Exception {
// Prepare our context and publisher
ZMQ.Context context = ZMQ.context(1);
ZMQ.Socket publisher = context.socket(ZMQ.PUB);
publisher.bind("epgm://xx.x.x.xx:5556");
publisher.bind("ipc://weather");
// Initialize random number generator
Random srandom = new Random(System.currentTimeMillis());
while (!Thread.currentThread ().isInterrupted ()) {
// Get values that will fool the boss
int zipcode, temperature, relhumidity;
zipcode = 10000 + srandom.nextInt(10000) ;
temperature = srandom.nextInt(215) - 80 + 1;
relhumidity = srandom.nextInt(50) + 10 + 1;
// Send message to all subscribers
String update = String.format("%05d %d %d", zipcode, temperature, relhumidity);
publisher.send(update, 0);
}
publisher.close ();
context.term ();
}
}
Client:
public class wuclient {
public static void main (String[] args) {
ZMQ.Context context = ZMQ.context(1);
// Socket to talk to server
System.out.println("Collecting updates from weather server");
ZMQ.Socket subscriber = context.socket(ZMQ.SUB);
//subscriber.connect("tcp://localhost:5556");
subscriber.connect("epgm://xx.x.x.xx:5556");
// Subscribe to zipcode, default is NYC, 10001
String filter = (args.length > 0) ? args[0] : "10001 ";
subscriber.subscribe(filter.getBytes());
// Process 100 updates
int update_nbr;
long total_temp = 0;
for (update_nbr = 0; update_nbr < 100; update_nbr++) {
// Use trim to remove the tailing '0' character
String string = subscriber.recvStr(0).trim();
StringTokenizer sscanf = new StringTokenizer(string, " ");
int zipcode = Integer.valueOf(sscanf.nextToken());
int temperature = Integer.valueOf(sscanf.nextToken());
int relhumidity = Integer.valueOf(sscanf.nextToken());
total_temp += temperature;
}
System.out.println("Average temperature for zipcode '"
+ filter + "' was " + (int) (total_temp / update_nbr));
subscriber.close();
context.term();
}
}
There are a couple possibilities:
You need to make sure ZMQ is compiled with the --with-pgm option: see here - but this doesn't appear to be your issue if you're not seeing "protocol not supported"
Using raw pgm requires root privileges because it requires the ability to create raw sockets... but epgm doesn't require that, so it shouldn't be your issue either (I only bring it up because you use the term "pgm/epgm", and you should be aware that they are not equally available in all situations)
What actually appears to be the problem in your case is that pgm/epgm requires support along the network path. In theory, it requires support out to your router, so your application can send a single message and have your router send out multiple messages to each client, but if your server is aware enough, it can probably send out multiple messages immediately and bypass this router support. The problem is, as you correctly guessed, trying to do this all on one host is not supported.
So, you need different hosts for client and server.
Another bit to be aware of is that some virtualization environments--RHEV/Ovirt and libvirt/KVM with the mac_filter option enabled come to mind-- that, by default, neuter one's abilities via (eb|ip)tables to utilize mcast between guests. With libvirt, of course, the solution is to simply set the option to '0' and restart libvirtd. RHEV/Ovirt require a custom plugin.
At any rate, I would suggest putting a sniffer on the network devices on each system you are using and watching to be sure traffic that is exiting the one host is actually visible on the other.
I’m using FreePBX with Asterisk’s Java API.
For the moment, I’m able to display all my SIP peers with their respective states:
public void onManagerEvent(ManagerEvent event)
{
// Look if the event is a IP phone (Peer entry)
if(event instanceof PeerEntryEvent)
{
PeerEntryEvent ev = (PeerEntryEvent)event;
// Get the user extension
peer = ev.getObjectName();
// Add to the array
peersName.add(peer);
}
}
I’m able to display the phone number and name of both callers when a channel is open:
private String GetExtensionPeer(String extension)
{
for (AsteriskChannel e : channels)
if (e.number.equals(extension) && e.bridge != null )
for (AsteriskChannel channel : channels)
if (z.channel.equals(e.bridge))
return " with " + channel.number + " - " + channel.name;
return "";
}
But now, I would like to display the name of my extensions without a channel connection.
In FreePBX's panel, it's look like :
In freepbx you can get list of extensions from asterisk db. To see info, do
asterisk -rx "database show"
To get info use manager action "command" with DBGET.
Other option - got that info from freepbx's mysql db.
I have a system with a db4o server that has two clients. One client is hosted in process, the other is a web server hosting a number of servlets that need to query the database.
In the web server's connection code, I have registered for the commit event, and use it to refresh objects as suggested by the db4o documentation at http://community.versant.com/documentation/reference/db4o-8.0/java/reference/Content/advanced_topics/callbacks/possible_usecases/committed_event_example.htm :
client = Db4oClientServer.openClient (context.getBean ("db4oClientConfiguration", ClientConfiguration.class),
arg0.getServletContext ().getInitParameter ("databasehost"),
Integer.parseInt (arg0.getServletContext ().getInitParameter ("databaseport")),
arg0.getServletContext ().getInitParameter ("databaseuser"),
arg0.getServletContext ().getInitParameter ("databasepassword"));
System.out.println ("DB4O connection established");
EventRegistry events = EventRegistryFactory.forObjectContainer (client);
events.committed ().addListener (new EventListener4<CommitEventArgs> () {
public void onEvent (Event4<CommitEventArgs> commitEvent, CommitEventArgs commitEventArgs)
{
for (Iterator4<?> it = commitEventArgs.updated ().iterator (); it.moveNext ();)
{
LazyObjectReference reference = (LazyObjectReference) it.current ();
System.out.println ("Updated object: " + reference.getClass () + ":" + reference.getInternalID ());
//if (trackedClasses.contains (reference.getClass ()))
{
Object obj = reference.getObject ();
commitEventArgs.objectContainer ().ext ().refresh (obj, 1);
System.out.println (" => updated (" + obj + ")");
}
}
}
});
In the in-process client, the following code is then executed:
try {
PlayerCharacter pc = new PlayerCharacter (player, name);
pc.setBio(bio);
pc.setArchetype(archetype);
player.getCharacters ().add (pc);
database.store (pc);
database.store (player.getCharacters ());
database.store (player);
database.commit ();
con.sendEvent (id, "CHARACTER_CREATED".getBytes (Constants.CHARSET));
}
catch (Exception e)
{
con.sendEvent (id, EventNames.ERROR, e.toString ());
}
The 'CHARACTER_CREATED' event gets sent successfully, so I know that commit isn't throwing an exception, but nothing shows up on the other client. It continues to use the old versions of the objects, and the 'updated object' messages I'm expecting don't show up on the server console.
Any ideas what I'm doing wrong?
Apparently the .committed() event only fires on a client, when the commit is from a other TCP client.
So you would need to turn your internal .openClient() / .openSession() clients to full blown TCP clients to see the events.
The .openClient() / .openSession() object containers are way more light weight and bypass all code which is related to network communication. Apparently also the event distribution across the network.