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