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