Hi Martijn,

On Thu, Aug 22, 2013 at 5:55 PM, Martijn Dashorst
<martijn.dasho...@gmail.com> wrote:
> So we started to write an RFC for Wicket, trying to document exactly what
> we want to change and how it should behave. It is quite a work in progress,
> but I like the first baby steps.

Nice work. It's kinda funny because we were working on the exact same
subject with one of my coworkers lately.

Here is what we really like about how Wicket works on managing the URLs:
- the mount directives centralized in the Application are really nice.
It's a central point to find your pages and they are just one click
away in your IDE. It's simple to maintain, simple to understand for
newcomers and people joining a project can find very easily where they
have to change something to change a page. It's a really important
point for us and I really like the default Wicket way instead of
having annotations spread everywhere in the application.

OK, there is only one bullet point but, believe it or not, it's really
a life changer compared to Spring MVC for example.

Here are now the problems we have and they are mostly addressed in
your document:
- the contract of a page is unclear in the constructor;
- parameter extraction leads to writing boring code and is prone to bugs;
- constructing the links/redirects/... is also painful as you don't
have any contract either. This is really important and we haven't
found a lot of this in your RFC.
- it's quite painful to build links which are dynamic: sometimes,
either the page or the parameters might change depending on the
context.

We've spent some time working on it lately and we debated about using
injection or not (in the Spring MVC/Jax-RS way of doing things) but
eventually we came to the conclusion that, even if it would be nice,
it wasn't the main problem to address and we could work on it later.

My coworker Yoann have built an API to build a IPageLinkDescriptor
(and a IResourceLinkDescriptor) to describe what is a link to this
page, what are the parameters, how they should be extracted and how
the link/redirect/... should be built.

Note that we agree that injection would be nice but we think our API
is a good summary of all the problems we need to address to have
something great. The one problem we haven't worked on is the mount
directive. Mostly because we like the way it is currently and we don't
want to lose the ability to see at a glance which page is mounted on a
URL.

In a page, we have the following method describing what is a link to this page:
    public static IPageLinkDescriptor linkDescriptor(IModel<User> userModel) {
        return new LinkDescriptorBuilder()
                .page(AdministrationUserDescriptionPage.class)
                .map(ID_PARAMETER, userModel, User.class).mandatory()
                .build();
    }
The fluid API is here to make it painless.

The IPageLinkDescriptor has the following API:
public interface IPageLinkDescriptor {
    AbstractDynamicBookmarkableLink link(String wicketId);

    String fullUrl();

    void extract(PageParameters parameters);

    void setResponsePage();

    RestartResponseException newRestartResponseException();

    RestartResponseAtInterceptPageException
newRestartResponseAtInterceptPageException();
}

Except for the extract() method, I think they are self understandable.

The extract() method is called with the following pattern:
        IModel<User> userModel = new GenericEntityModel<Long, User>(null);

        try {
            linkDescriptor(userModel).extract(parameters);
        } catch (Exception e) {
            LOGGER.error("Error on user loading", e);
            getSession().error(getString("administration.user.error"));

            throw
AdministrationUserListPage.linkDescriptor().newRestartResponseException();
        }

You can of course extract several parameters at once if needed. Here,
we just need the identifier of the user.

Note:
We decided to use the ConversionService infrastructure of Spring
instead of the Converter infrastructure of Wicket, mainly because it
deals with inheritance (which is useful when dealing with Hibernate
proxies) and because we know it works well for this purpose (it's used
by Spring MVC). It's an implementation detail but using the Wicket
converter infrastructure without providing a way to fix this issue
will be quite painful.

There is another reason why we didn't use
Application#getConverterLocator(), though, and we think it is also
valid in the context of this RFC. Wicket converters are also used to
convert business objects to a human-readable representation. If you
already use this type of Wicket converters for Labels,
StringResourceModels, etc. in your application, you won't be able to
add another wicket converter to convert the same business objects to a
parameter string, which will often be something like
person.getId().toString(), and is definitely not human-readable. If
you decide to use the Wicket converter system in the implementation of
this RFC, I think it might be a good idea to use a different
ConverterLocator. Not another class, just another instance: there
would be an Application#getConverterLocator() and a
Application#getPageParameterConverterLocator(), or something
approaching.

-- 
Guillaume and Yoann

Reply via email to