1 package org.apache.maven.jxr.pacman;
2
3 /*
4 * Licensed to the Apache Software Foundation (ASF) under one
5 * or more contributor license agreements. See the NOTICE file
6 * distributed with this work for additional information
7 * regarding copyright ownership. The ASF licenses this file
8 * to you under the Apache License, Version 2.0 (the
9 * "License"); you may not use this file except in compliance
10 * with the License. You may obtain a copy of the License at
11 *
12 * http://www.apache.org/licenses/LICENSE-2.0
13 *
14 * Unless required by applicable law or agreed to in writing,
15 * software distributed under the License is distributed on an
16 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
17 * KIND, either express or implied. See the License for the
18 * specific language governing permissions and limitations
19 * under the License.
20 */
21
22 import java.io.FileInputStream;
23 import java.io.FileReader;
24 import java.io.IOException;
25 import java.io.InputStreamReader;
26 import java.io.Reader;
27 import java.io.StreamTokenizer;
28 import java.nio.file.Files;
29 import java.nio.file.Path;
30
31 /**
32 * PacMan implementation of a JavaFile. This will parse out the file and
33 * determine package, class, and imports
34 *
35 * @author <a href="mailto:burton@apache.org">Kevin A. Burton</a>
36 * @version $Id$
37 */
38 public class JavaFileImpl
39 extends JavaFile
40 {
41 /**
42 * Create a new JavaFileImpl that points to a given file...
43 *
44 * @param path
45 * @param encoding
46 * @throws IOException
47 */
48 public JavaFileImpl( Path path, String encoding )
49 throws IOException
50 {
51 super( path, encoding );
52
53 //always add java.lang.* to the package imports because the JVM always
54 //does this implicitly. Unless we add this to the ImportTypes JXR
55 //won't pick up on this.
56 this.addImportType( new ImportType( "java.lang.*" ) );
57
58 //now parse out this file.
59 this.parse();
60 }
61
62 /**
63 * Open up the file and try to determine package, class and import
64 * statements.
65 */
66 private void parse()
67 throws IOException
68 {
69 StreamTokenizer stok = null;
70 try ( Reader reader = getReader() )
71 {
72 stok = this.getTokenizer( reader );
73
74 parseRecursive( "", stok );
75 }
76 finally
77 {
78 stok = null;
79 }
80 }
81
82 private void parseRecursive( String nestedPrefix, StreamTokenizer stok )
83 throws IOException
84 {
85 int openBracesCount = 0;
86
87 while ( stok.nextToken() != StreamTokenizer.TT_EOF )
88 {
89
90 if ( stok.sval == null )
91 {
92 if ( stok.ttype == '{' )
93 {
94 openBracesCount++;
95 }
96 else if ( stok.ttype == '}' )
97 {
98 if ( --openBracesCount == 0 )
99 {
100 // break out of recursive
101 return;
102 }
103 }
104 continue;
105 }
106
107 //set the package
108 if ( "package".equals( stok.sval ) && stok.ttype != '\"' )
109 {
110 stok.nextToken();
111 this.setPackageType( new PackageType( stok.sval ) );
112 }
113
114 //set the imports
115 if ( "import".equals( stok.sval ) && stok.ttype != '\"' )
116 {
117 stok.nextToken();
118
119 String name = stok.sval;
120
121 /*
122 WARNING: this is a bug/non-feature in the current
123 StreamTokenizer. We needed to set the comment char as "*"
124 and packages that are imported with this (ex "test.*") will be
125 stripped( and become "test." ). Here we need to test for this
126 and if necessary re-add the char.
127 */
128 if ( name.charAt( name.length() - 1 ) == '.' )
129 {
130 name = name + '*';
131 }
132
133 this.addImportType( new ImportType( name ) );
134 }
135
136 // Add the class or classes. There can be several classes in one file so
137 // continue with the while loop to get them all.
138 if ( ( "class".equals( stok.sval ) || "interface".equals( stok.sval ) || "enum".equals( stok.sval ) )
139 && stok.ttype != '\"' )
140 {
141 stok.nextToken();
142 this.addClassType( new ClassType( nestedPrefix + stok.sval,
143 getFilenameWithoutPathOrExtension( this.getPath() ) ) );
144 parseRecursive( nestedPrefix + stok.sval + ".", stok );
145 }
146
147 }
148 }
149
150 /**
151 * Get a StreamTokenizer for this file.
152 */
153 private StreamTokenizer getTokenizer( Reader reader )
154 {
155 StreamTokenizer stok = new StreamTokenizer( reader );
156 //int tok;
157
158 stok.commentChar( '*' );
159 stok.wordChars( '_', '_' );
160
161 // set tokenizer to skip comments
162 stok.slashStarComments( true );
163 stok.slashSlashComments( true );
164
165 return stok;
166 }
167
168 private Reader getReader()
169 throws IOException
170 {
171 if ( Files.notExists( this.getPath() ) )
172 {
173 throw new IOException( this.getPath() + " does not exist!" );
174 }
175
176 if ( this.getEncoding() != null )
177 {
178 return new InputStreamReader( new FileInputStream( this.getPath().toFile() ), this.getEncoding() );
179 }
180 else
181 {
182 return new FileReader( this.getPath().toFile() );
183 }
184 }
185 }