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 }