9
9
import java .lang .instrument .ClassDefinition ;
10
10
import java .nio .file .Files ;
11
11
import java .nio .file .Path ;
12
- import java .util .HashMap ;
13
- import java .util .HashSet ;
12
+ import java .util .Collections ;
14
13
import java .util .Map ;
15
14
import java .util .Set ;
16
- import java .util .function .Consumer ;
15
+ import java .util .concurrent .ConcurrentMap ;
16
+ import java .util .concurrent .ConcurrentSkipListSet ;
17
+ import java .util .stream .Collectors ;
18
+ import java .util .stream .Stream ;
17
19
18
20
import org .fakereplace .core .Fakereplace ;
19
21
import org .fakereplace .replacement .AddedClass ;
@@ -86,57 +88,36 @@ public void handleRequest(HttpServerExchange exchange) throws Exception {
86
88
}
87
89
88
90
private boolean doScan () throws IOException {
89
- Set <File > changedSourceFiles = new HashSet <>() ;
91
+ final Set <File > changedSourceFiles ;
90
92
final long start = System .currentTimeMillis ();
91
- if (sourcesDir != null ) {
92
- Files .walk (sourcesDir ).forEach (new Consumer <Path >() {
93
- @ Override
94
- public void accept (Path path ) {
95
- try {
96
- if (!path .toString ().endsWith (".java" )) {
97
- return ;
98
- }
99
- long lastModified = Files .getLastModifiedTime (path ).toMillis ();
100
- if (lastModified > lastChange ) {
101
- changedSourceFiles .add (path .toFile ());
102
- }
103
- } catch (IOException e ) {
104
- e .printStackTrace ();
105
- }
106
- }
107
- });
93
+ if (sourcesDir != null ) {
94
+ try (final Stream <Path > sourcesStream = Files .walk (sourcesDir )) {
95
+ changedSourceFiles = sourcesStream
96
+ .parallel ()
97
+ .filter (p -> p .toString ().endsWith (".java" ))
98
+ .filter (p -> wasRecentlyModified (p ))
99
+ .map (Path ::toFile )
100
+ //Needing a concurrent Set, not many standard options:
101
+ .collect (Collectors .toCollection (ConcurrentSkipListSet ::new ));
102
+ }
103
+ }
104
+ else {
105
+ changedSourceFiles = Collections .EMPTY_SET ;
108
106
}
109
107
if (!changedSourceFiles .isEmpty ()) {
110
108
compiler .compile (changedSourceFiles );
111
109
}
112
- Map <String , byte []> changedClasses = new HashMap <>();
113
- Files .walk (classesDir ).forEach (new Consumer <Path >() {
114
- @ Override
115
- public void accept (Path path ) {
116
- try {
117
- if (!path .toString ().endsWith (".class" )) {
118
- return ;
119
- }
120
- long lastModified = Files .getLastModifiedTime (path ).toMillis ();
121
- if (lastModified > lastChange ) {
122
- String pathName = classesDir .relativize (path ).toString ();
123
- String className = pathName .substring (0 , pathName .length () - 6 ).replace ("/" , "." );
124
- ByteArrayOutputStream out = new ByteArrayOutputStream ();
125
- byte [] buf = new byte [1024 ];
126
- int r ;
127
- try (FileInputStream in = new FileInputStream (path .toFile ())) {
128
- while ((r = in .read (buf )) > 0 ) {
129
- out .write (buf , 0 , r );
130
- }
131
- changedClasses .put (className , out .toByteArray ());
132
- }
133
-
134
- }
135
- } catch (IOException e ) {
136
- e .printStackTrace ();
137
- }
138
- }
139
- });
110
+ final ConcurrentMap <String , byte []> changedClasses ;
111
+ try (final Stream <Path > classesStream = Files .walk (classesDir )) {
112
+ changedClasses = classesStream
113
+ .parallel ()
114
+ .filter (p -> p .toString ().endsWith (".class" ))
115
+ .filter (p -> wasRecentlyModified (p ))
116
+ .collect (Collectors .toConcurrentMap (
117
+ p -> pathToClassName (p ),
118
+ p -> readFileContentNoIOExceptions (p ))
119
+ );
120
+ }
140
121
if (changedClasses .isEmpty ()) {
141
122
return false ;
142
123
}
@@ -153,6 +134,48 @@ public void accept(Path path) {
153
134
return true ;
154
135
}
155
136
137
+ private boolean wasRecentlyModified (final Path p ) {
138
+ try {
139
+ return Files .getLastModifiedTime (p ).toMillis () > lastChange ;
140
+ } catch (IOException e ) {
141
+ throw new RuntimeException (e );
142
+ }
143
+ }
144
+
145
+ private String pathToClassName (final Path path ) {
146
+ String pathName = classesDir .relativize (path ).toString ();
147
+ String className = pathName .substring (0 , pathName .length () - 6 ).replace ("/" , "." );
148
+ return className ;
149
+ }
150
+
151
+ private byte [] readFileContentNoIOExceptions (final Path path ) {
152
+ try {
153
+ return readFileContent (path );
154
+ } catch (IOException e ) {
155
+ throw new RuntimeException (e );
156
+ }
157
+ }
158
+
159
+ private byte [] readFileContent (final Path path ) throws IOException {
160
+ final File file = path .toFile ();
161
+ final long fileLength = file .length ();
162
+ if (fileLength >Integer .MAX_VALUE ) {
163
+ throw new RuntimeException ("Can't process class files larger than Integer.MAX_VALUE bytes" );
164
+ }
165
+ try (FileInputStream stream = new FileInputStream (file )) {
166
+ //Might be large but we need a single byte[] at the end of things, might as well allocate it in one shot:
167
+ ByteArrayOutputStream out = new ByteArrayOutputStream ((int )fileLength );
168
+ byte [] buf = new byte [1024 ];
169
+ int r ;
170
+ try (FileInputStream in = new FileInputStream (path .toFile ())) {
171
+ while ((r = in .read (buf )) > 0 ) {
172
+ out .write (buf , 0 , r );
173
+ }
174
+ return out .toByteArray ();
175
+ }
176
+ }
177
+ }
178
+
156
179
public static void displayErrorPage (HttpServerExchange exchange , final Throwable exception ) throws IOException {
157
180
StringBuilder sb = new StringBuilder ();
158
181
//todo: make this good
0 commit comments