Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

verticle extends with org.vertx.scala.platform.Verticle failed to deploy #47

Closed
angeloh opened this issue Sep 2, 2013 · 20 comments
Closed
Assignees
Milestone

Comments

@angeloh
Copy link
Contributor

angeloh commented Sep 2, 2013

When testing verticle extends with org.vertx.scala.platform.Verticle, it would throw an exception.

java.lang.ClassCastException: verticles.SockJSVerticle cannot be cast to org.vertx.java.platform.Verticle

Here is my deploy code:

container.deployVerticle(
  classOf[SockJSVerticle].getName,
  (ar: AsyncResult[String]) => {

  })

Here is my verticle code

import org.vertx.scala.platform.Verticle

class SockJSVerticle extends Verticle {

   override def start(future: Future[Void]):Unit = {
    start()
   }
} 
@Narigo
Copy link
Member

Narigo commented Sep 2, 2013

Umm, can you try this?

container.deployVerticle("scala:" + classOf[SockJSVerticle].getName,
  (ar: AsyncResult[String]) => { ... })

I think it tries to use Java as a default if you have a class name and don't prefix it. That's why you need to have "main" : "scala:your.company.your.ScalaVerticle" in the mod.json at least.

@raniejade
Copy link
Contributor

@Narigo If that's the case, I think the scala: prefix should be automatically added by the scala container implementation if not present.

@angeloh
Copy link
Contributor Author

angeloh commented Sep 2, 2013

Ok. I got different error now.

At first, I use add "scala" prefix like you said above. It gave me an error.

   java.lang.IllegalStateException: No language implementation known for prefix scala

Then, I added langs.properties to src/main/resources. Note, I already have "io.vertx:lang-scala:0.1.0-SNAPSHOT" in my build.gradle dependencies. After I added langs.properties, now it complains "can't cast to scala's verticle" instead of "can't cast to java's verticle". I did not change SockJSVerticle.

   java.lang.ClassCastException: verticles.SockJSVerticle cannot be cast to org.vertx.scala.platform.Verticle

@angeloh
Copy link
Contributor Author

angeloh commented Sep 2, 2013

I think above problem is due to different classloader in the system. One loads org.vertx.scala.platform.Verticle and the other one loads my verticle. They should be in the same classloader.

According to http://stackoverflow.com/a/11945858/772481, maybe Vertx ModuleClassLoader should call super(classpath, platformClassLoader) to pass parent's classloader to URLClassLoader constructor.

  public class ModuleClassLoader extends URLClassLoader {
        public ModuleClassLoader(ClassLoader platformClassLoader, URL[] classpath, boolean loadResourcesFromTCCL) {
            super(classpath);
            this.platformClassLoader = platformClassLoader;
            this.loadResourcesFromTCCL = loadResourcesFromTCCL;
          }
  }

@angeloh
Copy link
Contributor Author

angeloh commented Sep 3, 2013

Here is a simple test case for this issue.

  import org.vertx.scala.platform.Verticle

  class MyTestVerticle extends Verticle {
    import org.vertx.scala.core.eventbus.EventBus._
    val hdl: EventBusHandler[String] = EventBus.toBusHandler(
      (msg: Message[String]) => {
        assertNotNull(msg.body)
      })
    override def start() {
      vertx.eventBus.registerHandler("some-address")(hdl, rst => {
        if (!rst.succeeded)
          fail()
      })
    }
  }


  class VerticleTest extends TestVerticle {
    @Test
    def localPubSubTest() {
      import org.vertx.scala.core.FunctionConverters._
        container.deployVerticle(
          classOf[MyTestVerticle].getName,
          (ar: AsyncResult[String]) => {
            if (ar.succeeded)
                  assertTrue(ar.succeeded)
            else {
              ar.cause.printStackTrace()
              fail()
            }
          })
    }
  }

Here is the exception I got.

java.lang.ClassCastException: verticles.MyTestVerticle cannot be cast to org.vertx.java.platform.Verticle
    at org.vertx.java.platform.impl.java.JavaVerticleFactory.createVerticle(JavaVerticleFactory.java:57)
    at org.vertx.java.platform.impl.DefaultPlatformManager$18.run(DefaultPlatformManager.java:1269)
    at org.vertx.java.core.impl.DefaultContext$3.run(DefaultContext.java:170)
    at io.netty.util.concurrent.SingleThreadEventExecutor.runAllTasks(SingleThreadEventExecutor.java:354)
    at io.netty.channel.nio.NioEventLoop.run(NioEventLoop.java:366)
    at io.netty.util.concurrent.SingleThreadEventExecutor$2.run(SingleThreadEventExecutor.java:101)
    at java.lang.Thread.run(Thread.java:724)

@Narigo
Copy link
Member

Narigo commented Sep 4, 2013

@angeloh Could you create a small project and share it on github to be able to reproduce that problem?
I haven't worked with deployVerticle yet, only deployModule in my tests (which worked, btw). So there might be a bug, but I'm not sure how to reproduce it...

@angeloh
Copy link
Contributor Author

angeloh commented Sep 4, 2013

@Narigo Thank you! I create 3 tests in the following commit. Only 3rd one runs okay. The differences are explained below:

angeloh@dea3d8d

1st: this test case throws "cannot be cast to org.vertx.java.platform.Verticle" error
2nd: I replace the handler with line vertx.eventBus.publish("some-address", "foo"); {}. Now it will time out instead of throwing above error
3rd: Use org.vertx.java.platform.Verticle instead. This test runs okay.

@Narigo
Copy link
Member

Narigo commented Sep 6, 2013

Ok, here are my findings:
1st and 2nd: The module doesn't get deployed in both cases, so 2nd won't register the handler -> times out. It's the same root cause.
3rd: Okay, since you just use Java here.

I'm not sure what to do with 1st/2nd test cases. If I prepend a "scala:" right before the deployed verticle name, I get a class cast exception, that it cannot be casted to org.vertx.scala.platform.Verticle - but debug output says that it is. Maybe someone with more inside view can handle this.

@raniejade from what I can see, the "scala:" doesn't get prepend to the Verticle automatically. But to be honest I think that's good as you might want to start Java Verticles, too - and I'm not sure whether there is a java: prefix available. Anyways, I see a problem here about these class cast exceptions, can you have a look at it? Don't know too much about ClassLoaders, maybe it gets multiple org.vertx.scala.platform.Verticle and selects the wrong one?!

@edgarchan
Copy link
Contributor

Hi, I'm not sure if it's possible to deploy scala verticles under the current testtools infraestructure (issue #23). But you can use the same trick of the scala test suite. Create a java verticle and add all the needed conversions manually, e.g.

class LocalTestVerticle1 extends org.vertx.java.platform.Verticle {
  import org.vertx.scala.core.eventbus.EventBus._
  lazy val eb:EventBus = EventBus(vertx.eventBus)
    ...
  override def start() {
    eb.registerHandler("some-address")(hdl, rst => {
      if (!rst.succeeded)
        fail()
      else
        testComplete()
    })
  }
} 

look at local "eb" val and it's use.

@angeloh
Copy link
Contributor Author

angeloh commented Sep 7, 2013

@galderz
Copy link
Contributor

galderz commented Sep 17, 2013

Sorry guys for the delay. Just getting around to catching up with this (I've been working on some improvements to be able to run Scala scripts as well as Scala classes).

Do we have a fix for this? Do you need me to look into it?

@Narigo
Copy link
Member

Narigo commented Oct 18, 2013

Can you try this again with the branch of #63 ? I hope everything is fixed with that then as we had a lot of refactorings and class loading stuff changed in vert.x itself.

@galderz galderz removed this from the 0.4.0 milestone Mar 12, 2014
@brendanator
Copy link

This doesn't work in 1.0.0

I'm trying to avoid having a langs.properties file so that I can specify the language implementation in the mod.json and keep each module fully modular.

Unfortunately I need to use "scala:" when deploying the verticle to avoid the class cast exception. This then means I need to provide a langs.properties so it runs

Ideally when deploying a scala class from within a scala module you wouldn't need to specify the prefix it would just use the current ScalaVerticleFactory

@galderz
Copy link
Contributor

galderz commented Apr 11, 2014

@brendanator Thanks for the info! I'll look into it and see if we can fix it and release a patch version.

@galderz
Copy link
Contributor

galderz commented Apr 17, 2014

All, this is a bit tricky, but I might have found a workaround that does not involve langs.properties files. Let me explain the issue first:

First of all, the module does not get deployed by the scala specific verticle factory in the first place. Instead, it's vert.x core's DefaultPlatformManager that, given the verticle name, tries to figure what verticle factory it needs to use. Without any hints, it defaults to the Java verticle factory, which leads to the CCE you see.

The default can be changed either via langs.properties, or with system properties, with the latter overriding the former.

So, the workarounds here are:

a) Modify langs.properties so that by default the scala verticle factory is used:

    scala=io.vertx~lang-scala~1.0.0:org.vertx.scala.platform.impl.ScalaVerticleFactory
    .=scala

b) Prepend the verticle name with scala:

c) Pass the following system properties:

-Dvertx.langs..=scala -Dvertx.langs.scala=io.vertx~lang-scala~1.0.0:org.vertx.scala.platform.impl.ScalaVerticleFactory

(NOTE: the first system property needs two . characters!)

From a Scala language extension, there's little else we can do to force one verticle factory by default. In the current set up, it's down to Vert.x core to decide what verticle factory to use. The workarounds explained here try to take advantage of the facilities within core to override defaults.

@galderz
Copy link
Contributor

galderz commented Apr 17, 2014

@brendanator Can you verify if the system property method works for you?

galderz added a commit to galderz/mod-lang-scala that referenced this issue Apr 17, 2014
galderz added a commit to galderz/mod-lang-scala that referenced this issue Apr 17, 2014
@galderz
Copy link
Contributor

galderz commented Apr 17, 2014

In the referenced pull request, I'm adding a test that verifies that system property overrides I mentioned in the last comment work as expected.

@galderz
Copy link
Contributor

galderz commented May 13, 2014

Guys, can you verify this? As far as I'm concerned, the workaround I suggested gets rid of this issue. Unless I see an update, I'll be closing this in the next few days.

@galderz galderz added this to the 1.1.0-M1 milestone May 13, 2014
@galderz galderz self-assigned this May 13, 2014
@galderz
Copy link
Contributor

galderz commented May 15, 2014

Closing this, feel free to reopen if the issue is still present after applying wokaround.

@galderz galderz closed this as completed May 15, 2014
@galderz galderz added the 1.1.x label Sep 12, 2014
galderz added a commit to galderz/mod-lang-scala that referenced this issue Sep 12, 2014
galderz added a commit to galderz/mod-lang-scala that referenced this issue Sep 12, 2014
galderz added a commit to galderz/mod-lang-scala that referenced this issue Sep 12, 2014
@galderz galderz added the 1.0.x label Sep 12, 2014
@galderz galderz modified the milestones: 1.0.1, 1.1.0-M1 Sep 12, 2014
@galderz
Copy link
Contributor

galderz commented Sep 12, 2014

Backported test to 1.0.x too.

galderz added a commit that referenced this issue Sep 12, 2014
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants