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

#425#120 Rework Actionhandler/Operationhandler API #135

Merged
merged 6 commits into from
Oct 26, 2021

Conversation

tortmayr
Copy link
Contributor

With the DI rework #127 its no longer necessary to pass the model state object as part of the execute method. instead action/operation handlers
can simply directly inject the model state if the want to use it. Since action & operation handlers are now client session scoped an arbitary state object can be injected and used for execution. (Part of eclipse-glsp/glsp/issues/120)

  • Remove the modelstate argument from the execute() method of ActionHandler and OperationHandler
  • Remove Handler super interface because it doesn't provide any additional value
  • Add documentation for affected API.
  • Introduce new DefaultActionHandler & DefaultOperationHandler that serve as replacement for the now deprecated BasicActionHandler & BasicOperationHandler
  • Deprecate BasicOperationHandler & BasicActionHandler & BasicCreateOperationHandler
  • Replace usage of BasicActionHandler with DefaultActionHandler
  • Replace usage of BasicOperationHandler' with DefaultActionHandler`
  • Replace usage of BasicCreateOperationhandler' with DefaultOperationHandler&DefaultCreateOperationHandler`

Fixes eclipse-glsp/glsp/issues/425

Copy link
Member

@planger planger left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, @tortmayr! Looks already very good!

I haven't really made up my mind yet, but we could even go as far as injecting also the action / operation with the concrete type. This could make several abstract classes superfluous. But it would also make the interface of handlers a bit implicit. WDYT?

I'd also be very interested in the opinion of others, @martin-fleck-at, @CamilleLetavernier?

Maybe I missed it, but do we already bind a concrete GModelState class so that handlers can inject their concrete class directly?

@tortmayr
Copy link
Contributor Author

tortmayr commented Oct 19, 2021

I haven't really made up my mind yet, but we could even go as far as injecting also the action / operation with the concrete type. This could make several abstract classes superfluous. But it would also make the interface of handlers a bit implicit. WDYT?

I'm a bit lost here. I don't see how injecting the action/operation could help here. Can you please eloborate?

Maybe I missed it, but do we already bind a concrete GModelState class so that handlers can inject their concrete class directly?

Yes we do:

bind(GModelState.class).to(bindGModelState()).in(Singleton.class);

@planger
Copy link
Member

planger commented Oct 19, 2021

I haven't really made up my mind yet, but we could even go as far as injecting also the action / operation with the concrete type. This could make several abstract classes superfluous. But it would also make the interface of handlers a bit implicit. WDYT?

I'm a bit lost here. I don't see how injecting the action/operation could help here. Can you please eloborate?

I was wondering whether we could, before we invoke the handler, put the action (to be processed) with the concrete type into the DI container, so that handlers could also use @Inject protected MyAction myAction;. Then they wouldn't need to implement a generic typed interface.
One step further, we could to even allow them to not implement an interface at all but annotate the method that they want to be invoked on action processing and use method injection in this method.
However, this would also affect the registration of the action handler, as the interface doesn't show the action that they are repsonsible for.

Maybe I missed it, but do we already bind a concrete GModelState class so that handlers can inject their concrete class directly?

Yes we do:

bind(GModelState.class).to(bindGModelState()).in(Singleton.class);

Yes, but can clients now also inject a subclass of GModelState with @Inject protected MyModelState myModelState;

@tortmayr
Copy link
Contributor Author

tortmayr commented Oct 25, 2021

I was wondering whether we could, before we invoke the handler, put the action (to be processed) with the concrete type into the DI container, so that handlers could also use @Inject protected MyAction myAction;. Then they wouldn't need to implement a generic typed interface.

I see a couple of problems with that proposal:

  • First it's not possible to add new bindings an existing injector. (apart from Just-In-Time bindings, but that's not want we want here we would need a toInstance() binding). So we would need a hacky workaround involving handler factories, and dynamically creating a new child container where we bind the dispatched action for each invocation of ActionHandler.dispatch(). Sounds like a lot of overhead for little benefit to me.
  • We would lose the ability to process multiple Action with one handler
  • We no longer can registrate the action handler because we have not Type-argument to derive the handledActionKinds
  • Currently all handlers (action & operations) are stateful and one instance is reused per session. With the proposal this would no longer be possible. At least for action handlers, which essentially also would render the corresponding Registry useless and we would have to find a workaround for that

One step further, we could to even allow them to not implement an interface at all but annotate the method that they want to be invoked on action processing and use method injection in this method.
However, this would also affect the registration of the action handler, as the interface doesn't show the action that they are repsonsible for.
I see why that would be handy, however, I don't necessarily like the idea of shifting away from the use of interfaces for one subpart of the exposed API. Also this would require us to construct action handlers at runtime for each newly dispatched action.

To sum up, I'm not sure if the proposal is feasible from a technical perspective (without working around the limitations of Guice) and would also affect alot of the existing API and the current behavior. I personally don't think that the benefits are worth the effort and think that the current approach of providing a TypedInterface for the basic 1-to-1 action handelers is a good compromise.

Yes, but can clients now also inject a subclass of GModelState with @Inject protected MyModelState myModelState;

Yes, with 1d33c76 this is now possible

tortmayr and others added 5 commits October 26, 2021 00:21
With the DI rework #127 its no longer necessary to pass the model state object as part of the execute method. instead action/operation handlers
can simply directly inject the model state if the want to use it.  Since action & operation handlers are now client session scoped an arbitary state object can be injected and used for execution. (Part of eclipse-glsp/glsp/issues/120)

- Remove the modelstate argument from the execute() method of `ActionHandler` and `OperationHandler`
- Remove `Handler` super interface because it doesn't provide any additional value
- Add documentation for affected API.
- Introduce new `DefaultActionHandler` & `DefaultOperationHandler` that serve as replacement for the now deprecated `BasicActionHandler` & `BasicOperationHandler`
- Deprecate `BasicOperationHandler` & `BasicActionHandler` & `BasicCreateOperationHandler`
- Replace usage of `BasicActionHandler` with `DefaultActionHandler`
- Replace usage of `BasicOperationHandler'  with `DefaultActionHandler`
- Replace usage of `BasicCreateOperationhandler'  with `DefaultOperationHandler` & `DefaultCreateOperationHandler`

Fixes eclipse-glsp/glsp/issues/425
…tions/ActionHandler.java

Co-authored-by: Philip Langer <planger@users.noreply.github.com>
Co-authored-by: Philip Langer <planger@users.noreply.github.com>
Naming: Default->Abstract
Bind actual implementation class of GModelState to itself as singleton before binding it to GModelState.
e.g. by overriding the following method of `GLSPDiagramModule`

```java
bindGModelState(){
  return MyModelState.class
}
```

clients can also directly inject the implementing subclass with
```java
@Inject 
protected MyModelState myModelState;
```

Also fix type in `GLSPServerModule`
@ivy-cst
Copy link
Contributor

ivy-cst commented Oct 26, 2021

@tortmayr This looks now very promising. I really like the way how it is done now.

@planger planger self-requested a review October 26, 2021 07:51
Copy link
Member

@planger planger left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for the feedback and the further improvements! Looks great!

I agree that if Guice makes it hard to add a binding to the injector after initial creation of the container, it is probably not worth going that route.

@planger
Copy link
Member

planger commented Oct 26, 2021

Btw I also successfully tested a custom GModelState class and it works fine! Thanks!
There are a couple of interfaces that still pass the GModelState directly. This is tracked with eclipse-glsp/glsp#422

@planger
Copy link
Member

planger commented Oct 26, 2021

With 4a6af53 I've removed the GModelState from the interfaces. @tortmayr please review and feel free to merge after that. Thanks!

@planger
Copy link
Member

planger commented Oct 26, 2021

With 4a6af53 I've removed the GModelState from the interfaces. @tortmayr please review and feel free to merge after that. Thanks!

Oh I just realized while testing that label validation broke, I guess with my change (GModelState is null). Unfortunately I have to work on something else now, but will investigate the issue later today or tomorrow.

This simplifies the use of custom model state classes because
implementations can now inject their concrete custom class instead of
the generic GModelState that they'd have to cast again.
Also several implementations often don't need the model state making the
method parameter superfluous.

Signed-off-by: Philip Langer <planger@eclipsesource.com>
@planger
Copy link
Member

planger commented Oct 26, 2021

With 4a6af53 I've removed the GModelState from the interfaces. @tortmayr please review and feel free to merge after that. Thanks!

Oh I just realized while testing that label validation broke, I guess with my change (GModelState is null). Unfortunately I have to work on something else now, but will investigate the issue later today or tomorrow.

Fixed with 17535e9

@tortmayr
Copy link
Contributor Author

@planger Thanks for the update. I was initially planning to do that in a follow-up PR because it's not directly related to this issue but we of course can do it directly with this PR as well.

@tortmayr tortmayr merged commit c969357 into master Oct 26, 2021
@tortmayr tortmayr deleted the tortmayr/issues/425 branch October 26, 2021 17:17
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Rework Action/Operation handler API
3 participants