KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > com > caucho > java > LineMap


1 /*
2  * Copyright (c) 1998-2006 Caucho Technology -- all rights reserved
3  *
4  * This file is part of Resin(R) Open Source
5  *
6  * Each copy or derived work must preserve the copyright notice and this
7  * notice unmodified.
8  *
9  * Resin Open Source is free software; you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation; either version 2 of the License, or
12  * (at your option) any later version.
13  *
14  * Resin Open Source is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, or any warranty
17  * of NON-INFRINGEMENT. See the GNU General Public License for more
18  * details.
19  *
20  * You should have received a copy of the GNU General Public License
21  * along with Resin Open Source; if not, write to the
22  *
23  * Free Software Foundation, Inc.
24  * 59 Temple Place, Suite 330
25  * Boston, MA 02111-1307 USA
26  *
27  * @author Scott Ferguson
28  */

29
30 package com.caucho.java;
31
32 import com.caucho.util.CharBuffer;
33
34 import java.io.CharArrayWriter JavaDoc;
35 import java.io.IOException JavaDoc;
36 import java.io.OutputStream JavaDoc;
37 import java.io.PrintWriter JavaDoc;
38 import java.io.Serializable JavaDoc;
39 import java.util.ArrayList JavaDoc;
40 import java.util.Iterator JavaDoc;
41
42 /**
43  * LineMap maps generated code lines back to the source lines.
44  *
45  * <p>Resin uses LineMap to tell the user the line in the JSP or XSL
46  * file that is broken, as opposed to the generated Java line.
47  */

48 public class LineMap implements Serializable JavaDoc {
49   private String JavaDoc _dstFilename;
50   private String JavaDoc _srcFilename;
51
52   private String JavaDoc _srcType = "JSP";
53   
54   private String JavaDoc _lastSrcFilename;
55   
56   private ArrayList JavaDoc<Line> _lines = new ArrayList JavaDoc<Line>();
57
58   /**
59    * Null-arg constructor for serialization.
60    */

61   public LineMap()
62   {
63   }
64
65   public LineMap(String JavaDoc dstFilename, String JavaDoc srcFilename)
66   {
67     int tail = dstFilename.lastIndexOf('/');
68     if (tail < 0)
69       _dstFilename = dstFilename;
70     else
71       dstFilename = dstFilename.substring(tail + 1);
72     
73     _srcFilename = srcFilename;
74     _lastSrcFilename = _srcFilename;
75   }
76
77   public LineMap(String JavaDoc dstFilename)
78   {
79     int tail = dstFilename.lastIndexOf('/');
80     if (tail < 0)
81       _dstFilename = dstFilename;
82     else
83       _dstFilename = dstFilename.substring(tail + 1);
84   }
85
86   public void setSourceType(String JavaDoc type)
87   {
88     _srcType = type;
89   }
90
91   public String JavaDoc getSourceType()
92   {
93     return _srcType;
94   }
95
96   public String JavaDoc getDestFilename()
97   {
98     return _dstFilename;
99   }
100
101   public String JavaDoc getLastSourceFilename()
102   {
103     return _lastSrcFilename;
104   }
105
106   /**
107    * Adds a new line map entry.
108    *
109    * <p>LineMap assumes that dstLine increases monotonically.
110    *
111    * @param srcFilename the source filename, e.g. the included filename
112    * @param srcLine the source line, e.g. the line in the included file
113    * @param dstLine the line of the generated file.
114    *
115    * @return true if a new entry is needed
116    */

117   public boolean add(String JavaDoc srcFilename, int srcLine, int dstLine)
118   {
119     _lastSrcFilename = srcFilename;
120
121     if (_lines.size() > 0) {
122       Line line = _lines.get(_lines.size() - 1);
123
124       if (line.add(srcFilename, srcLine, dstLine)) {
125     if (_lines.size() > 1) {
126       Line prevLine = _lines.get(_lines.size() - 2);
127
128       if (prevLine.merge(line)) {
129         _lines.remove(_lines.size() - 1);
130       }
131     }
132
133     return true;
134       }
135
136       if (line.getLastDestinationLine() + 1 < dstLine) {
137     _lines.add(new Line(line.getLastSourceLine(),
138                 line.getSourceFilename(),
139                 1,
140                 line.getLastDestinationLine() + 1,
141                 dstLine - line.getLastDestinationLine()));
142       }
143     }
144     
145     _lines.add(new Line(srcFilename, srcLine, dstLine));
146
147     return true;
148   }
149
150   /**
151    * Adds a line from the smap
152    */

153   public void addLine(int startLine, String JavaDoc sourceFile, int repeatCount,
154               int outputLine, int outputIncrement)
155   {
156     _lines.add(new Line(startLine, sourceFile, repeatCount,
157             outputLine, outputIncrement));
158   }
159   
160   public void add(int srcLine, int dstLine)
161   {
162     add(_lastSrcFilename, srcLine, dstLine);
163   }
164
165   public Iterator JavaDoc<Line> iterator()
166   {
167     return _lines.iterator();
168   }
169
170   public int size()
171   {
172     return _lines.size();
173   }
174
175   public Line get(int i)
176   {
177     return _lines.get(i);
178   }
179
180   public Line getLine(int line)
181   {
182     for (int i = 0; i < _lines.size(); i++) {
183       Line map = _lines.get(i);
184
185       if (map._dstLine <= line && line <= map.getLastDestinationLine()) {
186         return map;
187       }
188     }
189
190     return null;
191   }
192
193   /**
194    * Converts an error in the generated file to a CompileError based on
195    * the source.
196    */

197   public String JavaDoc convertError(String JavaDoc filename, int line,
198                  int column, String JavaDoc message)
199   {
200     String JavaDoc srcFilename = null;
201     int destLine = 0;
202     int srcLine = 0;
203     
204     for (int i = 0; i < _lines.size(); i++) {
205       Line map = _lines.get(i);
206
207       if (filename != null && ! filename.endsWith(_dstFilename)) {
208       }
209       else if (map._dstLine <= line && line <= map.getLastDestinationLine()) {
210     srcFilename = map._srcFilename;
211     srcLine = map.getSourceLine(line);
212       }
213     }
214
215     if (srcFilename != null)
216       return srcFilename + ":" + srcLine + ": " + message;
217     else
218       return filename + ":" + line + ": " + message;
219   }
220
221   public String JavaDoc convertLine(String JavaDoc filename, int line)
222   {
223     Line bestLine = getLine(line);
224
225     if (bestLine != null)
226       return bestLine.getSourceFilename() + ":" + bestLine.getSourceLine(line);
227     else
228       return filename + ":" + line;
229   }
230
231   /**
232    * Filter a stack trace, replacing names.
233    */

234   public void printStackTrace(Throwable JavaDoc e, OutputStream JavaDoc os)
235   {
236     CharArrayWriter JavaDoc writer = new CharArrayWriter JavaDoc();
237     PrintWriter JavaDoc pw = new PrintWriter JavaDoc(writer);
238     
239     e.printStackTrace(pw);
240
241     pw.close();
242     char []array = writer.toCharArray();
243
244     CharBuffer cb = filter(array);
245
246     if (os != null) {
247       byte []b = cb.toString().getBytes();
248
249       try {
250     os.write(b, 0, b.length);
251       } catch (IOException JavaDoc e1) {
252       }
253     } else
254       System.out.println(cb);
255   }
256
257   /**
258    * Filter a stack trace, replacing names.
259    */

260   public void printStackTrace(Throwable JavaDoc e, PrintWriter JavaDoc os)
261   {
262     CharArrayWriter JavaDoc writer = new CharArrayWriter JavaDoc();
263     PrintWriter JavaDoc pw = new PrintWriter JavaDoc(writer);
264     
265     e.printStackTrace(pw);
266
267     pw.close();
268     char []array = writer.toCharArray();
269
270     CharBuffer cb = filter(array);
271
272     if (os != null)
273       os.print(cb.toString());
274     else
275       System.out.println(cb);
276   }
277
278   /**
279    * Parses a Java stack trace, converting files and line numbers when
280    * possible.
281    */

282   private CharBuffer filter(char []array)
283   {
284     CharBuffer buf = new CharBuffer();
285     CharBuffer fun = new CharBuffer();
286     CharBuffer file = new CharBuffer();
287
288     int i = 0;
289     while (i < array.length) {
290       fun.clear();
291       file.clear();
292       int start = i;
293       int end;
294       for (end = i; end < array.length && array[end] != '\n'; end++) {
295       }
296
297       for (; i < end && Character.isWhitespace(array[i]); i++) {
298     fun.append(array[i]);
299       }
300
301       // skip 'at'
302
for (; i < end && ! Character.isWhitespace(array[i]); i++) {
303     fun.append(array[i]);
304       }
305
306       if (! fun.endsWith("at")) {
307     for (i = start; i < end; i++) {
308       buf.append(array[i]);
309     }
310     i = end + 1;
311
312     buf.append('\n');
313     
314     continue;
315       }
316
317       for (; i < end && Character.isWhitespace(array[i]); i++) {
318       }
319
320       fun.clear();
321       for (; i < end && ! Character.isWhitespace(array[i]) &&
322          array[i] != '('; i++) {
323     fun.append(array[i]);
324       }
325
326       if (i < end && array[i] == '(')
327     i++;
328
329       for (; i < end && ! Character.isWhitespace(array[i]) &&
330          array[i] != ':' && array[i] != ')'; i++) {
331     file.append(array[i]);
332       }
333       
334       int line = -1;
335       if (i < end && array[i] == ':') {
336     line = 0;
337     for (i++; i < end && array[i] >= '0' && array[i] <= '9'; i++) {
338       line = 10 * line + array[i] - '0';
339     }
340       }
341
342       for (; i < end && ! Character.isWhitespace(array[i]) &&
343          array[i] != ':' && array[i] != ')'; i++) {
344     file.append(array[i]);
345       }
346
347       buf.append("\tat ");
348       buf.append(fun);
349       buf.append("(");
350       String JavaDoc dstFile = file.toString();
351
352       if (dstFile.equals(_dstFilename)) {
353     convertError(buf, line);
354       }
355       else {
356     buf.append(file);
357     if (line > 0) {
358       buf.append(":");
359       buf.append(line);
360     }
361       }
362       buf.append(array, i, end - i);
363       buf.append('\n');
364       i = end + 1;
365     }
366
367     return buf;
368   }
369
370   /**
371    * Maps a destination line to an error location.
372    *
373    * @param buf CharBuffer to write the error location
374    * @param line generated source line to convert.
375    */

376   private void convertError(CharBuffer buf, int line)
377   {
378     String JavaDoc srcFilename = null;
379     int destLine = 0;
380     int srcLine = 0;
381     int srcTailLine = Integer.MAX_VALUE;
382     
383     for (int i = 0; i < _lines.size(); i++) {
384       Line map = (Line) _lines.get(i);
385
386       if (map._dstLine <= line && line <= map.getLastDestinationLine()) {
387     srcFilename = map._srcFilename;
388     destLine = map._dstLine;
389     srcLine = map.getSourceLine(line);
390     break;
391       }
392     }
393
394     if (srcFilename != null) {
395     }
396     else if (_lines.size() > 0)
397       srcFilename = ((Line) _lines.get(0))._srcFilename;
398     else
399       srcFilename = "";
400
401     buf.append(srcFilename);
402     if (line >= 0) {
403       buf.append(":");
404       buf.append(srcLine + (line - destLine));
405     }
406   }
407
408   public static class Line implements Serializable JavaDoc {
409     String JavaDoc _srcFilename;
410     int _srcLine;
411     
412     int _dstLine;
413     int _dstIncrement = 1;
414     
415     int _repeat = 1;
416
417     /**
418      * Constructor for serialization.
419      */

420     public Line()
421     {
422     }
423
424     Line(String JavaDoc srcFilename, int srcLine, int dstLine)
425     {
426       _srcFilename = srcFilename;
427       _srcLine = srcLine;
428       _dstLine = dstLine;
429     }
430
431     Line(int srcLine, String JavaDoc srcFilename, int repeat,
432      int dstLine, int dstIncrement)
433     {
434       _srcFilename = srcFilename;
435       _srcLine = srcLine;
436       _dstLine = dstLine;
437       _repeat = repeat;
438       _dstIncrement = dstIncrement;
439     }
440
441     /**
442      * Tries to add a new location.
443      */

444     boolean add(String JavaDoc srcFilename, int srcLine, int dstLine)
445     {
446       if (_srcFilename != null &&
447       (! _srcFilename.equals(srcFilename) || srcFilename == null))
448     return false;
449
450       // XXX:
451
if (dstLine <= _dstLine) {
452     return true;
453       }
454
455       if (srcLine == _srcLine) {
456     _dstIncrement = dstLine - _dstLine + 1;
457
458     return true;
459       }
460       else if (dstLine - _dstLine == (srcLine - _srcLine) * _dstIncrement) {
461     _repeat = srcLine - _srcLine + 1;
462
463     return true;
464       }
465       else if (srcLine == _srcLine + 1 && _repeat == 1) {
466     _dstIncrement = dstLine - _dstLine;
467
468     return false;
469       }
470       /*
471       else if (_repeat == 1 && _dstIncrement <= 1) {
472     _dstIncrement = dstLine - 1 - _dstLine;
473     if (_dstIncrement < 0)
474       _dstIncrement = 1;
475
476     return true;
477       }
478       */

479
480       return false;
481     }
482
483     /**
484      * Tries to merge two lines
485      */

486     boolean merge(Line next)
487     {
488       if (_srcFilename != null && ! _srcFilename.equals(next._srcFilename))
489     return false;
490
491       else if (_dstIncrement != next._dstIncrement)
492     return false;
493       else if (getLastDestinationLine() + 1 != next._dstLine)
494     return false;
495       else if (getLastSourceLine() + 1 != next._srcLine)
496     return false;
497       else {
498     _repeat += next._repeat;
499
500     return true;
501       }
502     }
503
504     public String JavaDoc getSourceFilename()
505     {
506       return _srcFilename;
507     }
508
509     public int getSourceLine()
510     {
511       return _srcLine;
512     }
513
514     /**
515      * Returns the source line.
516      */

517     public int getSourceLine(int dstLine)
518     {
519       return _srcLine + (dstLine - _dstLine) / _dstIncrement;
520     }
521
522     public int getRepeatCount()
523     {
524       return _repeat;
525     }
526
527     public int getDestinationLine()
528     {
529       return _dstLine;
530     }
531
532     public int getLastSourceLine()
533     {
534       return _srcLine + _repeat - 1;
535     }
536
537     public int getLastDestinationLine()
538     {
539       return _dstLine + _dstIncrement * _repeat - 1;
540     }
541
542     public int getDestinationIncrement()
543     {
544       return _dstIncrement;
545     }
546
547     public String JavaDoc toString()
548     {
549       return "Line[src:" + _srcFilename + ":" + _srcLine + ",dst:" + _dstLine + "]";
550     }
551   }
552 }
553
Popular Tags