View Javadoc

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   * Performs an upgrade of a plugin.  Originally copied from Confluence's AbstractUpgradeManager.
22   */
23  public class PluginUpgrader
24  {
25  
26      public static final String BUILD = ":build";
27      protected List<PluginUpgradeTask> upgradeTasks = new ArrayList<PluginUpgradeTask>();
28      private static final Logger log = LoggerFactory.getLogger(PluginUpgrader.class);
29      protected Plugin plugin;
30      protected PluginSettings pluginSettings;
31      protected List<Message> errors = new ArrayList<Message>();
32  
33      private static final Comparator<PluginUpgradeTask> UPGRADE_TASK_COMPARATOR = new Comparator<PluginUpgradeTask>()
34      {
35          public int compare(final PluginUpgradeTask t1, final PluginUpgradeTask t2)
36          {
37              if (t1 == null)
38              {
39                  return -1;
40              }
41              if (t2 == null)
42              {
43                  return 1;
44              }
45              if (t1.getBuildNumber() > t2.getBuildNumber())
46              {
47                  return 1;
48              }
49  
50              return (t1.getBuildNumber() < t2.getBuildNumber()) ? -1 : 0;
51          }
52      };
53  
54      protected PluginUpgrader(final Plugin plugin, final PluginSettings pluginSettings, final List<PluginUpgradeTask> upgradeTasks)
55      {
56          this.plugin = plugin;
57          this.pluginSettings = pluginSettings;
58          this.upgradeTasks = upgradeTasks;
59          Collections.sort(this.upgradeTasks, UPGRADE_TASK_COMPARATOR);
60      }
61  
62      protected List<Message> upgrade()
63      {
64          if (needUpgrade())
65          {
66              doUpgrade();
67          } 
68          return errors;
69      }
70  
71      protected void doUpgrade()
72      {
73          try
74          {
75              log.info("Upgrading plugin " + plugin.getKey());
76              for (final PluginUpgradeTask upgradeTask : upgradeTasks)
77              {
78  
79                  if (upgradeTask.getBuildNumber() <= getDataBuildNumber())
80                  {
81                      // Current buildnumber of data is higher or equal to this upgrade task. No need to run
82                      continue;
83                  }
84  
85                  final Collection<Message> messages = upgradeTask.doUpgrade();
86  
87                  if (messages == null || messages.isEmpty())
88                  {
89                      upgradeTaskSucceeded(upgradeTask);
90                  }
91                  else
92                  {
93                      upgradeTaskFailed(upgradeTask, messages);
94                  }
95              }
96          }
97          catch (final Throwable e)
98          {
99              // stringify the stacktrace.
100             StringWriter sw = new StringWriter();
101             e.printStackTrace(new PrintWriter(sw));
102 
103             // use a message here intentionally instead of key. it won't get translated.
104             errors.add(new DefaultMessage("Unexpected exception caught during plugin upgrade: " + sw.toString()));
105             log.error("Upgrade failed: " + e.getMessage(), e);
106         }
107         finally
108         {
109             postUpgrade();
110         }
111     }
112 
113 
114     protected void upgradeTaskSucceeded(final PluginUpgradeTask upgradeTask)
115     {
116         setDataBuildNumber(upgradeTask.getBuildNumber());
117         log.info("Upgraded plugin " + upgradeTask.getPluginKey() + " to version " + upgradeTask.getBuildNumber() + " - " + upgradeTask.getShortDescription());
118     }
119 
120     protected void upgradeTaskFailed(final PluginUpgradeTask upgradeTask, final Collection<Message> messages)
121     {
122         errors.addAll(messages);
123         final StringBuilder msg = new StringBuilder();
124         msg.append("Plugin upgrade failed for ").append(upgradeTask.getPluginKey());
125         msg.append(" to version ").append(upgradeTask.getBuildNumber());
126         msg.append(" - ").append(upgradeTask.getShortDescription());
127         msg.append("\n");
128         for (final Message message : messages)
129         {
130             msg.append("\t* ").append(message.getKey()).append(" ").append(Arrays.toString(message.getArguments()));
131         }
132 
133         log.warn(msg.toString());
134     }
135 
136     protected List<Message> getErrors()
137     {
138         return errors;
139     }
140 
141     protected boolean needUpgrade()
142     {
143         final PluginUpgradeTask lastUpgradeTask = this.upgradeTasks.get(this.upgradeTasks.size()-1);
144         final int dataBuildNumber = getDataBuildNumber();
145         log.info("Plugin: " +plugin.getKey() + ", current version: " + dataBuildNumber + ", highest upgrade task found: " + lastUpgradeTask.getBuildNumber() + ".");
146         return lastUpgradeTask.getBuildNumber() > dataBuildNumber;
147     }
148 
149 
150     /**
151      * This is the build number of the current version that the user is running under.
152      */
153     protected int getDataBuildNumber()
154     {
155         final String val = (String) pluginSettings.get(plugin.getKey() + BUILD);
156         if (val != null)
157         {
158             return Integer.parseInt(val);
159         }
160         else
161         {
162             return 0;
163         }
164     }
165 
166     protected void setDataBuildNumber(final int buildNumber)
167     {
168         pluginSettings.put(plugin.getKey() + BUILD, String.valueOf(buildNumber));
169     }
170 
171     protected void postUpgrade()
172     {
173         log.info("Plugin " + plugin.getKey() + " upgrade completed. Current version is: "+ getDataBuildNumber());
174     }
175 }