Java tutorial
/* * 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); } }