287
288 /**
289 * Returns {@code true} if the implementation of {@link #destroy} is to
290 * normally terminate the process,
291 * Returns {@code false} if the implementation of {@code destroy}
292 * forcibly and immediately terminates the process.
293 * <p>
294 * Invoking this method on {@code Process} objects returned by
295 * {@link ProcessBuilder#start} and {@link Runtime#exec} return
296 * {@code true} or {@code false} depending on the platform implementation.
297 *
298 * @implSpec
299 * This implementation throws an instance of
300 * {@link java.lang.UnsupportedOperationException} and performs no other action.
301 *
302 * @return {@code true} if the implementation of {@link #destroy} is to
303 * normally terminate the process;
304 * otherwise, {@link #destroy} forcibly terminates the process
305 * @throws UnsupportedOperationException if the Process implementation
306 * does not support this operation
307 * @since 1.9
308 */
309 public boolean supportsNormalTermination() {
310 throw new UnsupportedOperationException(this.getClass()
311 + ".supportsNormalTermination() not supported" );
312 }
313
314 /**
315 * Tests whether the process represented by this {@code Process} is
316 * alive.
317 *
318 * @return {@code true} if the process represented by this
319 * {@code Process} object has not yet terminated.
320 * @since 1.8
321 */
322 public boolean isAlive() {
323 try {
324 exitValue();
325 return false;
326 } catch(IllegalThreadStateException e) {
327 return true;
328 }
329 }
330
331 /**
332 * Returns the native process ID of the process.
333 * The native process ID is an identification number that the operating
334 * system assigns to the process.
335 *
336 * @implSpec
337 * The implementation of this method returns the process id as:
338 * {@link #toHandle toHandle().getPid()}.
339 *
340 * @return the native process id of the process
341 * @throws UnsupportedOperationException if the Process implementation
342 * does not support this operation
343 * @since 1.9
344 */
345 public long getPid() {
346 return toHandle().getPid();
347 }
348
349 /**
350 * Returns a {@code CompletableFuture<Process>} for the termination of the Process.
351 * The {@link java.util.concurrent.CompletableFuture} provides the ability
352 * to trigger dependent functions or actions that may be run synchronously
353 * or asynchronously upon process termination.
354 * When the process has terminated the CompletableFuture is
355 * {@link java.util.concurrent.CompletableFuture#complete completed} regardless
356 * of the exit status of the process.
357 * <p>
358 * Calling {@code onExit().get()} waits for the process to terminate and returns
359 * the Process. The future can be used to check if the process is
360 * {@link java.util.concurrent.CompletableFuture#isDone done} or to
361 * {@link java.util.concurrent.CompletableFuture#get() wait} for it to terminate.
362 * {@link java.util.concurrent.CompletableFuture#cancel(boolean) Cancelling}
363 * the CompletableFuture does not affect the Process.
392 * {@link java.util.concurrent.CompletableFuture#complete completed} regardless
393 * of the exit status of the process.
394 *
395 * This implementation may consume a lot of memory for thread stacks if a
396 * large number of processes are waited for concurrently.
397 * <p>
398 * External implementations should override this method and provide
399 * a more efficient implementation. For example, to delegate to the underlying
400 * process, it can do the following:
401 * <pre>{@code
402 * public CompletableFuture<Process> onExit() {
403 * return delegate.onExit().thenApply(p -> this);
404 * }
405 * }</pre>
406 * @apiNote
407 * The process may be observed to have terminated with {@link #isAlive}
408 * before the ComputableFuture is completed and dependent actions are invoked.
409 *
410 * @return a new {@code CompletableFuture<Process>} for the Process
411 *
412 * @since 1.9
413 */
414 public CompletableFuture<Process> onExit() {
415 return CompletableFuture.supplyAsync(this::waitForInternal);
416 }
417
418 /**
419 * Wait for the process to exit by calling {@code waitFor}.
420 * If the thread is interrupted, remember the interrupted state to
421 * be restored before returning. Use ForkJoinPool.ManagedBlocker
422 * so that the number of workers in case ForkJoinPool is used is
423 * compensated when the thread blocks in waitFor().
424 *
425 * @return the Process
426 */
427 private Process waitForInternal() {
428 boolean interrupted = false;
429 while (true) {
430 try {
431 ForkJoinPool.managedBlock(new ForkJoinPool.ManagedBlocker() {
432 @Override
454 /**
455 * Returns a ProcessHandle for the Process.
456 *
457 * {@code Process} objects returned by {@link ProcessBuilder#start} and
458 * {@link Runtime#exec} implement {@code toHandle} as the equivalent of
459 * {@link ProcessHandle#of(long) ProcessHandle.of(pid)} including the
460 * check for a SecurityManager and {@code RuntimePermission("manageProcess")}.
461 *
462 * @implSpec
463 * This implementation throws an instance of
464 * {@link java.lang.UnsupportedOperationException} and performs no other action.
465 * Subclasses should override this method to provide a ProcessHandle for the
466 * process. The methods {@link #getPid}, {@link #info}, {@link #children},
467 * and {@link #descendants}, unless overridden, operate on the ProcessHandle.
468 *
469 * @return Returns a ProcessHandle for the Process
470 * @throws UnsupportedOperationException if the Process implementation
471 * does not support this operation
472 * @throws SecurityException if a security manager has been installed and
473 * it denies RuntimePermission("manageProcess")
474 * @since 1.9
475 */
476 public ProcessHandle toHandle() {
477 throw new UnsupportedOperationException(this.getClass()
478 + ".toHandle() not supported");
479 }
480
481 /**
482 * Returns a snapshot of information about the process.
483 *
484 * <p> A {@link ProcessHandle.Info} instance has accessor methods
485 * that return information about the process if it is available.
486 *
487 * @implSpec
488 * This implementation returns information about the process as:
489 * {@link #toHandle toHandle().info()}.
490 *
491 * @return a snapshot of information about the process, always non-null
492 * @throws UnsupportedOperationException if the Process implementation
493 * does not support this operation
494 * @since 1.9
495 */
496 public ProcessHandle.Info info() {
497 return toHandle().info();
498 }
499
500 /**
501 * Returns a snapshot of the direct children of the process.
502 * The parent of a direct child process is the process.
503 * Typically, a process that is {@link #isAlive not alive} has no children.
504 * <p>
505 * <em>Note that processes are created and terminate asynchronously.
506 * There is no guarantee that a process is {@link #isAlive alive}.
507 * </em>
508 *
509 * @implSpec
510 * This implementation returns the direct children as:
511 * {@link #toHandle toHandle().children()}.
512 *
513 * @return a sequential Stream of ProcessHandles for processes that are
514 * direct children of the process
515 * @throws UnsupportedOperationException if the Process implementation
516 * does not support this operation
517 * @throws SecurityException if a security manager has been installed and
518 * it denies RuntimePermission("manageProcess")
519 * @since 1.9
520 */
521 public Stream<ProcessHandle> children() {
522 return toHandle().children();
523 }
524
525 /**
526 * Returns a snapshot of the descendants of the process.
527 * The descendants of a process are the children of the process
528 * plus the descendants of those children, recursively.
529 * Typically, a process that is {@link #isAlive not alive} has no children.
530 * <p>
531 * <em>Note that processes are created and terminate asynchronously.
532 * There is no guarantee that a process is {@link #isAlive alive}.
533 * </em>
534 *
535 * @implSpec
536 * This implementation returns all children as:
537 * {@link #toHandle toHandle().descendants()}.
538 *
539 * @return a sequential Stream of ProcessHandles for processes that
540 * are descendants of the process
541 * @throws UnsupportedOperationException if the Process implementation
542 * does not support this operation
543 * @throws SecurityException if a security manager has been installed and
544 * it denies RuntimePermission("manageProcess")
545 * @since 1.9
546 */
547 public Stream<ProcessHandle> descendants() {
548 return toHandle().descendants();
549 }
550
551
552 }
|
287
288 /**
289 * Returns {@code true} if the implementation of {@link #destroy} is to
290 * normally terminate the process,
291 * Returns {@code false} if the implementation of {@code destroy}
292 * forcibly and immediately terminates the process.
293 * <p>
294 * Invoking this method on {@code Process} objects returned by
295 * {@link ProcessBuilder#start} and {@link Runtime#exec} return
296 * {@code true} or {@code false} depending on the platform implementation.
297 *
298 * @implSpec
299 * This implementation throws an instance of
300 * {@link java.lang.UnsupportedOperationException} and performs no other action.
301 *
302 * @return {@code true} if the implementation of {@link #destroy} is to
303 * normally terminate the process;
304 * otherwise, {@link #destroy} forcibly terminates the process
305 * @throws UnsupportedOperationException if the Process implementation
306 * does not support this operation
307 * @since 9
308 */
309 public boolean supportsNormalTermination() {
310 throw new UnsupportedOperationException(this.getClass()
311 + ".supportsNormalTermination() not supported" );
312 }
313
314 /**
315 * Tests whether the process represented by this {@code Process} is
316 * alive.
317 *
318 * @return {@code true} if the process represented by this
319 * {@code Process} object has not yet terminated.
320 * @since 1.8
321 */
322 public boolean isAlive() {
323 try {
324 exitValue();
325 return false;
326 } catch(IllegalThreadStateException e) {
327 return true;
328 }
329 }
330
331 /**
332 * Returns the native process ID of the process.
333 * The native process ID is an identification number that the operating
334 * system assigns to the process.
335 *
336 * @implSpec
337 * The implementation of this method returns the process id as:
338 * {@link #toHandle toHandle().getPid()}.
339 *
340 * @return the native process id of the process
341 * @throws UnsupportedOperationException if the Process implementation
342 * does not support this operation
343 * @since 9
344 */
345 public long getPid() {
346 return toHandle().getPid();
347 }
348
349 /**
350 * Returns a {@code CompletableFuture<Process>} for the termination of the Process.
351 * The {@link java.util.concurrent.CompletableFuture} provides the ability
352 * to trigger dependent functions or actions that may be run synchronously
353 * or asynchronously upon process termination.
354 * When the process has terminated the CompletableFuture is
355 * {@link java.util.concurrent.CompletableFuture#complete completed} regardless
356 * of the exit status of the process.
357 * <p>
358 * Calling {@code onExit().get()} waits for the process to terminate and returns
359 * the Process. The future can be used to check if the process is
360 * {@link java.util.concurrent.CompletableFuture#isDone done} or to
361 * {@link java.util.concurrent.CompletableFuture#get() wait} for it to terminate.
362 * {@link java.util.concurrent.CompletableFuture#cancel(boolean) Cancelling}
363 * the CompletableFuture does not affect the Process.
392 * {@link java.util.concurrent.CompletableFuture#complete completed} regardless
393 * of the exit status of the process.
394 *
395 * This implementation may consume a lot of memory for thread stacks if a
396 * large number of processes are waited for concurrently.
397 * <p>
398 * External implementations should override this method and provide
399 * a more efficient implementation. For example, to delegate to the underlying
400 * process, it can do the following:
401 * <pre>{@code
402 * public CompletableFuture<Process> onExit() {
403 * return delegate.onExit().thenApply(p -> this);
404 * }
405 * }</pre>
406 * @apiNote
407 * The process may be observed to have terminated with {@link #isAlive}
408 * before the ComputableFuture is completed and dependent actions are invoked.
409 *
410 * @return a new {@code CompletableFuture<Process>} for the Process
411 *
412 * @since 9
413 */
414 public CompletableFuture<Process> onExit() {
415 return CompletableFuture.supplyAsync(this::waitForInternal);
416 }
417
418 /**
419 * Wait for the process to exit by calling {@code waitFor}.
420 * If the thread is interrupted, remember the interrupted state to
421 * be restored before returning. Use ForkJoinPool.ManagedBlocker
422 * so that the number of workers in case ForkJoinPool is used is
423 * compensated when the thread blocks in waitFor().
424 *
425 * @return the Process
426 */
427 private Process waitForInternal() {
428 boolean interrupted = false;
429 while (true) {
430 try {
431 ForkJoinPool.managedBlock(new ForkJoinPool.ManagedBlocker() {
432 @Override
454 /**
455 * Returns a ProcessHandle for the Process.
456 *
457 * {@code Process} objects returned by {@link ProcessBuilder#start} and
458 * {@link Runtime#exec} implement {@code toHandle} as the equivalent of
459 * {@link ProcessHandle#of(long) ProcessHandle.of(pid)} including the
460 * check for a SecurityManager and {@code RuntimePermission("manageProcess")}.
461 *
462 * @implSpec
463 * This implementation throws an instance of
464 * {@link java.lang.UnsupportedOperationException} and performs no other action.
465 * Subclasses should override this method to provide a ProcessHandle for the
466 * process. The methods {@link #getPid}, {@link #info}, {@link #children},
467 * and {@link #descendants}, unless overridden, operate on the ProcessHandle.
468 *
469 * @return Returns a ProcessHandle for the Process
470 * @throws UnsupportedOperationException if the Process implementation
471 * does not support this operation
472 * @throws SecurityException if a security manager has been installed and
473 * it denies RuntimePermission("manageProcess")
474 * @since 9
475 */
476 public ProcessHandle toHandle() {
477 throw new UnsupportedOperationException(this.getClass()
478 + ".toHandle() not supported");
479 }
480
481 /**
482 * Returns a snapshot of information about the process.
483 *
484 * <p> A {@link ProcessHandle.Info} instance has accessor methods
485 * that return information about the process if it is available.
486 *
487 * @implSpec
488 * This implementation returns information about the process as:
489 * {@link #toHandle toHandle().info()}.
490 *
491 * @return a snapshot of information about the process, always non-null
492 * @throws UnsupportedOperationException if the Process implementation
493 * does not support this operation
494 * @since 9
495 */
496 public ProcessHandle.Info info() {
497 return toHandle().info();
498 }
499
500 /**
501 * Returns a snapshot of the direct children of the process.
502 * The parent of a direct child process is the process.
503 * Typically, a process that is {@link #isAlive not alive} has no children.
504 * <p>
505 * <em>Note that processes are created and terminate asynchronously.
506 * There is no guarantee that a process is {@link #isAlive alive}.
507 * </em>
508 *
509 * @implSpec
510 * This implementation returns the direct children as:
511 * {@link #toHandle toHandle().children()}.
512 *
513 * @return a sequential Stream of ProcessHandles for processes that are
514 * direct children of the process
515 * @throws UnsupportedOperationException if the Process implementation
516 * does not support this operation
517 * @throws SecurityException if a security manager has been installed and
518 * it denies RuntimePermission("manageProcess")
519 * @since 9
520 */
521 public Stream<ProcessHandle> children() {
522 return toHandle().children();
523 }
524
525 /**
526 * Returns a snapshot of the descendants of the process.
527 * The descendants of a process are the children of the process
528 * plus the descendants of those children, recursively.
529 * Typically, a process that is {@link #isAlive not alive} has no children.
530 * <p>
531 * <em>Note that processes are created and terminate asynchronously.
532 * There is no guarantee that a process is {@link #isAlive alive}.
533 * </em>
534 *
535 * @implSpec
536 * This implementation returns all children as:
537 * {@link #toHandle toHandle().descendants()}.
538 *
539 * @return a sequential Stream of ProcessHandles for processes that
540 * are descendants of the process
541 * @throws UnsupportedOperationException if the Process implementation
542 * does not support this operation
543 * @throws SecurityException if a security manager has been installed and
544 * it denies RuntimePermission("manageProcess")
545 * @since 9
546 */
547 public Stream<ProcessHandle> descendants() {
548 return toHandle().descendants();
549 }
550
551
552 }
|