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  package org.apache.struts2.jasper.compiler;
18  
19  import org.apache.struts2.jasper.JspCompilationContext;
20  
21  import java.net.MalformedURLException;
22  import java.net.URL;
23  import java.util.Stack;
24  
25  /***
26   * Mark represents a point in the JSP input.
27   *
28   * @author Anil K. Vijendran
29   */
30  final class Mark {
31  
32      // position within current stream
33      int cursor, line, col;
34  
35      // directory of file for current stream
36      String baseDir;
37  
38      // current stream
39      char[] stream = null;
40  
41      // fileid of current stream
42      private int fileId;
43  
44      // name of the current file
45      private String fileName;
46  
47      /*
48       * stack of stream and stream state of streams that have included
49       * current stream
50       */
51      private Stack includeStack = null;
52  
53      // encoding of current file
54      private String encoding = null;
55  
56      // reader that owns this mark (so we can look up fileid's)
57      private JspReader reader;
58  
59      private JspCompilationContext ctxt;
60  
61      /***
62       * Constructor
63       *
64       * @param reader     JspReader this mark belongs to
65       * @param inStream   current stream for this mark
66       * @param fileId     id of requested jsp file
67       * @param name       JSP file name
68       * @param inBaseDir  base directory of requested jsp file
69       * @param inEncoding encoding of current file
70       */
71      Mark(JspReader reader, char[] inStream, int fileId, String name,
72           String inBaseDir, String inEncoding) {
73  
74          this.reader = reader;
75          this.ctxt = reader.getJspCompilationContext();
76          this.stream = inStream;
77          this.cursor = 0;
78          this.line = 1;
79          this.col = 1;
80          this.fileId = fileId;
81          this.fileName = name;
82          this.baseDir = inBaseDir;
83          this.encoding = inEncoding;
84          this.includeStack = new Stack();
85      }
86  
87  
88      /***
89       * Constructor
90       */
91      Mark(Mark other) {
92  
93          this.reader = other.reader;
94          this.ctxt = other.reader.getJspCompilationContext();
95          this.stream = other.stream;
96          this.fileId = other.fileId;
97          this.fileName = other.fileName;
98          this.cursor = other.cursor;
99          this.line = other.line;
100         this.col = other.col;
101         this.baseDir = other.baseDir;
102         this.encoding = other.encoding;
103 
104         // clone includeStack without cloning contents
105         includeStack = new Stack();
106         for (int i = 0; i < other.includeStack.size(); i++) {
107             includeStack.addElement(other.includeStack.elementAt(i));
108         }
109     }
110 
111 
112     /***
113      * Constructor
114      */
115     Mark(JspCompilationContext ctxt, String filename, int line, int col) {
116 
117         this.reader = null;
118         this.ctxt = ctxt;
119         this.stream = null;
120         this.cursor = 0;
121         this.line = line;
122         this.col = col;
123         this.fileId = -1;
124         this.fileName = filename;
125         this.baseDir = "le-basedir";
126         this.encoding = "le-endocing";
127         this.includeStack = null;
128     }
129 
130 
131     /***
132      * Sets this mark's state to a new stream.
133      * It will store the current stream in it's includeStack.
134      *
135      * @param inStream   new stream for mark
136      * @param inFileId   id of new file from which stream comes from
137      * @param inBaseDir  directory of file
138      * @param inEncoding encoding of new file
139      */
140     public void pushStream(char[] inStream, int inFileId, String name,
141                            String inBaseDir, String inEncoding) {
142         // store current state in stack
143         includeStack.push(new IncludeState(cursor, line, col, fileId,
144                 fileName, baseDir,
145                 encoding, stream));
146 
147         // set new variables
148         cursor = 0;
149         line = 1;
150         col = 1;
151         fileId = inFileId;
152         fileName = name;
153         baseDir = inBaseDir;
154         encoding = inEncoding;
155         stream = inStream;
156     }
157 
158 
159     /***
160      * Restores this mark's state to a previously stored stream.
161      *
162      * @return The previous Mark instance when the stream was pushed, or null
163      *         if there is no previous stream
164      */
165     public Mark popStream() {
166         // make sure we have something to pop
167         if (includeStack.size() <= 0) {
168             return null;
169         }
170 
171         // get previous state in stack
172         IncludeState state = (IncludeState) includeStack.pop();
173 
174         // set new variables
175         cursor = state.cursor;
176         line = state.line;
177         col = state.col;
178         fileId = state.fileId;
179         fileName = state.fileName;
180         baseDir = state.baseDir;
181         stream = state.stream;
182         return this;
183     }
184 
185 
186     // -------------------- Locator interface --------------------
187 
188     public int getLineNumber() {
189         return line;
190     }
191 
192     public int getColumnNumber() {
193         return col;
194     }
195 
196     public String getSystemId() {
197         return getFile();
198     }
199 
200     public String getPublicId() {
201         return null;
202     }
203 
204     public String toString() {
205         return getFile() + "(" + line + "," + col + ")";
206     }
207 
208     public String getFile() {
209         return this.fileName;
210     }
211 
212     /***
213      * Gets the URL of the resource with which this Mark is associated
214      *
215      * @return URL of the resource with which this Mark is associated
216      * @throws MalformedURLException if the resource pathname is incorrect
217      */
218     public URL getURL() throws MalformedURLException {
219         return ctxt.getResource(getFile());
220     }
221 
222     public String toShortString() {
223         return "(" + line + "," + col + ")";
224     }
225 
226     public boolean equals(Object other) {
227         if (other instanceof Mark) {
228             Mark m = (Mark) other;
229             return this.reader == m.reader && this.fileId == m.fileId
230                     && this.cursor == m.cursor && this.line == m.line
231                     && this.col == m.col;
232         }
233         return false;
234     }
235 
236     /***
237      * @return true if this Mark is greather than the <code>other</code>
238      *         Mark, false otherwise.
239      */
240     public boolean isGreater(Mark other) {
241 
242         boolean greater = false;
243 
244         if (this.line > other.line) {
245             greater = true;
246         } else if (this.line == other.line && this.col > other.col) {
247             greater = true;
248         }
249 
250         return greater;
251     }
252 
253     /***
254      * Keep track of parser before parsing an included file.
255      * This class keeps track of the parser before we switch to parsing an
256      * included file. In other words, it's the parser's continuation to be
257      * reinstalled after the included file parsing is done.
258      */
259     class IncludeState {
260         int cursor, line, col;
261         int fileId;
262         String fileName;
263         String baseDir;
264         String encoding;
265         char[] stream = null;
266 
267         IncludeState(int inCursor, int inLine, int inCol, int inFileId,
268                      String name, String inBaseDir, String inEncoding,
269                      char[] inStream) {
270             cursor = inCursor;
271             line = inLine;
272             col = inCol;
273             fileId = inFileId;
274             fileName = name;
275             baseDir = inBaseDir;
276             encoding = inEncoding;
277             stream = inStream;
278         }
279     }
280 
281 }
282