001: /*
002: * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS HEADER.
003: *
004: * Copyright 1997-2007 Sun Microsystems, Inc. All rights reserved.
005: *
006: * The contents of this file are subject to the terms of either the GNU
007: * General Public License Version 2 only ("GPL") or the Common
008: * Development and Distribution License("CDDL") (collectively, the
009: * "License"). You may not use this file except in compliance with the
010: * License. You can obtain a copy of the License at
011: * http://www.netbeans.org/cddl-gplv2.html
012: * or nbbuild/licenses/CDDL-GPL-2-CP. See the License for the
013: * specific language governing permissions and limitations under the
014: * License. When distributing the software, include this License Header
015: * Notice in each file and include the License file at
016: * nbbuild/licenses/CDDL-GPL-2-CP. Sun designates this
017: * particular file as subject to the "Classpath" exception as provided
018: * by Sun in the GPL Version 2 section of the License file that
019: * accompanied this code. If applicable, add the following below the
020: * License Header, with the fields enclosed by brackets [] replaced by
021: * your own identifying information:
022: * "Portions Copyrighted [year] [name of copyright owner]"
023: *
024: * Contributor(s):
025: *
026: * The Original Software is NetBeans. The Initial Developer of the Original
027: * Software is Sun Microsystems, Inc. Portions Copyright 1997-2007 Sun
028: * Microsystems, Inc. All Rights Reserved.
029: *
030: * If you wish your version of this file to be governed by only the CDDL
031: * or only the GPL Version 2, indicate your decision by adding
032: * "[Contributor] elects to include this software in this distribution
033: * under the [CDDL or GPL Version 2] license." If you do not indicate a
034: * single choice of license, a recipient has the option to distribute
035: * your version of this file under either the CDDL, the GPL Version 2 or
036: * to extend the choice of license to its licensees as provided above.
037: * However, if you add GPL Version 2 code and therefore, elected the GPL
038: * Version 2 license, then the option applies only if the new code is
039: * made subject to such option by the copyright holder.
040: */
041:
042: /*
043: * File : REJavaParser.java
044: * Created on : Nov 4, 2003
045: * Author : aztec
046: */
047: package org.netbeans.modules.uml.core.reverseengineering.parsers.javaparser;
048:
049: import java.io.BufferedReader;
050: import java.io.FileNotFoundException;
051: import java.io.FileInputStream;
052: import java.io.InputStreamReader;
053: import java.io.IOException;
054: import java.io.StringReader;
055: import java.io.UnsupportedEncodingException;
056: import java.nio.charset.Charset;
057:
058: import org.dom4j.Node;
059:
060: import antlr.ANTLRException;
061: import antlr.CharBuffer;
062: import antlr.CommonHiddenStreamToken;
063: import antlr.RecognitionException;
064: import antlr.TokenStreamHiddenTokenFilter;
065: import antlr.CommonASTWithLocationsAndHidden;
066:
067: import org.netbeans.modules.uml.core.reverseengineering.reframework.IParserData;
068: import org.netbeans.modules.uml.core.reverseengineering.reframework.IREOperation;
069: import org.netbeans.modules.uml.core.reverseengineering.reframework.parsingframework.CommentGather;
070: import org.netbeans.modules.uml.core.reverseengineering.reframework.parsingframework.IErrorListener;
071: import org.netbeans.modules.uml.core.reverseengineering.reframework.parsingframework.IStateFilter;
072: import org.netbeans.modules.uml.core.reverseengineering.reframework.parsingframework.IStateListener;
073: import org.netbeans.modules.uml.core.reverseengineering.reframework.parsingframework.ITokenDescriptor;
074: import org.netbeans.modules.uml.core.reverseengineering.reframework.parsingframework.ITokenFilter;
075: import org.netbeans.modules.uml.core.reverseengineering.reframework.parsingframework.ITokenProcessor;
076: import org.netbeans.modules.uml.core.reverseengineering.reframework.parsingframework.ParserEventController;
077: import org.netbeans.modules.uml.core.reverseengineering.reframework.parsingframework.ProcessTypeKind;
078:
079: /**
080: * @author aztec
081: */
082: public class REJavaParser implements IREJavaParser {
083: private ParserEventController m_EventController = new ParserEventController(
084: new CommentGather(JavaTokenTypes.SL_COMMENT,
085: JavaTokenTypes.ML_COMMENT), "Java");
086:
087: private String m_Filename;
088:
089: /* (non-Javadoc)
090: * @see org.netbeans.modules.uml.core.reverseengineering.parsers.javaparser.IREJavaParser#notifyPackageEvent(org.dom4j.Node)
091: */
092: public void notifyPackageEvent(Node eventData) {
093: // Missing in C++ code.
094: }
095:
096: /* (non-Javadoc)
097: * @see org.netbeans.modules.uml.core.reverseengineering.parsers.javaparser.IREJavaParser#notifyDependencyEvent(org.dom4j.Node)
098: */
099: public void notifyDependencyEvent(Node eventData) {
100: // Missing in C++ code.
101: }
102:
103: /* (non-Javadoc)
104: * @see org.netbeans.modules.uml.core.reverseengineering.parsers.javaparser.IREJavaParser#notifyClassEvent(org.dom4j.Node)
105: */
106: public void notifyClassEvent(Node eventData) {
107: // Missing in C++ code.
108: }
109:
110: /* (non-Javadoc)
111: * @see org.netbeans.modules.uml.core.reverseengineering.parsers.javaparser.IREJavaParser#notifyActionEvent(org.dom4j.Node)
112: */
113: public void notifyActionEvent(Node eventData) {
114: // Missing in C++ code.
115: }
116:
117: /* (non-Javadoc)
118: * @see org.netbeans.modules.uml.core.reverseengineering.parsers.javaparser.IREJavaParser#notifyError(antlr.RecognitionException)
119: */
120: public void notifyError(RecognitionException e) {
121: // Missing in C++ code.
122: }
123:
124: /* (non-Javadoc)
125: * @see org.netbeans.modules.uml.core.reverseengineering.reframework.parsingframework.ILanguageParser#parseFile(java.lang.String, java.lang.String)
126: */
127: public void parseFile(String filename, String charset) {
128: try {
129: InputStreamReader reader = null;
130: if (charset != null) {
131: try {
132: reader = new InputStreamReader(new FileInputStream(
133: filename), charset);
134: } catch (UnsupportedEncodingException uee) {
135: // catch it here thus giving chance
136: // to default charset version below
137: }
138: }
139: if (reader == null) {
140: reader = new InputStreamReader(new FileInputStream(
141: filename));
142: }
143: BufferedReader bufr = new BufferedReader(reader);
144: CharBuffer buffer = new CharBuffer(bufr);
145: processStreamAsFile(buffer, filename);
146: bufr.close();
147: reader.close();
148: } catch (FileNotFoundException e) {
149: e.printStackTrace();
150: } catch (IOException e) {
151: e.printStackTrace();
152: }
153: }
154:
155: /* (non-Javadoc)
156: * @see org.netbeans.modules.uml.core.reverseengineering.reframework.parsingframework.ILanguageParser#parseFile(java.lang.String)
157: */
158: public void parseFile(String filename) {
159: parseFile(filename, null);
160: }
161:
162: /* (non-Javadoc)
163: * @see org.netbeans.modules.uml.core.reverseengineering.reframework.parsingframework.ILanguageParser#parseOperation(java.lang.String, java.lang.String, org.netbeans.modules.uml.core.reverseengineering.reframework.IREOperation)
164: */
165: public void parseOperation(String filename, String charset,
166: IREOperation operation) {
167: if (filename != null && operation != null) {
168: // Now that I have the parser I can create a OperationBuffer and
169: // give it to the parser to start parsing.
170: long start = getPosition(operation, "StartPosition"), end = getPosition(
171: operation, "EndPosition");
172: // This is non-ideal, but easier than creating a constrained Reader
173: // AZTEC. TODO: Fix this to use a constrained Reader so that we
174: // don't introduce a memory bottleneck here.
175: String text = extractText(filename, charset, (int) start,
176: (int) end);
177: StringReader read = new StringReader(text);
178: CharBuffer buf = new CharBuffer(read);
179: processStreamAsFragment(buf, filename);
180: }
181: }
182:
183: /* (non-Javadoc)
184: * @see org.netbeans.modules.uml.core.reverseengineering.reframework.parsingframework.ILanguageParser#parseOperation(java.lang.String, org.netbeans.modules.uml.core.reverseengineering.reframework.IREOperation)
185: */
186: public void parseOperation(String filename, IREOperation operation) {
187: parseOperation(filename, null, operation);
188: }
189:
190: private long getPosition(IParserData data, String tagname) {
191: long pos = -1;
192:
193: ITokenDescriptor desc = data.getTokenDescriptor(tagname);
194: if (desc != null && tagname.equals(desc.getType())) {
195: pos = desc.getPosition();
196: if ("EndPosition".equals(tagname))
197: pos += desc.getLength();
198: }
199: return pos;
200: }
201:
202: private String extractText(String filename, String charset,
203: int start, int end) {
204: if (end < start)
205: return null;
206:
207: try {
208: InputStreamReader reader = null;
209: if (charset != null) {
210: try {
211: reader = new InputStreamReader(new FileInputStream(
212: filename), charset);
213: } catch (UnsupportedEncodingException uee) {
214: // catch it here thus giving chance
215: // to default charset version below
216: }
217: }
218: if (reader == null) {
219: reader = new InputStreamReader(new FileInputStream(
220: filename));
221: }
222: BufferedReader bufr = new BufferedReader(reader);
223: bufr.skip(start);
224:
225: char[] readc = new char[end - start];
226: int readchars = bufr.read(readc);
227: bufr.close();
228: reader.close();
229: return new String(readc, 0, readchars);
230: } catch (Exception e) {
231: e.printStackTrace();
232: }
233: return null;
234: }
235:
236: /**
237: * Gets the state listener for the parser. The state listener will recieve
238: * state events as the parser changes state. When the state filter filters
239: * out a state a state events will not be sent to the state listener.
240: *
241: * @param pVal [out] The state listener.
242: * @see #get_StateFilter(IStateFilter* *pVal)
243: */
244: public IStateListener getStateListener() {
245: return m_EventController.getStateListener();
246: }
247:
248: /**
249: * Sets the state listener for the parser. The state listener will recieve
250: * state events as the parser changes state. When the state filter filters
251: * out a state a state events will not be sent to the state listener.
252: *
253: * @param newVal [in] The state listener.
254: * @see #put_StateFilter(IStateFilter* newVal)
255: */
256: public void setStateListener(IStateListener stateListener) {
257: m_EventController.setStateListener(stateListener);
258: }
259:
260: /**
261: * Gets the state filter for the parser. The state filter determines
262: * if a state is to be filtered or not. When a state is filtered all sub
263: * states are also filtered. The token listener will not recieve any
264: * token events found while in a filtered state.
265: *
266: * @param pVal [out] The state filter.
267: * @see #get_StateListener(IStateListener* *pVal)
268: */
269: public IStateFilter getStateFilter() {
270: return m_EventController.getStateFilter();
271: }
272:
273: /**
274: * Sets the state filter for the parser. The state filter determines
275: * if a state is to be filtered or not. When a state is filtered all sub
276: * states are also filtered. The token listener will not recieve any
277: * token events found while in a filtered state.
278: *
279: * @param newVal [in] The state filter.
280: * @see #put_StateListener (IStateListener* newVal)
281: */
282: public void setStateFilter(IStateFilter filter) {
283: m_EventController.setStateFilter(filter);
284: }
285:
286: /**
287: * Get the the interface that will process tokens found while
288: * parsing a file. Tokens will not be sent while in a state
289: * that has bee filtered out,
290: *
291: * @param pVal [out] The token processor.
292: */
293: public ITokenProcessor getTokenProcessor() {
294: return m_EventController.getTokenProcessor();
295: }
296:
297: /**
298: * Set the the interface that will process tokens found while
299: * parsing a file. Tokens will not be sent while in a state
300: * that has bee filtered out,
301: *
302: * @param newVal [in] The token processor.
303: */
304: public void setTokenProcessor(ITokenProcessor tokenProcessor) {
305: m_EventController.setTokenProcessor(tokenProcessor);
306: }
307:
308: /**
309: * Get the the interface that will be used to filter tokens
310: * before they are sent to the token processor. Tokens will
311: * not be sent if they have be filtered out.
312: *
313: * @param pVal [out] The token filter.
314: */
315: public ITokenFilter getTokenFilter() {
316: return m_EventController.getTokenFilter();
317: }
318:
319: /**
320: * Set the the interface that will be used to filter tokens
321: * before they are sent to the token processor. Tokens will
322: * not be sent if they have be filtered out.
323: *
324: * @param pVal [out] The token filter.
325: */
326: public void setTokenFilter(ITokenFilter filter) {
327: m_EventController.setTokenFilter(filter);
328: }
329:
330: /**
331: * Get the the interface that will recieve the error information
332: * will parsing the file.
333: *
334: * @param pVal [out] The error listener.
335: */
336: public IErrorListener getErrorListener() {
337: return m_EventController.getErrorListener();
338: }
339:
340: /**
341: * Set the the interface that will recieve the error information
342: * will parsing the file.
343: *
344: * @param newVal [int] The error listener.
345: */
346: public void setErrorListener(IErrorListener errorListener) {
347: m_EventController.setErrorListener(errorListener);
348: }
349:
350: /* (non-Javadoc)
351: * @see org.netbeans.modules.uml.core.reverseengineering.reframework.parsingframework.ILanguageParser#processStreamByType(java.lang.String, int)
352: */
353: public void processStreamByType(String stream, int type) {
354: StringReader sr = new StringReader(stream);
355: CharBuffer cb = new CharBuffer(sr);
356: if (type == ProcessTypeKind.PTK_PROCESS_FILE)
357: processStreamAsFile(cb, null);
358: else if (type == ProcessTypeKind.PTK_PROCESS_FRAGMENT)
359: processStreamAsFragment(cb, null);
360: }
361:
362: private void processStreamAsFragment(CharBuffer buffer,
363: String filename) {
364: // Create a scanner that reads from the input stream
365: JavaLexer lexer = new JavaLexer(buffer);
366: if (filename != null)
367: lexer.setFilename(filename);
368: lexer.setTokenObjectClass(CommonHiddenStreamToken.class
369: .getName());
370: // lexer.setTokenObjectFactory(&antlr::CommonHiddenStreamToken::factory);
371:
372: lexer.setEventController(m_EventController);
373:
374: // Now initialize create and initialize a filter to keep track of
375: // WS and Comments.
376: TokenStreamHiddenTokenFilter filter = new TokenStreamHiddenTokenFilter(
377: lexer);
378: filter.hide(JavaLexer.SL_COMMENT);
379: filter.hide(JavaLexer.ML_COMMENT);
380:
381: // Create a parser that reads from the scanner
382: JavaRecognizer parser = new JavaRecognizer(filter);
383: parser.setASTNodeClass(CommonASTWithLocationsAndHidden.class
384: .getName());
385:
386: // parser.setASTNodeFactory(&antlr::CommonASTWithLocationsAndHidden::factory);
387:
388: try {
389: parser.setEventController(m_EventController);
390: parser.methodCompilationUnit();
391: } catch (ANTLRException e) {
392: m_EventController.errorFound(e.getMessage(), -1, -1,
393: filename);
394: }
395:
396: try {
397: EmbarcaderoJavaTreeParser treeParser = new EmbarcaderoJavaTreeParser();
398: treeParser.initializeStateNameMap();
399: treeParser.setEventController(m_EventController);
400: treeParser.parseMethodBody(parser.getAST());
401: } catch (ANTLRException e) {
402: m_EventController.errorFound(e.getMessage(), -1, -1,
403: filename);
404: }
405: }
406:
407: private void processStreamAsFile(CharBuffer buffer, String filename) {
408: if (filename != null)
409: m_EventController.setFilename(filename);
410: try {
411: // Create a scanner that reads from the input stream
412: JavaLexer lexer = new JavaLexer(buffer);
413: //JavaLexer lexer(s);
414: if (filename != null)
415: lexer.setFilename(filename);
416:
417: lexer.setTokenObjectClass(CommonHiddenStreamToken.class
418: .getName());
419: // lexer.setTokenObjectFactory(CommonHiddenStreamToken.class);
420: lexer.setEventController(m_EventController);
421:
422: // Now initialize create and initialize a filter to keep track of
423: // WS and Comments.
424: TokenStreamHiddenTokenFilter filter = new TokenStreamHiddenTokenFilter(
425: lexer);
426: filter.hide(JavaLexer.WS);
427: filter.hide(JavaLexer.SL_COMMENT);
428: filter.hide(JavaLexer.ML_COMMENT);
429:
430: // Create a parser that reads from the scanner
431: // JavaRecognizer parser(lexer);
432: JavaRecognizer parser = new JavaRecognizer(filter);
433: parser
434: .setASTNodeClass(CommonASTWithLocationsAndHidden.class
435: .getName());
436:
437: //***********************************************************************
438: // Antlr 2.7.2
439: //***********************************************************************
440: // parser.setASTFactory(new ASTFactory())
441: // ASTFactory myFactory =
442: // new ASTFactory();
443: // antlr::ASTFactory my_factory("CommonASTWithLocationsAndHidden",
444: // &antlr::CommonASTWithLocationsAndHidden::factory);
445: // // tell the parser about the factory
446: // parser.setASTFactory(&my_factory);
447: //
448: // // let the parser initialize the factory
449: // parser.initializeFactory();
450: // parser.setASTNodeFactory(&my_factory);
451:
452: //***********************************************************************
453: // Antlr 2.7.1
454: //***********************************************************************
455: // parser.setASTFactory(CommonAST)
456: // parser.setASTNodeFactory(&antlr::CommonASTWithLocationsAndHidden::factory);
457:
458: if (filename != null)
459: parser.setFilename(filename);
460:
461: try {
462: // start parsing at the compilationUnit rule
463: parser.setEventController(m_EventController);
464: parser.compilationUnit();
465: } catch (ANTLRException e) {
466: m_EventController.errorFound(e.getMessage(), -1, -1,
467: filename);
468: } catch (Exception e) {
469: m_EventController.errorFound(e.getMessage(), -1, -1,
470: filename);
471: }
472:
473: // #if _DEBUG
474: //
475: // ASTUtilities::DumpTree(_T("c:\\TestDump.txt"), parser.getAST(), false);
476: // #endif
477:
478: boolean errorOccurred = false;
479: try {
480: EmbarcaderoJavaTreeParser treeParser = new EmbarcaderoJavaTreeParser();
481: treeParser.initializeStateNameMap();
482: treeParser.setEventController(m_EventController);
483: treeParser.compilationUnit(parser.getAST());
484: } catch (ANTLRException e) {
485: m_EventController.errorFound(e.getMessage(), -1, -1,
486: filename);
487: } catch (Exception e) {
488: e.printStackTrace();
489: errorOccurred = true;
490: m_EventController.errorFound(e.getMessage(), -1, -1,
491: filename);
492: }
493:
494: if (errorOccurred) {
495: m_EventController
496: .errorFound(
497: "Unable to complete parsing the file. Possible Stack Overflow.",
498: -1, -1, filename);
499: }
500:
501: // The AST Tree will desctruct in a recursive mannor. When the
502: // tree is deep the descruction process can cause a stack overflow. To
503: // protect against the stack overflow DeleteTree will desctruct the AST
504: // tree in a non-recursive mannor.
505: // ASTUtilities astUtils = new ASTUt;
506: // astUtils.DeleteTree(parser.getAST());
507: } catch (Exception e) {
508: e.printStackTrace();
509: }
510: }
511: }
|