I have a GWT application where MVP pattern is followed.
We have multiple views to show data on UI.
We set the data to view via Activity. Something like this
public class SomeActivityImpl extends AbstractActivity implements SomeView.Presenter {
public SomeActivityImpl{
//some initialization goes here.
}
public void start(AcceptsOneWidget containerWidget, EventBus eventBus) {
//presenter is set here
loadDetails();
}
private void loadDetails(){
SomeRequestFactory.context().findSomeEntity().fire(new Receiver<SomeProxy>() {
#Override
public void onSuccess(SomeProxy proxyObject) {
someView.setName("name");
someview.setSurname("surname");
someview.setMothersName("mothers name");
}
)
}
Now my question is how can I make sure that all the setters of View are set and nothing is missed?
Is there any solution which is GWT specific or can someone suggest a design pattern?
You should use the editor framework. It has a Request Factory driver to help you use it with request Factory. Here's a good tutorial
If you don't like that tutorial, consider looking at GWT in action
Related
Is it possible?
Currently I am using some aspects for my MVC controllers, what works really fine. I'm wrapping their responses and I have desired effect.
I also want to do this with Spring Data JPA repositories. But since they're generated based on the interface e.g:
public interface SomeRepository<T extends Some, ID extends Serializable> extends
BaseRepository<T, ID>, JpaSpecificationExecutor<T> {
public List<T> findById(Long id)
}
It generates me controller which is ready to use:
http://localhost:8080/findById?id=1234
I also want to wrap this controller. Is it possible?
This should work:
#Component
#Aspect
public class MyAdvice {
#Before("execution(* com.company.jpa.SomeRepository+.findById(..))")
public void intercept() { ... }
}
Basically, we are telling the framework to intercept the call to the findById method on any sub-class of SomeRepository.
Here is a sample application demonstrating this in action.
There is a PickList widget in PrimeFaces JSF component library?
Does GWT (or any other GWT component library) has such a widget?
Have a look at SmartGWT's featured example on Databound Dragging. You can also view its source. But since gwt does not have such widget, the best solution is to create your own custom component with the help of CellList.
I prefer to create my own PickList as it's easy and straightforward, below is what it looks like:
public abstract class PickList<T> extends Composite {
//The renderer provide the flexibility for client class customize the cell
public PickList(SafeHtmlRenderer<T> renderer) {
...
}
public void setCandidates(List<T> candidates, List<T> selected) {
//todo
}
public List<T> getSelectedValues() {
//todo
}
//Below two abstract method can facilitate getting values from view or rendering view from value
protected abstract T fromIdentity(String identity);
protected abstract String toIdentity(T value);
}
I am using GWT 2.4 with MVP.
Here is my view object:
public class LoginWidget extends Composite implements LoginWidgetView {
interface Binder extends UiBinder<Widget, LoginWidget> {
}
private static final Binder BINDER = GWT.create(Binder.class);
#UiField Anchor settings;
public LoginWidget() {
initWidget(BINDER.createAndBindUi(this));
}
#UiHandler("settings")
void handleSettingsClick(ClickEvent e) {
presenter.showSettings();
}
private Presenter presenter;
#Override
public void setPresenter(Presenter presenter) {
this.presenter = presenter;
}
}
I am setting the view´s presenter by
...
getLoginWidget().setPresenter(new LoginWidgetPresenter(placeController));
LoginWidgetPresenter of course implements the view´s Presenter interface. But when I click on the settings anchor, the presenter reference is still null, so presenter.showSettings() throws a NullPointerException.
I suppose that after calling the LoginWidget´s constructor and initializing the widget by
initWidget(BINDER.createAndBindUi(this));
the click handling code in my #UiHandler("settings") method ignores changes to the used objects like my presenter object??
Is there a way to set the presenter object after calling the initWidget() method?
Or is it possible to customize the #UiHandler/initWidget()-behaviour that I can set my presenter afterwards?
Thanks, Manuel
I implement MVP in another way and UIBinder work for my. Maybe if you pass the LoginWidgetPresenter in LoginWidget constructor it works.
public LoginWidget(Presenter presenter) {
this.presenter = presenter;
initWidget(BINDER.createAndBindUi(this));
}
...
getLoginWidget(new LoginWidgetPresenter(placeController));
There are lot of things, which could have gone wrong. The easiest thing is to try to debug your code, by putting breakpoints handleSettings and 'setPresenter' methods.
My guess is that one of following is happening:
setPresenter is never actually called
or
getLoginWidget() always returns a new instance of the widget, and it is quite possible that you are setting presenter on one instance of login widget, but displaying totally different instance of the widget
or
You have getLoginWidget().setPresenter(null) somewhere in your code
or any other guess. It is much more easier to debug, and see for yourself, where and how presenter instance is passed. Anyway, UiBinder will not erase your field values (unless it is modified by someone else to make fun of you)
I can't make a custom event be received in the Activity. Can anyone please tell me what am I missing? I am using GWT 2.1, MVP pattern and UiBinder.
Here's a sample of what I wrote:
Let's say I have MyCustomEvent class and its handler interface MyCustomEventHandler with its onMyCustomEvent(MyCustomEvent event) method.
I implement the handler interface in the Activity:
class MyActivity extends AbstractActivity implements MyCustomEventHandler {
....
public void onMyCustomEvent(MyCustomEvent event) {
doWhatYouKnow();
}
//EventBus is injected with GIN
public void start(AcceptsOneWidget container, EventBus eventBus) {
...
eventBus.addHandler(MyEvent.TYPE, this);
}
}
Now, the sending part in the view:
public class MyWidget extends Composite {
final PopUpPanel myPopUp;
public MyWidget() {
initWidget(uiBinder.createAndBindUi(this));
myPopUp.addCloseHandler(new CloseHandler<PopupPanel>() {
#Override
public void onClose(CloseEvent<PopupPanel> event) {
MyEvent event = new MyEvent();
fireEvent(event);
}
});
}
}
No exception are thrown and unfortunately onMyCustomEvent is never called in the MyActivity class. Any idea? Thanks a million.
#MyWidget
you can make the constructor take parameter ( eventBus )
which you can pass this from class MyActivity
so when you fire the event #MyActivity
the action will be executed #MyWidget
try this , i think it will work .
I think one of your comments is pointing you in the right direction here. What I'm going to guess is going on is that you have more than one EventBus floating around (there should usually only be one event bus per application).
First of all, make sure the EventBus in your Gin module is bound in the Singleton scope. Also, make sure this is the event bus that you pass in to your PlaceController, and not one you're constructing on your own.
Also, I wouldn't be too worried about the fact that your object is a ResettableEventBus in one place. I believe that's just an object that's created by the Activities/Places framework that just wraps the EventBus object you give it.
I have some questions regarding gwt-dispatch and guice. I'm using Guice 2.0, gwt-dispatch 1.1.0 snapshot, mvp4g 1.1.0 and GIN 1.0
First of all, I have defined simple action, result and handler:
ListContactsAction.java
public class ListContactsAction implements Action<ListContactsResult>{
public ListContactsAction() {
}
}
ListContactsResult.java
public class ListContactsResult implements Result {
private List<Contact> contactList;
public ListContactsResult() {
}
public ListContactsResult(List<Contact> contactList) {
this.contactList = contactList;
}
public List<Contact> getContactList() {
return contactList;
}
}
ListContactsHandler.java
public class ListContactsHandler implements ActionHandler<ListContactsAction, ListContactsResult>{
#Inject
private SqlSessionFactory factory;
public Class<ListContactsAction> getActionType() {
return ListContactsAction.class;
}
public ListContactsResult execute(ListContactsAction a, ExecutionContext ec) throws DispatchException {
// some code using SqlSessionFactory and returning ListContactResult
// with list of contacts
}
public void rollback(ListContactsAction a, ListContactsResult r, ExecutionContext ec) throws DispatchException {
/* get action - no rollback needed */
}
}
In previous version of my app, which was using rpc service instead of command pattern, I had a method which was providing SqlSessionFactory for injections, something like this:
#Provides
public SqlSessionFactory getSqlSessionFactory(){
// some code here
}
I read on gwt-dispatch getting started that I have to provide binding between my action and it's handler, which should look something like that:
public class ContactModule extends ActionHandlerModule{
#Override
protected void configureHandlers() {
bindHandler(ListContactsAction.class, ListContactsHandler.class);
}
}
But I have problem wiring it all with Guice, because this example from gwt-dispatch site:
public class DispatchServletModule extends ServletModule {
#Override
public void configureServlets() {
serve( "/path/to/dispatch" ).with( DispatchServiceServlet.class );
}
}
doesn't work, since there is no DispatchServiceServlet in the package.
My questions are:
How should I write DispatchServletModule and how to make it going (with what I should serve path)
what should I put in the web.xml file of my app to be able to correctly execute actions from my presenter, which has GIN injected DispatcherAsync implementation
Where should I put my SqlSessionFactory providing method (in which module) to be able to inject SqlSessionFactory where I need it
How I instantiate the injector so then I can use it in other action handlers properly
I think that is all and I made myself clear. If something isn't clear enough, I'll try to be more specific.
Have you created a GuiceServletConfig class? This is where you setup your Dispatch servlet module as well as your action handler module with Guice.
plubic class GuiceServletConfig extends GuiceServletContextListener {
#Override
protected Injector getInjector() {
return Guice.createInjector(new HandlerModule(), new DispatchServletModule());
}
}
The HandlerModule is your ActionHandler module class, so from your code you would put your ContactModule class.
For your SqlSessionFactory, you could setup the binding for it in your ContactModule, with my code I only have a single ServerModule that sets up all my service and action handler bindings. This is mainly for the sake of simplicity.
GWT-Platform framework uses a gwt-dispatch fork to handle rpc requests. There's a lot of code, which you probably had to wtite yourself, if you think of seriously using dispatcher and Guice. I highly recommend it.
Firstly, I sympathise. Putting this all together isn't documented in any one spot. I'll answer each of your questions in turn. Add comments to my answer if any of it is unclear.
QU: How should I write DispatchServletModule and how to make it going (with what I should serve path)?
There's a GuiceStandardDispatchServlet class in the net.customware.gwt.dispatch.server.guice package; use that. I'm not 100 percent sure why, but the path I use includes the name of my GWT module, followed by '/dispatch'. You might have to experiment with that.
public class MyServletModule extends ServletModule {
#Override protected void configureServlets() {
serve("/com.my.module.name/dispatch")
.with(GuiceStandardDispatchServlet.class);
}
}
QU: what should I put in the web.xml file of my app to be able to correctly execute actions from my presenter, which has GIN injected DispatcherAsync implementation?
<?xml version="1.0" encoding="UTF-8"?>
<web-app>
<filter>
<filter-name>guiceFilter</filter-name>
<filter-class>com.google.inject.servlet.GuiceFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>guiceFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
<listener>
<listener-class>com.myapp.whatever.MyContextListener</listener-class>
</listener>
...
</web-app>
... and then you'll need a custom context listener that creates a Guice injector as follows. Notice that I've included your ContactModule, which binds action handlers.
public class MyContextListener extends GuiceServletContextListener {
#Override protected Injector getInjector() {
return Guice.createInjector(new MyServletModule(),
new ContactModule(), new SQLStuffModule());
}
}
QU: Where should I put my SqlSessionFactory providing method (in which module) to be able to inject SqlSessionFactory where I need it?
Notice that I included a new SQLStuffModule in the previous code snippet; that would be a good place to put your SqlSessionFactory binding. There's no harm having multiple modules, and I find that it keeps the various concerns nicely separated.
QU: How I instantiate the injector so then I can use it in other action handlers properly?
For the server-side, see the MyContextListener code snippet above.
On the client side, you'll need a custom injector interface something like this:
#GinModules(StandardDispatchModule.class, MyClientModule.class)
public interface MyGinjector extends Ginjector {
MyWidgetMainPanel getMainPanel();
}
...and you can bind your MVP stuff in a custom Gin module as follows. I'm sorry that I'm not familiar with mvp4g, but I assume that you'll need to wire the views and presenters together in the module class.
public class MyClientModule extends AbstractGinModule {
#Override protected void configure() {
bind(...).to(...);
...
}
}