You are viewing a plain text version of this content. The canonical link for it is here.
Posted to issues@tiles.apache.org by "Mck SembWever (JIRA)" <ji...@apache.org> on 2013/05/27 09:12:23 UTC

[jira] [Commented] (TILES-569) Proposal for conditionals in tiles definitions

    [ https://issues.apache.org/jira/browse/TILES-569?page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel&focusedCommentId=13667507#comment-13667507 ] 

Mck SembWever commented on TILES-569:
-------------------------------------

{quote}I've recently tried the OptionsRenderer suggested in this tutorial http://tech.finn.no/2012/07/25/the-ultimate-view-tiles-3/4/, but wasn't able to succeed. The defined attributes wasn't available for some reason.{quote}

Marc,
 please post this, with a little more info, on the users list and i'll give you the help you need to get things working as they should.
                
> Proposal for conditionals in tiles definitions
> ----------------------------------------------
>
>                 Key: TILES-569
>                 URL: https://issues.apache.org/jira/browse/TILES-569
>             Project: Tiles
>          Issue Type: Improvement
>          Components: tiles-core
>    Affects Versions: 3.0.1
>            Reporter: Marc Ewert
>
> Hi,
> I've recently tried the OptionsRenderer suggested in this tutorial [http://tech.finn.no/2012/07/25/the-ultimate-view-tiles-3/4/], but wasn't able to succeed. The defined attributes wasn't available for some reason.
> So I took the idea and implemented my own solution. Perhaps it's something for the trunk? My syntax is as follows:
> {code}
> <tiles-definitions>
> 	<definition name="main/*/*" template="/WEB-INF/tiles/_layout/main.jsp">
> 	    <put-attribute name="title" value="/WEB-INF/tiles/[{1}/{2}|{1}|_common]/title.jsp"/>
> 	    <put-attribute name="navigation" value="/WEB-INF/tiles/[{1}/{2}|{1}|_common]/navigation.jsp"/>
> 	    <put-attribute name="content" value="/WEB-INF/tiles/[{1}/{2}|{1}|_common]/content.jsp"/>
> 	    <put-attribute name="footer" value="/WEB-INF/tiles/[{1}/{2}|{1}|_common]/footer.jsp"/>
> 	    <put-attribute name="javaScript" value="/WEB-INF/tiles/[{1}/{2}|{1}|_common]/javaScript.jsp"/>
> 	</definition>
> </tiles-definitions>
> {code}
> The renderer searches for patterns like [opt_1|opt_2|...|opt_n] which may occur several times in the value partameters. With a backtrack algorithm the first matching valid path is searched and rendered.
> I like the compactness of the notation, no need for attribute lists, which didn't function in my case.
> Here is my renderer implementation, perhaps you are interested in integrating it. The path evaluation eventually has to be refactored. I don't know if there is a more elegant way and how costly the current solution is. Perhaps there has to be done some caching...
> {code}
> /**
>  * Renderer implementation supporting the notation "[CHOICE_1|...|CHOICE_n]" in the paths.
>  * The first matching path replacement will be choosen. 
>  */
> public final class ChoiceRenderer implements Renderer {
>     private static final Pattern CHOICE_PATTERN = Pattern.compile("\\[([^\\]]+)\\]");
>     private final Renderer renderer;
>     /**
>      * Creates a new instance wrapping the given renderer.
>      */
>     public ChoiceRenderer(Renderer renderer) {
>         this.renderer = renderer;
>     }
>     /**
>      * @see org.apache.tiles.request.render.Renderer#isRenderable(java.lang.String, org.apache.tiles.request.Request)
>      */
>     @Override
>     public boolean isRenderable(String path, Request request) {
>         // only the overall format is checked, so no extra handling here
>         return this.renderer.isRenderable(path, request);
>     }
>     /**
>      * @see org.apache.tiles.request.render.Renderer#render(java.lang.String, org.apache.tiles.request.Request)
>      */
>     @Override
>     public void render(String path, Request request) throws IOException {
>         Matcher matcher = CHOICE_PATTERN.matcher(path);
>         List<String[]> groups = new ArrayList<String[]>();
>         StringBuffer sb = new StringBuffer();
>         while (matcher.find()) {
>             // adds a pattern to the resulting path, which will be replaced by the
>             // available choices
>             matcher.appendReplacement(sb, "{[" + groups.size() + "]}");
>             groups.add(matcher.group(1).split("\\|"));
>         }
>         matcher.appendTail(sb);
>         if (groups.isEmpty()) {
>             this.renderer.render(path, request);
>         } else {
>             backtrackPaths(sb.toString(), request, groups, 0);
>         }
>     }
>     private String backtrackPaths(String pathPattern, Request request, List<String[]> groups, int depth)
>             throws IOException {
>         String matchPath = null;
>         String[] parts = groups.get(depth);
>         for (int i = 0; i < parts.length; ++i) {
>             String path = pathPattern.replace("{[" + depth + "]}", parts[i]);
>             if (depth == groups.size() - 1) {
>                 if (isPathValid(path, request)) {
>                     // found the first matching choice
>                     this.renderer.render(path, request);
>                     matchPath = path;
>                     break;
>                 }
>             } else {
>                 matchPath = backtrackPaths(path, request, groups, depth + 1);
>             }
>         }
>         return matchPath;
>     }
>     // TODO should we use caching here?
>     private boolean isPathValid(String path, Request request) {
>         boolean rtn = false;
>         // apparently the corresponding Renderer method seems to check the
>         // path's format only
>         if (this.renderer.isRenderable(path, request)) {
>             try {
>                 rtn = request.getApplicationContext().getResource(path) != null;
>             } catch (IllegalArgumentException e) {
>                 // TODO the javadoc states that null will be returned, but
>                 // instead of it an exception is thrown.
>                 // Seems to be a bug?!
>                 boolean throwException = true;
>                 if (e.getCause() instanceof FileNotFoundException) {
>                     FileNotFoundException fex = (FileNotFoundException) e.getCause();
>                     throwException = fex.getMessage().indexOf(path) == -1;
>                 }
>                 if (throwException) {
>                     // seems to be a different reason as our searched path
>                     throw e;
>                 }
>             }
>         }
>         return rtn;
>     }
> }
> {code}

--
This message is automatically generated by JIRA.
If you think it was sent incorrectly, please contact your JIRA administrators
For more information on JIRA, see: http://www.atlassian.com/software/jira