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("&nbsp;");
153                    continue;
154                }
155    
156                if (vals[i] == '\t')
157                {
158                    ret.append("&nbsp;&nbsp;");
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    }