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