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 }