173 ClassPathEntry src = cp.accept(visitor, pathname); 174 if (src != null) { 175 // cache the ClassPathEntry from which this class is copied 176 // Most of the files in a module likely come from the 177 // same jar or directory. 178 lastVisitedClassPath = src; 179 return visitor.bytes; 180 } 181 } 182 return 0; 183 } 184 185 /** 186 * Write the resource file if not filtered 187 * 188 * @param res a ResourceFile 189 * @param filter a Filter 190 * @return the number of bytes copied 191 */ 192 long writeResource(ResourceFile res, Filter filter) throws IOException { 193 String pathname = res.getPathname(); 194 Copier visitor = new Copier(classDir, filter); 195 if (lastVisitedClassPath != null) { 196 ClassPathEntry cp = lastVisitedClassPath.accept(visitor, pathname); 197 if (cp != null) { 198 assert cp == lastVisitedClassPath; 199 return visitor.bytes; 200 } 201 } 202 203 // locate the source of the given resource file from the classpath 204 for (ClassPathEntry cp : cpath.entries()) { 205 ClassPathEntry src = cp.accept(visitor, pathname); 206 if (src != null) { 207 // cache the ClassPathEntry from which this class is copied 208 // Most of the files in a module likely come from the 209 // same jar or directory. 210 lastVisitedClassPath = src; 211 return visitor.bytes; 212 } 213 } 214 return 0; 215 } 216 217 /** 218 * A ClassPathEntry visitor to copy a file to the given destination 219 * if not filtered. 220 */ 221 class Copier implements ClassPathEntry.Visitor<ClassPathEntry, String> { 222 final Filter filter; 223 final File dest; 224 long bytes = 0; 225 226 Copier(File dest, Filter filter) { 227 this.filter = filter; 228 this.dest = dest; 229 } 230 231 @Override 232 public ClassPathEntry visitFile(File src, ClassPathEntry cp, String pathname) throws IOException { 233 String name = pathname.replace(File.separatorChar, '/'); 234 if (cp.getName().endsWith(File.separator + pathname) 235 && matches(src, name)) { 236 if (filter == null || filter.accept(src)) { 237 File dst = new File(dest, pathname); 238 bytes += copy(src, dst); 239 } 240 return cp; 241 } else { 242 return null; 243 } 244 } 245 246 @Override 247 public ClassPathEntry visitDir(File dir, ClassPathEntry cp, String pathname) throws IOException { 248 File src = new File(cp.getFile(), pathname); 249 File dst = new File(dest, pathname); 250 String name = pathname.replace(File.separatorChar, '/'); 257 } else { 258 return null; 259 } 260 } 261 262 @Override 263 public ClassPathEntry visitJarFile(JarFile jf, ClassPathEntry cp, String pathname) throws IOException { 264 String name = pathname.replace(File.separatorChar, '/'); 265 JarEntry e = jf.getJarEntry(name); 266 if (e != null && matches(jf, e, name)) { 267 if (filter == null || filter.accept(jf, e)) { 268 bytes += copy(jf, e); 269 } 270 return cp; 271 } else { 272 return null; 273 } 274 } 275 276 boolean matches(File src, String name) throws IOException { 277 if (!name.startsWith("META-INF/services")) { 278 return true; 279 } 280 281 BufferedInputStream in = new BufferedInputStream(new FileInputStream(src)); 282 try { 283 return matches(in, name); 284 } finally { 285 in.close(); 286 } 287 } 288 289 boolean matches(JarFile jf, JarEntry e, String name) throws IOException { 290 if (!name.startsWith("META-INF/services")) { 291 return true; 292 } 293 return matches(jf.getInputStream(e), name); 294 } 295 296 boolean matches(InputStream in, String name) throws IOException { 297 ServiceProviderConfigFile sp = new ServiceProviderConfigFile(name, in); 298 for (String p : sp.providers) { 299 Klass k = Klass.findKlass(p); 300 if (k == null) { 301 Trace.trace("Service %s: provider class %s not found%n", sp.service, p); 302 continue; 303 } 304 if (module.contains(k)) { 305 return true; 306 } 307 } 308 // return true if no provider; otherwise false 309 return sp.providers.isEmpty(); 310 } 311 312 long copy(JarFile jf, JarEntry e) throws IOException { 313 File dst = new File(dest, e.getName().replace('/', File.separatorChar)); 314 if (!dst.exists()) { 315 Files.createFile(dst); 316 } 317 318 byte[] buf = new byte[8192]; 319 InputStream in = jf.getInputStream(e); 320 long bytes = 0; 321 try { 322 FileOutputStream out = new FileOutputStream(dst); 323 try { 324 int n; 325 while ((n = in.read(buf)) > 0) { 326 out.write(buf, 0, n); 327 bytes += n; 328 } 329 } finally { 330 out.close(); 331 } 332 } finally { 333 in.close(); 334 } 335 336 long lastModified = e.getTime(); 337 if (lastModified > 0) { 338 dst.setLastModified(lastModified); 339 } 340 return bytes; 341 } 342 343 long copy(File src, File dst) 344 throws IOException { 345 assert src.exists(); 346 347 if (!dst.exists()) { 348 Files.createFile(dst); 349 } 350 351 BufferedInputStream in = new BufferedInputStream(new FileInputStream(src)); 352 byte[] buf = new byte[8192]; 353 long bytes = 0; 354 try { 355 FileOutputStream out = new FileOutputStream(dst); 356 try { 357 int n; 358 while ((n = in.read(buf)) > 0) { 359 out.write(buf, 0, n); 360 bytes += n; 361 } 362 } finally { 363 out.close(); 364 } 365 } finally { 366 in.close(); 367 } 368 dst.setLastModified(src.lastModified()); 369 if (src.canExecute()) { 370 dst.setExecutable(true, false); 371 } 372 return bytes; 373 } 374 } 375 } 376 377 /** 378 * A filter that accepts files that don't exist in the given 379 * location or modified since it's copied. 380 */ 381 class Filter implements ClassPath.Filter { 382 private final long timestamp; 383 Filter(File dir, String pathname) { 384 File destfile = new File(dir, pathname); 385 this.timestamp = destfile.exists() ? destfile.lastModified() : -1L; 386 } 387 | 173 ClassPathEntry src = cp.accept(visitor, pathname); 174 if (src != null) { 175 // cache the ClassPathEntry from which this class is copied 176 // Most of the files in a module likely come from the 177 // same jar or directory. 178 lastVisitedClassPath = src; 179 return visitor.bytes; 180 } 181 } 182 return 0; 183 } 184 185 /** 186 * Write the resource file if not filtered 187 * 188 * @param res a ResourceFile 189 * @param filter a Filter 190 * @return the number of bytes copied 191 */ 192 long writeResource(ResourceFile res, Filter filter) throws IOException { 193 if (res.isService()) 194 return writeService(res, filter); 195 196 String pathname = res.getPathname(); 197 Copier visitor = new Copier(classDir, filter); 198 if (lastVisitedClassPath != null) { 199 ClassPathEntry cp = lastVisitedClassPath.accept(visitor, pathname); 200 if (cp != null) { 201 assert cp == lastVisitedClassPath; 202 return visitor.bytes; 203 } 204 } 205 206 // locate the source of the given resource file from the classpath 207 for (ClassPathEntry cp : cpath.entries()) { 208 ClassPathEntry src = cp.accept(visitor, pathname); 209 if (src != null) { 210 // cache the ClassPathEntry from which this class is copied 211 // Most of the files in a module likely come from the 212 // same jar or directory. 213 lastVisitedClassPath = src; 214 return visitor.bytes; 215 } 216 } 217 return 0; 218 } 219 220 /** 221 * Write the service descriptor file if not filtered 222 * 223 * @param res a ResourceFile 224 * @param filter a Filter 225 * @return the number of bytes copied 226 */ 227 long writeService(ResourceFile res, Filter filter) throws IOException { 228 String pathname = res.getPathname(); 229 Copier visitor = new Copier(classDir, filter); 230 boolean foundOne = false; 231 int bytes = 0; 232 233 // scan all class path entries for services 234 for (ClassPathEntry cp : cpath.entries()) { 235 ClassPathEntry src = cp.accept(visitor, pathname); 236 if (src != null) { 237 bytes += visitor.bytes; 238 if (foundOne == false) { 239 foundOne = true; 240 visitor = new Copier(classDir, null, true); // append subsequent 241 } 242 } 243 } 244 return bytes; 245 } 246 247 /** 248 * A ClassPathEntry visitor to copy a file to the given destination 249 * if not filtered. 250 */ 251 class Copier implements ClassPathEntry.Visitor<ClassPathEntry, String> { 252 final Filter filter; 253 final File dest; 254 final boolean append; 255 long bytes = 0; 256 257 Copier(File dest, Filter filter) { 258 this(dest, filter, false); 259 } 260 261 Copier(File dest, Filter filter, boolean append) { 262 this.filter = filter; 263 this.dest = dest; 264 this.append = append; 265 } 266 267 private boolean isService(String name) { 268 return name.startsWith("META-INF/services") ? true : false; 269 } 270 271 @Override 272 public ClassPathEntry visitFile(File src, ClassPathEntry cp, String pathname) throws IOException { 273 String name = pathname.replace(File.separatorChar, '/'); 274 if (cp.getName().endsWith(File.separator + pathname) 275 && matches(src, name)) { 276 if (filter == null || filter.accept(src)) { 277 File dst = new File(dest, pathname); 278 bytes += copy(src, dst); 279 } 280 return cp; 281 } else { 282 return null; 283 } 284 } 285 286 @Override 287 public ClassPathEntry visitDir(File dir, ClassPathEntry cp, String pathname) throws IOException { 288 File src = new File(cp.getFile(), pathname); 289 File dst = new File(dest, pathname); 290 String name = pathname.replace(File.separatorChar, '/'); 297 } else { 298 return null; 299 } 300 } 301 302 @Override 303 public ClassPathEntry visitJarFile(JarFile jf, ClassPathEntry cp, String pathname) throws IOException { 304 String name = pathname.replace(File.separatorChar, '/'); 305 JarEntry e = jf.getJarEntry(name); 306 if (e != null && matches(jf, e, name)) { 307 if (filter == null || filter.accept(jf, e)) { 308 bytes += copy(jf, e); 309 } 310 return cp; 311 } else { 312 return null; 313 } 314 } 315 316 boolean matches(File src, String name) throws IOException { 317 if (!isService(name)) { 318 return true; 319 } 320 321 try (FileInputStream fis = new FileInputStream(src); 322 BufferedInputStream in = new BufferedInputStream(fis)) { 323 return matches(in, name); 324 } 325 } 326 327 boolean matches(JarFile jf, JarEntry e, String name) throws IOException { 328 if (!isService(name)) { 329 return true; 330 } 331 return matches(jf.getInputStream(e), name); 332 } 333 334 boolean matches(InputStream in, String name) throws IOException { 335 ServiceProviderConfigFile sp = new ServiceProviderConfigFile(name, in); 336 for (String p : sp.providers) { 337 Klass k = Klass.findKlass(p); 338 if (k == null) { 339 Trace.trace("Service %s: provider class %s not found%n", sp.service, p); 340 continue; 341 } 342 if (module.contains(k)) { 343 return true; 344 } 345 } 346 // return true if no provider; otherwise false 347 return sp.providers.isEmpty(); 348 } 349 350 long copy(JarFile jf, JarEntry e) throws IOException { 351 File dst = new File(dest, e.getName().replace('/', File.separatorChar)); 352 if (!dst.exists()) { 353 Files.createFile(dst); 354 } 355 356 byte[] buf = new byte[8192]; 357 long bytes = 0; 358 try (InputStream in = jf.getInputStream(e); 359 FileOutputStream out = new FileOutputStream(dst, append)) { 360 int n; 361 while ((n = in.read(buf)) > 0) { 362 out.write(buf, 0, n); 363 bytes += n; 364 } 365 } 366 367 long lastModified = e.getTime(); 368 if (lastModified > 0) { 369 dst.setLastModified(lastModified); 370 } 371 return bytes; 372 } 373 374 long copy(File src, File dst) 375 throws IOException { 376 assert src.exists(); 377 378 if (!dst.exists()) { 379 Files.createFile(dst); 380 } 381 382 byte[] buf = new byte[8192]; 383 long bytes = 0; 384 try (InputStream fin = new FileInputStream(src); 385 BufferedInputStream in = new BufferedInputStream(fin); 386 FileOutputStream out = new FileOutputStream(dst, append)) { 387 int n; 388 while ((n = in.read(buf)) > 0) { 389 out.write(buf, 0, n); 390 bytes += n; 391 } 392 } 393 dst.setLastModified(src.lastModified()); 394 if (src.canExecute()) { 395 dst.setExecutable(true, false); 396 } 397 return bytes; 398 } 399 } 400 } 401 402 /** 403 * A filter that accepts files that don't exist in the given 404 * location or modified since it's copied. 405 */ 406 class Filter implements ClassPath.Filter { 407 private final long timestamp; 408 Filter(File dir, String pathname) { 409 File destfile = new File(dir, pathname); 410 this.timestamp = destfile.exists() ? destfile.lastModified() : -1L; 411 } 412 |