CDI MVP add-on

MVP (model-view-presenter) is an emphasized pattern for larger Vaadin applications.
CDI MVP
provides a lightweight approach to building a foundation for your front-end layer with Vaadin and MVP.

A good example on how to use CDI MVP in a Vaadin project can be found in
https://github.com/tomivirkki/cdiutils-addressbook
.

[/b]The add-on can only be used in
Vaadin CDI
enabled projects.
[/b]

  1. Question: is there a specific reason why you did not add the enter() method to the MVPView interface ?
  2. org.vaadin.addon.cdimvp.MVPPresenter should be public or Glassfish gives an error that the injection point does not have access to the interface.
  1. MVPView.java is the super of presenter’s interface to the corresponding view but enter() was never meant to be invoked by the presenter. So exposing this api to the presenter didn’t feel right imo.
  2. Ah, I see. I’ll fix this soon.

The reason I asked about the enter() method is that I do not expose the View implementations to other packages ( prevents someone from doing a new TestViewImp() for example) and forces the dev team to use cdi to get a reference to a view, but now we have to add the enter() method in our view interfaces that extends MVPView , not really an issue. I was just wondering what the rational was.

for example :

public interface PaperEditView extends MVPView, Component {

    void enter();

    Paper getPaper() throws FieldGroup.CommitException;

    Paper getPaper(boolean commit) throws FieldGroup.CommitException;

    void setPaper(final Paper notification) throws DisplayException, MetaException, ObjException, ElementRenderException;

    // This view is inteded for display in a PopupWindow, this will close the Window.
    void close();
}

usage:

    @Inject
    private Instance<PaperEditView> editView;// Note not using the Implementation , only the interface.

@Override
    public void editPaper(final Paper paper) {
        final com.vaadin.ui.Window pop = new com.vaadin.ui.Window();
        pop.setCaption("Correnspondence : " + paper.getFileName());
        final PaperEditView view = editView.get();
        view.enter(); // I have to expose this method in my interface.
        try {
            view.setPaper(paper);
        } catch (Exception ex) {
            logger.log(Level.SEVERE, null, ex);
            Notification.show("Oops, error occured when trying to render edit screen", Notification.Type.ERROR_MESSAGE);
        }
        pop.setWidth(600.f, Unit.PIXELS);
        pop.setContent(view);
        pop.setClosable(false);
        pop.center();
        pop.setResizable(false);
        pop.addCloseListener(this);
        pop.setModal(true);
        UI.getCurrent().addWindow(pop);
    }

BTW something I have used quite frequently now is a combination of the MVPView and the navigator.View , it might be worth while to add it to the addon too (will cut down on some boiler plate code for people). I’m willing to supply some sample code it you are interested.

Ok the second issue is fixed. Thanks for reporting.

I’ve been doing some attempts in trying to integrate Navigator with the add-on but haven’t yet come up with a satisfying result. I’d be happy to check out your solution though.

Attached are some cleanedup classes of the Navigator Views I used in my most resent project.



public interface SearchResultsView extends MVPNavigationView {

    String NAVIGATION_NAME = "search.RESULT";
    String PARAM_TERMS = "words";
     ...
}


@com.vaadin.cdi.CDIView(supportsParameters = true, uis = {PortalUI.class}, value = SearchResultsView.NAVIGATION_NAME)
class SearchResultsViewImpl extends AbstractMVPNavigationView implements SearchResultsView {

      ...
}


@ViewInterface(SearchResultsView.class)
class SearchResultsViewPresenter extends AbstractMVPNavigationPresenter<SearchResultsView> {

@Override
    public void viewEntered() {
        if (view.hasParameter(SearchResultsView.PARAM_TERMS)) {
              doAndDisplaySearch(view.getParameterValue(SearchResultsView.PARAM_TERMS));
        } else {
              Notification.show("Missing required parameter "+SearchResultsView.PARAM_TERMS, Notification.Type.ERROR_MESSAGE);
        }
    }
}

13259.java (1.73 KB)
13260.java (3.69 KB)
13261.java (1.48 KB)

BTW , I encountered a very strange problem when we deployed to our staging server, (Glassfish 3.1.2.2 opensource addition) , your extension MVPExtension would not work ( No errors logged ) , CDI still worked the only thing that did not work was the the presenters viewEntered() was never called.
When I replaced the empty beans.xml in cdi-mvp with a simple one, it would work. I don’t quite understand why the beans.xml file will have any influence on the Extenstion that is configured via META-INF/services.
You have any idea ?

The empty beans.xml file works fine on all our development machines also running Glassfish 3.1.2.2 ) , One of the dev machines is nearly identical to the staging server (updates and all).

Simple beans.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://java.sun.com/xml/ns/javaee"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/beans_1_0.xsd">
</beans>

Good things are happen here.
I’m studding vaadin and working on a Java EE application, I use MVP to make one simple view, and was thinking how to implement this pattern in cdi, to cut down the effort of wire Model View Presenter Layouts Applications and CDI Services toggetther.

I think this approach is in development, but Do someone know some article or tutorial to get started? I will use the example.
How stable is this approach right now, in terms of API changes? I’m planning to build an production application not so complex and with low concurrent with this archtecture.

I see that problems like the same view instance per client, where the same view instance is served for the client (one form or window by example) are solved in this case, by giving the View @UIScoped. Another good thing is the Lazy instantiation.

Hi guys,

I’ve a problem with CDI. Injection is only working sometimes…

@UIScoped
public class CalendarComponent extends ViewComponent {

    @Inject // Working
    private CustomCalendar calendar; // CustomCalendar only extends Calendar, nothing else

@Inject // Not working
private Calendar cal;

@Inject // Not working
    private Label label;

    @Inject // Working
    @LabelProperties(immediate = false, id = "3")
    private Label label;
    
    ...
}

Here’s the error I got when injection doesn’t work :

SEVERE: Exception while loading the app : WELD-001408 Unsatisfied dependencies for type [Label]
 with qualifiers [@Default]
 at injection point [[field]
 @Inject private com.project.ui.component.calendar.CalendarComponent.label]
org.jboss.weld.exceptions.DeploymentException: WELD-001408 Unsatisfied dependencies for type [Label]
 with qualifiers [@Default]
 at injection point [[field]
 @Inject private com.project.ui.component.calendar.CalendarComponent.label]

The weird thing is it does work when it’s my component, or when using a component with @XXProperties, but not for others.

I suspect it has something related to beans.xml, because I think CDI 1.0 needs this file and the vaadin-client.jar/META-INF doesn’t contains a beans.xml

I’m using Glassfish 3.1.2.2, Netbeans 7.3.1 and Java EE 6.

Any suggestions ?

Thanks a lot,

Cédric

Hi Cedric

Only the modules containing beans.xml descriptor file are scanned for CDI beans. Your own module most likely contains the file and that’s why CustomCalendar is recognized as an injectable bean. However, Calendar and Label come from Vaadin jar archives that don’t have the marker file included and thus are not scanned for beans by the container.

Vaadin core component injected to a field with @XXProperties -annotation works because the container discovers a producer method for it in the CDI Properties add-on jar (which in turn does have a beans.xml descriptor).

All this behaviour is defined by the CDI specification. The first Q/A at
http://www.cdi-spec.org/faq/
explains the rationale behind beans.xml in short.

The add-on was formerly part of a plugin called CDI Utils. CDI MVP was extracted as an individual add-on a month ago due to various reasons and the API was partially changed/cleaned up in the process. Applied changes stem mostly from the user feedback and better insight gained in personal use.

From the users’ point of view the current API should be quite stable. I might add some functionality regarding the compatibility with Vaadin Navigator (as discussed earlier in this thread) but any future change should not invalidate the existing API.

Sounds strange indeed. Really can’t say what can cause such behaviour on your staging server.
Anyway, I’ll change the beans.xml to the simple version for the next release to avoid this in the future.

Thanks for the Navigation source files. I’ll take a look asap.

Hi Tomi,

Thanks for the explanation, everything is clear for me now.
Is the beans.xml planned to be integrated to the official release ?

Because right now, I have no choice but recompile myself de vaadin-client with the beans.xml right ?

I don’t think Vaadin core libraries will nor should contain the beans.xml file. Wouldn’t recommend compiling a custom build of the libraries just for this purpose either.

However, if you do want to @inject a Vaadin core component in your project, there are some options:

[b]

  1. Create producers in your own project
    [/b]
@Produces
public Button createButton(){
    return new Button();
}

This allows you to change the injected Button later on if you wish (by adding a styleName for all you buttons at once or changing the implementation to NativeButton etc.). Like so:

@Produces
public Button createButton(){
    Button button = new NativeButton();
    button.addStyleName("mybutton");
    return button;
}

(Using a qualifier wouldn’t hurt here either)


2. Create a Button extension in your project

public class MyButton extends Button{...}


3. Use the @XXProperties qualifier (CDI Properties contains the necessary producers)

@Inject
@ButtonProperties
private Button button;

That’s great, thank you for your help Tomi !

Hi,

I’m trying to use sub-windows in my app to modify some values.
I’m using CDIViews and using the fireViewEvent(…) method to call my EJB and I would also like to use this method in my own subwindows.

The problem is I need to extends Window therefore I can’t extends ViewComponent too.
Any ideas how I can reach the presenter class using fireViewEvent(…) from a subwindow using the MVP Pattern ?

Thanks a lot,

Cédric

The Content you want to display should be a View or extends ViewComponent.

I prefere to display a separate View imlementation in my SubWindows, but note there is a pitfall you should take care when displaying a View in a SubWindow , Views are currently UIScoped and thus you have one instance per UI, you cannot have two windows displaying the same View …

Usually I dont even create a subclass of Window, I simply initialize the window from where I want to display it…

    @Inject
    private Instance<WorkOrderEntryEditView> editView;

@Override
    public void editWorkOrderEntry(final AbstractWorkEntry entry) {
        final com.vaadin.ui.Window pop = new com.vaadin.ui.Window();
        pop.setCaption("Equipment Entry");
        final WorkOrderEntryEditView view = editView.get();
        view.enter();
        view.setWorkOrderEntry(entry);
        pop.setWidth(600.f, Unit.PIXELS);
        pop.setContent(view);
        pop.setClosable(false);
        pop.center();
        pop.setResizable(false);
        pop.addCloseListener(this);
        pop.setModal(true);
        UI.getCurrent().addWindow(pop);
    }

Great idea, I haven’t thought about doing it that way.
Thanks a lot !

Hi,

I’m using this addon in addition to the other vaadin-cdi-add-ons. Works like a charme.
Now I want to test my application. Here I run in a lot of problems. Which test-framework can you recommend? I tried CDI-Unit.

Hi Dennis

Haven’t tried CDI-Unit myself so can’t say much about that. But in general, for testing CDI applications I’d go with Arquillian (
http://arquillian.org/
).