Skip to content

Commit

Permalink
Added UpgradeLog class, which will simplify doing upgrade tasks in th…
Browse files Browse the repository at this point in the history
…e future.
  • Loading branch information
LadyCailin committed Aug 7, 2013
1 parent 1421637 commit fa647ba
Show file tree
Hide file tree
Showing 4 changed files with 304 additions and 7 deletions.
Expand Up @@ -15,6 +15,12 @@ public class CacheAnnotations {
public static void main(String[] args) throws Exception {
File outputDir = new File(args[0]);
File scanDir = new File(args[1]);
if(outputDir.toString().startsWith("-classpath")){
//This happens when running locally. I dunno what that is, but we
//can skip this step.
System.out.println("Skipping annotation caching, running locally.");
return;
}
System.out.println("-- Caching annotations --");
System.out.println("Scanning for classes in " + scanDir.getAbsolutePath());
System.out.println("Outputting file to directory " + outputDir.getAbsolutePath());
Expand Down
Expand Up @@ -82,6 +82,11 @@ public class CommandHelperPlugin extends JavaPlugin {
private static int hostnameThreadPoolID = 0;
public static final File chDirectory = new File("plugins/CommandHelper");
public static final File preferencesFile = new File(chDirectory, "preferences.ini");
/**
* This is the
*/
public static final File cdcDir = new File(chDirectory, ".cache");
public static final File upgradeLogFile = new File(cdcDir, "upgradeLog.json");
public Profiler profiler;
public final ExecutionQueue executionQueue = new MethodScriptExecutionQueue("CommandHelperExecutionQueue", "default");
public PermissionsResolver permissionsResolver;
Expand All @@ -106,22 +111,58 @@ public class CommandHelperPlugin extends JavaPlugin {

@Override
public void onLoad() {
File cdcDir = new File(chDirectory, ".cache");
cdcDir.mkdirs();
ClassDiscoveryCache cdc = new ClassDiscoveryCache(cdcDir);
cdc.setLogger(Logger.getLogger(CommandHelperPlugin.class.getName()));
ClassDiscovery.getDefaultInstance().setClassDiscoveryCache(cdc);
ClassDiscovery.getDefaultInstance().addDiscoveryLocation(ClassDiscovery.GetClassContainer(CommandHelperPlugin.class));
ClassDiscovery.getDefaultInstance().addDiscoveryLocation(ClassDiscovery.GetClassContainer(Server.class));
Implementation.setServerType(Implementation.Type.BUKKIT);
try {
//Upgrade preferences.txt to preferences.ini
UpgradeLog upgradeLog = new UpgradeLog(upgradeLogFile);
upgradeLog.addUpgradeTask(new UpgradeLog.UpgradeTask() {

String version = null;
@Override
public boolean doRun() {
try {
version = "versionUpgrade-" + Main.loadSelfVersion();
return !hasBreadcrumb(version);
} catch (Exception ex) {
Logger.getLogger(CommandHelperPlugin.class.getName()).log(Level.SEVERE, null, ex);
return false;
}
}

@Override
public void run() {
leaveBreadcrumb(version);
}
});
upgradeLog.addUpgradeTask(new UpgradeLog.UpgradeTask() {

File oldPreferences = new File(chDirectory, "preferences.txt");
if(oldPreferences.exists() && !preferencesFile.exists()){
Logger.getLogger(CommandHelperPlugin.class.getName()).log(Level.WARNING, TermColors.BRIGHT_YELLOW + "Old preferences.txt file detected. Moving preferences.txt to preferences.ini.");
FileUtility.copy(oldPreferences, preferencesFile, true);
oldPreferences.deleteOnExit();
@Override
public boolean doRun() {
return oldPreferences.exists() && !preferencesFile.exists();
}

@Override
public void run() {
Logger.getLogger(CommandHelperPlugin.class.getName()).log(Level.WARNING, "{0}Old preferences.txt file detected. Moving preferences.txt to preferences.ini.", TermColors.BRIGHT_YELLOW);
try {
FileUtility.copy(oldPreferences, preferencesFile, true);
oldPreferences.deleteOnExit();
} catch (IOException ex) {
Logger.getLogger(CommandHelperPlugin.class.getName()).log(Level.SEVERE, null, ex);
}
}
});
try {
upgradeLog.runTasks();
} catch (IOException ex) {
Logger.getLogger(CommandHelperPlugin.class.getName()).log(Level.SEVERE, null, ex);
}
try{
Prefs.init(preferencesFile);
} catch (IOException ex) {
Logger.getLogger(CommandHelperPlugin.class.getName()).log(Level.SEVERE, null, ex);
Expand Down
135 changes: 135 additions & 0 deletions src/main/java/com/laytonsmith/core/UpgradeLog.java
@@ -0,0 +1,135 @@

package com.laytonsmith.core;

import com.laytonsmith.PureUtilities.FileUtility;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.SortedSet;
import java.util.TreeSet;
import org.json.simple.JSONValue;

/**
* This class performs a check to see if this is an upgrade, and if so,
* can be used to perform various upgrades. The upgrade log is updated with
* information about upgrade history, so upgrade actions are not performed
* unnecessarily.
*/
public class UpgradeLog {

private final File logFile;
private final List<UpgradeTask> tasks;
private final List<Upgrade> upgrades = new ArrayList<Upgrade>();

/**
* Creates a new UpgradeLog object.
* @param logFile The location of the upgrade log. This doesn't need to yet
* exist, but it does need to be createable as a file.
*/
public UpgradeLog(File logFile) {
this.logFile = logFile;
this.tasks = new ArrayList<UpgradeTask>();
}

/**
* Adds an upgrade task. This task will be run only if the task's
* doRun() method returns true.
* @param task
*/
public void addUpgradeTask(UpgradeTask task) {
tasks.add(task);
task.that = this;
}

/**
* Runs the required upgrade tasks. Tasks are run sequentially, from oldest to newest
* version tasks, starting with the last version that was run.
* @throws java.io.IOException If the output log can't be written to.
*/
public void runTasks() throws IOException{
if(logFile.exists()){
List<Map<String, String>> jsonUpgrades = (List<Map<String, String>>)JSONValue.parse(FileUtility.read(logFile));
for(Map<String, String> m : jsonUpgrades){
upgrades.add(Upgrade.fromMap(m));
}
}

for(UpgradeTask task : tasks){
if(task.doRun()){
task.run();
}
}

List<Map<String, String>> jsonUpgrades = new ArrayList<Map<String, String>>();
for(Upgrade u : upgrades){
jsonUpgrades.add(u.toMap());
}
String newJSON = JSONValue.toJSONString(jsonUpgrades);
FileUtility.write(newJSON, logFile);
}

public static abstract class UpgradeTask implements Runnable {
UpgradeLog that = null;

/**
* Checks to see if a previous task has left a breadcrumb.
* See {@link UpgradeTask#leaveBreadcrumb(java.lang.String)} for
* more information about breadcrumbs.
* @param breadcrumb
* @return
*/
protected boolean hasBreadcrumb(String breadcrumb){
for(Upgrade u : that.upgrades){
if(u.breadcrumb.equals(breadcrumb)){
return true;
}
}
return false;
}

/**
* This method should return true if the associated upgrade task
* should be run, or false if not. If true is returned, run() will
* be called. If false, run() will not be called.
* @return
*/
public abstract boolean doRun();

/**
* Leaves a breadcrumb. A breadcrumb should be a unique
* name, which can be used by future upgrade detection
* algorithms to determine if this task has run or not.
* @param breadcrumb
*/
protected void leaveBreadcrumb(String breadcrumb){
Upgrade u = new Upgrade();
u.breadcrumb = breadcrumb;
u.upgradeTime = System.currentTimeMillis();
that.upgrades.add(u);
}
}

private static class Upgrade {

String breadcrumb;
long upgradeTime;

public static Upgrade fromMap(Map<String, String> map){
Upgrade u = new Upgrade();
u.breadcrumb = map.get("breadcrumb");
u.upgradeTime = Long.parseLong(map.get("upgradeTime"));
return u;
}

public Map<String, String> toMap(){
Map<String, String> map = new HashMap<String, String>();
map.put("breadcrumb", breadcrumb);
map.put("upgradeTime", Long.toString(upgradeTime));
return map;
}
}
}
115 changes: 115 additions & 0 deletions src/test/java/com/laytonsmith/core/UpgradeLogTest.java
@@ -0,0 +1,115 @@
package com.laytonsmith.core;

import com.laytonsmith.PureUtilities.FileUtility;
import java.io.File;
import java.util.concurrent.atomic.AtomicInteger;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import static org.junit.Assert.*;

/**
*
*/
public class UpgradeLogTest {

public UpgradeLogTest() {
}

@BeforeClass
public static void setUpClass() {
}

@AfterClass
public static void tearDownClass() {
}

@Before
public void setUp() {
}

@After
public void tearDown() {
}

@Test
public void testOldTasksArentRun() throws Exception {
File log = new File("upgradeLogTestOldTasksArentRun");
FileUtility.write("[{\"upgradeTime\":\"1234\",\"breadcrumb\":\"task\"}]", log);
try{
UpgradeLog l = new UpgradeLog(log);
final AtomicInteger i = new AtomicInteger(0);
l.addUpgradeTask(new UpgradeLog.UpgradeTask() {

@Override
public boolean doRun() {
return false;
}

@Override
public void run() {
fail("This task should not run");
}
});
l.addUpgradeTask(new UpgradeLog.UpgradeTask() {

@Override
public boolean doRun() {
return !hasBreadcrumb("task");
}

@Override
public void run() {
fail("This task should not run");
}
});
l.addUpgradeTask(new UpgradeLog.UpgradeTask() {

@Override
public boolean doRun() {
return hasBreadcrumb("task");
}

@Override
public void run() {
i.incrementAndGet();
}
});
l.addUpgradeTask(new UpgradeLog.UpgradeTask() {

@Override
public boolean doRun() {
return true;
}

@Override
public void run() {
if(i.get() != 1){
fail("This task isn't sequential");
}
i.incrementAndGet();
}
});
l.addUpgradeTask(new UpgradeLog.UpgradeTask() {

@Override
public boolean doRun() {
return true;
}

@Override
public void run() {
leaveBreadcrumb("task2");
}
});
l.runTasks();
assertTrue(FileUtility.read(log).contains("task2"));
assertEquals(2, i.get());
} finally {
log.delete();
}
}

}

0 comments on commit fa647ba

Please sign in to comment.