001 // Copyright 2005 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.describe; 016 017 import org.apache.hivemind.Location; 018 import org.apache.tapestry.IMarkupWriter; 019 import org.apache.tapestry.IRequestCycle; 020 021 import java.io.*; 022 import java.net.URL; 023 024 /** 025 * Adapter for displaying {@link org.apache.hivemind.Location} objects as 026 * HTML. This may include showing the content of the 027 * {@link org.apache.hivemind.Resource}, with the line indicated in the 028 * Location highlighted. 029 * 030 * @author Howard M. Lewis Ship 031 * @since 4.0 032 */ 033 public class LocationRenderStrategy implements RenderStrategy 034 { 035 036 /** 037 * Lines before and after the actual location to display. 038 */ 039 private static final int RANGE = 5; 040 041 public void renderObject(Object object, IMarkupWriter writer, 042 IRequestCycle cycle) 043 { 044 Location l = (Location) object; 045 046 // Always print out the location as a string. 047 048 writer.print(l.toString()); 049 050 int lineNumber = l.getLineNumber(); 051 052 if (lineNumber < 1) 053 return; 054 055 URL url = l.getResource().getResourceURL(); 056 057 if (url == null) 058 return; 059 060 writeResourceContent(writer, url, lineNumber); 061 } 062 063 private void writeResourceContent(IMarkupWriter writer, URL url, int lineNumber) 064 { 065 LineNumberReader reader = null; 066 067 try 068 { 069 reader = new LineNumberReader(new BufferedReader( new InputStreamReader(url.openStream()))); 070 071 writer.beginEmpty("br"); 072 writer.begin("table"); 073 writer.attribute("class", "location-content"); 074 writer.attribute("cellspacing", "0"); 075 writer.attribute("cellpadding", "0"); 076 077 while(true) 078 { 079 String line = reader.readLine(); 080 081 if (line == null) 082 break; 083 084 int currentLine = reader.getLineNumber(); 085 086 if (currentLine > lineNumber + RANGE) 087 break; 088 089 if (currentLine < lineNumber - RANGE) 090 continue; 091 092 writer.begin("tr"); 093 094 if (currentLine == lineNumber) 095 writer.attribute("class", "target-line"); 096 097 writer.begin("td"); 098 writer.attribute("class", "line-number"); 099 writer.print(currentLine); 100 writer.end(); 101 102 writer.begin("td"); 103 104 // pretty print tabs and spaces properly 105 106 String spacers = extractWhitespaceStart(line); 107 108 if (spacers != null && spacers.length() > 0) 109 { 110 writer.printRaw(spacers); 111 } 112 113 writer.print(line); 114 writer.end("tr"); 115 writer.println(); 116 } 117 118 reader.close(); 119 reader = null; 120 } 121 catch (Exception ex) 122 { 123 // Ignore it. 124 } 125 finally 126 { 127 writer.end("table"); 128 close(reader); 129 } 130 } 131 132 /** 133 * Finds any tab or whitespace characters in the beginning of this string - up 134 * to the first occurrence of normal character data and returns it. 135 * 136 * @param input The string to extract whitespace/tab characters from. 137 * 138 * @return The whitespace/tab characters found, or null if none found. 139 */ 140 String extractWhitespaceStart(String input) 141 { 142 if (input == null || input.length() < 1) 143 return null; 144 145 char[] vals = input.toCharArray(); 146 StringBuffer ret = new StringBuffer(); 147 148 for (int i=0; i < vals.length; i++) 149 { 150 if (Character.isWhitespace(vals[i])) 151 { 152 ret.append(" "); 153 continue; 154 } 155 156 if (vals[i] == '\t') 157 { 158 ret.append(" "); 159 continue; 160 } 161 162 break; 163 } 164 165 return ret.toString(); 166 } 167 168 private void close(Reader reader) 169 { 170 try 171 { 172 if (reader != null) 173 reader.close(); 174 } 175 catch (IOException ex) 176 { 177 // Ignore 178 } 179 } 180 181 }