SmartFoxServer 2x using sfsApi, NullPointerException - java

I am simply trying to set a room variable (adding the user's name to a room varible) in my UserJoinedRoomHandler:
From my JAVA extension:
public class UserJoinedRoomHandler extends BaseServerEventHandler
{
#Override
public void handleServerEvent(ISFSEvent arg0) throws SFSException
{
User user = (User) arg0.getParameter(SFSEventParam.USER);
Room room = (Room) arg0.getParameter(SFSEventParam.ROOM);
trace("add p1 = " + user.getName() + " to room=" + room.getId());
List<RoomVariable> listOfVars = new ArrayList<RoomVariable>();
listOfVars.add( new SFSRoomVariable("player1Name", user.getName()) );
((MyExtension) getParentExtension()).sfsApi.setRoomVariables(user, room, listOfVars); // NullPointerException here :(
}
}
Note, I grab the sfsAPI when in MyExtention init() function:
ISFSApi sfsApi = SmartFoxServer.getInstance().getAPIManager().getSFSApi();
To me this should work, the only thing I can think of is that the room might not have fully initialised (the user had just created the room before this event is fired). But in any case I thought this should be a trivial scenario, but it has cost me a good handful of hours already.
Cheers for any help.

The solution was to use the Api directly:
((MyExtension) getParentExtension()).getApi().setRoomVariables(user, room, listOfVars);
PS: Unfortunately there is no method to issue 1 Room Variable. You have to submit a list, even if its only 1 in length.

Related

Getting the guild owner in JDA raising NullPointerException

I was trying to make a function which displays info about the server.
public static void serverInfo(Guild guild, MessageChannel channel) {
EmbedBuilder embed = new EmbedBuilder();
//Calculations
int people = 0;
int roles = 0;
int tc = 0;
int vc = 0;
for (Member member : guild.getMembers()) {
if (!member.getUser().isBot())
++people;
}
for (Role ignored : guild.getRoles())
++roles;
for (TextChannel ignored : guild.getTextChannels())
++tc;
for (VoiceChannel ignored : guild.getVoiceChannels())
++vc;
String time = String.valueOf(guild.getTimeCreated());
String created = time.substring(8, 10) + "-" + time.substring(5, 7) + "-" + time.substring(0, 4);
embed.setTitle(guild.getName());
embed.setThumbnail(guild.getIconUrl());
embed.addField("Total Members", String.valueOf(guild.getMemberCount()+1), true);
embed.addField("Members", String.valueOf(people),true);
embed.addField("Bots", String.valueOf((guild.getMemberCount()+1)-people), true);
embed.addField("Owner", Objects.requireNonNull(guild.getOwner()).getUser().getName(), true);
embed.addField("Roles", String.valueOf(roles), true);
embed.addField("Text Channels", String.valueOf(tc), false);
embed.addField("Voice Channels", String.valueOf(vc), true);
embed.addField("Date Created", created, false);
channel.sendMessageEmbeds(embed.build()).queue();
}
However, this raises a NullPointerException
java.lang.NullPointerException at
java.base/java.util.Objects.requireNonNull(Objects.java:208) at
com.television.Commands.Infos.serverInfo(Infos.java:38) at
com.television.CommandExecutor.onMessageReceived(CommandExecutor.java:19)
But, if I removed this part from the function, it works just fine, and no exception is raised.
for (Member member : guild.getMembers()) {
if (!member.getUser().isBot())
++people;
}
Why does this happen? This problem also gets raised only in 1 server, out of the 3 servers I've tested in.
And, secondly, I know this is not much related to the question from the title, how can I calculate the number of members/bots because this part (the for-each loop in the code snippet above) does not calculate the number of members correctly, it always has 1 as the value of the bot variable, and therefore number of members - 1 is the value of people.
Two things in advance: You have to either cache all the members from every guild or instead (recommended) retrieve them when needed. To be able to do so, you need to enable the GUILD_MEMBERS Privileged Intent.
You can pretty easily retrieve a List representing all members of a guild with the following method:
public CompletableFuture<List<Member>> loadMembersFull(Guild guild) {
CompletableFuture<List<Member>> future = new CompletableFuture<>();
if (guild.isLoaded()) {
future.complete(guild.getMembers());
} else {
guild.loadMembers()
.onError(future::completeExceptionally)
.onSuccess(future::complete);
}
}
With that you can then move on with all your other stuff.
I actually don't know why it would work without the for-loop, but it looks like the error does not occur there, but when loading the owner, as it throws the exception in your #requireNonNull.
The owner object is null when he/she is no longer in the guild or not yet loaded. The owner could also have deleted the account or get banned by Discord.
To also solve this problem, I recommend you to replace your line with the following one:
embed.addField("Owner", Optional.ofNullable(guild.getOwner()).map(owner -> owner.getUser().getName()).orElse("<not found>"), true);
To get the proper amount of users, you should filter the list of users for whether they are bots or not.
int amount = (int) loadMembersFull(guild).join().stream()
.map(Member::getUser)
.filter(user -> !user.isBot())
.count();
If you need more help, feel free to ask me on my Discord server

Return the Specified Fields and the _id Field Only in java

UPDATE: Spuggiehawk advised in his answer to fix the include keyword issue, and also suggest an alternative way to get the _id other than projections. However, I still have trouble to call this method from my service class, which edit the user detail, that I must admit I have limited knowledge to make it right.
#Override
public User get(Object userId) {
FindIterable<User> userTbl = database.getCollection("User", User.class).find();
User user = new User();
for (User doc : userTbl) {
String oid = doc.getId().toHexString();
System.out.println("_id = " + oid);
return user;
}
return null;
}
In the Service class
public void editUser() {
String userId = request.getParameter("id");
User user = userDAO.get(userId);
System.out.println(user.getFullName());
}
You don't need to use projection if you just want the object ID. The syntax you want to get that (in a loop) is:
FindIterable<Document> userTbl = db.getCollection("User").find();
for (Document doc: userTbl2)
{
String id = doc.getObjectId("_id").toString();
System.out.println("_id = " + id);
}
Do what you need to with that id value.
As far as your use of include is concerned, if you do find a situation where you need that, then you need the static import. Eclipse should give you the option if you hover over the keyword:
If Eclipse doesn't show that, you might need to add the references in your Eclipse configuration under Window -> Preferences -> Java -> Editor -> Content Assist -> Favorites:
The important part is at the top of your code, it should include:
import static com.mongodb.client.model.Projections.include;
You'll find that useful for your filters too, eg.
Bson filter = eq("email", "email.com");
db.getCollection("User").find(filter);
Finally, if you only want to get the first matching record in your find(), use:
Document = db.getCollection("User").find(filter).first();

Java/Android studio : For loop - Same data shows multiple times

So I am trying to create this page that compares a user's interest with other users and shows the list of all those users.. Now, with the for loop i created, one particular user's name repeats until the end of the loop. I only one one name per username to appear on the textfield.. However, I don't know how to do that.. Here's my code for showing users with common interests:
Realm realm= Realm.getDefaultInstance();
RealmResults<interests> result=realm.where(interests.class).findAll();
RealmResults<Users> user=realm.where(Users.class).findAll();
for(int i=0;i<result.size();i++)
{
for(int j=0;j<result.size();j++)
{
if(result.get(i).getId().equals(userid))
{
if(result.get(i).getInterest().equals(result.get(j).getInterest()))
{
if(!result.get(j).getId().equals(userid)) {
users = result.get(j).getId();
interestss.append("Interests :" + result.get(i).getInterest());
}
}
id.append("\n"+users);
}
}
}
for(int i=0;i<result.size();i++)
{
for(int j=0;j<result.size();j++)
{
if(result.get(i).getId().equals(userid))
{
if(result.get(i).getInterest().equals(result.get(j).getInterest()))
I'm almost 98% sure that you shouldn't even need to write this kind of code if you use Realm's query system and a link query, instead of looping and comparing things manually.
RealmResults<Interests> interests = realm.where(Interests.class)
.equalTo("user.userId", userId)
.findAll();
Which should be possible if you have a backlink from Interests to Users.
// in Interests class
#LinkingObjects("interest")
private final RealmResults<User> user = null;

Access object info from another method

I have a program, but I do not understand how I can access info from one particular object in another method.
This is a minor sample of my program, I want to create this method riders in the same class(called Cyclist). I want to print out the list of riders here, but I do not understand how...
public void riders() {
//System.out.print(c1.getName())
//this does not work.
//here I want to print out all the names of the riders, i.e. c1's name, c2's name... cn...
}
public void abilities() {
//Pardilla blir til!
Cyclist c1 = new Cyclist();
c1.setName("Sergio Pardilla");
c1.setMountain(75);
c1.setTimeTrial(60);
c1.setSprint(60);
c1.setAge(30);
System.out.println(c1.getName() + "'s abilities:");
System.out.println("Mountain - " + c1.getMountain());
System.out.println("TimeTrial - " + c1.getTimeTrial());
System.out.println("Sprint - " + c1.getSprint());
System.out.println("Age - " +c1.getAge());
}
You have no visibility of c1 variable in riders() method.
c1 is declared inside abilities(), and then its local to it, only visible inside.
If you want to use a variable outside this method, you should use a field instead a local variable, or pass it as parameter to rider method.
List<Cyclist> cyclists = new ArrayList<>(); // Declared as field
public void riders() {
for (cyclist : cyclists){
System.out.print(cyclist.getName())
}
}
public void abilities() {
//Pardilla blir til!
Cyclist c1 = new Cyclist();
c1.setName("Sergio Pardilla");
c1.setMountain(75);
c1.setTimeTrial(60);
c1.setSprint(60);
c1.setAge(30);
System.out.println(c1.getName() + "'s abilities:");
System.out.println("Mountain - " + c1.getMountain());
System.out.println("TimeTrial - " + c1.getTimeTrial());
System.out.println("Sprint - " + c1.getSprint());
System.out.println("Age - " +c1.getAge());
cyclists.add(c1); //Add cyclist to cyclists list
}
Cyclist c1 is confined within the scope of the abilities method, which is why you can't access it in the riders() method.
First of all, I would keep an instance-scope ArrayList of Cyclists declared at the top of the class.
private ArrayList<Cyclist> cyclists = new ArrayList<Cyclist>();
Then, in your abilities method, you should add c1 to the ArrayList cyclists, like
cyclists.add(c1);
after you've changed c1's settings. Then, from the riders() method, you can get c1's name with
cyclists.get(0).getName();
c1 is defined locally in the abilities() method. Other methods are unable to access it. You either need abilities to return c1 so you can use it in other methods or you can declare a field in that class to store c1.
short : you cannot access objects from a method which are only declared within another method
1) let riders accept a Cyclist object, and then pass the object.
or
2) make the Cyclist class wide accessable :
public class XY {
private Cyclist c1;
public void riders() {
// show stuff
}
public void abilities() {
// init stuff
}
}
Furthermore if u want to output all Cyclists, consider using a List<Cyclist> which should store each Cyclist object.

Akka actors and futures: Understanding by example

I'm trying to learn Akka actors and futures but after reading the docs at http://akka.io
and doing http://doc.akka.io/docs/akka/2.0.2/intro/getting-started-first-java.html
I'm still having some issues with understanding. I guess calculate the value of Pi
is a thing a lot of people can relate too, but not me =). I have search around a bit
but haven't found any examples that suits me. Therefore I thought that I would take some real-life code of mine and throw it in here and exchange it for an example of how to do this with Akka.
Ok so here we go:
I have an java play2 application where I need to take some data from my DB and index it in my elasticsearch instance.
I call the DB and get the ids for the venues.
I then split the list and create a couple of callable indextasks.
After that I invoke all tasks where each task collects the venues for the assigned ids
from the db.
For each venue index it to the elasticsearch instance and make it searchable.
Done.
Application.java:
public class Application extends Controller {
private static final int VENUE_BATCH = 1000;
private static int size;
public static Result index() {
List<Long> venueIds = DbService.getAllVenueIds();
size = venueIds.size();
Logger.info("Will index " + size + " items in total.");
ExecutorService service = Executors.newFixedThreadPool(getRuntime().availableProcessors());
int startIx = 0;
Collection<Callable<Object>> indexTasks = new ArrayList<Callable<Object>>();
do {
int endIx = Math.min(startIx + VENUE_BATCH, size);
List<Long> subList = venueIds.subList(startIx, endIx);
VenueIndexTask indexTask = new VenueIndexTask(subList);
indexTasks.add(indexTask);
} while ((startIx += VENUE_BATCH) < size);
Logger.info("Invoking all tasks!");
try {
service.invokeAll(indexTasks);
} catch (InterruptedException e) {
e.printStackTrace();
}
return ok(index.render("Done indexing."));
}
}
VenueTask:
public class VenueIndexTask implements Callable<Object> {
private List<Long> idSubList;
public VenueIndexTask(List<Long> idSubList){
this.idSubList = idSubList;
Logger.debug("Creating task which will index " + idSubList.size() + " items. " +
"Range: " + rangeAsString() + ".");
}
#Override
public Object call() throws Exception {
List<Venue> venues = DbService.getVenuesForIds(idSubList);
Logger.debug("Doing some indexing: "+venues.size());
for(Venue venue : venues) {
venue.index();
}
return null;
}
private String rangeAsString() {
return "[" + idSubList.get(0) + "-" + idSubList.get(idSubList.size() - 1) + "]";
}
}
Venue:
#IndexType(name = "venue")
public class Venue extends Index {
private String name;
// Find method static for request
public static Finder<Venue> find = new Finder<Venue>(Venue.class);
public Venue() {
}
public Venue(String id, String name) {
super.id = id;
this.name = name;
}
#Override
public Map toIndex() {
HashMap map = new HashMap();
map.put("id", super.id);
map.put("name", name);
return map;
}
#Override
public Indexable fromIndex(Map map) {
if (map == null) {
return this;
}
this.name = (String) map.get("name");
return this;
}
}
So all you Akka people out there go nuts! And please do as much as you can, propose cool futures functionality that could be used or any other knowledge/code that I could use to learn this stuff.
How I like to think of Akka (or any other message based systems) is to think like a conveyor belt, like in factories. A simplified way of thinking in Actors could be taking a pizza Order.
You, the hungry customer (Actor/Role) sends a order (A Message) to Pizza Shop
Customer service (Actor/Role) takes your order, gives you the order number (Future)
If you were impatient, you might've waited on the phone/internet/shop till you got your pizza (A synchronous/blocking transaction) otherwise you would be happy with the order number an check up on it later (non-blocking)
Customer service sends the message to the Chefs (Actor) under the supervision of Kitchen Manager (Actor). This is a very process heavy kitchen, with hierarchy. Akka likes that. See Supervision
Chef creates a new Pizza and attaches the details of the order (A new message) and passes that to the delivery boy (Actor) via the delivery manager (Supervisor Actor).
During this process, your order details haven't changed, that would be a nightmare. You would not be happy if you had pepperoni if you wanted plain cheese! All messages should be immutable! However, it may be that the message might be different for different actors. A delivery boy would expect a Pizza and the order details attached, the chef would expect an order. When a message needs to change, a new message is created.
Each actor is good at one role, how effective would it be if one guy had to do all the tasks? It may be that some actors out number others (e.q. 10 threads for Chefs, 2 for Delivery boys, 1 Customer Service).
Blocking behavior is a pain, imagine customer service is waiting for the chef and delivery boy before seeing the next customer?
Hopefully I've helped you a little, this is a huge topic and large change of mind. Good luck
Coursera currently runs a course on reactive programming which has the 3 last lectures on Akka and the actor model. This includes video lectures and homework (in Scala though not Java).
While you are too late to receive the full certificate, you can still join the course and just check the last three weeks.
https://class.coursera.org/reactive-001/class

Categories

Resources