    001    // Copyright 2007, 2008 The Apache Software Foundation
    002    //
    003    // Licensed under the Apache License, Version 2.0 (the "License");
    004    // you may not use this file except in compliance with the License.
    005    // You may obtain a copy of the License at
    006    //
    007    //     http://www.apache.org/licenses/LICENSE-2.0
    008    //
    009    // Unless required by applicable law or agreed to in writing, software
    010    // distributed under the License is distributed on an "AS IS" BASIS,
    011    // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    012    // See the License for the specific language governing permissions and
    013    // limitations under the License.
    014
    015    package org.apache.tapestry5.internal.renderers;
    016
    017    import org.apache.tapestry5.MarkupWriter;
    018    import org.apache.tapestry5.dom.Element;
    019    import org.apache.tapestry5.ioc.Location;
    020    import org.apache.tapestry5.ioc.Resource;
    021    import org.apache.tapestry5.ioc.ScopeConstants;
    022    import org.apache.tapestry5.ioc.annotations.Scope;
    023    import org.apache.tapestry5.ioc.internal.util.CollectionFactory;
    024    import org.apache.tapestry5.ioc.internal.util.InternalUtils;
    025    import org.apache.tapestry5.services.ObjectRenderer;
    026
    027    import java.io.*;
    028    import java.util.Set;
    029
    030    /**
    031     * Responsible for rendering a {@link Location}. It is designed to only perform the full output (which includes a
    032     * snippet of the source file) once per render. This requires the use of the "perthread" scope (since the service
    033     * tracks, internally, which locations have already been rendered, to avoid repetition).
    034     */
    035    @Scope(ScopeConstants.PERTHREAD)
    036    public class LocationRenderer implements ObjectRenderer<Location>
    037    {
    038        private static final int RANGE = 5;
    039
    040        private final Set<Location> rendered = CollectionFactory.newSet();
    041
    042        public void render(Location location, MarkupWriter writer)
    043        {
    044            writer.write(location.toString());
    045
    046            /** If the full details were already rendered this request, then skip the rest. */
    047            if (rendered.contains(location)) return;
    048
    049            rendered.add(location);
    050
    051            Resource r = location.getResource();
    052            int line = location.getLine();
    053
    054            // No line number? then nothing more to render.
    055
    056            if (line <= 0) return;
    057
    058            if (!r.exists()) return;
    059
    060
    061            int start = line - RANGE;
    062            int end = line + RANGE;
    063
    064            writer.element("table", "class", "t-location-outer");
    065
    066            LineNumberReader reader = null;
    067
    068            try
    069            {
    070                InputStream is = r.openStream();
    071                InputStreamReader isr = new InputStreamReader(is);
    072                reader = new LineNumberReader(new BufferedReader(isr));
    073
    074                while (true)
    075                {
    076                    String input = reader.readLine();
    077
    078                    if (input == null) break;
    079
    080                    int current = reader.getLineNumber();
    081
    082                    if (current < start) continue;
    083
    084                    if (current > end) break;
    085
    086                    writer.element("tr");
    087
    088                    writer.element("td", "class", "t-location-line");
    089
    090                    if (line == current) writer.getElement().addClassName("t-location-current");
    091
    092                    writer.write(Integer.toString(current));
    093                    writer.end();
    094
    095                    Element td = writer.element("td", "class", "t-location-content");
    096
    097                    if (line == current) td.addClassName("t-location-current");
    098
    099                    if (start == current) td.addClassName("t-location-content-first");
    100
    101                    writer.write(input);
    102                    writer.end();
    103
    104                    writer.end(); // tr
    105                }
    106
    107                reader.close();
    108                reader = null;
    109            }
    110            catch (IOException ex)
    111            {
    112                writer.write(ex.toString());
    113            }
    114            finally
    115            {
    116                InternalUtils.close(reader);
    117            }
    118
    119            writer.end(); // div
    120        }
    121    }