All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.rapidoid.deploy.DeploymentHandler Maven / Gradle / Ivy

package org.rapidoid.deploy;

import org.rapidoid.annotation.Authors;
import org.rapidoid.annotation.Since;
import org.rapidoid.commons.Str;
import org.rapidoid.gui.Btn;
import org.rapidoid.gui.GUI;
import org.rapidoid.html.Tag;
import org.rapidoid.http.Current;
import org.rapidoid.http.HttpVerb;
import org.rapidoid.http.Req;
import org.rapidoid.http.ReqHandler;
import org.rapidoid.io.IO;
import org.rapidoid.process.ProcessHandle;
import org.rapidoid.u.U;
import org.rapidoid.util.Msc;
import org.rapidoid.util.Tokens;

import java.io.File;
import java.util.Date;
import java.util.List;
import java.util.Map;

/*
 * #%L
 * rapidoid-platform
 * %%
 * Copyright (C) 2014 - 2017 Nikolche Mihajlovski and contributors
 * %%
 * 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.
 * #L%
 */

@Authors("Nikolche Mihajlovski")
@Since("5.1.0")
public class DeploymentHandler extends GUI implements ReqHandler {

	public static final String SCOPES = "POST:/rapidoid/stage, POST:/rapidoid/deploy, GET:POST:/rapidoid/deployment";

	private static final String DEPLOYMENT_HELP = "Application deployment works by uploading a JAR and executing it in a child Java process.";

	@Override
	public Object execute(Req req) throws Exception {
		List info = U.list();

		Map tokenData = U.map(Tokens._USER, Current.username(), Tokens._SCOPE, SCOPES);
		String token = Tokens.serialize(tokenData);

		String appJar = Msc.mainAppJar();
		String stagedAppJar = appJar + ".staged";

		info.add(h3("Deployment status:"));
		info.add(grid(jarsInfo(appJar, stagedAppJar, req)));

		info.add(h3("Your deployment token is:"));
		info.add(copy(textarea(token).rows("2").attr("readonly", "readonly").style("width:100%; font-size: 10px;")));

		info.add(h3("Upload an application JAR to stage it and then deploy it:"));
		info.add(render("upload-jar.html"));

		info.add(h3("Packaging and deploying with Maven:"));

		String cmd = "mvn clean org.rapidoid:app:deploy";
		info.add(copy(textarea(cmd).rows("2").attr("readonly", "readonly").style("width:100%; font-size: 10px;")));

		info.add(h3("HTTP API for Deployment:"));

		info.add(grid(apisInfo()));

		return multi(info);
	}

	@SuppressWarnings("unchecked")
	private List> jarsInfo(String appJar, String stagedAppJar, Req req) {
		return U.list(
			jarInfo(appJar, "Currently deployed application JAR", false, req),
			jarInfo(stagedAppJar, "Application JAR to be deployed", true, req)
		);
	}

	private Map jarInfo(final String filename, String desc, boolean staged, Req req) {

		File file = new File(filename);
		boolean exists = file.exists();

		String size = exists ? (file.length() / 1024) + " KB" : "";
		Object since = exists ? GUI.display(new Date(file.lastModified())) : "";

		Btn deploy = staged && exists ? btn("Deploy")
			.class_("btn btn-primary btn-xs")
			.confirm("Do you want to DEPLOY the application?")
			.onSuccess(new Runnable() {
				@Override
				public void run() {
					AppDeployer.deploy(filename, Str.trimr(filename, ".staged"));
				}
			}) : null;

		String cmd = staged ? "staged" : "deployed";
		Btn delete = exists
			? btn("Delete").command("delete_" + cmd)
			.class_("btn btn-danger btn-xs")
			.confirm("Do you want to delete the file '" + filename + "'?")
			: null;

		if (delete != null) {
			delete.onSuccess(new Runnable() {
				@Override
				public void run() {
					AppDeployer.stopApp("app");
					IO.delete(filename);
				}
			});
		}

		Btn details = null;
		Btn restart = null;

		if (!staged && exists) {

			List processes = AppDeployer.processes().items();
			if (U.notEmpty(processes)) {

				String procHandleId = processes.get(0).id();
				String processUrl = Msc.specialUri("processes/" + procHandleId);

				details = btn("Details")
					.class_("btn btn-default btn-xs")
					.go(processUrl);

				restart = btn("Restart")
					.class_("btn btn-warning btn-xs")
					.onSuccess(new Runnable() {
						@Override
						public void run() {
							AppDeployer.startOrRestartApp("app");
						}
					});
			}
		}

		return U.map(
			"file", filename,
			"description", desc,
			"exists", exists,
			"size", size,
			"since", since,
			"actions", multi(deploy, details, restart, delete)
		);
	}

	@SuppressWarnings("unchecked")
	private List> apisInfo() {
		return U.list(
			apiInfo("Staging of the application JAR",
				verb(HttpVerb.POST), "/rapidoid/stage",
				U.map("_token", "Deployment token", "file", ""),
				"curl -F '[email protected]' 'http://example.com/rapidoid/stage?_token=..."),

			apiInfo("Deployment of the staged JAR",
				verb(HttpVerb.POST), "/rapidoid/deploy",
				U.map("_token", "Deployment token"),
				"curl -X POST 'http://example.com/rapidoid/deploy?_token=...")
		);
	}

	private Map apiInfo(String desc, Tag verb, String uri, Map params, String example) {
		return U.map("description", desc, "verb", verb, "uri", span(uri).class_("text-box"), "parameters", grid(params).headless(true), "example", example);
	}
}