1 /* 2 * Copyright (c) 1995, 2021, Oracle and/or its affiliates. All rights reserved. 3 * Copyright (c) 2019, Azul Systems, Inc. All rights reserved. 4 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 5 * 6 * This code is free software; you can redistribute it and/or modify it 7 * under the terms of the GNU General Public License version 2 only, as 8 * published by the Free Software Foundation. Oracle designates this 9 * particular file as subject to the "Classpath" exception as provided 10 * by Oracle in the LICENSE file that accompanied this code. 11 * 12 * This code is distributed in the hope that it will be useful, but WITHOUT 13 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or 14 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 15 * version 2 for more details (a copy is included in the LICENSE file that 16 * accompanied this code). 17 * 18 * You should have received a copy of the GNU General Public License version 19 * 2 along with this work; if not, write to the Free Software Foundation, 20 * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA. 21 * 22 * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA 23 * or visit www.oracle.com if you need additional information or have any 24 * questions. 25 */ 26 27 package java.lang; 28 29 import java.io.*; 30 import java.math.BigInteger; 31 import java.util.regex.Matcher; 32 import java.util.regex.Pattern; 33 import java.util.stream.Collectors; 34 import java.util.List; 35 import java.util.Optional; 36 import java.util.StringTokenizer; 37 38 import jdk.internal.access.SharedSecrets; 39 import jdk.internal.loader.NativeLibrary; 40 import jdk.internal.reflect.CallerSensitive; 41 import jdk.internal.reflect.Reflection; 42 43 /** 44 * Every Java application has a single instance of class 45 * {@code Runtime} that allows the application to interface with 46 * the environment in which the application is running. The current 47 * runtime can be obtained from the {@code getRuntime} method. 48 * <p> 49 * An application cannot create its own instance of this class. 50 * 51 * @see java.lang.Runtime#getRuntime() 52 * @since 1.0 53 */ 54 55 public class Runtime { 56 private static final Runtime currentRuntime = new Runtime(); 57 58 private static Version version; 59 60 /** 61 * Returns the runtime object associated with the current Java application. 62 * Most of the methods of class {@code Runtime} are instance 63 * methods and must be invoked with respect to the current runtime object. 64 * 65 * @return the {@code Runtime} object associated with the current 66 * Java application. 67 */ 68 public static Runtime getRuntime() { 69 return currentRuntime; 70 } 71 72 /** Don't let anyone else instantiate this class */ 73 private Runtime() {} 74 75 /** 76 * Terminates the currently running Java virtual machine by initiating its 77 * shutdown sequence. This method never returns normally. The argument 78 * serves as a status code; by convention, a nonzero status code indicates 79 * abnormal termination. 80 * 81 * <p> All registered {@linkplain #addShutdownHook shutdown hooks}, if any, 82 * are started in some unspecified order and allowed to run concurrently 83 * until they finish. Once this is done the virtual machine 84 * {@linkplain #halt halts}. 85 * 86 * <p> If this method is invoked after all shutdown hooks have already 87 * been run and the status is nonzero then this method halts the 88 * virtual machine with the given status code. Otherwise, this method 89 * blocks indefinitely. 90 * 91 * <p> The {@link System#exit(int) System.exit} method is the 92 * conventional and convenient means of invoking this method. 93 * 94 * @param status 95 * Termination status. By convention, a nonzero status code 96 * indicates abnormal termination. 97 * 98 * @throws SecurityException 99 * If a security manager is present and its 100 * {@link SecurityManager#checkExit checkExit} method does not permit 101 * exiting with the specified status 102 * 103 * @see java.lang.SecurityException 104 * @see java.lang.SecurityManager#checkExit(int) 105 * @see #addShutdownHook 106 * @see #removeShutdownHook 107 * @see #halt(int) 108 */ 109 public void exit(int status) { 110 @SuppressWarnings("removal") 111 SecurityManager security = System.getSecurityManager(); 112 if (security != null) { 113 security.checkExit(status); 114 } 115 Shutdown.exit(status); 116 } 117 118 /** 119 * Registers a new virtual-machine shutdown hook. 120 * 121 * <p> The Java virtual machine <i>shuts down</i> in response to two kinds 122 * of events: 123 * 124 * <ul> 125 * 126 * <li> The program <i>exits</i> normally, when the last non-daemon 127 * thread exits or when the {@link #exit exit} (equivalently, 128 * {@link System#exit(int) System.exit}) method is invoked, or 129 * 130 * <li> The virtual machine is <i>terminated</i> in response to a 131 * user interrupt, such as typing {@code ^C}, or a system-wide event, 132 * such as user logoff or system shutdown. 133 * 134 * </ul> 135 * 136 * <p> A <i>shutdown hook</i> is simply an initialized but unstarted 137 * thread. When the virtual machine begins its shutdown sequence it will 138 * start all registered shutdown hooks in some unspecified order and let 139 * them run concurrently. When all the hooks have finished it will then 140 * halt. Note that daemon threads will continue to run during the shutdown 141 * sequence, as will non-daemon threads if shutdown was initiated by 142 * invoking the {@link #exit exit} method. 143 * 144 * <p> Once the shutdown sequence has begun it can be stopped only by 145 * invoking the {@link #halt halt} method, which forcibly 146 * terminates the virtual machine. 147 * 148 * <p> Once the shutdown sequence has begun it is impossible to register a 149 * new shutdown hook or de-register a previously-registered hook. 150 * Attempting either of these operations will cause an 151 * {@link IllegalStateException} to be thrown. 152 * 153 * <p> Shutdown hooks run at a delicate time in the life cycle of a virtual 154 * machine and should therefore be coded defensively. They should, in 155 * particular, be written to be thread-safe and to avoid deadlocks insofar 156 * as possible. They should also not rely blindly upon services that may 157 * have registered their own shutdown hooks and therefore may themselves in 158 * the process of shutting down. Attempts to use other thread-based 159 * services such as the AWT event-dispatch thread, for example, may lead to 160 * deadlocks. 161 * 162 * <p> Shutdown hooks should also finish their work quickly. When a 163 * program invokes {@link #exit exit} the expectation is 164 * that the virtual machine will promptly shut down and exit. When the 165 * virtual machine is terminated due to user logoff or system shutdown the 166 * underlying operating system may only allow a fixed amount of time in 167 * which to shut down and exit. It is therefore inadvisable to attempt any 168 * user interaction or to perform a long-running computation in a shutdown 169 * hook. 170 * 171 * <p> Uncaught exceptions are handled in shutdown hooks just as in any 172 * other thread, by invoking the 173 * {@link ThreadGroup#uncaughtException uncaughtException} method of the 174 * thread's {@link ThreadGroup} object. The default implementation of this 175 * method prints the exception's stack trace to {@link System#err} and 176 * terminates the thread; it does not cause the virtual machine to exit or 177 * halt. 178 * 179 * <p> In rare circumstances the virtual machine may <i>abort</i>, that is, 180 * stop running without shutting down cleanly. This occurs when the 181 * virtual machine is terminated externally, for example with the 182 * {@code SIGKILL} signal on Unix or the {@code TerminateProcess} call on 183 * Microsoft Windows. The virtual machine may also abort if a native 184 * method goes awry by, for example, corrupting internal data structures or 185 * attempting to access nonexistent memory. If the virtual machine aborts 186 * then no guarantee can be made about whether or not any shutdown hooks 187 * will be run. 188 * 189 * @param hook 190 * An initialized but unstarted {@link Thread} object 191 * 192 * @throws IllegalArgumentException 193 * If the specified hook has already been registered, 194 * or if it can be determined that the hook is already running or 195 * has already been run 196 * 197 * @throws IllegalStateException 198 * If the virtual machine is already in the process 199 * of shutting down 200 * 201 * @throws SecurityException 202 * If a security manager is present and it denies 203 * {@link RuntimePermission}{@code ("shutdownHooks")} 204 * 205 * @see #removeShutdownHook 206 * @see #halt(int) 207 * @see #exit(int) 208 * @since 1.3 209 */ 210 public void addShutdownHook(Thread hook) { 211 @SuppressWarnings("removal") 212 SecurityManager sm = System.getSecurityManager(); 213 if (sm != null) { 214 sm.checkPermission(new RuntimePermission("shutdownHooks")); 215 } 216 ApplicationShutdownHooks.add(hook); 217 } 218 219 /** 220 * De-registers a previously-registered virtual-machine shutdown hook. 221 * 222 * @param hook the hook to remove 223 * @return {@code true} if the specified hook had previously been 224 * registered and was successfully de-registered, {@code false} 225 * otherwise. 226 * 227 * @throws IllegalStateException 228 * If the virtual machine is already in the process of shutting 229 * down 230 * 231 * @throws SecurityException 232 * If a security manager is present and it denies 233 * {@link RuntimePermission}{@code ("shutdownHooks")} 234 * 235 * @see #addShutdownHook 236 * @see #exit(int) 237 * @since 1.3 238 */ 239 public boolean removeShutdownHook(Thread hook) { 240 @SuppressWarnings("removal") 241 SecurityManager sm = System.getSecurityManager(); 242 if (sm != null) { 243 sm.checkPermission(new RuntimePermission("shutdownHooks")); 244 } 245 return ApplicationShutdownHooks.remove(hook); 246 } 247 248 /** 249 * Forcibly terminates the currently running Java virtual machine. This 250 * method never returns normally. 251 * 252 * <p> This method should be used with extreme caution. Unlike the 253 * {@link #exit exit} method, this method does not cause shutdown 254 * hooks to be started. If the shutdown sequence has already been 255 * initiated then this method does not wait for any running 256 * shutdown hooks to finish their work. 257 * 258 * @param status 259 * Termination status. By convention, a nonzero status code 260 * indicates abnormal termination. If the {@link Runtime#exit exit} 261 * (equivalently, {@link System#exit(int) System.exit}) method 262 * has already been invoked then this status code 263 * will override the status code passed to that method. 264 * 265 * @throws SecurityException 266 * If a security manager is present and its 267 * {@link SecurityManager#checkExit checkExit} method 268 * does not permit an exit with the specified status 269 * 270 * @see #exit 271 * @see #addShutdownHook 272 * @see #removeShutdownHook 273 * @since 1.3 274 */ 275 public void halt(int status) { 276 @SuppressWarnings("removal") 277 SecurityManager sm = System.getSecurityManager(); 278 if (sm != null) { 279 sm.checkExit(status); 280 } 281 Shutdown.beforeHalt(); 282 Shutdown.halt(status); 283 } 284 285 /** 286 * Executes the specified string command in a separate process. 287 * 288 * <p>This is a convenience method. An invocation of the form 289 * {@code exec(command)} 290 * behaves in exactly the same way as the invocation 291 * {@link #exec(String, String[], File) exec}{@code (command, null, null)}. 292 * 293 * @param command a specified system command. 294 * 295 * @return A new {@link Process} object for managing the subprocess 296 * 297 * @throws SecurityException 298 * If a security manager exists and its 299 * {@link SecurityManager#checkExec checkExec} 300 * method doesn't allow creation of the subprocess 301 * 302 * @throws IOException 303 * If an I/O error occurs 304 * 305 * @throws NullPointerException 306 * If {@code command} is {@code null} 307 * 308 * @throws IllegalArgumentException 309 * If {@code command} is empty 310 * 311 * @see #exec(String[], String[], File) 312 * @see ProcessBuilder 313 */ 314 public Process exec(String command) throws IOException { 315 return exec(command, null, null); 316 } 317 318 /** 319 * Executes the specified string command in a separate process with the 320 * specified environment. 321 * 322 * <p>This is a convenience method. An invocation of the form 323 * {@code exec(command, envp)} 324 * behaves in exactly the same way as the invocation 325 * {@link #exec(String, String[], File) exec}{@code (command, envp, null)}. 326 * 327 * @param command a specified system command. 328 * 329 * @param envp array of strings, each element of which 330 * has environment variable settings in the format 331 * <i>name</i>=<i>value</i>, or 332 * {@code null} if the subprocess should inherit 333 * the environment of the current process. 334 * 335 * @return A new {@link Process} object for managing the subprocess 336 * 337 * @throws SecurityException 338 * If a security manager exists and its 339 * {@link SecurityManager#checkExec checkExec} 340 * method doesn't allow creation of the subprocess 341 * 342 * @throws IOException 343 * If an I/O error occurs 344 * 345 * @throws NullPointerException 346 * If {@code command} is {@code null}, 347 * or one of the elements of {@code envp} is {@code null} 348 * 349 * @throws IllegalArgumentException 350 * If {@code command} is empty 351 * 352 * @see #exec(String[], String[], File) 353 * @see ProcessBuilder 354 */ 355 public Process exec(String command, String[] envp) throws IOException { 356 return exec(command, envp, null); 357 } 358 359 /** 360 * Executes the specified string command in a separate process with the 361 * specified environment and working directory. 362 * 363 * <p>This is a convenience method. An invocation of the form 364 * {@code exec(command, envp, dir)} 365 * behaves in exactly the same way as the invocation 366 * {@link #exec(String[], String[], File) exec}{@code (cmdarray, envp, dir)}, 367 * where {@code cmdarray} is an array of all the tokens in 368 * {@code command}. 369 * 370 * <p>More precisely, the {@code command} string is broken 371 * into tokens using a {@link StringTokenizer} created by the call 372 * {@code new StringTokenizer(command)} with no 373 * further modification of the character categories. The tokens 374 * produced by the tokenizer are then placed in the new string 375 * array {@code cmdarray}, in the same order. 376 * 377 * @param command a specified system command. 378 * 379 * @param envp array of strings, each element of which 380 * has environment variable settings in the format 381 * <i>name</i>=<i>value</i>, or 382 * {@code null} if the subprocess should inherit 383 * the environment of the current process. 384 * 385 * @param dir the working directory of the subprocess, or 386 * {@code null} if the subprocess should inherit 387 * the working directory of the current process. 388 * 389 * @return A new {@link Process} object for managing the subprocess 390 * 391 * @throws SecurityException 392 * If a security manager exists and its 393 * {@link SecurityManager#checkExec checkExec} 394 * method doesn't allow creation of the subprocess 395 * 396 * @throws IOException 397 * If an I/O error occurs 398 * 399 * @throws NullPointerException 400 * If {@code command} is {@code null}, 401 * or one of the elements of {@code envp} is {@code null} 402 * 403 * @throws IllegalArgumentException 404 * If {@code command} is empty 405 * 406 * @see ProcessBuilder 407 * @since 1.3 408 */ 409 public Process exec(String command, String[] envp, File dir) 410 throws IOException { 411 if (command.isEmpty()) 412 throw new IllegalArgumentException("Empty command"); 413 414 StringTokenizer st = new StringTokenizer(command); 415 String[] cmdarray = new String[st.countTokens()]; 416 for (int i = 0; st.hasMoreTokens(); i++) 417 cmdarray[i] = st.nextToken(); 418 return exec(cmdarray, envp, dir); 419 } 420 421 /** 422 * Executes the specified command and arguments in a separate process. 423 * 424 * <p>This is a convenience method. An invocation of the form 425 * {@code exec(cmdarray)} 426 * behaves in exactly the same way as the invocation 427 * {@link #exec(String[], String[], File) exec}{@code (cmdarray, null, null)}. 428 * 429 * @param cmdarray array containing the command to call and 430 * its arguments. 431 * 432 * @return A new {@link Process} object for managing the subprocess 433 * 434 * @throws SecurityException 435 * If a security manager exists and its 436 * {@link SecurityManager#checkExec checkExec} 437 * method doesn't allow creation of the subprocess 438 * 439 * @throws IOException 440 * If an I/O error occurs 441 * 442 * @throws NullPointerException 443 * If {@code cmdarray} is {@code null}, 444 * or one of the elements of {@code cmdarray} is {@code null} 445 * 446 * @throws IndexOutOfBoundsException 447 * If {@code cmdarray} is an empty array 448 * (has length {@code 0}) 449 * 450 * @see ProcessBuilder 451 */ 452 public Process exec(String[] cmdarray) throws IOException { 453 return exec(cmdarray, null, null); 454 } 455 456 /** 457 * Executes the specified command and arguments in a separate process 458 * with the specified environment. 459 * 460 * <p>This is a convenience method. An invocation of the form 461 * {@code exec(cmdarray, envp)} 462 * behaves in exactly the same way as the invocation 463 * {@link #exec(String[], String[], File) exec}{@code (cmdarray, envp, null)}. 464 * 465 * @param cmdarray array containing the command to call and 466 * its arguments. 467 * 468 * @param envp array of strings, each element of which 469 * has environment variable settings in the format 470 * <i>name</i>=<i>value</i>, or 471 * {@code null} if the subprocess should inherit 472 * the environment of the current process. 473 * 474 * @return A new {@link Process} object for managing the subprocess 475 * 476 * @throws SecurityException 477 * If a security manager exists and its 478 * {@link SecurityManager#checkExec checkExec} 479 * method doesn't allow creation of the subprocess 480 * 481 * @throws IOException 482 * If an I/O error occurs 483 * 484 * @throws NullPointerException 485 * If {@code cmdarray} is {@code null}, 486 * or one of the elements of {@code cmdarray} is {@code null}, 487 * or one of the elements of {@code envp} is {@code null} 488 * 489 * @throws IndexOutOfBoundsException 490 * If {@code cmdarray} is an empty array 491 * (has length {@code 0}) 492 * 493 * @see ProcessBuilder 494 */ 495 public Process exec(String[] cmdarray, String[] envp) throws IOException { 496 return exec(cmdarray, envp, null); 497 } 498 499 500 /** 501 * Executes the specified command and arguments in a separate process with 502 * the specified environment and working directory. 503 * 504 * <p>Given an array of strings {@code cmdarray}, representing the 505 * tokens of a command line, and an array of strings {@code envp}, 506 * representing "environment" variable settings, this method creates 507 * a new process in which to execute the specified command. 508 * 509 * <p>This method checks that {@code cmdarray} is a valid operating 510 * system command. Which commands are valid is system-dependent, 511 * but at the very least the command must be a non-empty list of 512 * non-null strings. 513 * 514 * <p>If {@code envp} is {@code null}, the subprocess inherits the 515 * environment settings of the current process. 516 * 517 * <p>A minimal set of system dependent environment variables may 518 * be required to start a process on some operating systems. 519 * As a result, the subprocess may inherit additional environment variable 520 * settings beyond those in the specified environment. 521 * 522 * <p>{@link ProcessBuilder#start()} is now the preferred way to 523 * start a process with a modified environment. 524 * 525 * <p>The working directory of the new subprocess is specified by {@code dir}. 526 * If {@code dir} is {@code null}, the subprocess inherits the 527 * current working directory of the current process. 528 * 529 * <p>If a security manager exists, its 530 * {@link SecurityManager#checkExec checkExec} 531 * method is invoked with the first component of the array 532 * {@code cmdarray} as its argument. This may result in a 533 * {@link SecurityException} being thrown. 534 * 535 * <p>Starting an operating system process is highly system-dependent. 536 * Among the many things that can go wrong are: 537 * <ul> 538 * <li>The operating system program file was not found. 539 * <li>Access to the program file was denied. 540 * <li>The working directory does not exist. 541 * </ul> 542 * 543 * <p>In such cases an exception will be thrown. The exact nature 544 * of the exception is system-dependent, but it will always be a 545 * subclass of {@link IOException}. 546 * 547 * <p>If the operating system does not support the creation of 548 * processes, an {@link UnsupportedOperationException} will be thrown. 549 * 550 * 551 * @param cmdarray array containing the command to call and 552 * its arguments. 553 * 554 * @param envp array of strings, each element of which 555 * has environment variable settings in the format 556 * <i>name</i>=<i>value</i>, or 557 * {@code null} if the subprocess should inherit 558 * the environment of the current process. 559 * 560 * @param dir the working directory of the subprocess, or 561 * {@code null} if the subprocess should inherit 562 * the working directory of the current process. 563 * 564 * @return A new {@link Process} object for managing the subprocess 565 * 566 * @throws SecurityException 567 * If a security manager exists and its 568 * {@link SecurityManager#checkExec checkExec} 569 * method doesn't allow creation of the subprocess 570 * 571 * @throws UnsupportedOperationException 572 * If the operating system does not support the creation of processes. 573 * 574 * @throws IOException 575 * If an I/O error occurs 576 * 577 * @throws NullPointerException 578 * If {@code cmdarray} is {@code null}, 579 * or one of the elements of {@code cmdarray} is {@code null}, 580 * or one of the elements of {@code envp} is {@code null} 581 * 582 * @throws IndexOutOfBoundsException 583 * If {@code cmdarray} is an empty array 584 * (has length {@code 0}) 585 * 586 * @see ProcessBuilder 587 * @since 1.3 588 */ 589 public Process exec(String[] cmdarray, String[] envp, File dir) 590 throws IOException { 591 return new ProcessBuilder(cmdarray) 592 .environment(envp) 593 .directory(dir) 594 .start(); 595 } 596 597 /** 598 * Returns the number of processors available to the Java virtual machine. 599 * 600 * <p> This value may change during a particular invocation of the virtual 601 * machine. Applications that are sensitive to the number of available 602 * processors should therefore occasionally poll this property and adjust 603 * their resource usage appropriately. </p> 604 * 605 * @return the maximum number of processors available to the virtual 606 * machine; never smaller than one 607 * @since 1.4 608 */ 609 public native int availableProcessors(); 610 611 /** 612 * Returns the amount of free memory in the Java Virtual Machine. 613 * Calling the 614 * {@code gc} method may result in increasing the value returned 615 * by {@code freeMemory.} 616 * 617 * @return an approximation to the total amount of memory currently 618 * available for future allocated objects, measured in bytes. 619 */ 620 public native long freeMemory(); 621 622 /** 623 * Returns the total amount of memory in the Java virtual machine. 624 * The value returned by this method may vary over time, depending on 625 * the host environment. 626 * <p> 627 * Note that the amount of memory required to hold an object of any 628 * given type may be implementation-dependent. 629 * 630 * @return the total amount of memory currently available for current 631 * and future objects, measured in bytes. 632 */ 633 public native long totalMemory(); 634 635 /** 636 * Returns the maximum amount of memory that the Java virtual machine 637 * will attempt to use. If there is no inherent limit then the value 638 * {@link java.lang.Long#MAX_VALUE} will be returned. 639 * 640 * @return the maximum amount of memory that the virtual machine will 641 * attempt to use, measured in bytes 642 * @since 1.4 643 */ 644 public native long maxMemory(); 645 646 /** 647 * Runs the garbage collector in the Java Virtual Machine. 648 * <p> 649 * Calling this method suggests that the Java Virtual Machine 650 * expend effort toward recycling unused objects in order to 651 * make the memory they currently occupy available for reuse 652 * by the Java Virtual Machine. 653 * When control returns from the method call, the Java Virtual Machine 654 * has made a best effort to reclaim space from all unused objects. 655 * There is no guarantee that this effort will recycle any particular 656 * number of unused objects, reclaim any particular amount of space, or 657 * complete at any particular time, if at all, before the method returns or ever. 658 * There is also no guarantee that this effort will determine 659 * the change of reachability in any particular number of objects, 660 * or that any particular number of {@link java.lang.ref.Reference Reference} 661 * objects will be cleared and enqueued. 662 * <p> 663 * The name {@code gc} stands for "garbage 664 * collector". The Java Virtual Machine performs this recycling 665 * process automatically as needed, in a separate thread, even if the 666 * {@code gc} method is not invoked explicitly. 667 * <p> 668 * The method {@link System#gc()} is the conventional and convenient 669 * means of invoking this method. 670 */ 671 public native void gc(); 672 673 /** 674 * Runs the finalization methods of any objects pending finalization. 675 * Calling this method suggests that the Java virtual machine expend 676 * effort toward running the {@code finalize} methods of objects 677 * that have been found to be discarded but whose {@code finalize} 678 * methods have not yet been run. When control returns from the 679 * method call, the virtual machine has made a best effort to 680 * complete all outstanding finalizations. 681 * <p> 682 * The virtual machine performs the finalization process 683 * automatically as needed, in a separate thread, if the 684 * {@code runFinalization} method is not invoked explicitly. 685 * <p> 686 * The method {@link System#runFinalization()} is the conventional 687 * and convenient means of invoking this method. 688 * 689 * @see java.lang.Object#finalize() 690 */ 691 public void runFinalization() { 692 SharedSecrets.getJavaLangRefAccess().runFinalization(); 693 } 694 695 /** 696 * Loads the native library specified by the filename argument. The filename 697 * argument must be an absolute path name. 698 * (for example 699 * {@code Runtime.getRuntime().load("/home/avh/lib/libX11.so");}). 700 * 701 * If the filename argument, when stripped of any platform-specific library 702 * prefix, path, and file extension, indicates a library whose name is, 703 * for example, L, and a native library called L is statically linked 704 * with the VM, then the JNI_OnLoad_L function exported by the library 705 * is invoked rather than attempting to load a dynamic library. 706 * A filename matching the argument does not have to exist in the file 707 * system. 708 * See the <a href="{@docRoot}/../specs/jni/index.html"> JNI Specification</a> 709 * for more details. 710 * 711 * Otherwise, the filename argument is mapped to a native library image in 712 * an implementation-dependent manner. 713 * <p> 714 * First, if there is a security manager, its {@code checkLink} 715 * method is called with the {@code filename} as its argument. 716 * This may result in a security exception. 717 * <p> 718 * This is similar to the method {@link #loadLibrary(String)}, but it 719 * accepts a general file name as an argument rather than just a library 720 * name, allowing any file of native code to be loaded. 721 * <p> 722 * The method {@link System#load(String)} is the conventional and 723 * convenient means of invoking this method. 724 * 725 * @param filename the file to load. 726 * @throws SecurityException if a security manager exists and its 727 * {@code checkLink} method doesn't allow 728 * loading of the specified dynamic library 729 * @throws UnsatisfiedLinkError if either the filename is not an 730 * absolute path name, the native library is not statically 731 * linked with the VM, or the library cannot be mapped to 732 * a native library image by the host system. 733 * @throws NullPointerException if {@code filename} is 734 * {@code null} 735 * @see java.lang.Runtime#getRuntime() 736 * @see java.lang.SecurityException 737 * @see java.lang.SecurityManager#checkLink(java.lang.String) 738 */ 739 @CallerSensitive 740 public void load(String filename) { 741 load0(Reflection.getCallerClass(), filename); 742 } 743 744 void load0(Class<?> fromClass, String filename) { 745 @SuppressWarnings("removal") 746 SecurityManager security = System.getSecurityManager(); 747 if (security != null) { 748 security.checkLink(filename); 749 } 750 File file = new File(filename); 751 if (!file.isAbsolute()) { 752 throw new UnsatisfiedLinkError( 753 "Expecting an absolute path of the library: " + filename); 754 } 755 ClassLoader.loadLibrary(fromClass, file); 756 } 757 758 /** 759 * Loads the native library specified by the {@code libname} 760 * argument. The {@code libname} argument must not contain any platform 761 * specific prefix, file extension or path. If a native library 762 * called {@code libname} is statically linked with the VM, then the 763 * JNI_OnLoad_{@code libname} function exported by the library is invoked. 764 * See the <a href="{@docRoot}/../specs/jni/index.html"> JNI Specification</a> 765 * for more details. 766 * 767 * Otherwise, the libname argument is loaded from a system library 768 * location and mapped to a native library image in an 769 * implementation-dependent manner. 770 * <p> 771 * First, if there is a security manager, its {@code checkLink} 772 * method is called with the {@code libname} as its argument. 773 * This may result in a security exception. 774 * <p> 775 * The method {@link System#loadLibrary(String)} is the conventional 776 * and convenient means of invoking this method. If native 777 * methods are to be used in the implementation of a class, a standard 778 * strategy is to put the native code in a library file (call it 779 * {@code LibFile}) and then to put a static initializer: 780 * <blockquote><pre> 781 * static { System.loadLibrary("LibFile"); } 782 * </pre></blockquote> 783 * within the class declaration. When the class is loaded and 784 * initialized, the necessary native code implementation for the native 785 * methods will then be loaded as well. 786 * <p> 787 * If this method is called more than once with the same library 788 * name, the second and subsequent calls are ignored. 789 * 790 * @param libname the name of the library. 791 * @throws SecurityException if a security manager exists and its 792 * {@code checkLink} method doesn't allow 793 * loading of the specified dynamic library 794 * @throws UnsatisfiedLinkError if either the libname argument 795 * contains a file path, the native library is not statically 796 * linked with the VM, or the library cannot be mapped to a 797 * native library image by the host system. 798 * @throws NullPointerException if {@code libname} is 799 * {@code null} 800 * @see java.lang.SecurityException 801 * @see java.lang.SecurityManager#checkLink(java.lang.String) 802 */ 803 @CallerSensitive 804 public void loadLibrary(String libname) { 805 loadLibrary0(Reflection.getCallerClass(), libname); 806 } 807 808 void loadLibrary0(Class<?> fromClass, String libname) { 809 @SuppressWarnings("removal") 810 SecurityManager security = System.getSecurityManager(); 811 if (security != null) { 812 security.checkLink(libname); 813 } 814 if (libname.indexOf((int)File.separatorChar) != -1) { 815 throw new UnsatisfiedLinkError( 816 "Directory separator should not appear in library name: " + libname); 817 } 818 ClassLoader.loadLibrary(fromClass, libname); 819 } 820 821 /** 822 * Returns the version of the Java Runtime Environment as a {@link Version}. 823 * 824 * @return the {@link Version} of the Java Runtime Environment 825 * 826 * @since 9 827 */ 828 public static Version version() { 829 var v = version; 830 if (v == null) { 831 v = new Version(VersionProps.versionNumbers(), 832 VersionProps.pre(), VersionProps.build(), 833 VersionProps.optional()); 834 version = v; 835 } 836 return v; 837 } 838 839 /** 840 * A representation of a version string for an implementation of the 841 * Java SE Platform. A version string consists of a version number 842 * optionally followed by pre-release and build information. 843 * 844 * <h2><a id="verNum">Version numbers</a></h2> 845 * 846 * <p> A <em>version number</em>, {@code $VNUM}, is a non-empty sequence of 847 * elements separated by period characters (U+002E). An element is either 848 * zero, or an unsigned integer numeral without leading zeros. The final 849 * element in a version number must not be zero. When an element is 850 * incremented, all subsequent elements are removed. The format is: </p> 851 * 852 * <blockquote><pre> 853 * [1-9][0-9]*((\.0)*\.[1-9][0-9]*)* 854 * </pre></blockquote> 855 * 856 * <p> The sequence may be of arbitrary length but the first four elements 857 * are assigned specific meanings, as follows:</p> 858 * 859 * <blockquote><pre> 860 * $FEATURE.$INTERIM.$UPDATE.$PATCH 861 * </pre></blockquote> 862 * 863 * <ul> 864 * 865 * <li><p> <a id="FEATURE">{@code $FEATURE}</a> — The 866 * feature-release counter, incremented for every feature release 867 * regardless of release content. Features may be added in a feature 868 * release; they may also be removed, if advance notice was given at least 869 * one feature release ahead of time. Incompatible changes may be made 870 * when justified. </p></li> 871 * 872 * <li><p> <a id="INTERIM">{@code $INTERIM}</a> — The 873 * interim-release counter, incremented for non-feature releases that 874 * contain compatible bug fixes and enhancements but no incompatible 875 * changes, no feature removals, and no changes to standard APIs. 876 * </p></li> 877 * 878 * <li><p> <a id="UPDATE">{@code $UPDATE}</a> — The update-release 879 * counter, incremented for compatible update releases that fix security 880 * issues, regressions, and bugs in newer features. </p></li> 881 * 882 * <li><p> <a id="PATCH">{@code $PATCH}</a> — The emergency 883 * patch-release counter, incremented only when it's necessary to produce 884 * an emergency release to fix a critical issue. </p></li> 885 * 886 * </ul> 887 * 888 * <p> The fifth and later elements of a version number are free for use by 889 * platform implementors, to identify implementor-specific patch 890 * releases. </p> 891 * 892 * <p> A version number never has trailing zero elements. If an element 893 * and all those that follow it logically have the value zero then all of 894 * them are omitted. </p> 895 * 896 * <p> The sequence of numerals in a version number is compared to another 897 * such sequence in numerical, pointwise fashion; <em>e.g.</em>, {@code 898 * 10.0.4} is less than {@code 10.1.2}. If one sequence is shorter than 899 * another then the missing elements of the shorter sequence are considered 900 * to be less than the corresponding elements of the longer sequence; 901 * <em>e.g.</em>, {@code 10.0.2} is less than {@code 10.0.2.1}. </p> 902 * 903 * <h2><a id="verStr">Version strings</a></h2> 904 * 905 * <p> A <em>version string</em>, {@code $VSTR}, is a version number {@code 906 * $VNUM}, as described above, optionally followed by pre-release and build 907 * information, in one of the following formats: </p> 908 * 909 * <blockquote><pre> 910 * $VNUM(-$PRE)?\+$BUILD(-$OPT)? 911 * $VNUM-$PRE(-$OPT)? 912 * $VNUM(\+-$OPT)? 913 * </pre></blockquote> 914 * 915 * <p> where: </p> 916 * 917 * <ul> 918 * 919 * <li><p> <a id="pre">{@code $PRE}</a>, matching {@code ([a-zA-Z0-9]+)} 920 * — A pre-release identifier. Typically {@code ea}, for a 921 * potentially unstable early-access release under active development, or 922 * {@code internal}, for an internal developer build. </p></li> 923 * 924 * <li><p> <a id="build">{@code $BUILD}</a>, matching {@code 925 * (0|[1-9][0-9]*)} — The build number, incremented for each promoted 926 * build. {@code $BUILD} is reset to {@code 1} when any portion of {@code 927 * $VNUM} is incremented. </p></li> 928 * 929 * <li><p> <a id="opt">{@code $OPT}</a>, matching {@code ([-a-zA-Z0-9.]+)} 930 * — Additional build information, if desired. In the case of an 931 * {@code internal} build this will often contain the date and time of the 932 * build. </p></li> 933 * 934 * </ul> 935 * 936 * <p> A version string {@code 10-ea} matches {@code $VNUM = "10"} and 937 * {@code $PRE = "ea"}. The version string {@code 10+-ea} matches 938 * {@code $VNUM = "10"} and {@code $OPT = "ea"}. </p> 939 * 940 * <p> When comparing two version strings, the value of {@code $OPT}, if 941 * present, may or may not be significant depending on the chosen 942 * comparison method. The comparison methods {@link #compareTo(Version) 943 * compareTo()} and {@link #compareToIgnoreOptional(Version) 944 * compareToIgnoreOptional()} should be used consistently with the 945 * corresponding methods {@link #equals(Object) equals()} and {@link 946 * #equalsIgnoreOptional(Object) equalsIgnoreOptional()}. </p> 947 * 948 * <p> A <em>short version string</em>, {@code $SVSTR}, often useful in 949 * less formal contexts, is a version number optionally followed by a 950 * pre-release identifier:</p> 951 * 952 * <blockquote><pre> 953 * $VNUM(-$PRE)? 954 * </pre></blockquote> 955 * 956 * <p>This is a <a href="{@docRoot}/java.base/java/lang/doc-files/ValueBased.html">value-based</a> 957 * class; programmers should treat instances that are 958 * {@linkplain #equals(Object) equal} as interchangeable and should not 959 * use instances for synchronization, or unpredictable behavior may 960 * occur. For example, in a future release, synchronization may fail.</p> 961 * 962 * @since 9 963 */ 964 @jdk.internal.ValueBased 965 public static final class Version 966 implements Comparable<Version> 967 { 968 private final List<Integer> version; 969 private final Optional<String> pre; 970 private final Optional<Integer> build; 971 private final Optional<String> optional; 972 973 /* 974 * List of version number components passed to this constructor MUST 975 * be at least unmodifiable (ideally immutable). In the case of an 976 * unmodifiable list, the caller MUST hand the list over to this 977 * constructor and never change the underlying list. 978 */ 979 private Version(List<Integer> unmodifiableListOfVersions, 980 Optional<String> pre, 981 Optional<Integer> build, 982 Optional<String> optional) 983 { 984 this.version = unmodifiableListOfVersions; 985 this.pre = pre; 986 this.build = build; 987 this.optional = optional; 988 } 989 990 /** 991 * Parses the given string as a valid 992 * <a href="#verStr">version string</a> containing a 993 * <a href="#verNum">version number</a> followed by pre-release and 994 * build information. 995 * 996 * @param s 997 * A string to interpret as a version 998 * 999 * @throws IllegalArgumentException 1000 * If the given string cannot be interpreted as a valid 1001 * version 1002 * 1003 * @throws NullPointerException 1004 * If the given string is {@code null} 1005 * 1006 * @throws NumberFormatException 1007 * If an element of the version number or the build number 1008 * cannot be represented as an {@link Integer} 1009 * 1010 * @return The Version of the given string 1011 */ 1012 public static Version parse(String s) { 1013 if (s == null) 1014 throw new NullPointerException(); 1015 1016 // Shortcut to avoid initializing VersionPattern when creating 1017 // feature-version constants during startup 1018 if (isSimpleNumber(s)) { 1019 return new Version(List.of(Integer.parseInt(s)), 1020 Optional.empty(), Optional.empty(), Optional.empty()); 1021 } 1022 Matcher m = VersionPattern.VSTR_PATTERN.matcher(s); 1023 if (!m.matches()) 1024 throw new IllegalArgumentException("Invalid version string: '" 1025 + s + "'"); 1026 1027 // $VNUM is a dot-separated list of integers of arbitrary length 1028 String[] split = m.group(VersionPattern.VNUM_GROUP).split("\\."); 1029 Integer[] version = new Integer[split.length]; 1030 for (int i = 0; i < split.length; i++) { 1031 version[i] = Integer.parseInt(split[i]); 1032 } 1033 1034 Optional<String> pre = Optional.ofNullable( 1035 m.group(VersionPattern.PRE_GROUP)); 1036 1037 String b = m.group(VersionPattern.BUILD_GROUP); 1038 // $BUILD is an integer 1039 Optional<Integer> build = (b == null) 1040 ? Optional.empty() 1041 : Optional.of(Integer.parseInt(b)); 1042 1043 Optional<String> optional = Optional.ofNullable( 1044 m.group(VersionPattern.OPT_GROUP)); 1045 1046 // empty '+' 1047 if (!build.isPresent()) { 1048 if (m.group(VersionPattern.PLUS_GROUP) != null) { 1049 if (optional.isPresent()) { 1050 if (pre.isPresent()) 1051 throw new IllegalArgumentException("'+' found with" 1052 + " pre-release and optional components:'" + s 1053 + "'"); 1054 } else { 1055 throw new IllegalArgumentException("'+' found with neither" 1056 + " build or optional components: '" + s + "'"); 1057 } 1058 } else { 1059 if (optional.isPresent() && !pre.isPresent()) { 1060 throw new IllegalArgumentException("optional component" 1061 + " must be preceded by a pre-release component" 1062 + " or '+': '" + s + "'"); 1063 } 1064 } 1065 } 1066 return new Version(List.of(version), pre, build, optional); 1067 } 1068 1069 private static boolean isSimpleNumber(String s) { 1070 for (int i = 0; i < s.length(); i++) { 1071 char c = s.charAt(i); 1072 char lowerBound = (i > 0) ? '0' : '1'; 1073 if (c < lowerBound || c > '9') { 1074 return false; 1075 } 1076 } 1077 return true; 1078 } 1079 1080 /** 1081 * Returns the value of the <a href="#FEATURE">feature</a> element of 1082 * the version number. 1083 * 1084 * @return The value of the feature element 1085 * 1086 * @since 10 1087 */ 1088 public int feature() { 1089 return version.get(0); 1090 } 1091 1092 /** 1093 * Returns the value of the <a href="#INTERIM">interim</a> element of 1094 * the version number, or zero if it is absent. 1095 * 1096 * @return The value of the interim element, or zero 1097 * 1098 * @since 10 1099 */ 1100 public int interim() { 1101 return (version.size() > 1 ? version.get(1) : 0); 1102 } 1103 1104 /** 1105 * Returns the value of the <a href="#UPDATE">update</a> element of the 1106 * version number, or zero if it is absent. 1107 * 1108 * @return The value of the update element, or zero 1109 * 1110 * @since 10 1111 */ 1112 public int update() { 1113 return (version.size() > 2 ? version.get(2) : 0); 1114 } 1115 1116 /** 1117 * Returns the value of the <a href="#PATCH">patch</a> element of the 1118 * version number, or zero if it is absent. 1119 * 1120 * @return The value of the patch element, or zero 1121 * 1122 * @since 10 1123 */ 1124 public int patch() { 1125 return (version.size() > 3 ? version.get(3) : 0); 1126 } 1127 1128 /** 1129 * Returns the value of the major element of the version number. 1130 * 1131 * @deprecated As of Java SE 10, the first element of a version 1132 * number is not the major-release number but the feature-release 1133 * counter, incremented for every time-based release. Use the {@link 1134 * #feature()} method in preference to this method. For compatibility, 1135 * this method returns the value of the <a href="#FEATURE">feature</a> 1136 * element. 1137 * 1138 * @return The value of the feature element 1139 */ 1140 @Deprecated(since = "10") 1141 public int major() { 1142 return feature(); 1143 } 1144 1145 /** 1146 * Returns the value of the minor element of the version number, or 1147 * zero if it is absent. 1148 * 1149 * @deprecated As of Java SE 10, the second element of a version 1150 * number is not the minor-release number but the interim-release 1151 * counter, incremented for every interim release. Use the {@link 1152 * #interim()} method in preference to this method. For compatibility, 1153 * this method returns the value of the <a href="#INTERIM">interim</a> 1154 * element, or zero if it is absent. 1155 * 1156 * @return The value of the interim element, or zero 1157 */ 1158 @Deprecated(since = "10") 1159 public int minor() { 1160 return interim(); 1161 } 1162 1163 /** 1164 * Returns the value of the security element of the version number, or 1165 * zero if it is absent. 1166 * 1167 * @deprecated As of Java SE 10, the third element of a version 1168 * number is not the security level but the update-release counter, 1169 * incremented for every update release. Use the {@link #update()} 1170 * method in preference to this method. For compatibility, this method 1171 * returns the value of the <a href="#UPDATE">update</a> element, or 1172 * zero if it is absent. 1173 * 1174 * @return The value of the update element, or zero 1175 */ 1176 @Deprecated(since = "10") 1177 public int security() { 1178 return update(); 1179 } 1180 1181 /** 1182 * Returns an unmodifiable {@link java.util.List List} of the integers 1183 * represented in the <a href="#verNum">version number</a>. 1184 * The {@code List} always contains at least one element corresponding to 1185 * the <a href="#FEATURE">feature version number</a>. 1186 * 1187 * @return An unmodifiable list of the integers 1188 * represented in the version number 1189 */ 1190 public List<Integer> version() { 1191 return version; 1192 } 1193 1194 /** 1195 * Returns the optional <a href="#pre">pre-release</a> information. 1196 * 1197 * @return The optional pre-release information as a String 1198 */ 1199 public Optional<String> pre() { 1200 return pre; 1201 } 1202 1203 /** 1204 * Returns the <a href="#build">build number</a>. 1205 * 1206 * @return The optional build number. 1207 */ 1208 public Optional<Integer> build() { 1209 return build; 1210 } 1211 1212 /** 1213 * Returns <a href="#opt">optional</a> additional identifying build 1214 * information. 1215 * 1216 * @return Additional build information as a String 1217 */ 1218 public Optional<String> optional() { 1219 return optional; 1220 } 1221 1222 /** 1223 * Compares this version to another. 1224 * 1225 * <p> Each of the components in the <a href="#verStr">version</a> is 1226 * compared in the following order of precedence: version numbers, 1227 * pre-release identifiers, build numbers, optional build information. 1228 * </p> 1229 * 1230 * <p> Comparison begins by examining the sequence of version numbers. 1231 * If one sequence is shorter than another, then the missing elements 1232 * of the shorter sequence are considered to be less than the 1233 * corresponding elements of the longer sequence. </p> 1234 * 1235 * <p> A version with a pre-release identifier is always considered to 1236 * be less than a version without one. Pre-release identifiers are 1237 * compared numerically when they consist only of digits, and 1238 * lexicographically otherwise. Numeric identifiers are considered to 1239 * be less than non-numeric identifiers. </p> 1240 * 1241 * <p> A version without a build number is always less than one with a 1242 * build number; otherwise build numbers are compared numerically. </p> 1243 * 1244 * <p> The optional build information is compared lexicographically. 1245 * During this comparison, a version with optional build information is 1246 * considered to be greater than a version without one. </p> 1247 * 1248 * @param obj 1249 * The object to be compared 1250 * 1251 * @return A negative integer, zero, or a positive integer if this 1252 * {@code Version} is less than, equal to, or greater than the 1253 * given {@code Version} 1254 * 1255 * @throws NullPointerException 1256 * If the given object is {@code null} 1257 */ 1258 @Override 1259 public int compareTo(Version obj) { 1260 return compare(obj, false); 1261 } 1262 1263 /** 1264 * Compares this version to another disregarding optional build 1265 * information. 1266 * 1267 * <p> Two versions are compared by examining the version string as 1268 * described in {@link #compareTo(Version)} with the exception that the 1269 * optional build information is always ignored. </p> 1270 * 1271 * <p> This method provides ordering which is consistent with 1272 * {@code equalsIgnoreOptional()}. </p> 1273 * 1274 * @param obj 1275 * The object to be compared 1276 * 1277 * @return A negative integer, zero, or a positive integer if this 1278 * {@code Version} is less than, equal to, or greater than the 1279 * given {@code Version} 1280 * 1281 * @throws NullPointerException 1282 * If the given object is {@code null} 1283 */ 1284 public int compareToIgnoreOptional(Version obj) { 1285 return compare(obj, true); 1286 } 1287 1288 private int compare(Version obj, boolean ignoreOpt) { 1289 if (obj == null) 1290 throw new NullPointerException(); 1291 1292 int ret = compareVersion(obj); 1293 if (ret != 0) 1294 return ret; 1295 1296 ret = comparePre(obj); 1297 if (ret != 0) 1298 return ret; 1299 1300 ret = compareBuild(obj); 1301 if (ret != 0) 1302 return ret; 1303 1304 if (!ignoreOpt) 1305 return compareOptional(obj); 1306 1307 return 0; 1308 } 1309 1310 private int compareVersion(Version obj) { 1311 int size = version.size(); 1312 int oSize = obj.version().size(); 1313 int min = Math.min(size, oSize); 1314 for (int i = 0; i < min; i++) { 1315 int val = version.get(i); 1316 int oVal = obj.version().get(i); 1317 if (val != oVal) 1318 return val - oVal; 1319 } 1320 return size - oSize; 1321 } 1322 1323 private int comparePre(Version obj) { 1324 Optional<String> oPre = obj.pre(); 1325 if (!pre.isPresent()) { 1326 if (oPre.isPresent()) 1327 return 1; 1328 } else { 1329 if (!oPre.isPresent()) 1330 return -1; 1331 String val = pre.get(); 1332 String oVal = oPre.get(); 1333 if (val.matches("\\d+")) { 1334 return (oVal.matches("\\d+") 1335 ? (new BigInteger(val)).compareTo(new BigInteger(oVal)) 1336 : -1); 1337 } else { 1338 return (oVal.matches("\\d+") 1339 ? 1 1340 : val.compareTo(oVal)); 1341 } 1342 } 1343 return 0; 1344 } 1345 1346 private int compareBuild(Version obj) { 1347 Optional<Integer> oBuild = obj.build(); 1348 if (oBuild.isPresent()) { 1349 return (build.isPresent() 1350 ? build.get().compareTo(oBuild.get()) 1351 : -1); 1352 } else if (build.isPresent()) { 1353 return 1; 1354 } 1355 return 0; 1356 } 1357 1358 private int compareOptional(Version obj) { 1359 Optional<String> oOpt = obj.optional(); 1360 if (!optional.isPresent()) { 1361 if (oOpt.isPresent()) 1362 return -1; 1363 } else { 1364 if (!oOpt.isPresent()) 1365 return 1; 1366 return optional.get().compareTo(oOpt.get()); 1367 } 1368 return 0; 1369 } 1370 1371 /** 1372 * Returns a string representation of this version. 1373 * 1374 * @return The version string 1375 */ 1376 @Override 1377 public String toString() { 1378 StringBuilder sb 1379 = new StringBuilder(version.stream() 1380 .map(Object::toString) 1381 .collect(Collectors.joining("."))); 1382 1383 pre.ifPresent(v -> sb.append("-").append(v)); 1384 1385 if (build.isPresent()) { 1386 sb.append("+").append(build.get()); 1387 if (optional.isPresent()) 1388 sb.append("-").append(optional.get()); 1389 } else { 1390 if (optional.isPresent()) { 1391 sb.append(pre.isPresent() ? "-" : "+-"); 1392 sb.append(optional.get()); 1393 } 1394 } 1395 1396 return sb.toString(); 1397 } 1398 1399 /** 1400 * Determines whether this {@code Version} is equal to another object. 1401 * 1402 * <p> Two {@code Version}s are equal if and only if they represent the 1403 * same version string. 1404 * 1405 * @param obj 1406 * The object to which this {@code Version} is to be compared 1407 * 1408 * @return {@code true} if, and only if, the given object is a {@code 1409 * Version} that is identical to this {@code Version} 1410 * 1411 */ 1412 @Override 1413 public boolean equals(Object obj) { 1414 boolean ret = equalsIgnoreOptional(obj); 1415 if (!ret) 1416 return false; 1417 1418 Version that = (Version)obj; 1419 return (this.optional().equals(that.optional())); 1420 } 1421 1422 /** 1423 * Determines whether this {@code Version} is equal to another 1424 * disregarding optional build information. 1425 * 1426 * <p> Two {@code Version}s are equal if and only if they represent the 1427 * same version string disregarding the optional build information. 1428 * 1429 * @param obj 1430 * The object to which this {@code Version} is to be compared 1431 * 1432 * @return {@code true} if, and only if, the given object is a {@code 1433 * Version} that is identical to this {@code Version} 1434 * ignoring the optional build information 1435 * 1436 */ 1437 public boolean equalsIgnoreOptional(Object obj) { 1438 if (this == obj) 1439 return true; 1440 return (obj instanceof Version that) 1441 && (this.version().equals(that.version()) 1442 && this.pre().equals(that.pre()) 1443 && this.build().equals(that.build())); 1444 } 1445 1446 /** 1447 * Returns the hash code of this version. 1448 * 1449 * @return The hashcode of this version 1450 */ 1451 @Override 1452 public int hashCode() { 1453 int h = 1; 1454 int p = 17; 1455 1456 h = p * h + version.hashCode(); 1457 h = p * h + pre.hashCode(); 1458 h = p * h + build.hashCode(); 1459 h = p * h + optional.hashCode(); 1460 1461 return h; 1462 } 1463 } 1464 1465 private static class VersionPattern { 1466 // $VNUM(-$PRE)?(\+($BUILD)?(\-$OPT)?)? 1467 // RE limits the format of version strings 1468 // ([1-9][0-9]*(?:(?:\.0)*\.[1-9][0-9]*)*)(?:-([a-zA-Z0-9]+))?(?:(\+)(0|[1-9][0-9]*)?)?(?:-([-a-zA-Z0-9.]+))? 1469 1470 private static final String VNUM 1471 = "(?<VNUM>[1-9][0-9]*(?:(?:\\.0)*\\.[1-9][0-9]*)*)"; 1472 private static final String PRE = "(?:-(?<PRE>[a-zA-Z0-9]+))?"; 1473 private static final String BUILD 1474 = "(?:(?<PLUS>\\+)(?<BUILD>0|[1-9][0-9]*)?)?"; 1475 private static final String OPT = "(?:-(?<OPT>[-a-zA-Z0-9.]+))?"; 1476 private static final String VSTR_FORMAT = VNUM + PRE + BUILD + OPT; 1477 1478 static final Pattern VSTR_PATTERN = Pattern.compile(VSTR_FORMAT); 1479 1480 static final String VNUM_GROUP = "VNUM"; 1481 static final String PRE_GROUP = "PRE"; 1482 static final String PLUS_GROUP = "PLUS"; 1483 static final String BUILD_GROUP = "BUILD"; 1484 static final String OPT_GROUP = "OPT"; 1485 } 1486 }