View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    * 
9    *      http://www.apache.org/licenses/LICENSE-2.0
10   * 
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  
18  package org.apache.struts2.jasper.compiler;
19  
20  import org.apache.struts2.jasper.JspCompilationContext;
21  
22  import java.io.*;
23  import java.util.ArrayList;
24  import java.util.List;
25  
26  /***
27   * Class providing details about a javac compilation error.
28   *
29   * @author Jan Luehe
30   * @author Kin-man Chung
31   */
32  public class JavacErrorDetail {
33  
34      private String javaFileName;
35      private int javaLineNum;
36      private String jspFileName;
37      private int jspBeginLineNum;
38      private StringBuffer errMsg;
39      private String jspExtract = null;
40  
41      /***
42       * Constructor.
43       *
44       * @param javaFileName The name of the Java file in which the
45       *                     compilation error occurred
46       * @param javaLineNum  The compilation error line number
47       * @param errMsg       The compilation error message
48       */
49      public JavacErrorDetail(String javaFileName,
50                              int javaLineNum,
51                              StringBuffer errMsg) {
52  
53          this.javaFileName = javaFileName;
54          this.javaLineNum = javaLineNum;
55          this.errMsg = errMsg;
56          this.jspBeginLineNum = -1;
57      }
58  
59      /***
60       * Constructor.
61       *
62       * @param javaFileName    The name of the Java file in which the
63       *                        compilation error occurred
64       * @param javaLineNum     The compilation error line number
65       * @param jspFileName     The name of the JSP file from which the Java source
66       *                        file was generated
67       * @param jspBeginLineNum The start line number of the JSP element
68       *                        responsible for the compilation error
69       * @param errMsg          The compilation error message
70       */
71      public JavacErrorDetail(String javaFileName,
72                              int javaLineNum,
73                              String jspFileName,
74                              int jspBeginLineNum,
75                              StringBuffer errMsg) {
76  
77          this(javaFileName, javaLineNum, jspFileName, jspBeginLineNum, errMsg,
78                  null);
79      }
80  
81      public JavacErrorDetail(String javaFileName,
82                              int javaLineNum,
83                              String jspFileName,
84                              int jspBeginLineNum,
85                              StringBuffer errMsg,
86                              JspCompilationContext ctxt) {
87          this(javaFileName, javaLineNum, errMsg);
88          this.jspFileName = jspFileName;
89          this.jspBeginLineNum = jspBeginLineNum;
90  
91          if (jspBeginLineNum > 0 && ctxt != null) {
92              InputStream is = null;
93              FileInputStream fis = null;
94              try {
95                  // Read both files in, so we can inspect them
96                  is = ctxt.getResourceAsStream(jspFileName);
97                  String[] jspLines = readFile(is);
98  
99                  fis = new FileInputStream(ctxt.getServletJavaFileName());
100                 String[] javaLines = readFile(fis);
101 
102                 // If the line contains the opening of a multi-line scriptlet
103                 // block, then the JSP line number we got back is probably
104                 // faulty.  Scan forward to match the java line...
105                 if (jspLines[jspBeginLineNum - 1].lastIndexOf("<%") >
106                         jspLines[jspBeginLineNum - 1].lastIndexOf("%>")) {
107                     String javaLine = javaLines[javaLineNum - 1].trim();
108 
109                     for (int i = jspBeginLineNum - 1; i < jspLines.length; i++) {
110                         if (jspLines[i].indexOf(javaLine) != -1) {
111                             // Update jsp line number
112                             this.jspBeginLineNum = i + 1;
113                             break;
114                         }
115                     }
116                 }
117 
118                 // copy out a fragment of JSP to display to the user
119                 StringBuffer fragment = new StringBuffer(1024);
120                 int startIndex = Math.max(0, this.jspBeginLineNum - 1 - 3);
121                 int endIndex = Math.min(
122                         jspLines.length - 1, this.jspBeginLineNum - 1 + 3);
123 
124                 for (int i = startIndex; i <= endIndex; ++i) {
125                     fragment.append(i + 1);
126                     fragment.append(": ");
127                     fragment.append(jspLines[i]);
128                     fragment.append("\n");
129                 }
130                 jspExtract = fragment.toString();
131 
132             } catch (IOException ioe) {
133                 // Can't read files - ignore
134             } finally {
135                 if (is != null) {
136                     try {
137                         is.close();
138                     } catch (IOException ioe) {
139                         // Ignore
140                     }
141                 }
142                 if (fis != null) {
143                     try {
144                         fis.close();
145                     } catch (IOException ioe) {
146                         // Ignore
147                     }
148                 }
149             }
150         }
151 
152     }
153 
154     /***
155      * Gets the name of the Java source file in which the compilation error
156      * occurred.
157      *
158      * @return Java source file name
159      */
160     public String getJavaFileName() {
161         return this.javaFileName;
162     }
163 
164     /***
165      * Gets the compilation error line number.
166      *
167      * @return Compilation error line number
168      */
169     public int getJavaLineNumber() {
170         return this.javaLineNum;
171     }
172 
173     /***
174      * Gets the name of the JSP file from which the Java source file was
175      * generated.
176      *
177      * @return JSP file from which the Java source file was generated.
178      */
179     public String getJspFileName() {
180         return this.jspFileName;
181     }
182 
183     /***
184      * Gets the start line number (in the JSP file) of the JSP element
185      * responsible for the compilation error.
186      *
187      * @return Start line number of the JSP element responsible for the
188      *         compilation error
189      */
190     public int getJspBeginLineNumber() {
191         return this.jspBeginLineNum;
192     }
193 
194     /***
195      * Gets the compilation error message.
196      *
197      * @return Compilation error message
198      */
199     public String getErrorMessage() {
200         return this.errMsg.toString();
201     }
202 
203     /***
204      * Gets the extract of the JSP that corresponds to this message.
205      *
206      * @return Extract of JSP where error occurred
207      */
208     public String getJspExtract() {
209         return this.jspExtract;
210     }
211 
212     /***
213      * Reads a text file from an input stream into a String[]. Used to read in
214      * the JSP and generated Java file when generating error messages.
215      */
216     private String[] readFile(InputStream s) throws IOException {
217         BufferedReader reader = new BufferedReader(new InputStreamReader(s));
218         List lines = new ArrayList();
219         String line;
220 
221         while ((line = reader.readLine()) != null) {
222             lines.add(line);
223         }
224 
225         return (String[]) lines.toArray(new String[lines.size()]);
226     }
227 }