Java tutorial
/** * Copyright 2012 meltmedia * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.meltmedia.cadmium.cli; import com.beust.jcommander.Parameter; import com.beust.jcommander.Parameters; import com.google.gson.Gson; import com.google.gson.reflect.TypeToken; import com.meltmedia.cadmium.core.api.DeployRequest; import com.meltmedia.cadmium.core.api.UpdateRequest; import org.apache.commons.lang3.StringUtils; import org.apache.http.Header; import org.apache.http.HttpEntity; import org.apache.http.HttpResponse; import org.apache.http.HttpStatus; import org.apache.http.client.ClientProtocolException; import org.apache.http.client.HttpClient; import org.apache.http.client.methods.HttpGet; import org.apache.http.client.methods.HttpOptions; import org.apache.http.client.methods.HttpPost; import org.apache.http.entity.StringEntity; import org.apache.http.util.EntityUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import javax.ws.rs.core.MediaType; import java.io.IOException; import java.net.URI; import java.util.Arrays; import java.util.List; import java.util.Map; /** * This command is used to tell a Cadmium-Deployer instance to create and deploy a new Cadmium war. * * * @author Brian Barr * @author John McEntire * @author Christian Trimble * */ @Parameters(commandDescription = "Deploys the cadmium war to the specified(domain) server", separators = "=") public class DeployCommand extends AbstractAuthorizedOnly implements CliCommand { private final Logger log = LoggerFactory.getLogger(getClass()); @Parameter(names = "--branch", description = "The branch from which cadmium will serve content initially", required = false) private String branch; @Parameter(names = { "--configuration-branch", "-C" }, description = "The branch from which cadmium will load configuration from initially", required = false) private String configBranch; @Parameter(names = "--configuration-repo", description = "The git repository uri to load the configuration from. If not specified the configuration will load from the same repo as content.", required = false) private String configRepo; @Parameter(names = "--artifact", description = "The maven coordinates to a cadmium war.", required = false) private String artifact; @Parameter(names = "--disable-security", hidden = true) private boolean disableSecurity = false; @Parameter(description = "<repo> <site>", required = true) private List<String> parameters; /** * * @throws ClientProtocolException * @throws IOException */ public void execute() throws ClientProtocolException, IOException { if (parameters.size() < 2) { System.err.println("The site and repository must be specified."); System.exit(1); } String repo = parameters.get(0); String site = getSecureBaseUrl(parameters.get(1)); if (!site.endsWith("/")) site = site + "/"; if (StringUtils.isBlank(branch)) branch = UpdateRequest.CONTENT_BRANCH_PREFIX + "-master"; if (StringUtils.isBlank(configBranch)) configBranch = UpdateRequest.CONFIG_BRANCH_PREFIX + "-master"; boolean validRequest = true; if (!StringUtils.startsWithIgnoreCase(branch, UpdateRequest.CONTENT_BRANCH_PREFIX + "-")) { validRequest = false; System.err.println("Content branch must start with \"" + UpdateRequest.CONTENT_BRANCH_PREFIX + "-\""); } if (!StringUtils.startsWithIgnoreCase(configBranch, UpdateRequest.CONFIG_BRANCH_PREFIX + "-")) { validRequest = false; System.err.println( "Configuration branch must start with \"" + UpdateRequest.CONFIG_BRANCH_PREFIX + "-\""); } if (!validRequest) { System.exit(1); } String domain = URI.create(site).getHost(); String url = removeSubDomain(site) + "system/deploy"; System.out.println(url); log.debug("siteUrl + JERSEY_ENDPOINT = {}", url); String warName = null; try { HttpClient client = httpClient(); HttpPost post = new HttpPost(url); addAuthHeader(post); post.setHeader("Content-Type", MediaType.APPLICATION_JSON); DeployRequest req = new DeployRequest(); req.setBranch(branch); req.setConfigBranch(configBranch); req.setRepo(repo); req.setConfigRepo(StringUtils.isBlank(configRepo) ? repo : configRepo); req.setDomain(domain); req.setArtifact(artifact); req.setDisableSecurity(disableSecurity); post.setEntity(new StringEntity(new Gson().toJson(req), "UTF-8")); HttpResponse response = client.execute(post); if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) { HttpEntity entity = response.getEntity(); String resp = EntityUtils.toString(entity); try { post.releaseConnection(); } catch (Exception e) { log.warn("Failed to release connection.", e); } if (!resp.equals("ok") && canCheckWar(resp, url, client)) { System.out.println("Waiting for Jboss to deploy new war: " + resp); warName = resp; int secondsToWait = 120; while (secondsToWait-- > 0) { Thread.sleep(5000l); if (checkWarDeployment(warName, url, client)) { break; } } if (secondsToWait < 0) { System.err.println("Timeout: Deployment of cadmium application to [" + site + "], with repo [" + repo + "] and branch [" + branch + "]"); System.exit(1); } } else { System.out.println("Deployer not compatible with deployment waiting."); } log.debug("entity content type: {}", entity.getContentType().getValue()); System.out.println("Successfully deployed cadmium application to [" + site + "], with repo [" + repo + "] and branch [" + branch + "]"); } else { throw new Exception("Bad response status: " + response.getStatusLine().toString()); } } catch (Exception e) { System.err.println("Failed to deploy cadmium application to [" + site + "], with repo [" + repo + "] and branch [" + branch + "]"); if (warName != null) { try { System.err.println("Attempting to undeploy partial deployment of " + warName + "."); UndeployCommand.undeploy(removeSubDomain(site), warName, token); System.err.println(""); } catch (Exception e1) { System.err.println("Failed to undeploy partial deployment."); } } System.exit(1); } } @Override public String getCommandName() { return "deploy"; } /** * Removes the subdomain of the passed in url to get the url of the deployer instance. * * @param url * @return */ static String removeSubDomain(String url) { return url.replaceAll("\\A([^:]+://)[^\\.]+\\.(.*)\\Z", "$1$2"); } /** * Checks via an http options request that the endpoint exists to check for deployment state. * @param warName * @param url * @param client * @return */ public boolean canCheckWar(String warName, String url, HttpClient client) { HttpOptions opt = new HttpOptions(url + "/" + warName); try { HttpResponse response = client.execute(opt); if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) { Header allowHeader[] = response.getHeaders("Allow"); for (Header allow : allowHeader) { List<String> values = Arrays.asList(allow.getValue().toUpperCase().split(",")); if (values.contains("GET")) { return true; } } } EntityUtils.consumeQuietly(response.getEntity()); } catch (Exception e) { log.warn("Failed to check if endpoint exists.", e); } finally { opt.releaseConnection(); } return false; } private boolean started = false; public boolean checkWarDeployment(String warName, String url, HttpClient client) throws Exception { HttpGet get = new HttpGet(url + "/" + warName); try { HttpResponse response = client.execute(get); if (response.getStatusLine().getStatusCode() == HttpStatus.SC_OK) { Map<String, Object> responseObj = new Gson().fromJson(EntityUtils.toString(response.getEntity()), new TypeToken<Map<String, Object>>() { }.getType()); if (responseObj.get("errors") != null && responseObj.get("errors") instanceof List) { List<String> errors = (List<String>) responseObj.get("errors"); System.err.println("The following nodes have failed:"); for (String node : errors) { System.err.println(" " + node); } throw new Exception(); } if (!started && (Boolean) responseObj.get("started")) { started = true; System.out.println("The server has began to deploy."); } else if (started && !((Boolean) responseObj.get("started"))) { System.err.println("The server has stopped deploying the new war."); throw new Exception(); } if ((Boolean) responseObj.get("finished")) { return true; } } else { EntityUtils.consumeQuietly(response.getEntity()); System.err.println("Failed to wait for war to deploy."); throw new Exception(); } } finally { get.releaseConnection(); } return false; } }