What happened to PrettyFaces?

Splash Forums PrettyFaces Users What happened to PrettyFaces?

This topic contains 19 replies, has 4 voices, and was last updated by  Lincoln Baxter III 3 years ago.

Viewing 15 posts - 1 through 15 (of 20 total)
  • Author
    Posts
  • #24156

    0swald
    Participant

    Just dropped in to see if there is a new version of PrettyFaces and saw that the project has revolutionary changed: servlet instead of filter, absolutely new welcome page, “get started” guide, etc. New maven artifact does not contain old classes which I used to rely upon – bean annotations, url builders, PrettyContext, url actions… In other words – wtf is going on?)))

    I’d appreciate very much if someone could explain to old pretty user (and contributor) what happened to PF, where is it going, will it be supported and how do I upgrade my projects to utilize new PrettyFaces framework.

    Best regards,
    Osw.

    #24160

    Hey Oswald,

    the story is pretty simple. We are now focusing on Rewrite, which can be considered as the successor of PrettyFaces. We’ve learned much from the work on PrettyFaces and came to the conclusion, that there are some aspects in the core of PrettyFaces that would have to fundamentally change to implement features that users are requesting. Therefore we started over and created Rewrite, which is a URL rewriting engine which is not tied to JSF but works with every web framework that is build on top of the Servlet API. There is a JSF integration module for Rewrite which can be considered as PrettyFaces 4.0. But note that the way of configuration has fundamentally changed in the JSF integration module!!

    There is no more active development happening for PrettyFaces 3.3.x. Therefore we recommend to migrate applications to Rewrite. To simplify the migration to Rewrite, Lincoln created a “PrettyFaces compatibility module”, which basically allows you to keep your existing PrettyFaces configuration (pretty-config.xml and @URLMapping annotations) and use it with Rewrite.

    We are still working on more documentation for Rewrite which is very time-consuming task, because Rewrite can do MUCH MORE compared to PrettyFaces. I started to work on a migration guide for PrettyFaces users. It’s still in an early stage, but you can read how to migrate your existing application to Rewrite using the PrettyFaces compatibility module:

    http://ocpsoft.org/rewrite/docs/migration/prettyfaces3

    However, you wrote that your code doesn’t compile any more. What exactly did you update to? Which artifacts are you using?

    #24161

    0swald
    Participant

    Hi Chris,
    I was sure you’d be the first to answer)) I was just unable to find the migration guide, think it deserves better position on the project page)) Now I got it, will test it later today. Btw some of 3.3.x snapshot features didn’t get to the ‘rewrite-config-prettyfaces’, will think of contribution if I don’t decide to migrate to the Rewrite.

    As for the migration, I still do not get how do I replace dozens of JSF2 managed beans (having @EJB injections, different scopes, annotated with @URLMapping and @URLAction and having business logic inside) with a subclass(es) of HttpConfigurationProvider. From what I see on the Rewrite examples page, I could say that Rewrite itself is rather a smart proxy than a replacement for the old PrettyFaces, sort of java-based nginx, having almost nothing to do with JSF2. Will be glad to be wrong, but at this moment of time I cant even imagine first steps of the migration process))

    #24162

    Hey Oswald,

    I created the migration guide today and therefore it is not linked from the main page yet. 🙂

    Which features do you refer to that didn’t make it into rewrite-config-prettyfaceS? If I remember correctly Lincoln used the latest snapshots for creating the module.

    Regarding migration: HttpConfigurationProvider can be seen as a replacement for pretty-config.xml. So if you used a central configuration file before, you should use a HttpConfigurationProvider now.

    If you used the PrettyFaces annotations before and want to migrate completely to Rewrite, you can use Rewrite’s annotation support. You can have a look at the bookstore sample application to get an idea of how this looks like:

    https://github.com/ocpsoft/rewrite/tree/master/showcase/bookstore

    Here is an example bean showing the new annotation syntax:

    https://github.com/ocpsoft/rewrite/blob/master/showcase/bookstore/src/main/java/org/ocpsoft/rewrite/showcase/bookstore/web/details/BookBean.java#L38

    I’ll spend some more time on the migration guide in the next days. I plan to add a more detailed explanation there. 🙂

    #24163

    0swald
    Participant

    Hi Chris,
    Thanks for example, it looks VERY promising, especially Navigate class inside the bean, that’s what I’ve used to implement by myself in my own libs created upon old PrettyFaces. Questions still remain regarding @ViewScoped beans and postbacks, but with such a good start I don’t think they will be a problem))

    Missing feature I’ve mentioned is described here http://ocpsoft.org/support/topic/prettyurlbuffer-proposal-for-improvement/ , but now I’m not sure it’s relevant in case of migration.

    Best regards,
    Osw.

    #24169

    Regarding view scoped beans and postbacks. You can just add @IgnorePostback to you parameters and/or page actions. 🙂

    I just checked the code regarding the missing feature. It looks like this is also part of rewrite-config-prettyfaces:

    https://github.com/ocpsoft/rewrite/blob/master/config-prettyfaces/src/main/java/com/ocpsoft/pretty/faces/component/renderer/UrlBufferRenderer.java#L59

    #24170

    0swald
    Participant

    Thanks Chris,

    Maybe I’ve overlooked something (I’ve been checking tld docs), but let’s put it aside for now)))
    As for migration, I’ve successfully tested new approach, looks great, but there is one issue I need help with: how do I programmatic redirect to the specific @Join with a set of parameters? Another question is if there is a replacement for old-fashioned @URLMappings(mappings = {...}).
    Many thanks in advance,
    /Osw

    #24171

    Tony Herstell
    Participant

    Snap…

    I use this very simple (and useful) annotations all over (config close to the code that uses it (them)).

    e.g.

    
    //Tell prettyfaces to use this bean when the pattern matches and show the manageXXXs page. Also support a Query Param (cid).
    @URLMappings(mappings = { @URLMapping(id = "manageXXXs", pattern = "/xxx/manage", viewId = "/pages/xxx/manageXXX.xhtml"),
            @URLMapping(id = "createXxx", pattern = "/xxx/create", viewId = "/pages/xxx/CRUDXxx.xhtml"),
            @URLMapping(id = "readXxx", pattern = "/xxx/view", viewId = "/pages/xxx/CRUDXxx.xhtml"),
            @URLMapping(id = "updateXxx", pattern = "/xxx/update", viewId = "/pages/xxx/CRUDXxx.xhtml"),
            @URLMapping(id = "deleteXxx", pattern = "/xxx/delete", viewId = "/pages/xxx/CRUDXxx.xhtml") })
    

    I hope the need to put the CID on the URL for conversations has got magically fixed.
    (https://community.jboss.org/thread/194639 refers)

    
    // Lets be long running (multiple client-server round trips) - Needs Extended on
    // PersistanceContext too to hold onto my objects and not get LIEs.
    @ConversationScoped
    
    ...
        @SuppressWarnings("unused")
        @URLQueryParameter("cid")
        private String cid;
    
    ...
    
        /*
         * Hack to pass cid to prettyfaces so it can add it to URL - DONT remove.
         */
        public String getCid() {
            return this.conversation.getId();
        }
    
        public void setCid(String cid) {
            this.cid = cid;
        }
    
    //
    

    #24175

    @Oswald:

    For programmatic navigation I recommend to use the Navigate class, which makes the navigation very simple. I already added a section regarding this to the Migration Guide. Have a look at the “Programmatic navigation” here:

    http://ocpsoft.org/rewrite/docs/migration/prettyfaces3

    Currently there is nothing like @URLMappings in the Rewrite annotation support. To be honest, after writing many many application using PrettyFaces, I never found a single case where this annotation was useful for me.

    IMHO if there are different mappings, they should be seen as different pages, which are independent from each other (that’s what RESTful URLs are all about). So if the page are independent, you should also use different classes for their code. If there is common functionality, you can use an abstract base class. And sharing state between pages is an anti-pattern.

    Could you perhaps show an example of code where you think this annotation is useful?

    @Tony Herstell:

    If I remember correctly, Lincoln fixed a bug regarding cid some time ago. So I think this should be a problem.

    If you are using many very similar mappings, I suggest to use a ConfigurationProvider and use a single rule for all e.g. “create pages” like this:

    .addRule( Join.path("/{type}/create").to("/pages/{type}/CRUDX{type}.xhtml") )

    #24179

    0swald
    Participant

    Hi Chris,

    As for @URLMappings, I’ve used it mostly as a storage of seo-friednly static pages with minimum functionality inside:

    
    @URLMappings(mappings = {
    	@URLMapping(id = StaticPages.MAPPING_HOME,     pattern = "/#{langBean.lang}/", viewId = "/faces/pages/pub/home.xhtml"),
    	@URLMapping(id = StaticPages.MAPPING_ABOUT,    pattern = "/#{langBean.lang}/about/", viewId = "/faces/pages/pub/about.xhtml"),
    	@URLMapping(id = StaticPages.MAPPING_CONTACTS, pattern = "/#{langBean.lang}/contacts/", viewId = "/faces/pages/pub/contacts.xhtml")
    })
    public class StaticPages {
    
    	public static final String MAPPING_HOME = "p_mapping_home";
    	public static final String MAPPING_ABOUT = "p_mapping_about";
    	public static final String MAPPING_CONTACTS = "p_mapping_contacts";
    ...
    	
    

    OR

    
    @URLMappings(mappings = {
    	@URLMapping(id = OrderBean.MAPPING_MAIN, pattern = "/order/#{orderBean.orderId}/", viewId = "/faces/pages/priv/order.xhtml"),
    	@URLMapping(id = OrderBean.MAPPING_DETAILS, pattern = "/order/#{orderBean.orderId}/details/", viewId = "/faces/pages/priv/order-details.xhtml"),
    	@URLMapping(id = OrderBean.MAPPING_HISTORY, pattern = "/order/#{orderBean.orderId}/history/", viewId = "/faces/pages/priv/order-history.xhtml")
    })
    public class OrderBean {
    
    	public static final String MAPPING_MAIN = "p_mapping_order_main";
    	public static final String MAPPING_DETAILS = "p_mapping_order_details";
    	public static final String MAPPING_HISTORY = "p_mapping_order_history";
    	private String orderId;
    ...
    

    As you can see, there are different pages, different mappings, but the same functionality, e.g. retrieving order by it’s id or setting the language from user’s request.

    UPDATE

    Speaking of programmatic navigation I didn’t mean returning Navigate class instead of String (it’s nice but obvious), but rather building URL from Navigate entity and passing it to FacesContext for redirection, something similar to the code below:

    
    PrettyURLBuilder builder = new PrettyURLBuilder();
    String url = builder.build(mapping, false, new Object[]{1,2,3});
    

    There is a simple example where it could be useful, personally I do it in every project, – sending activation or password recovery E-Mails containing action url like http://www.mydomain.com/passrecovery/en/29b4033ca6f93ae78495108b629f3ec3fda055a0/

    • This reply was modified 3 years, 1 month ago by  0swald.
    • This reply was modified 3 years, 1 month ago by  0swald.
    #24182

    If you are using @URLMappings just as a store of very very simple pages without any (or much) functionality, you should use a ConfigurationProvider instead. You will get the type-safety of the Java configuration style and have all the configuration in one place. You can also use constants and stuff like that.

    For the programmatic navigation: If you want to build an URL, you could use the AddressBuilder. This class provides a fluent API for building URLs.

    
    String url = AddressBuilder.begin()
        .path("/passrecovery/{lang}/{token}/")
        .set("lang", "en")
        .set("token", "29b4033ca6f93ae78495108b629f3ec3fda055a0")
        .toString();
    

    See also the tests here:

    https://github.com/ocpsoft/rewrite/blob/master/addressbuilder/src/test/java/org/ocpsoft/urlbuilder/AddressBuilderTest.java

    #24184

    0swald
    Participant

    Chris,
    Definitely there is another way of building an address from Navigate class entity, it should reside somewhere in a view- or navigation handler, plus servlet code, I believe. Messing around slashes and static parts in @Join‘s path attribute doesn’t seem a good idea to me. Do you agree, that Navigate.to(BookBean.class).with("isbn", isbn) can be finally presented as a pretty-url and having such conversion at hand is of any value for Rewrite end-users?

    I will try to find it out by myself, in the sources, not a big problem indeed, but your help or hints could save me (and others) couple of hours, at least))

    #24185

    I see two options if you want to navigate from non-JSF code:

    1. Use constant and AddressBuilder

    Use a constant for the path:

    
    @Join(path = RecoveryBean.PATH, to="/faces/passrecovery.xhtml")
    public class RecoveryBean {
    
      public final String PATH = "/passrecovery/{lang}/{token}/";
    
    }
    

    And then navigate like this:

    
    String url = AddressBuilder.begin()
        .path(RecoveryBean.PATH)
        .set("lang", "en")
        .set("token", "29b4033ca6f93ae78495108b629f3ec3fda055a0")
        .toString();
    
    response.sendRedirect(url);
    

    I like this one because the pattern for the path is the same for the annotation and for AddressBuilder, so using a constant makes things really easy.

    2. Use Navigate and encode URL

    You can also use Navigate to create a standard JSF URL and than use HttpServletResponse.encodeURL() to create the pretty URL.

    
    String uglyUrl = Navigate.to(RecoveryBean.class)
        .with("lang", "en")
        .with("token", "29b4033ca6f93ae78495108b629f3ec3fda055a0")
        .withoutRedirect()
        .toString();
    
    /*
     * after that 'uglyUrl' will be:
     *    /faces/passrecovery.xhtml?lang=en&token=29b4033ca6f93ae78495108b629f3ec3fda055a0
     */
    
    String prettyUrl = response.encodeURL(uglyUrl);
    
    /*
     * after that 'prettyUrl' will be:
     *    /passrecovery/en/29b4033ca6f93ae78495108b629f3ec3fda055a0/
     */
    
    response.sendRedirect(prettyUrl);
    

    Please note .withoutRedirect() which is important to add so that Navigate creates a standard JSF URL.

    #24198

    Hey Oswald!

    Long time no see 🙂 Sorry for my late response, I was at a conference all last week and didn’t really have time to stay “wired in.”

    I just wanted to clarify one thing, which is that we still use a Servlet Filter, not a Servlet itself; that part is the same. I’m surprised that the URLBuffer doesn’t work for you, actually, since I believe there’s a test for this in the rewrite-config-prettyfaces module. Could you describe a little about what exactly the problem is in specific? Even better, want to upload a sample project?

    Thanks! Good to see you again 🙂
    ~Lincoln

    #24199

    0swald
    Participant

    @Christian
    Thanks! Now I’m fully armed and ready to start the migration and update my utility libs, which are based upon old PrettyFaces project.

    @lincoln
    Nice to hear from you, Lincoln. I was busy too, lived between Moscow, Germany and US, fund raising and stuff like that.
    Forget about rewrite-config-prettyfaces)) Thanks to Christian, I have solved all of the migration issues and now I prefer to stick to the Rewrite project rather than to compatibility library which is less likely to be supported as goog as your new “child”))

    I’d like to raise the URLMappings topic again. Christian has offered the use of the ConfigurationProvider for JSF beans having the same business logic for different viewId’s (there is a discussion earlier in this thread). I feel uncomfortable with this idea, not because I will need to do more migration job, but rather because the logic should be splitted between the two absolutely different contexts – I wont have an access to the FacesContext, @EJB injection should be only singleton ones, no @ManagedProperty inside the ConfigurationProvider, etc. Now I understand that I will definitely create dozens of empty @Join-annotated sub-classes to get things working as they did with URLMappings. No problem, I can live with that, but I just do not understand why.

    I had a quick look at the sources and it seems to me that there is nothing that could prevent you from supporting something like this:

    @Joins(joins={
      @Join(),
      @Join()
    })
    

    That would possibly cause the @Rule name to be placed inside @Join (or created automatically) and some ambiguity checks in the Navigate and/or AnnotationJoinResourcePathResolver classes to be implemented, but that’d definitely give JSF part of the project more flexibility and saved it from the functional degrade which I think the one-to-one (class-to-page) approach definitely leads to.

    Am I missing something here? What do both of you think about it? As an old and experienced PF-user I’d be glad to contribute if you think this idea is worth implementing.

    Btw, there is a bug (I believe it is) in the initialization of the HttpConfigurationProvider – two entities of the class are created if there is an entry in META-INF/services/org.ocpsoft.rewrite.config.ConfigurationProvider – one from the services entry, another from some class-scanner I believe. Don’t think this is the expected behavior.

Viewing 15 posts - 1 through 15 (of 20 total)

You must be logged in to reply to this topic.

Comments are closed.