Custom Business Logic / CodeRunner update problem

Hi Mark, the Event Handler gets triggered from REST console, an error was caught but it´s ok as my REST object was incomplete, here is the output from CodeRunner:

P.S.: I´m having to debug from linux VM as it´s not deploying from windows.

fabio@fabio-VirtualBox ~/Desktop/Shared/Jkb-1403/bin $ sh CodeRunner.sh
Listening for transport dt_socket at address: 5005
[INFO] CodeRunner™ Backendless Debugging Utility
[INFO] Copyright© 2016 Backendless Corp. All rights reserved.
[INFO] Version: 3.0.10 Build date: 20160309-0738
[INFO] CodeRunner session is running for 2 hour and will be terminated on 13:15:39.602[UTC]

[INFO] Registering runner on: https://api.backendless.com with secretKey: 043A27FA-70CD-8BCF-FFF5-387B87608E00
[INFO] Runner successfully registered
[INFO] Parsing event model…
[INFO] Build successfully: 2 handlers, 0 timers
[INFO] Deploying model to server, and starting debug…
[INFO] Model successfully deployed.
[INFO] Waiting for events…
Mar 15, 2016 11:48:04 AM com.backendless.coderunner.runtime.task.EventInvocationTask runImpl
SEVERE: null
java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.backendless.coderunner.runtime.task.EventInvocationTask.runImpl(EventInvocationTask.java:92)
at com.backendless.coderunner.runtime.concurrent.ExtendedRunnable.run(ExtendedRunnable.java:26)
at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.NullPointerException
at com.backendless.jkb.methods.CreateMethods.MainMethod(CreateMethods.java:30)
at com.backendless.jkb.events.persistence_service.PlaysTableEventHandler.afterCreate(PlaysTableEventHandler.java:29)
at com.backendless.jkb.events.persistence_service.PlaysTableEventHandler.afterCreate(PlaysTableEventHandler.java:16)
… 7 more

Mar 15, 2016 11:49:38 AM com.backendless.coderunner.runtime.task.EventInvocationTask runImpl
SEVERE: null
java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:498)
at com.backendless.coderunner.runtime.task.EventInvocationTask.runImpl(EventInvocationTask.java:92)
at com.backendless.coderunner.runtime.concurrent.ExtendedRunnable.run(ExtendedRunnable.java:26)
at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.NullPointerException
at com.backendless.jkb.methods.CreateMethods.MainMethod(CreateMethods.java:30)
at com.backendless.jkb.events.persistence_service.PlaysTableEventHandler.afterCreate(PlaysTableEventHandler.java:29)
at com.backendless.jkb.events.persistence_service.PlaysTableEventHandler.afterCreate(PlaysTableEventHandler.java:16)
… 7 more

So the problem right now is the event handler is triggered from REST Console, but not triggered from code?

My Event Handlers call static methods from other classes like this:

@Override
public void afterUpdate(RunnerContext context, Plays plays, ExecutionResult<Plays> result) throws Exception {
if (plays.getStatus() == “FINISHED”) {
AchievementMethods.verificaAchievements(plays);
}
}

@Async
@Override
public void afterCreate(RunnerContext context, Plays plays, ExecutionResult&lt;Plays&gt; result) throws Exception {
    CreateMethods.MainMethod(plays);
}

Here is the AchievementMethods Class:

package com.backendless.jkb.methods;

import com.backendless.Backendless;
import com.backendless.BackendlessCollection;
import com.backendless.BackendlessUser;
import com.backendless.jkb.models.Achievement;
import com.backendless.jkb.models.Plays;
import com.backendless.messaging.DeliveryOptions;
import com.backendless.messaging.PublishOptions;
import com.backendless.persistence.BackendlessDataQuery;
import com.backendless.persistence.QueryOptions;
import java.util.Date;
import java.util.List;

public class AchievementMethods {

private static Integer TOTAL_FINISHED = 0;
private static Integer TOTAL_FLY = 0;
private static Integer TOTAL_LIKES = 0;
private static Integer TOTAL_JUKEBOX = 0;
private BackendlessCollection&lt;Achievement&gt; achievements = null;
private static String channel = "JUKEBOX";

public static void verificaAchievements(Plays play) {
    channel = "JUKEBOX" + play.getJukebox().getObjectId().split("-")[0];
    BackendlessUser user = Backendless.UserService.findById(String.valueOf(play.getUsuario()));
    getPlayStats(user);
    checkUserAChievements(user, "FINISHED", TOTAL_FINISHED);
    checkUserAChievements(user, "FLY", TOTAL_FLY);
    checkUserAChievements(user, "LIKES", TOTAL_LIKES);
    checkUserAChievements(user, "JUKEBOX", TOTAL_JUKEBOX);
}

private static BackendlessCollection&lt;Achievement&gt; getUserAChievementsByTipo(BackendlessUser user, String tipo) {
    String whereClause = "usuario = " + user.getObjectId() + " and tipo = '" + tipo + "'";
    QueryOptions options = new QueryOptions("valor DESC");
    BackendlessDataQuery dataQuery = new BackendlessDataQuery();
    dataQuery.setWhereClause(whereClause);
    return Backendless.Persistence.of(Achievement.class).find(dataQuery);
}

private static void getPlayStats(BackendlessUser user) {
    String tempjukebox = "";
    String whereClause = "ownerId = " + user.getObjectId();
    QueryOptions options = new QueryOptions("jukebox");
    BackendlessDataQuery dataQuery = new BackendlessDataQuery();
    dataQuery.setWhereClause(whereClause);
    dataQuery.setQueryOptions(options);

    BackendlessCollection&lt;Plays&gt; totalplays = Backendless.Persistence.of(Plays.class).find(dataQuery);

    for (Plays play : totalplays.getData()) {
        if (play.getStatus() == "FINISHED") {
            TOTAL_FINISHED++;
        }

        if (play.getStylename() == "FLY") {
            TOTAL_FLY++;
        }

        if (tempjukebox != play.getJukebox().getObjectId()) {
            TOTAL_JUKEBOX++;
            tempjukebox = play.getJukebox().getObjectId();
        }

        TOTAL_LIKES = TOTAL_LIKES + play.getLikes();
    }

}

private static void checkUserAChievements(BackendlessUser user, String tipo, Integer valor) {
    Integer CURRENT_VAL = 0;
    BackendlessCollection&lt;Achievement&gt; lista = getUserAChievementsByTipo(user, tipo);

    if (lista.getTotalObjects() > 0) {
        CURRENT_VAL = Integer.valueOf(lista.getData().get(0).getValor());
    }

    if (valor > CURRENT_VAL) {
        switch (valor) {
            case 1:
                criaNovoAchievement(1, tipo, user);
                break;
            case 3:
                criaNovoAchievement(3, tipo, user);
                break;
            case 5:
                criaNovoAchievement(5, tipo, user);
                break;
            default:
                if (valor >= 10 && Math.floor(valor / 10) > CURRENT_VAL / 10) {
                    criaNovoAchievement(valor, tipo, user);
                    break;
                }
        }
    }
}

private static void criaNovoAchievement(int valor, String tipo, BackendlessUser user) {
    Achievement conquista = new Achievement();
    conquista.setUsuario(user.getObjectId());
    conquista.setOwnerId(user.getObjectId());
    conquista.setTipo(tipo);
    conquista.setValor(String.valueOf(valor));
    conquista.setCodigo(tipo + String.valueOf(valor));

    Backendless.Persistence.save(conquista);
    sendNewAchievementMsg(conquista);
}

private static void sendNewAchievementMsg(Achievement conquista) {
    PublishOptions publishOptions = new PublishOptions();
    publishOptions.setSubtopic("newachievement");
    publishOptions.putHeader("user-token", conquista.getOwnerId());
    publishOptions.putHeader("BL_PUBLISHER_ID", conquista.getOwnerId());

    DeliveryOptions deliveryOptions = new DeliveryOptions();
    Date publishDate = new Date(System.currentTimeMillis() + 1000); // add 5 seconds
    deliveryOptions.setPublishAt(publishDate);

    Backendless.Messaging.publish(channel, conquista.getOwnerId(), publishOptions, deliveryOptions);
}

}

Yes, probably the missing CREATE method in the javascript API?

Is the afterUpdate event handler getting invoked for you?

It’s not.

What does your update request look like?

Hi, I´m calling it from android API:

private static final IDataStore<Plays> DATA_STORE = Backendless.Persistence.of(Plays.class);

public void saveEntity(Plays entity) {
DATA_STORE.save(entity, new DefaultCallback<Plays>() {
@Override
public void handleResponse(Plays response) {
super.handleResponse(response);
}
});
}

Does the “entity” object have a value for the “objectId” property?

Are there any errors or messages in CodeRunner when you call the update API method?

Yes

Nothing

Is the object updated in the persistent storage? In other words, does the update operation complete normally?

Yes, works fine.

Could you zip up your event handlers project (all of it) and upload to google drive and dropbox? Email the link to support@backendless.com and we will look into it. Also please include the Android secret key.

Regards,
Mark