001: // Copyright 2007 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.tapestry.internal.services;
016:
017: import static org.apache.tapestry.ioc.IOCConstants.PERTHREAD_SCOPE;
018: import static org.apache.tapestry.ioc.internal.util.CollectionFactory.newSet;
019:
020: import java.io.BufferedInputStream;
021: import java.io.BufferedReader;
022: import java.io.IOException;
023: import java.io.InputStream;
024: import java.io.InputStreamReader;
025: import java.io.LineNumberReader;
026: import java.net.URL;
027: import java.util.Set;
028:
029: import org.apache.tapestry.MarkupWriter;
030: import org.apache.tapestry.internal.TapestryInternalUtils;
031: import org.apache.tapestry.ioc.Location;
032: import org.apache.tapestry.ioc.Resource;
033: import org.apache.tapestry.ioc.annotations.Scope;
034: import org.apache.tapestry.services.ObjectRenderer;
035:
036: /**
037: * Responsible for rendering a {@link Location}. It is designed to only perform the full output
038: * (which includes a snippet of the source file) once per render. This requires the use of the
039: * "perthread" scope (since the service tracks, internally, which locations have already been
040: * rendered, to avoid repetition).
041: */
042: @Scope(PERTHREAD_SCOPE)
043: public class LocationRenderer implements ObjectRenderer<Location> {
044: private static final int RANGE = 5;
045:
046: private final Set<Location> _rendered = newSet();
047:
048: public void render(Location location, MarkupWriter writer) {
049: writer.write(location.toString());
050:
051: /** If the full details were already rendered this request, then skip the rest. */
052: if (_rendered.contains(location))
053: return;
054:
055: _rendered.add(location);
056:
057: Resource r = location.getResource();
058: int line = location.getLine();
059:
060: // No line number? then nothing more to render.
061:
062: if (line <= 0)
063: return;
064:
065: URL url = r.toURL();
066:
067: if (url == null)
068: return;
069:
070: int start = line - RANGE;
071: int end = line + RANGE;
072:
073: writer.element("table", "class", "t-location-outer");
074:
075: LineNumberReader reader = null;
076:
077: try {
078: InputStream is = new BufferedInputStream(url.openStream());
079: InputStreamReader isr = new InputStreamReader(is);
080: reader = new LineNumberReader(new BufferedReader(isr));
081:
082: while (true) {
083: String input = reader.readLine();
084:
085: if (input == null)
086: break;
087:
088: int current = reader.getLineNumber();
089:
090: if (current < start)
091: continue;
092:
093: if (current > end)
094: break;
095:
096: writer.element("tr");
097:
098: writer.element("td");
099: writer
100: .attributes(
101: "class",
102: line == current ? "t-location-line t-location-current"
103: : "t-location-line");
104: writer.write(Integer.toString(current));
105: writer.end();
106:
107: String css = "t-location-content";
108: if (line == current)
109: css += " t-location-current";
110: if (start == current)
111: css += " t-location-content-first";
112:
113: writer.element("td");
114: writer.attributes("class", css);
115: writer.write(input);
116: writer.end();
117:
118: writer.end(); // tr
119: }
120:
121: reader.close();
122: reader = null;
123: } catch (IOException ex) {
124: writer.write(ex.toString());
125: } finally {
126: TapestryInternalUtils.close(reader);
127: }
128:
129: writer.end(); // div
130: }
131:
132: }
|