PageRenderTime 22ms CodeModel.GetById 30ms RepoModel.GetById 0ms app.codeStats 0ms

/plugin/src/main/java/com/atlassian/labs/speakeasy/manager/PluginSystemManager.java

https://github.com/mrdon/speakeasy-plugin
Java | 267 lines | 235 code | 29 blank | 3 comment | 27 complexity | e2bb2876fa57c62c6d149912a5ddaaee MD5 | raw file
  1. package com.atlassian.labs.speakeasy.manager;
  2. import com.atlassian.labs.speakeasy.external.PluginType;
  3. import com.atlassian.labs.speakeasy.commonjs.descriptor.CommonJsModulesDescriptor;
  4. import com.atlassian.labs.speakeasy.data.SpeakeasyData;
  5. import com.atlassian.labs.speakeasy.manager.convention.ZipPluginTypeHandler;
  6. import com.atlassian.labs.speakeasy.product.ProductAccessor;
  7. import com.atlassian.plugin.*;
  8. import com.atlassian.plugin.descriptors.UnloadableModuleDescriptor;
  9. import com.atlassian.plugin.descriptors.UnrecognisedModuleDescriptor;
  10. import com.atlassian.plugin.util.WaitUntil;
  11. import com.google.common.collect.ImmutableMap;
  12. import org.slf4j.Logger;
  13. import org.slf4j.LoggerFactory;
  14. import org.springframework.beans.factory.annotation.Autowired;
  15. import org.springframework.stereotype.Component;
  16. import java.io.File;
  17. import java.io.IOException;
  18. import java.util.HashMap;
  19. import java.util.List;
  20. import java.util.Map;
  21. import java.util.Set;
  22. /**
  23. *
  24. */
  25. @Component
  26. public class PluginSystemManager
  27. {
  28. private final PluginController pluginController;
  29. private final PluginAccessor pluginAccessor;
  30. private final SpeakeasyData data;
  31. private final ProductAccessor productAccessor;
  32. private static final Logger log = LoggerFactory.getLogger(PluginSystemManager.class);
  33. private final Map<PluginType,PluginTypeHandler> typeHandlers;
  34. @Autowired
  35. public PluginSystemManager(PluginController pluginController, PluginAccessor pluginAccessor, SpeakeasyData data,
  36. ProductAccessor productAccessor,
  37. JarPluginTypeHandler jarPluginTypeHandler, ZipPluginTypeHandler zipPluginTypeHandler, XmlPluginTypeHandler xmlPluginTypeHandler)
  38. {
  39. this.pluginController = pluginController;
  40. this.pluginAccessor = pluginAccessor;
  41. this.data = data;
  42. this.productAccessor = productAccessor;
  43. this.typeHandlers = ImmutableMap.of(
  44. PluginType.JAR, jarPluginTypeHandler,
  45. PluginType.ZIP, zipPluginTypeHandler,
  46. PluginType.XML, xmlPluginTypeHandler
  47. );
  48. }
  49. public String install(File pluginFile, String expectedPluginKey, String user) throws PluginOperationFailedException
  50. {
  51. PluginArtifact pluginArtifact = null;
  52. String pluginKey = null;
  53. for (PluginTypeHandler handler : typeHandlers.values())
  54. {
  55. pluginKey = handler.canInstall(pluginFile);
  56. if (pluginKey != null)
  57. {
  58. if (expectedPluginKey != null && !pluginKey.equals(expectedPluginKey))
  59. {
  60. throw new PluginOperationFailedException("Unable to install plugin file "+
  61. "because the expected plugin key, " + expectedPluginKey + ", is different than the one in the file - " +
  62. pluginKey, expectedPluginKey);
  63. }
  64. String recordedAuthor = data.getPluginAuthor(pluginKey);
  65. if (pluginAccessor.getPlugin(pluginKey) != null && !user.equals(recordedAuthor))
  66. {
  67. throw new PluginOperationFailedException("Unable to upgrade the '" + pluginKey + "' as you didn't install it", pluginKey);
  68. }
  69. pluginArtifact = handler.createArtifact(pluginFile);
  70. break;
  71. }
  72. }
  73. if (pluginArtifact == null || pluginKey == null)
  74. {
  75. throw new PluginOperationFailedException("Unable to handle plugin file " + pluginFile.toString() + ", likely due to an invalid plugin key", null);
  76. }
  77. data.setPluginAuthor(pluginKey, user);
  78. Set<String> pluginKeys = pluginController.installPlugins(pluginArtifact);
  79. if (pluginKeys.size() == 1)
  80. {
  81. final String installedKey = pluginKeys.iterator().next();
  82. final Plugin plugin = pluginAccessor.getPlugin(installedKey);
  83. WaitUntil.invoke(new WaitUntil.WaitCondition()
  84. {
  85. public boolean isFinished()
  86. {
  87. for (ModuleDescriptor desc : plugin.getModuleDescriptors())
  88. {
  89. if (!pluginAccessor.isPluginModuleEnabled(desc.getCompleteKey()) && desc instanceof UnrecognisedModuleDescriptor)
  90. {
  91. return false;
  92. }
  93. }
  94. return true;
  95. }
  96. public String getWaitMessage()
  97. {
  98. return "Waiting for all module descriptors to be resolved and enabled";
  99. }
  100. });
  101. if (!pluginAccessor.isPluginEnabled(plugin.getKey()))
  102. {
  103. String cause = "Plugin didn't install correctly";
  104. for (ModuleDescriptor descriptor : plugin.getModuleDescriptors())
  105. {
  106. if (descriptor instanceof UnloadableModuleDescriptor)
  107. {
  108. cause = ((UnloadableModuleDescriptor)descriptor).getErrorText();
  109. break;
  110. }
  111. }
  112. throw new PluginOperationFailedException(cause, plugin.getKey());
  113. }
  114. else
  115. {
  116. for (ModuleDescriptor descriptor : plugin.getModuleDescriptors())
  117. {
  118. if (descriptor instanceof CommonJsModulesDescriptor)
  119. {
  120. Set<String> unresolved = ((CommonJsModulesDescriptor)descriptor).getUnresolvedExternalModuleDependencies();
  121. if (!unresolved.isEmpty())
  122. {
  123. throw new PluginOperationFailedException("Plugin didn't install due to missing modules: " + unresolved, plugin.getKey());
  124. }
  125. }
  126. }
  127. }
  128. return plugin.getKey();
  129. }
  130. else
  131. {
  132. throw new PluginOperationFailedException("Plugin didn't install correctly", null);
  133. }
  134. }
  135. public void uninstall(String pluginKey, String user) throws PluginOperationFailedException
  136. {
  137. Plugin plugin = pluginAccessor.getPlugin(pluginKey);
  138. if (user.equals(data.getPluginAuthor(pluginKey))) {
  139. pluginController.uninstall(plugin);
  140. data.clearPluginAuthor(pluginKey);
  141. } else {
  142. throw new PluginOperationFailedException("User '" + user + "' is not the author of plugin '" + pluginKey + "' and cannot uninstall it", pluginKey);
  143. }
  144. }
  145. public File getPluginAsProject(final String pluginKey, final PluginType pluginType, final String user)
  146. {
  147. final Plugin plugin = pluginAccessor.getPlugin(pluginKey);
  148. final Map<String,Object> context = new HashMap<String,Object>() {{
  149. put("pluginKey", plugin.getKey());
  150. put("user", sanitizeUser(user));
  151. put("version", plugin.getPluginInformation().getVersion());
  152. put("author", data.getPluginAuthor(plugin.getKey()));
  153. put("product", productAccessor.getSdkName());
  154. put("productVersion", productAccessor.getVersion());
  155. put("productDataVersion", productAccessor.getDataVersion());
  156. put("speakeasyVersion", data.getSpeakeasyVersion());
  157. }};
  158. return typeHandlers.get(pluginType).getPluginAsProject(pluginKey, context);
  159. }
  160. public File getPluginArtifact(String pluginKey, PluginType pluginType)
  161. {
  162. try
  163. {
  164. return typeHandlers.get(pluginType).getPluginArtifact(pluginKey);
  165. }
  166. catch (IOException e)
  167. {
  168. throw new RuntimeException("Unable to create plugin project", e);
  169. }
  170. }
  171. public List<String> getPluginFileNames(String pluginKey, PluginType pluginType)
  172. {
  173. return typeHandlers.get(pluginType).getPluginFileNames(pluginKey);
  174. }
  175. private String sanitizeUser(String user)
  176. {
  177. return user.replace("@", "at");
  178. }
  179. public String getPluginFile(String pluginKey, PluginType type, String fileName)
  180. {
  181. try
  182. {
  183. return typeHandlers.get(type).getPluginFile(pluginKey, fileName);
  184. }
  185. catch (IOException e)
  186. {
  187. throw new IllegalArgumentException(e);
  188. }
  189. }
  190. public String saveAndRebuild(String pluginKey, PluginType pluginType, String fileName, String contents, String user) throws PluginOperationFailedException
  191. {
  192. try
  193. {
  194. File tmpFile = typeHandlers.get(pluginType).rebuildPlugin(pluginKey, fileName, contents);
  195. return install(tmpFile, pluginKey, user);
  196. }
  197. catch (IOException e)
  198. {
  199. e.printStackTrace();
  200. throw new PluginOperationFailedException("Unable to create extension file: " + e.getMessage(), e, pluginKey);
  201. }
  202. }
  203. public String forkAndInstall(String pluginKey, String forkPluginKey, PluginType pluginType, String user, String description) throws PluginOperationFailedException
  204. {
  205. if (pluginKey.contains("-fork-"))
  206. {
  207. throw new PluginOperationFailedException("Cannot fork an existing fork", pluginKey);
  208. }
  209. try
  210. {
  211. File forkFile = typeHandlers.get(pluginType).createFork(pluginKey, forkPluginKey, user, description);
  212. return install(forkFile, forkPluginKey, user);
  213. }
  214. catch (IOException e)
  215. {
  216. log.error(e.getMessage(), e);
  217. throw new PluginOperationFailedException("Unable to create forked plugin jar", e, pluginKey);
  218. }
  219. catch (RuntimeException e)
  220. {
  221. log.error(e.getMessage(), e);
  222. throw new PluginOperationFailedException("Unable transform plugin descriptor xml", e, pluginKey);
  223. }
  224. }
  225. public String createExtension(PluginType pluginType, String pluginKey, String remoteUser, String description, String name)
  226. {
  227. final PluginTypeHandler typeHandler = typeHandlers.get(pluginType);
  228. try
  229. {
  230. File tmpFile = typeHandler.createExample(pluginKey, name, description);
  231. return install(tmpFile, pluginKey, remoteUser);
  232. }
  233. catch (IOException e)
  234. {
  235. throw new PluginOperationFailedException("Unable to create extension", e, pluginKey);
  236. }
  237. }
  238. }