vlingo / xoom-turbo

The VLINGO XOOM platform SDK for DOMA and DDD accelerates building highly scalable and high-performance Reactive microservices and applications.
https://vlingo.io
Mozilla Public License 2.0
8 stars 9 forks source link

ResourceHandler does not provide defaultLogger #4

Closed flaxel closed 4 years ago

flaxel commented 4 years ago

It's possible that extending ResourceHandler is improperly generated because that is only supported by "configuration resources" (declared in vlingo-http.properties). For dynamic resources handlers the Stage must be passed in via constructor. With the Stage the dynamic resources handlers can get to anything needed, including the Logger.

/cc @danilo-ambrosio @Florian-Schoenherr

Florian-Schoenherr commented 4 years ago

Could you use this for now?

private final Stage stage;
private final Logger logger;
public SomeResource(final Stage stage) {
       this.stage = stage;
       this.logger = stage.world().defaultLogger();
}

If you want to generate more Resources right now, I could change the generation to include these lines. If you just need it on one or two, or on already generated Resources, you can copy it in. Sorry, I really thought the logger() from ResourceHandler was usable like that! I will keep this open until this is resolved in a better way. This will suffice for now.

flaxel commented 4 years ago

Oh yeah, that's okay. 👍 Thank you for your fast support! 😄

VaughnVernon commented 4 years ago

@Florian-Schoenherr Has the code generation been fixed such that it supports your suggestion?

https://github.com/vlingo/vlingo-xoom/issues/4#issuecomment-714629090

Florian-Schoenherr commented 4 years ago

@VaughnVernon I kept this open mainly because #5 was not the most optimal solution. We could close, but I think there is still some misconception of extends ResourceHandler: In http docs: http In xoom docs: xoom And as said in #5, ServerActor doesn't know about routes without extends ResourceHandler, which means ResourceHandler is either used wrong or should have a stage (&context).

The fix I applied is just "here, have another logger".

VaughnVernon commented 4 years ago

Thanks, @Florian-Schoenherr

@danilo-ambrosio When you have an chance, please address this. I don't know where the problem is:

The problem is that when extends ResourceHandler is used with a DynamicResourceHandler it will never be initialized for each request that is handled, and thus, trying to access the inherited members will cause NullPointerExceptions.

Florian-Schoenherr commented 4 years ago

I tried removing extends ResourceHandler in schemata, e.g. right here, which doesn't work. That's the only thing I really know. (also, routes does Override ResourceHandler::routes())

VaughnVernon commented 4 years ago

If you remove extends ResourceHandler then routes() is no longer an @Override. In other words, just remove the @Override and you should be good to go. I don't understand why this would be a problem otherwise.

Florian-Schoenherr commented 4 years ago

That did not work. Maybe it was something specific to schemata, my guess is that xoom's @ResourceHandlers(packages = "io.vlingo.schemata.resource") looks at everything inside io.vlingo.schemata.resource that extends ResourceHandler. @danilo-ambrosio is that correct?

danilo-ambrosio commented 4 years ago

You're right, @Florian-Schoenherr.

ResourceHandler is also used as a key, speeding up the search for valid Resource classes inside a given package. I wasn't aware of the impacts @VaughnVernon mentioned when you extend ResourceHandler, but I have a straightforward solution. I can simply create a markup abstract class on vlingo-xoom for that purpose. Thus, we can maintain the package attribute of @ResourceHandlers annotation, which ease the resource handlers mapping.

What do you think? @VaughnVernon @Florian-Schoenherr

VaughnVernon commented 4 years ago

@danilo-ambrosio Do you mean a marker class/interface? I prefer not to use one. However, you could put a meaningful method on the interface:

public interface DynamicResourceHandler {
  Resource<?> routes();
}

Now overriding Resource<?> routes() in the implementing class makes sense.

Florian-Schoenherr commented 4 years ago

Well, I know why marker-classes are not so nice. Also, aren't annotations supposed to be used for marking (too)? Then again, having annotations on every resource class is also not what we are going for.

The interface with routes() from @VaughnVernon makes sense, maybe we could make it an abstract class and provide the logger(), too. Although having thought about it, generating the logger like this.$logger = $stage.world().defaultLogger(); makes more sense, because beginners will then have it right there and you can still just delete it if you didn't need it. So we just want routes().

@danilo-ambrosio do we need anything else on the marker class/interface?

VaughnVernon commented 4 years ago

@Florian-Schoenherr @danilo-ambrosio It could be an abstract base that has a constructor that requires the Stage and holds that and the logger. That's fine. I don't think it matters much in terms of code gen.

public abstract class DynamicResourceHandler {
  private final Logger logger;
  private final Stage stage;

  public abstract Resource<?> routes();

  protected DynamicResourceHandler(final Stage stage) {
    this.stage = stage;
    this.logger = stage.world().defaultLogger();
  }

  protected Logger logger() {
    return logger;
  }

  protected Stage stage() {
    return stage;
  }
}
danilo-ambrosio commented 4 years ago

@Florian-Schoenherr

We could use annotations but we still need to ensure some methods implementation on resources classes.

If we use annotations instead of marker interface/class, then a compile-time validation is required for making sure the right methods are implemented. That takes time to be implemented.

So I vote for @VaughnVernon 's suggestion which seems to be simpler. Note that Stage needs to be "injected" because, when using xoom annotation, developers are not able to do it by editing the Bootstrap class, which is automatically generated.

VaughnVernon commented 4 years ago

@danilo-ambrosio Do you mean injected as in passing a constructor parameter from the generated Bootstrap or by another means? Seems like all generated DynamicResourceHandler extenders should have a single constructor generated that takes a Stage and gives it to DynamicResourceHandler via super(stage).

danilo-ambrosio commented 4 years ago

Yes, "injected" means exactly what you've just said, @VaughnVernon . Thanks for clarifying.

Florian-Schoenherr commented 4 years ago

need to ensure some methods implementation

then obviously no annotation 👍 And yes, super(stage)!

danilo-ambrosio commented 4 years ago

@Florian-Schoenherr @VaughnVernon

If you get a chance, please review my changes below and let me know if everything is right:

After the review, could @Florian-Schoenherr please update VLINGO/SCHEMATA REST resources by extending DynamicResourceHandler ?

Florian-Schoenherr commented 4 years ago

Works as expected! 👍

VaughnVernon commented 4 years ago

@danilo-ambrosio @Florian-Schoenherr I am closing this. Note that I have added support for accessing Context from DynamicResourceHandler. To activate it, code must be generated to include a self reference in routes() when instantiating the ResoureBuilder.