Server-Sent Events using Play 2 Java - java

I'm trying to implement Server-sent events in the Play 2 framework (version 2.3.9) using Java. I'd like for an event to be sent to the client every time a "Message" entity is saved to the database. The entity should be sent to the client in Json format.
Message message = new Message();
//some code to populate bean here
message.save(); //save to db
//What do I do with message here?
I was thinking of making a service class that will send events.
public class SSEService {
public static void sendEvent(String data, String id, String name){
EventSource eventSource = new EventSource() {
#Override
public void onConnected() {
//no idea what to do here
}
};
EventSource.Event event = new EventSource.Event(data, id, name);
eventSource.send(event);
}
}
I would then call SSEService.sendEvent() after saving the message. Am I on the right track? What does data, id, and name correspond to in the Event constructor?
Can someone provide a good example in Java 7?

Related

JDA - Event if new user joined to Guild

I have a problem, I am trying to code a bot using Java Discord API (JDA).
When a new user joins a server, the bot shall send a message, but my code is not working.
Code:
public class UserJoinModule extends ListenerAdapter {
public void onGuildMemberJoined(GuildMemberJoinEvent event) throws LoginException {
String user = event.getMember().getAsMention();
JDA client = new JDABuilder("awesome token").build();
final List<TextChannel> channels = client.getTextChannelsByName("awesome channel name", true);
for (final TextChannel ch : channels) {
ch.sendMessage("New member joined: " + user).queue();
}
}
}
Can someone tell me what is wrong?
For me the issue was not from the listener and method I override.
I believe you have to add GatewayIntent.GUILD_MEMBERS to your JDABuilder.
builder.enableIntents(GatewayIntent.GUILD_MEMBERS);
This fixed the same issue for me.
In your Main.java or whatever the file is, there is a variable of type JDABuilder, on it's same line of code, there is your token, a .build() at the end etc...
Insert this code into that line:
.enableIntents(GatewayIntent.GUILD_MEMBERS)
So it looks like this:
jda = JDABuilder.createDefault("TOKEN").enableIntents(GatewayIntent.GUILD_MEMBERS).build();
For it to work, go to your Discord Developer Portal, click your bot, from the menu on the left, click Bot, then scroll down and enable:
Server Members Intent
There are still noticeable errors like registering a new client on every message and other issues, fix them, then start your bot and it shall work.
Your code should look like this:
public class UserJoinModule extends ListenerAdapter {
#Override // USE THIS WHEN YOU WANT TO OVERRIDE A METHOD
public void onGuildMemberJoin(GuildMemberJoinEvent event) {
String user = event.getMember().getAsMention();
JDA client = event.getJDA(); // DO NOT CREATE A NEW JDA INSTANCE EVERY TIME
List<TextChannel> channels = client.getTextChannelsByName("awesome channel name", true);
for (TextChannel ch : channels) {
ch.sendMessage("New member joined: " + user).queue();
}
}
}
And you must register this listeners in your JDABuilder instance, preferably you only have one of these in your entire codebase. See addEventListeners.
You have 2 problems in your code.
You are creating a new JDA client every time a member joins.
You are sending messages to every channel with that name, in every guild. Not just the guild that the user joined.
Here is what you want to do:
public class UserJoinModule extends ListenerAdapter {
#Override
public void onGuildMemberJoin(GuildMemberJoinEvent event) {
Guild guild = event.getGuild(); // Get the guild that the user joined.
User user = event.getUser(); // Get the user that joined.
JDA client = event.getJDA(); // Get the already existing JDA instance.
List<TextChannel> channels = guild.getTextChannelsByName("awesome channel name", true); // Get the list of channels in the guild that matches that name.
for (TextChannel channel : channels) { // Loops through the channels and sends a message to each one.
channel.sendMessage("New member joined: " + user).queue();
}
}
}

RxJava Retrofit chain of requests with foreach loop

I'm trying to migrate from using plain Retrofit to using the RxJava extension for retrofit in order to make chain of API calls on the background thread.
For example, I have an object called ModelGroup which has a list of ModelPerson objects. My goal is to do the following.
Send ModelGroup to the server and receive a response, which is an integer, representing the newly inserted ID, let's call it newGroupId.
For each ModelPerson in ModelGroup, set Person.groupId to newGroupId.
Send each person to the server.
If all ModelPerson objects from the ModelGroup were successfully updated with newGroupId then respond with onSuccess, otherwise onError.
My current solution can be seen below.
private void makeGroupInsert(ModelGroup modelGroup) {
int newGroupId = myApi.insertNewGroup(modelGroup.getName(), modelGroup.getRating())
.execute()
.body();
for (ModelPerson person : modelGroup.getPersons()) {
person.setGroupId(newGroupId);
String response = myApi.insertNewPerson(
person.getGroup_id(),
person.getFirst_Name(),
person.getLast_Name())
.execute()
.body();
if (!response.equals("success")) {
// One failed to update, send error to main thread.
}
}
// All succeeded, send success back to main thread.
}
Question
How can I achieve the same (or better) functionality using a RxJava + Retrofit solution?
EDIT 1
MyApi is defined below.
public interface MyApi {
#POST("insert_new_group")
Call<Integer> insertNewGroup(#Query("group_name") String groupName,
#Query("group_rating") int rating);
#POST("insert_new_person")
Call<String> insertNewPerson(#Query("group_id") int groupId,
#Query("first_name") String firstName,
#Query("last_name") String lastName);
}
First of all, you need to change Retrofit beans to use Observables. For example, it can look like the following line:
#POST("insert_new_group")
Observable<Integer> insertNewGroup(...
Then you can chain requests:
void updateData() {
myApi.insertNewGroup(modelGroup.getName(), modelGroup.getRating()) //Creating new group and getting its ID
.switchMap(this::setGroupIdAll) //Calling observable that will loop thru all persons and set their groupIDs
.subscribe(
(n) -> {/*you will get String after every 'insertNewPerson' run*/},
(e) -> {/*error handling*/}
);
}
Observable<String> setGroupIdAll(Integer id) {
return Observable.fromIterable(personsIterable) //personsIterable contains all your ModelPerson objects
.flatMap(this::updatePerson); //Call Observabl;e that will send updated person to the server
}
Observable<String> updatePerson(ModelPerson person) {
return myApi.insertNewPerson(
person.getGroup_id(),
person.getFirst_Name(),
person.getLast_Name());
}

Backendless - should i subscribe to a channel from service?

In Backendless, there is a method from which I can subscribe to a channel and listen for incoming messages.
Backendless.Messaging.subscribe(
channelName, //some random name
500, //500 ms interval for polling
new AsyncCallback<List<com.backendless.messaging.Message>>() {
#Override
public void handleResponse(List<com.backendless.messaging.Message> messages) {
System.out.println("message received on your channel");
}
#Override
public void handleFault(BackendlessFault backendlessFault) {
}
},
new AsyncCallback<Subscription>() {
#Override
public void handleResponse(Subscription subscription) {
System.out.println("You subscribed to channel" + subscription.getChannelName() + " succssesfuly");
}
#Override
public void handleFault(BackendlessFault backendlessFault) {
System.out.println("Error: " + backendlessFault.getMessage());
}
}
);
If it subscribes from the MainActivity, and data was sent while the app is in another Activity, how can it grab the data from the response (the List in the first handleResponse method) and use it in other activities?
Should I use a service? Should I bind activities to this service with the listener?
Or is there any less complicated way to accomplish my need?
In the very near future i want this listener to work when the app is in the background and show a notification to a user.
Backendless uses two types of Messaging, see Publish-Subscribe Messaging & Push Notifications. The first one is implemented using the listener you used above. The second one uses a service. please refer to the docs, although they are not very good at all they do provide the necessary information.

Best way to store messages (native + app2app)

I want to develop a messaging app which will show messages from native content provider (sms uri ) and messages that has been sent from my app.
I am stuck while managing this messages.I have tried below idea but plese do suggest which is the best .
Here is the observer code I have used:
public class MyObserver extends ContentObserver {
public MyObserver(Handler handler) {
super(handler);
}
#Override
public void onChange(boolean selfChange) {
Log.e("uri","change");
this.onChange(selfChange, null);
}
#Override
public void onChange(boolean selfChange, Uri uri) {
// do s.th.
// depending on the handler you might be on the UI
// thread, so be cautious!
Log.e("uri",""+uri.toString());
}
}
Uri uri = Uri.parse("content://sms/");
getContentResolver().registerContentObserver(uri,true,new MyObserver(new Handler()));
1.I have saved all native and A2A messages in databases so it was easy to show but I got problem while synching native message gets delete as there is not broadcast listener for message deletion.
2.Second option is two save only a2a message in database but it is complex to and time consuming to get messages from two different places (database and content provider and manage the to show view like inbox)
3.Third is to save all app to app messages in content provider with custom message type.and show all messages from content provider only .
Please guide me on this.

Remotely get notifications in order to update a progress monitor

I have a complex application containing a server and a frontend part.
I am trying in the frontend part to update a progress monitor according to an action that takes place in the server part. The action from the server part is called remotely from the frontend. But I am having trouble getting the notifications real time to update the monitor.
My code structure looks somewhat like this:
class frontend_class1{
public void method {
List<String> strings = initializeStrings();
progressMonitor.begingTask("", noOfSteps);
reponse = frontend_class2.method2(strings);
progressMonitor.worked(1);
}
class frontend_class2{
public responseType method2(List<String> strings){
ServerClassRemote remote = new ServerClassRemote();
response = remote.serverMethod(strings);
return response;
}
class server_class{
public serverMethod(List<String> strings){
otherMethod(strings);
}
public otherMethod(List<String> strings){
someOtherMethod(strings);
}
public someOtherMethod(List<String> strings){
for (String s:Strings){
doSomethingWithString(s);
setStatus(true);
}
}
public setStatus(boolean status){
myVar = status;
}
public boolean getStatus(){
return status;
}
My intention is to send a notification to the frontend from the server side, so that the progress monitor is updated with one each time a string is done with.
That is why I included the status methods: to ask from the frontend what the status is, in a separate thread running, theoretically, simultaneously with the other method (serverMethod) and then resetting the status. Something like this:
new Thread(new Runnable() {
public void run() {
if (remote.getChanged()) {
remote.setChanged(false);
}
}
}).start();
But they don't run concurrently. How could I get the status each time a string from the list is finished so that I can update my progress monitor?
Instead of just setting the status is someOtherMethod you could send the update report with a new thread to the front end.
If you do not have a way of sending this update yet you will probably need to have the fornt_end run some kind of server to receive at least these messages. Maybe some RMI, should be easy enough to implement.

Categories

Resources