001// Copyright 2007, 2008, 2012 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 015package org.apache.tapestry5.internal.renderers; 016 017import org.apache.tapestry5.MarkupWriter; 018import org.apache.tapestry5.commons.Location; 019import org.apache.tapestry5.commons.Resource; 020import org.apache.tapestry5.commons.util.CollectionFactory; 021import org.apache.tapestry5.dom.Element; 022import org.apache.tapestry5.ioc.ScopeConstants; 023import org.apache.tapestry5.ioc.annotations.Scope; 024import org.apache.tapestry5.ioc.internal.util.InternalUtils; 025import org.apache.tapestry5.services.ObjectRenderer; 026 027import java.io.*; 028import 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) 036public 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) 091 { 092 writer.getElement().attribute("class", "t-location-current"); 093 } 094 095 writer.write(Integer.toString(current)); 096 writer.end(); 097 098 Element td = writer.element("td", "class", "t-location-content"); 099 100 if (line == current) 101 { 102 td.attribute("class", "t-location-current"); 103 } 104 105 if (start == current) 106 { 107 td.attribute("class", "t-location-content-first"); 108 } 109 110 writer.write(input); 111 writer.end(); 112 113 writer.end(); // tr 114 } 115 116 reader.close(); 117 reader = null; 118 } 119 catch (IOException ex) 120 { 121 writer.write(ex.toString()); 122 } 123 finally 124 { 125 InternalUtils.close(reader); 126 } 127 128 writer.end(); // div 129 } 130}