Util The Version object: Compatibility checking.

Discussion in 'Resources' started by Europia79, Jul 9, 2014.

Thread Status:
Not open for further replies.
  1. Offline

    Europia79

    I didn't see any threads on the subject of version checking, so I thought that I'd share this neat little class that I made for handling versions. My original class was flawed because it would convert 1.11.9 and 1.9.11 into 1119 and 1911 integers... which would completely fail at the comparison. Luckily, I caught it before it actually caused a runtime failure.

    This is the rewrite. A typical plugin version might be 1.2.3.4-b567, which will get converted into an array of [1][2][3][4][567]. Originally, I just made this to compare plugin versions, but I did add some a couple methods you can use for the server version.

    Github (open)


    Here are some examples on using it:
    Code:java
    1. public class SomePlugin extends JavaPlugin {
    2.  
    3. private Version<Server> server;
    4. public static final String MAX = "1.7.10-R9.9-SNAPSHOT";
    5. public static final String MIN = "1.2.5";
    6. public static final String NMS = VersionFactory.getNmsVersion().toString();
    7.  
    8. @Override
    9. public void onEnable() {
    10. server = VersionFactory.getServerVersion();
    11. if (!server.isSupported(MAX) || !server.isCompatible(MIN)) {
    12. getLogger().info("This plugin is not compatible with your server.");
    13. getLogger().info("The maximum supported version is " + MAX);
    14. getLogger().info("The minimum compatible version is " + MIN);
    15. Bukkit.getServer().getPluginManager().disablePlugin(this);
    16. return;
    17. }
    18. // ...
    19. Version<Plugin> HD = VersionFactory.getPluginVersion("HolographicDisplays");
    20. Version<Plugin> Holoapi = VersionFactory.getPluginVersion("HoloAPI");
    21. debug.log("HolographicDisplays version = " + HD.toString());
    22. debug.log("HoloAPI version = " + Holoapi.toString());
    23. if (ShowHolograms && HD.isCompatible("1.8.5")) {
    24. this.holograms = new HolographicDisplay(this);
    25. debug.log("HolographicDisplays support is enabled.");
    26. } else if (ShowHolograms && Holoapi.isEnabled()) {
    27. this.holograms = new HolographicAPI(this);
    28. debug.log("HoloAPI support is enabled.");
    29. } else {
    30. this.holograms = new HologramsOff();
    31. debug.log("Hologram support is disabled.");
    32. debug.log("Please download HoloAPI or HolographicDisplays to enable Hologram support.");
    33. }
    34. }
    35.  
    36. public static Class<?> getNmsClass(String clazz) throws Exception {
    37. return Class.forName("com.yourdomain.yourproject.compat." + NMS + "." + clazz);
    38. }
    39. }

    As you can see: isCompatible() takes the minimum version required to achieve compatibility.
    Whereas, isSupported() takes the maximum version that is supported.

    For example, the HolographicDisplays method, teleport(), wasn't added until version 1.8.5... So that's the minimum version you need to use that method. Notice that isCompatible() doesn't always require the full target version: 2.6 is equivalent to 2.6.0. However, isSupported() requires the full versions: if you pass "1.7.2" then the version check will fail if the server has "1.7.2-R0.3"

    Basically, I never used the Comparator/Comparable before... So I wrote this for Java practice. Anyways, this was a pretty fun class to write (especially since it fixes the other flawed class).
     
    LCastr0 likes this.
  2. Offline

    Europia79

    I fixed the compatibility check for GroupManager, with help from Tux2
    Here's what we came up with:
    Code:java
    1. Version gm = new Version("GroupManager");
    2. if (gm.contains("Dev")) {
    3. System.out.println("This server is running a Development build of GroupManager");
    4. Version dev = gm.getSubVersion("\\(Dev(\\d+)\\.(\\d+)\\.(\\d+)\\)");
    5. if (dev.isCompatible("2.14.88")) {
    6. System.out.println("Dev version is compatible");
    7. } else {
    8. System.out.println("Dev version is not compatible");
    9. }
    10. } else {
    11. System.out.println("This server is not running a Dev build of GroupManager");
    12. if (gm.isCompatible("2.1.11")) {
    13. System.out.println("GroupManager is compatible");
    14. } else {
    15. System.out.println("GroupManager is not compatible");
    16. }
    17. }

    (just replace System.out.println() with your code).

    You can always find the most recent version of this class on github:
    https://github.com/Europia79/Demolition/blob/master/src/mc/euro/demolition/util/Version.java

    And also, if there are any other plugins that would break my version checking algorithm, just lemme know so I can get it fixed. Thanks!
     
  3. Offline

    LCastr0

    This mighty be very usefull for a lot of people (Including me :p), thanks for posting!
     
  4. Offline

    Europia79

    LCastr0

    Yep, useful for checking dependencies before executing version dependent code.

    The class is updated btw. A couple of notes about the behavior of the Version object:

    You guys have to spell the plugin's name correctly because I don't throw any kind of PluginNotFoundException (should I ?). If the name is misspelled, then the compatibility check will fail (as intended). Consequently, I no longer have to do a null check on plugins because the compatibility methods() will do this for me.

    If the plugin isDisabled() then the compatibility check will also fail (as intended). Hopefully, it's a safe assumption that I don't want to call code from another plugin that is disabled, right ? Or are there scenarios where it's safe ? Like static method calls ?
     
  5. Offline

    Europia79

    Updated:

    I added a unit test.

    IMPORTANT: I changed the constructors and the factories: The constructor no longer accepts a plugin name. Instead pass the plugin name to the factory: Version.getPluginVersion("ExamplePlugin");

    Factory name changed: Version.getVersion() changed to Version.getPluginVersion() - Longer name, but more descriptive and consistent with the other factory names: getServerVersion() and getNmsVersion();

    The Version constructor now accepts a String version (which allows the class to be re-used in other situations).

    The Version object is IMMUTABLE. The internal version field will never changed. If you need to extract a sub-string (like for Dev builds), then getSubVersion() will return a new Version() object (not change the internal state).

    Also, i deleted all the String wrapper methods. Having them was kinda silly. Instead, just do toString().anyStringMethod(); For example, you might want to do toString().contains("Dev"); Additionally, since the main methods are isCompatible() and isSupported(), you might just want to do toString().equals("1_7_R4") comparison instead.
     
  6. Offline

    Europia79

    This class has been updated:

    https://github.com/Europia79/Version

    - Version is now completely independent of Bukkit
    - Created a VersionFactory specific to Bukkit
    - Added Predicate functional interface called Tester (see documentation)
    - Added Maven repository, compiled with jdk 6

    Check out the documentation on Github. It has examples for using the new VersionFactory as well as Maven information.

    Eventho, the functional interface defines a method called isEnabled(), you can actually perform ANY custom test you want. The method name, isEnabled(), simply gives a hint to the primary purpose. I was going to call the method test(), but I thought that might confuse people as to how to use it. (Using the Tester interface is completely optional).
     
Thread Status:
Not open for further replies.

Share This Page