http://domain.com/{username} Short URLs or catchall (Facebook-style)

Splash Forums PrettyFaces Users http://domain.com/{username} Short URLs or catchall (Facebook-style)

This topic contains 34 replies, has 5 voices, and was last updated by  Christian Kaltepoth 5 years, 4 months ago.

Viewing 15 posts - 1 through 15 (of 35 total)
  • Author
    Posts
  • #18128

    ceefour
    Participant

    I’d like to rewrite “http://domain.com/{username}” where username is a shortname (slug) of any valid mapped entity.

    However other paths still work (e.g. http://domain.com/contact)

    So this rewrite acts more like a catchall, and if still not found then it passes to the next handler in the chain (ultimately giving a 404).

    I tried the following but got an infinite loop:

    <!– Slug –>

    <url-mapping id=”slug”>

    <pattern value=”/#{ slug : slugBean.slug }”>

    <validate index=”0″ validator=”#{slugBean.validateSlug}”/>

    </pattern>

    <view-id value=”#{slugBean.getViewPath}” />

    </url-mapping>

    SlugBean.java :

    public String getViewPath() {

    return “/people/” + slug;

    }

    public void validateSlug(FacesContext context, UIComponent component, Object value) {

    log.debug(“Validating slug: {}”, value);

    try {

    Integer.parseInt((String) value);

    } catch (NumberFormatException e) {

    throw new ValidatorException(new FacesMessage(“Cannot parse “+ value), e);

    }

    }

    This is almost like but different than http://ocpsoft.com/support/topic/rewrite-param-like-sitenamecomparam

    The best real-world example of this is http://facebook.com/{username} URLs

    #21950

    Hi @ceefour,

    Since URL-mappings are processed in order. Just placing this rule last in your configuration should be enough to provide the behavior you’re looking for. Does this work for you?

    Hope this helps,

    Lincoln

    #21951

    ceefour
    Participant

    @lincoln :

    It is the last rule, but it causes infinite loop when processed.

    #21952

    Sorry, I missed where you said that. I see it now.

    That’s strange. Any chance you could post the rest of your pretty-config.xml, web.xml, and any annotations you’re using to configure PrettyFaces?

    Thanks,

    ~Lincoln

    #21953

    Perhaps it would also be a good idea to give 3.3.3-SNAPSHOT a try. We recently fixed some issues that MAY be relevant to this.

    https://github.com/ocpsoft/prettyfaces/wiki/Snapshots

    #21954

    ceefour
    Participant

    @lincoln, This is the non-working entire pretty-config as you requested: http://pastebin.com/2Xv3c0G8

    When I access, say /hendy.irawan, it goes into infinite loop like this:

    at org.apache.catalina.core.ApplicationHttpRequest.setAttribute(ApplicationHttpRequest.java:303) [jbossweb-7.0.7.Final.jar:]

    at org.apache.catalina.core.ApplicationHttpRequest.setAttribute(ApplicationHttpRequest.java:303) [jbossweb-7.0.7.Final.jar:]

    All I need to fix is change the pattern here:

    <url-mapping id=”slug”>

    <pattern value=”/#{ slug : slugBean.slug }”>

    <validate index=”0″ validator=”#{slugBean.validateSlug}”/>

    </pattern>

    <view-id value=”#{slugBean.getViewPath}” />

    </url-mapping>

    to here:

    <pattern value=”/slug/#{ slug : slugBean.slug }”>

    Now I can access both:

    * /people/hendy.irawan

    * /slug/hendy.irawan

    What I want is to have a catchall /#{slug} where it can “forward” to /people/#{slug} or /interests/#{slug} depending on the looked up slug.

    Thank you.

    #21955

    I agree with @chkal. It looks like you might want to try 3.3.3-SNAPSHOT

    https://github.com/ocpsoft/prettyfaces/wiki/Snapshots

    ~Lincoln

    #21956

    After thinking a bit more about this “catch all” requirement I’m not really sure any more if something like this is currently possible with PrettyFaces.

    I think PrettyFaces identifies the mapping for an URL only using the <pattern> of the mappings (including the optional custom regular expressions for path parameters within the pattern). The validation happens at a much later time of the request processing (especially after the request has been forwarded to the viewId). The validation can currently only be used to abort processing of the request and prevent the execution of the URL action method and the page rendering.

    To be more specific, this is the order of execution:

    1. Identify the mapping for the URL using the patterns

    2. Forward the request to the viewId of the matching mapping

    3. Enter the JSF lifecycle

    4. Process the validators for the path parameters

    5. Inject the values of the path parameters

    6. Execute the page action

    7. Render the page

    You see that the validation happens AFTER the request has been forwarded to the viewId of the mapping. Therefore there is currently no way to use some other mapping in case of a validation error because the the request has already been forwarded.

    Thoughts on this?

    Christian

    #21957

    I believe you can also specify another “#{method.expression}” or “mapping:id” in the <validate onError=”…” /> element.

    #21958

    ceefour
    Participant

    @Christian:

    I guess we need to hook into #1 in your PrettyFaces lifecycle above.

    Or should I write my own servlet filter/listener? (after PrettyFaces, so will be handled when it fails before going to the 404).

    #21959

    @lincoln:

    Yeah, you are right. I forgot about that. That’s possible too. But I don’t think this helps for the usecase ceefour describes, doesn’t it?

    @ceefour:

    I have one other idea but I’m not sure if this can work. You could try to use a custom rewrite processor like this:

    <rewrite match="/.*" processor="com.example.MyProcessor" redirect="chain"/>

    And this Processor implementation:

    public class MyProcessor implements Processor {

    public String processInbound(HttpServletRequest request, HttpServletResponse response, RewriteRule rule, String url) {

    // parse slug name from the URL
    String slug = parseUrl(url);

    // if it is a known people slug, forward to the correct view
    if( isPeopleSlug(slug) ) {
    return "/people/"+slug;
    }

    // no slug, just continue processing
    else {
    return url;
    }

    }

    }

    But as I said. That’s just an idea. I don’t know if it works. And you should definitively use 3.3.3-SNAPSHOT if you want to try this because we recently fixed some interaction issues between URL mappings and rewrite rules.

    #21960

    @chkal,

    Is this something that Rewrite would help with? Aka, PrettyFaces 4, or is this also a problem there? I guess I don’t fully understand the issue yet.

    ~Lincoln

    #21961

    I think this is an issue that Rewrite could solve. Perhaps it has solved it already. I don’t know. :)

    Essentially the problem is that that mappings/rules with path parameters overlap. Like in this example:

    http://twitter.com/signup      <-- Simple mapping without path parameters
    http://twitter.com/login <-- Simple mapping without path parameters
    http://twitter.com/chkal <-- Mapping with path parameter: /#{username}

    The problem here is that whether “chkal” is a valid user name can only be checked at a very late point in time (validation phase).

    Does something like this work in Rewrite?

    #21962

    Ah, well that should work with PrettyFaces as well, but yes, this most definitely works in Rewrite :)

    https://github.com/ocpsoft/socialpm/blob/master/web/src/main/java/com/ocpsoft/socialpm/rewrite/AccessRewriteConfiguration.java

    And…

    https://github.com/ocpsoft/socialpm/blob/master/web/src/main/java/com/ocpsoft/socialpm/rewrite/ProjectRewriteConfiguration.java

    So you can see the order is what matters here, and the usage of the .isRequest() condition.

    This is a fairly complex example, but it shows that it works, and generally how to use many features.

    ~Lincoln

    #21963

    Yeah, I see! Now as I think more about my example I think it should work with both PrettyFaces and Rewrite. You are completely right!

    However if I understood @ceefour correctly, his problem is a bit different. My example was misleading. Let me try to describe another example that is more similar to his use case.

    Imagine the following two mappings:

    /project/#{projectName}
    /user/#{username}

    So you have URLs like:

    /project/prettyfaces
    /user/chkal

    Now what @ceefour is trying to achieve is some kind of composite mapping:

    /#{name}

    Some code has to look into the database and find out if the name identifies a project or a user and then forwards/redirects to the correct URL:

    /chkal        ->    /user/chkal
    /prettyfaces -> /project/prettyfaces

    @ceefour: Is this description correct?

    I think something like this could be implemented with PrettyFaces 3.x either with a custom rewrite processor (like described above) or perhaps using dynaview?

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

You must be logged in to reply to this topic.

Comments are closed.