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

/src/main/java/com/atlassian/bamboo/plugins/tomcat/manager/TomcatApplicationManagerImpl.java

https://bitbucket.org/atlassian/bamboo-tomcat-plugin/
Java | 342 lines | 288 code | 32 blank | 22 comment | 22 complexity | d55f197a4090c509a8fac952af06f91b MD5 | raw file
Possible License(s): Apache-2.0
  1. package com.atlassian.bamboo.plugins.tomcat.manager;
  2. import com.atlassian.bamboo.build.logger.BuildLogger;
  3. import com.atlassian.bamboo.plugins.tomcat.configuration.AbstractTomcatConfigurator;
  4. import com.atlassian.bamboo.task.CommonTaskContext;
  5. import com.atlassian.bamboo.task.TaskException;
  6. import com.atlassian.bamboo.variable.CustomVariableContext;
  7. import com.google.common.base.Predicate;
  8. import com.google.common.collect.Iterables;
  9. import com.google.common.collect.Lists;
  10. import org.apache.commons.httpclient.DefaultHttpMethodRetryHandler;
  11. import org.apache.commons.httpclient.HttpClient;
  12. import org.apache.commons.httpclient.HttpMethod;
  13. import org.apache.commons.httpclient.UsernamePasswordCredentials;
  14. import org.apache.commons.httpclient.auth.AuthScope;
  15. import org.apache.commons.httpclient.methods.GetMethod;
  16. import org.apache.commons.httpclient.methods.InputStreamRequestEntity;
  17. import org.apache.commons.httpclient.methods.PutMethod;
  18. import org.apache.commons.httpclient.params.HttpClientParams;
  19. import org.apache.commons.httpclient.params.HttpMethodParams;
  20. import org.apache.commons.io.IOUtils;
  21. import org.apache.commons.lang.StringUtils;
  22. import org.apache.log4j.Logger;
  23. import org.jetbrains.annotations.NotNull;
  24. import org.jetbrains.annotations.Nullable;
  25. import javax.servlet.http.HttpServletResponse;
  26. import java.io.File;
  27. import java.io.FileInputStream;
  28. import java.io.IOException;
  29. import java.io.UnsupportedEncodingException;
  30. import java.net.MalformedURLException;
  31. import java.net.URL;
  32. import java.net.URLEncoder;
  33. import java.util.List;
  34. public class TomcatApplicationManagerImpl implements TomcatApplicationManager
  35. {
  36. private static final Logger log = Logger.getLogger(TomcatApplicationManagerImpl.class);
  37. // ------------------------------------------------------------------------------------------------------- Constants
  38. // ------------------------------------------------------------------------------------------------- Type Properties
  39. private final String tomcatManagerUrl;
  40. private final HttpClient client;
  41. private boolean isTomcat6;
  42. private String confirmedTomcatVersion;
  43. @NotNull
  44. private final CustomVariableContext customVariableContext;
  45. @NotNull
  46. private final BuildLogger buildLogger;
  47. // ---------------------------------------------------------------------------------------------------- Dependencies
  48. // ---------------------------------------------------------------------------------------------------- Constructors
  49. public TomcatApplicationManagerImpl(@NotNull TomcatConnection tomcatCredentials, @NotNull CommonTaskContext taskContext, @NotNull final CustomVariableContext customVariableContext, @NotNull BuildLogger buildLogger) throws TaskException
  50. {
  51. this.customVariableContext = customVariableContext;
  52. this.buildLogger = buildLogger;
  53. try
  54. {
  55. this.tomcatManagerUrl = new URL(customVariableContext.substituteString(tomcatCredentials.getURL())).toString();
  56. }
  57. catch (MalformedURLException e)
  58. {
  59. throw new TaskException("Malformed Tomcat Manager URL, please fix your Tomcat Task configuration.", e);
  60. }
  61. HttpClientParams httpClientParams = new HttpClientParams();
  62. httpClientParams.setAuthenticationPreemptive(true);
  63. client = new HttpClient(httpClientParams);
  64. client.getState().setCredentials(AuthScope.ANY, new UsernamePasswordCredentials(customVariableContext.substituteString(tomcatCredentials.getUsername()), customVariableContext.substituteString(tomcatCredentials.getPassword())));
  65. this.isTomcat6 = taskContext.getConfigurationMap().getAsBoolean(AbstractTomcatConfigurator.TOMCAT_6);
  66. }
  67. // ----------------------------------------------------------------------------------------------- Interface Methods
  68. @NotNull
  69. @Override
  70. public List<Application> listApplications() throws IOException
  71. {
  72. final List<Application> applications = Lists.newArrayList();
  73. final String url = new StringBuilder(tomcatManagerUrl).append(getURLPrefix()).append("/list").toString();
  74. final String result = execute(new GetMethod(url));
  75. final String[] lines = StringUtils.split(result, '\n');
  76. if (lines.length > 1)
  77. {
  78. for (int i = 1; i < lines.length; i++)
  79. {
  80. final String[] appParts = StringUtils.split(lines[i], ":");
  81. applications.add(new Application(appParts[0], appParts[1], appParts[2], appParts[3]));
  82. }
  83. }
  84. return applications;
  85. }
  86. @Override
  87. public Application getApplicationByContext(@NotNull final String contextPath) throws IOException
  88. {
  89. return Iterables.find(listApplications(), new Predicate<Application>()
  90. {
  91. @Override
  92. public boolean apply(final Application application)
  93. {
  94. return contextPath.equals(application.getContext());
  95. }
  96. }, null);
  97. }
  98. @NotNull
  99. @Override
  100. public TomcatResult startApplication(@NotNull final String contextPath) throws IOException
  101. {
  102. final String url = new StringBuilder(tomcatManagerUrl).append(getURLPrefix()).append("/start?path=").append(encode(customVariableContext.substituteString(contextPath))).toString();
  103. final String result = execute(new GetMethod(url));
  104. return TomcatResult.parse(result);
  105. }
  106. @NotNull
  107. @Override
  108. public TomcatResult reloadApplication(@NotNull final String contextPath) throws IOException
  109. {
  110. final String url = new StringBuilder(tomcatManagerUrl).append(getURLPrefix()).append("/reload?path=").append(encode(customVariableContext.substituteString(contextPath))).toString();
  111. final String result = execute(new GetMethod(url));
  112. return TomcatResult.parse(result);
  113. }
  114. @NotNull
  115. @Override
  116. public TomcatResult stopApplication(@NotNull final String contextPath) throws IOException
  117. {
  118. final String url = new StringBuilder(tomcatManagerUrl).append(getURLPrefix()).append("/stop?path=").append(encode(customVariableContext.substituteString(contextPath))).toString();
  119. final String result = execute(new GetMethod(url));
  120. return TomcatResult.parse(result);
  121. }
  122. @NotNull
  123. @Override
  124. public TomcatResult undeployApplication(@NotNull final String contextPath) throws IOException
  125. {
  126. final String url = new StringBuilder(tomcatManagerUrl).append(getURLPrefix()).append("/undeploy?path=").append(encode(customVariableContext.substituteString(contextPath))).toString();
  127. final String result = execute(new GetMethod(url));
  128. return TomcatResult.parse(result);
  129. }
  130. @NotNull
  131. @Override
  132. public TomcatResult deployApplication(@NotNull final String contextPath, @Nullable final String version, @NotNull final String deploymentTag, @NotNull final File file) throws IOException
  133. {
  134. final FileInputStream inputStream = new FileInputStream(file);
  135. try
  136. {
  137. final StringBuilder urlBuilder = new StringBuilder(tomcatManagerUrl)
  138. .append(getURLPrefix())
  139. .append("/deploy?path=")
  140. .append(encode(customVariableContext.substituteString(contextPath)));
  141. if (version != null)
  142. {
  143. urlBuilder.append("&version=")
  144. .append(encode(customVariableContext.substituteString(version)));
  145. }
  146. urlBuilder.append("&update=true&tag=")
  147. .append(encode(customVariableContext.substituteString(deploymentTag)));
  148. final PutMethod putMethod = new PutMethod(urlBuilder.toString());
  149. putMethod.setRequestEntity(new InputStreamRequestEntity(inputStream, file.length()));
  150. // BAM-14883 InputStreamRequestEntity with length specified cannot be retried.
  151. putMethod.getParams().setParameter(HttpMethodParams.RETRY_HANDLER, new DefaultHttpMethodRetryHandler(0, false));
  152. final String result = execute(putMethod);
  153. return TomcatResult.parse(result);
  154. }
  155. finally {
  156. IOUtils.closeQuietly(inputStream);
  157. }
  158. }
  159. // -------------------------------------------------------------------------------------------------- Action Methods
  160. // -------------------------------------------------------------------------------------------------- Public Methods
  161. // -------------------------------------------------------------------------------------- Basic Accessors / Mutators
  162. @NotNull
  163. private String execute(HttpMethod httpMethod) throws IOException
  164. {
  165. try
  166. {
  167. addHeaders(httpMethod);
  168. client.executeMethod(httpMethod);
  169. final int status = httpMethod.getStatusCode();
  170. if (isSuccessfulCode(status))
  171. {
  172. return httpMethod.getResponseBodyAsString();
  173. }
  174. else
  175. {
  176. if (status == HttpServletResponse.SC_FORBIDDEN || status == HttpServletResponse.SC_UNAUTHORIZED)
  177. {
  178. throw new IOException("Could not connect to Tomcat manager at '" + httpMethod.getURI() + "' because the username and password provided is not authorized. Status: " + status);
  179. }
  180. throw new IOException("Could not connect to Tomcat manager at '" + httpMethod.getURI() + "'. Response code: " + status);
  181. }
  182. }
  183. finally
  184. {
  185. httpMethod.releaseConnection();
  186. }
  187. }
  188. private static boolean isSuccessfulCode(int status)
  189. {
  190. return status >= HttpServletResponse.SC_OK && status < HttpServletResponse.SC_MULTIPLE_CHOICES;
  191. }
  192. private void addHeaders(HttpMethod httpMethod)
  193. {
  194. httpMethod.setDoAuthentication(true);
  195. httpMethod.addRequestHeader("User-Agent", "Atlassian Tomcat API");
  196. httpMethod.getHostAuthState().isPreemptive();
  197. }
  198. private static String encode(String value)
  199. {
  200. try
  201. {
  202. return URLEncoder.encode(value, "UTF-8");
  203. }
  204. catch (UnsupportedEncodingException e)
  205. {
  206. throw new IllegalStateException(e);
  207. }
  208. }
  209. private String getURLPrefix()
  210. {
  211. if (confirmedTomcatVersion == null)
  212. {
  213. confirmTomcatVersionThroughServerInfo();
  214. }
  215. return getURLPrefixByTomcatVersion(isTomcat6);
  216. }
  217. /**
  218. * Use server info to confirm that the tomcat version is as configured.
  219. * Note that if we're unable to detect the Tomcat version automatically, we log that,
  220. * and then continue, assuming the user's configuration was correct but serverinfo is
  221. * somehow not available.
  222. */
  223. private void confirmTomcatVersionThroughServerInfo()
  224. {
  225. buildLogger.addBuildLogEntry("Confirm expected Tomcat manager location.");
  226. confirmedTomcatVersion = getTomcatVersionFromServerInfo(isTomcat6);
  227. if (confirmedTomcatVersion != null)
  228. {
  229. buildLogger.addBuildLogEntry("Confirmed Tomcat version: " + confirmedTomcatVersion);
  230. }
  231. else
  232. {
  233. buildLogger.addErrorLogEntry("Try likely variations of Tomcat manager location.");
  234. confirmedTomcatVersion = getTomcatVersionFromServerInfo(!isTomcat6);
  235. if (confirmedTomcatVersion != null)
  236. {
  237. if (isTomcat6)
  238. {
  239. buildLogger.addErrorLogEntry("Detected that Tomcat version is wrongly specified as 6.x but is actually: " + confirmedTomcatVersion);
  240. }
  241. else
  242. {
  243. buildLogger.addErrorLogEntry("Detected that Tomcat version is wrongly specified as 7.x or greater but is actually " + confirmedTomcatVersion);
  244. }
  245. isTomcat6 = !isTomcat6;
  246. }
  247. else
  248. {
  249. buildLogger.addErrorLogEntry("Could not detect Tomcat version from server info, trusting configuration of " +
  250. (isTomcat6 ? "Tomcat 6.x" : "Tomcat 7 or greater"));
  251. }
  252. }
  253. }
  254. /**
  255. * Look up the serverinfo of the Tomcat server, either at "manager/text/serverinfo" or "manager/serverinfo". Note
  256. * that while we print out and return the version found, the main thing this method does is confirm that something
  257. * is returned from the expected path.
  258. *
  259. * @return null if a version could not be read from the expected serverinfo path.
  260. */
  261. private String getTomcatVersionFromServerInfo(boolean isExpectingTomcat6)
  262. {
  263. GetMethod getMethod = new GetMethod(tomcatManagerUrl + getURLPrefixByTomcatVersion(isExpectingTomcat6) + "/serverinfo");
  264. addHeaders(getMethod);
  265. try
  266. {
  267. buildLogger.addBuildLogEntry("Trying to retrieve Tomcat details from " + getMethod.getURI());
  268. client.executeMethod(getMethod);
  269. }
  270. catch (IOException e)
  271. {
  272. buildLogger.addErrorLogEntry("Could not list server info from " + getMethod.getPath(), e);
  273. return null;
  274. }
  275. if (!isSuccessfulCode(getMethod.getStatusCode()))
  276. {
  277. buildLogger.addErrorLogEntry("Server info returned status code: " + getMethod.getStatusCode());
  278. return null;
  279. }
  280. String body = null;
  281. try
  282. {
  283. body = getMethod.getResponseBodyAsString();
  284. }
  285. catch (IOException e)
  286. {
  287. buildLogger.addErrorLogEntry("Error occurred trying to establish Tomcat version", e);
  288. }
  289. if (body == null)
  290. {
  291. buildLogger.addErrorLogEntry("Empty body occurred trying to establish Tomcat version");
  292. return null;
  293. }
  294. for (String line : StringUtils.split(body, '\n'))
  295. {
  296. if (line.startsWith("Tomcat Version: "))
  297. {
  298. buildLogger.addBuildLogEntry("Found " + line);
  299. return line.substring("Tomcat Version: ".length());
  300. }
  301. }
  302. buildLogger.addErrorLogEntry("Unable to find Tomcat Version in server info response: " + body);
  303. return null;
  304. }
  305. @NotNull
  306. private String getURLPrefixByTomcatVersion(boolean isTomcat6)
  307. {
  308. return isTomcat6 ? "" : "/text";
  309. }
  310. }