de.thejeterlp.bukkit.updater.Updater.java Source code

Java tutorial

Introduction

Here is the source code for de.thejeterlp.bukkit.updater.Updater.java

Source

/*
 * Copyright 2014 TheJeterLP.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package de.thejeterlp.bukkit.updater;

import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStreamReader;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Map;
import org.bukkit.plugin.java.JavaPlugin;
import org.json.simple.JSONArray;
import org.json.simple.JSONValue;

/**
 * @author TheJeterLP
 */
public class Updater {

    private final int id;
    private URL url;
    private final JavaPlugin main;
    private final String link;
    private final boolean enabled;
    private final UpdateType type;
    private final ReleaseType rType;
    private final Config config;

    /**
     * Inits a new updater
     * Notice: Automatically generates a update-config.yml file to en- / disable the updater.
     * Bukkit has the rule that every updater needs to be able to get disabled.
     *
     * @param main: Your plugin's main file
     * @param id: Your project id. Can be found using (http://wiki.bukkit.org/ServerMods_API#Searching_for_project_IDs)
     * @param link: Your project slug. http://dev.bukkit.org/bukkit-plugins/ is added automatically.
     */
    public Updater(JavaPlugin main, int id, String link) {
        main.getLogger().info("Loading updater by TheJeterLP. Project id: " + id);
        config = new Config(main, "update-config.yml");
        this.type = Config.Values.UPDATE_TYPE.getUpdateType(config);
        this.rType = Config.Values.RELEASE_TYPE.getReleaseType(config);
        this.main = main;
        this.id = id;
        this.link = "http://dev.bukkit.org/bukkit-plugins/" + link;
        boolean enable = (id == -1 ? false : Config.Values.ENABLED.getBoolean(config));

        try {
            this.url = new URL("https://api.curseforge.com/servermods/files?projectIds=" + this.id);
        } catch (MalformedURLException ex) {
            enable = false;
            ex.printStackTrace();
        }

        if (enable) {
            main.getServer().getPluginManager().registerEvents(new UpdateListener(this), main);
        }
        this.enabled = enable;
        main.getLogger().info("Updatechecker is " + (this.enabled ? "enabled" : "disabled") + ".");
    }

    /**
     * Search for an update.
     */
    public void search() {
        debug("Method: search()");
        if (!enabled)
            return;
        main.getServer().getScheduler().scheduleSyncDelayedTask(main, new Runnable() {
            @Override
            public void run() {
                String[] data = read();
                if (checkForNewVersions(data)) {
                    main.getLogger().info("A new update is available! (" + data[1] + ") current: "
                            + main.getDescription().getVersion());
                    if (type == UpdateType.ANNOUNCE) {
                        main.getLogger().info("You can get it at: " + link);
                    } else {
                        main.getLogger().info(
                                "It will be downloaded for you and will be installed automatically when the server restarts.");
                    }
                }
            }
        }, 3 * 20);
    }

    /**
     * @return true: If the updater is enabled.
     */
    public boolean isEnabled() {
        return enabled;
    }

    /**
     * @return the plugin this updater belongs to
     */
    public JavaPlugin getPlugin() {
        return main;
    }

    /**
     * @return updateType
     */
    public UpdateType getUpdateType() {
        return type;
    }

    /**
     * @return releaseType
     */
    public ReleaseType getReleaseType() {
        return rType;
    }

    /**
     * @return dev.bukkit.org link
     */
    public String getLink() {
        return link;
    }

    /**
     * Perform a complete update-check and download new file
     *
     * @param data
     * @return
     */
    protected boolean checkForNewVersions(String[] data) {
        debug("Method: checkForNewVersions(String[])");
        if (data == null || !versionCheck(data))
            return false;
        if (type == UpdateType.DOWNLOAD) {
            downloadFile(data);
        }
        return true;
    }

    /**
     * Check if the remote version is higher than the current version.
     *
     * @param data
     * @return
     */
    protected boolean versionCheck(String[] data) {
        debug("Method: versionCheck(String[])");
        String title = data[1];
        if (this.rType != ReleaseType.ALL) {
            ReleaseType releaseType = ReleaseType.valueOf(data[2].toUpperCase());
            if (releaseType != this.rType) {
                debug("Releasetype of the new file does not match the one which we search for! Ignoring the file...");
                return false;
            }
        }
        String remote;
        if (title.contains(" v")) {
            remote = title.split(" v")[1];
        } else {
            remote = title;
        }
        ArrayList<String> rNumbers = new ArrayList<String>();
        ArrayList<String> numbers = new ArrayList<String>();
        rNumbers.addAll(Arrays.asList(remote.split("\\.")));

        if (main.getDescription().getVersion().contains("-")) {
            numbers.addAll(Arrays.asList(main.getDescription().getVersion().split("-")[0].split("\\.")));
            debug("numbers: " + Arrays.toString(numbers.toArray()));
        } else {
            numbers.addAll(Arrays.asList(main.getDescription().getVersion().split("\\.")));
            debug("numbers: " + Arrays.toString(numbers.toArray()));
        }

        if (rNumbers.size() > numbers.size()) {
            int missing = rNumbers.size() - numbers.size();
            for (int i = 0; i < missing; i++) {
                numbers.add("0");
            }
            debug("numbers: " + Arrays.toString(numbers.toArray()));
        } else if (numbers.size() > rNumbers.size()) {
            int missing = numbers.size() - rNumbers.size();
            for (int i = 0; i < missing; i++) {
                rNumbers.add("0");
            }
            debug("rNumbers: " + Arrays.toString(rNumbers.toArray()));
        }

        for (int i = 0; i < rNumbers.size(); i++) {
            int rNumber = Integer.valueOf(rNumbers.get(i));
            int number = Integer.valueOf(numbers.get(i));
            if (rNumber > number) {
                debug(rNumber + " is bigger than " + number
                        + ". This means there is a new version. Returnign true...");
                return true;
            } else if (number > rNumber) {
                main.getLogger().info(
                        "It seems that your version is newer than the one on BukkitDev. Maybe you are using a development build?");
                return false;
            }
        }
        main.getLogger().info("There is no new version available. You are up-to-date!");
        return false;
    }

    /**
     * Index:
     * 0: downloadUrl
     * 1: name
     * 2: releaseType
     *
     * @return
     */
    protected String[] read() {
        debug("Method: read()");
        try {
            URLConnection conn = url.openConnection();
            conn.setConnectTimeout(5000);
            conn.setDoOutput(true);
            BufferedReader reader = new BufferedReader(new InputStreamReader(conn.getInputStream()));
            String response = reader.readLine();
            JSONArray array = (JSONArray) JSONValue.parse(response);
            if (array.size() == 0)
                return null;
            Map<?, ?> map = (Map) array.get(array.size() - 1);
            String downloadUrl = (String) map.get("downloadUrl");
            String name = (String) map.get("name");
            String releaseType = (String) map.get("releaseType");
            return new String[] { downloadUrl, name, releaseType };
        } catch (Exception e) {
            main.getLogger().severe("Error on trying to check remote versions. Error: " + e);
            return null;
        }
    }

    /**
     * Downloads a new file from BukkitDev
     *
     * @param data
     */
    protected void downloadFile(final String[] data) {
        debug("Method: downlaoadFile(String[])");
        main.getServer().getScheduler().scheduleSyncDelayedTask(main, new Runnable() {
            @Override
            public void run() {
                main.getLogger().info("Downloading update from " + link);
                File update = main.getServer().getUpdateFolderFile();
                if (!update.exists()) {
                    update.mkdirs();
                }
                BufferedInputStream in = null;
                FileOutputStream fout = null;
                try {
                    final URL url = new URL(data[0]);
                    final int fileLength = url.openConnection().getContentLength();
                    final String fileName = new File(
                            main.getClass().getProtectionDomain().getCodeSource().getLocation().toURI()).getName();
                    File target = new File(update, fileName);

                    in = new BufferedInputStream(url.openStream());
                    fout = new FileOutputStream(target);
                    final byte[] data = new byte[1024];
                    int count;
                    long downloaded = 0;
                    while ((count = in.read(data, 0, 1024)) != -1) {
                        downloaded += count;
                        fout.write(data, 0, count);
                        final int percent = (int) ((downloaded * 100) / fileLength);
                        if ((percent % 10) == 0) {
                            main.getLogger().info("Downloaded " + percent + "% of " + fileLength + " bytes.");
                        }
                    }
                    main.getLogger().info("Download done!");
                } catch (final Exception ex) {
                    main.getLogger().severe("Error on trying to download update. Error: " + ex);
                } finally {
                    try {
                        if (in != null) {
                            in.close();
                        }
                        if (fout != null) {
                            fout.close();
                        }
                    } catch (final Exception ex) {
                        main.getLogger().severe("Error on trying to close Streams. Error: " + ex);
                    }
                }
            }
        });
    }

    protected void debug(String message) {
        if (!Config.Values.DEBUG.getBoolean(config))
            return;
        main.getLogger().info("[Debug] " + message);
    }
}