1 package com.atlassian.sal.core.upgrade;
2
3 import com.atlassian.plugin.Plugin;
4 import com.atlassian.sal.api.message.Message;
5 import com.atlassian.sal.api.pluginsettings.PluginSettings;
6 import com.atlassian.sal.api.upgrade.PluginUpgradeTask;
7 import com.atlassian.sal.core.message.DefaultMessage;
8 import org.slf4j.Logger;
9 import org.slf4j.LoggerFactory;
10
11 import java.io.PrintWriter;
12 import java.io.StringWriter;
13 import java.util.ArrayList;
14 import java.util.Arrays;
15 import java.util.Collection;
16 import java.util.Collections;
17 import java.util.Comparator;
18 import java.util.List;
19
20
21
22
23 public class PluginUpgrader {
24
25 public static final String BUILD = ":build";
26 protected List<PluginUpgradeTask> upgradeTasks = new ArrayList<PluginUpgradeTask>();
27 private static final Logger log = LoggerFactory.getLogger(PluginUpgrader.class);
28 protected Plugin plugin;
29 protected PluginSettings pluginSettings;
30 protected List<Message> errors = new ArrayList<Message>();
31
32 private static final Comparator<PluginUpgradeTask> UPGRADE_TASK_COMPARATOR = new Comparator<PluginUpgradeTask>() {
33 public int compare(final PluginUpgradeTask t1, final PluginUpgradeTask t2) {
34 if (t1 == null) {
35 return -1;
36 }
37 if (t2 == null) {
38 return 1;
39 }
40 if (t1.getBuildNumber() > t2.getBuildNumber()) {
41 return 1;
42 }
43
44 return (t1.getBuildNumber() < t2.getBuildNumber()) ? -1 : 0;
45 }
46 };
47
48 protected PluginUpgrader(final Plugin plugin, final PluginSettings pluginSettings, final List<PluginUpgradeTask> upgradeTasks) {
49 this.plugin = plugin;
50 this.pluginSettings = pluginSettings;
51 this.upgradeTasks = upgradeTasks;
52 Collections.sort(this.upgradeTasks, UPGRADE_TASK_COMPARATOR);
53 }
54
55 protected List<Message> upgrade() {
56 if (needUpgrade()) {
57 doUpgrade();
58 }
59 return errors;
60 }
61
62 protected void doUpgrade() {
63 try {
64 log.info("Upgrading plugin " + plugin.getKey());
65 for (final PluginUpgradeTask upgradeTask : upgradeTasks) {
66
67 if (upgradeTask.getBuildNumber() <= getDataBuildNumber()) {
68
69 continue;
70 }
71
72 final Collection<Message> messages = upgradeTask.doUpgrade();
73
74 if (messages == null || messages.isEmpty()) {
75 upgradeTaskSucceeded(upgradeTask);
76 } else {
77 upgradeTaskFailed(upgradeTask, messages);
78 }
79 }
80 } catch (final Throwable e) {
81
82 StringWriter sw = new StringWriter();
83 e.printStackTrace(new PrintWriter(sw));
84
85
86 errors.add(new DefaultMessage("Unexpected exception caught during plugin upgrade: " + sw.toString()));
87 log.error("Upgrade failed: " + e.getMessage(), e);
88 } finally {
89 postUpgrade();
90 }
91 }
92
93
94 protected void upgradeTaskSucceeded(final PluginUpgradeTask upgradeTask) {
95 setDataBuildNumber(upgradeTask.getBuildNumber());
96 log.info("Upgraded plugin " + upgradeTask.getPluginKey() + " to version " + upgradeTask.getBuildNumber() + " - " + upgradeTask.getShortDescription());
97 }
98
99 protected void upgradeTaskFailed(final PluginUpgradeTask upgradeTask, final Collection<Message> messages) {
100 errors.addAll(messages);
101 final StringBuilder msg = new StringBuilder();
102 msg.append("Plugin upgrade failed for ").append(upgradeTask.getPluginKey());
103 msg.append(" to version ").append(upgradeTask.getBuildNumber());
104 msg.append(" - ").append(upgradeTask.getShortDescription());
105 msg.append("\n");
106 for (final Message message : messages) {
107 msg.append("\t* ").append(message.getKey()).append(" ").append(Arrays.toString(message.getArguments()));
108 }
109
110 log.warn(msg.toString());
111 }
112
113 protected List<Message> getErrors() {
114 return errors;
115 }
116
117 protected boolean needUpgrade() {
118 final PluginUpgradeTask lastUpgradeTask = this.upgradeTasks.get(this.upgradeTasks.size() - 1);
119 final int dataBuildNumber = getDataBuildNumber();
120 final int lastUpgradeTaskBuildNumber = lastUpgradeTask.getBuildNumber();
121 log.debug("Plugin: {}, current version: {}, highest upgrade task found: {}.", new Object[]{plugin.getKey(), dataBuildNumber, lastUpgradeTaskBuildNumber});
122 return lastUpgradeTaskBuildNumber > dataBuildNumber;
123 }
124
125
126
127
128
129 protected int getDataBuildNumber() {
130 final String val = (String) pluginSettings.get(plugin.getKey() + BUILD);
131 if (val != null) {
132 return Integer.parseInt(val);
133 } else {
134 return 0;
135 }
136 }
137
138 protected void setDataBuildNumber(final int buildNumber) {
139 pluginSettings.put(plugin.getKey() + BUILD, String.valueOf(buildNumber));
140 }
141
142 protected void postUpgrade() {
143 log.info("Plugin " + plugin.getKey() + " upgrade completed. Current version is: " + getDataBuildNumber());
144 }
145 }