Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Akka.io, No matching constructor found on class actors

I'm tring to set-up Akka actors to deal with web-socket in play.

I've defined a simple actor to send out messages trough web socket:

package actors;
import akka.actor.*;

public class MyWebSocketActor extends UntypedActor {

    public static Props props(ActorRef out) {
        return Props.create(MyWebSocketActor.class, out);
    }

    private final ActorRef out;

    public MyWebSocketActor(ActorRef out ) {
        this.out = out;
    }

    public void onReceive(Object message) throws Exception {
        if (message instanceof String) {
            out.tell(message, self());
        }
    }
}

In the Application controller I've got the web-socket:

package controllers;
import play.*;
import play.mvc.*;
import akka.util.*;
import views.html.*;
import actors.MyWebSocketActor;
import play.libs.F.*;

public class Application extends Controller {

    public static Result index() {
        return ok(index.render("Your new application is ready."));
    }

     public static WebSocket<String> socket() {
        return WebSocket.withActor(MyWebSocketActor::props);
     }

}

Until now everything works as I expected. Now, in a controller I'm trying to pass a message to that actor. I've try with:

public class Messages extends Controller {

    private static final Form<Message> messageForm = Form.form(Message.class);
    @BodyParser.Of(BodyParser.Json.class)

    public static Result list(Integer page) {
        // --- Render
        ActorRef myActor = Akka.system().actorOf(Props.create(MyWebSocketActor.class));
        String message = "test";
        myActor.tell(message, ActorRef.noSender());
        //  
    }

But Here comes the error: "Cannot invoke the action, eventually got an error: java.lang.IllegalArgumentException: no matching constructor found on class actors.MyWebSocketActor for arguments[].

2014-08-05 05:50:23,503 - [INFO] - from play in pool-4-thread-4 
Listening for HTTP on /0:0:0:0:0:0:0:0:9000

2014-08-05 05:51:02,887 - [ERROR] - from application in New I/O worker #1 


! @6j5b25956 - Internal server error, for (GET) [/] ->

play.PlayExceptions$CompilationException: Compilation error[error: method tell in class ActorRef cannot be applied to given types;]
    at play.PlayExceptions$CompilationException$.apply(PlayExceptions.scala:27) ~[na:na]
    at play.PlayExceptions$CompilationException$.apply(PlayExceptions.scala:27) ~[na:na]
    at scala.Option.map(Option.scala:145) ~[scala-library-2.11.1.jar:na]
    at play.PlayReloader$$anon$1$$anonfun$play$PlayReloader$$anon$$taskFailureHandler$1.apply(PlayReloader.scala:297) ~[na:na]
    at play.PlayReloader$$anon$1$$anonfun$play$PlayReloader$$anon$$taskFailureHandler$1.apply(PlayReloader.scala:292) ~[na:na]
    at scala.Option.map(Option.scala:145) ~[scala-library-2.11.1.jar:na]
    at play.PlayReloader$$anon$1.play$PlayReloader$$anon$$taskFailureHandler(PlayReloader.scala:292) ~[na:na]
    at play.PlayReloader$$anon$1$$anonfun$reload$2.apply(PlayReloader.scala:325) ~[na:na]
    at play.PlayReloader$$anon$1$$anonfun$reload$2.apply(PlayReloader.scala:325) ~[na:na]
    at scala.util.Either$LeftProjection.map(Either.scala:377) ~[scala-library-2.11.1.jar:na]
    at play.PlayReloader$$anon$1.reload(PlayReloader.scala:325) ~[na:na]
    at play.core.ReloadableApplication$$anonfun$get$1.apply(ApplicationProvider.scala:107) ~[play_2.11-2.3.1.jar:2.3.1]
    at play.core.ReloadableApplication$$anonfun$get$1.apply(ApplicationProvider.scala:105) ~[play_2.11-2.3.1.jar:2.3.1]
    at scala.concurrent.impl.Future$PromiseCompletingRunnable.liftedTree1$1(Future.scala:24) ~[scala-library-2.11.1.jar:na]
    at scala.concurrent.impl.Future$PromiseCompletingRunnable.run(Future.scala:24) ~[scala-library-2.11.1.jar:na]
    at scala.concurrent.forkjoin.ForkJoinTask$AdaptedRunnableAction.exec(ForkJoinTask.java:1361) ~[scala-library-2.11.1.jar:na]
    at scala.concurrent.forkjoin.ForkJoinTask.doExec(ForkJoinTask.java:260) ~[scala-library-2.11.1.jar:na]
    at scala.concurrent.forkjoin.ForkJoinPool$WorkQueue.runTask(ForkJoinPool.java:1339) ~[scala-library-2.11.1.jar:na]
    at scala.concurrent.forkjoin.ForkJoinPool.runWorker(ForkJoinPool.java:1979) ~[scala-library-2.11.1.jar:na]
    at scala.concurrent.forkjoin.ForkJoinWorkerThread.run(ForkJoinWorkerThread.java:107) ~[scala-library-2.11.1.jar:na]

2014-08-05 05:51:03,084 - [WARN] - from play in New I/O worker #1 
No application found at invoker init

2014-08-05 06:08:03,586 - [ERROR] - from application in New I/O worker #2 
like image 883
Ilproff_77 Avatar asked Aug 05 '14 14:08

Ilproff_77


2 Answers

A problem I can see is that in your controller you are trying to instantiate a new instance of the MyWebSocketActor but you are not giving it the correct constructor info to allow that new instance to be created. The issue is this line here:

ActorRef myActor = Akka.system().actorOf(Props.create(MyWebSocketActor.class));

In your MyWebSocketActor, you do not have a no-args constructor. You have a single constructor defined as:

public MyWebSocketActor(ActorRef out ) {
    this.out = out;
}

Now, you are doing this correctly in your static props method on MyWebSocketActor. If you truly want to be able to instantiate a new instance of this actor in your controller (as opposed to looking up an existing one), you will need to have an ActorRef (called out in your constructor) to pass in. If you have that, then you can modify your code as follows:

ActorRef myActor = Akka.system().actorOf(MyWebSocketActor.props(outRef));

Edit

Now if you wanted to lookup an existing actor as opposed to creating a per-request actor, you would first need to make sure that the actor instance you wanted to lookup was already created and named in such a way that you could look it up. So something like this:

Akka.system().actorOf(MyWebSocketActor.props(outRef), "myactor");

Then, in your controller, you could use an ActorSelection to find that pre-existing actor like so:

ActorSelection myActorSel = Akka.system().actorSelection("/user/myactor");

An ActorSelection is not an ActorRef, nor does it share some base interface/abstract class. It does however support the tell operation in the same way an ActorRef does, so you can call tell on it after you look it up. If you actor exists with that name, then things should work out just fine.

You can read more about ActorSelections here under the section "Identifying Actors via ActorSelection".

like image 71
cmbaxter Avatar answered Oct 23 '22 19:10

cmbaxter


Your actor has only one constructor which takes an argument, out. When creating the actor with actorOf, you do not pass that argument. This is also what the error message says, your actor has no constructor that takes no arguments.

The interesting thing is that you define a static props message in your actor. If you would use that instead of creating the Props in actorOf, you would have gotten a compiler warning ;-)

like image 43
pushy Avatar answered Oct 23 '22 19:10

pushy