/******************************************************************************* * Copyright (c) 2013 IBM Corporation and others * All rights reserved. This program and the accompanying materials * are made available under the terms of the Eclipse Public License v1.0 * which accompanies this distribution, and is available at * http://www.eclipse.org/legal/epl-v10.html * * Contributors: * IBM Corporation - initial API and implementation *******************************************************************************/ package org.eclipse.orion.server.cf.commands; import java.io.File; import java.net.URI; import javax.servlet.http.HttpServletResponse; import org.apache.commons.httpclient.Header; import org.apache.commons.httpclient.methods.GetMethod; import org.apache.commons.httpclient.methods.PutMethod; import org.apache.commons.httpclient.methods.multipart.FilePart; import org.apache.commons.httpclient.methods.multipart.MultipartRequestEntity; import org.apache.commons.httpclient.methods.multipart.Part; import org.apache.commons.httpclient.methods.multipart.StringPart; import org.eclipse.core.filesystem.IFileStore; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.URIUtil; import org.eclipse.orion.server.cf.CFProtocolConstants; import org.eclipse.orion.server.cf.ds.IDeploymentPackager; import org.eclipse.orion.server.cf.objects.App; import org.eclipse.orion.server.cf.objects.Target; import org.eclipse.orion.server.cf.utils.HttpUtil; import org.eclipse.orion.server.cf.utils.MultiServerStatus; import org.eclipse.orion.server.cf.utils.PackageUtils; import org.eclipse.orion.server.core.ServerStatus; import org.eclipse.osgi.util.NLS; import org.json.JSONObject; import org.slf4j.Logger; import org.slf4j.LoggerFactory; public class UploadBitsCommand extends AbstractCFApplicationCommand { private final Logger logger = LoggerFactory.getLogger("org.eclipse.orion.server.cf"); //$NON-NLS-1$ private static final int MAX_ATTEMPTS = 150; private String commandName; private IFileStore appStore; private String deployedAppPackageName; private String command; private IDeploymentPackager packager; public UploadBitsCommand(Target target, App app, IFileStore appStore, IDeploymentPackager packager, String command) { super(target, app); String[] bindings = {app.getName(), app.getGuid()}; this.commandName = NLS.bind("Upload application {0} bits (guid: {1})", bindings); this.appStore = appStore; this.packager = packager; this.command = command; } public String getDeployedAppPackageName() { return deployedAppPackageName; } @Override protected ServerStatus _doIt() { /* multi server status */ MultiServerStatus status = new MultiServerStatus(); try { /* upload project contents */ File appPackage = packager.getDeploymentPackage(super.getApplication(), appStore, command); deployedAppPackageName = PackageUtils.getApplicationPackageType(appStore); if (appPackage == null) { status.add(new ServerStatus(IStatus.ERROR, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Failed to read application content", null)); return status; } URI targetURI = URIUtil.toURI(target.getUrl()); PutMethod uploadMethod = new PutMethod(targetURI.resolve("/v2/apps/" + getApplication().getGuid() + "/bits?async=true").toString()); uploadMethod.addRequestHeader(new Header("Authorization", "bearer " + target.getCloud().getAccessToken().getString("access_token"))); Part[] parts = {new StringPart(CFProtocolConstants.V2_KEY_RESOURCES, "[]"), new FilePart(CFProtocolConstants.V2_KEY_APPLICATION, appPackage)}; uploadMethod.setRequestEntity(new MultipartRequestEntity(parts, uploadMethod.getParams())); /* send request */ ServerStatus jobStatus = HttpUtil.executeMethod(uploadMethod); status.add(jobStatus); if (!jobStatus.isOK()) return status; /* long running task, keep track */ int attemptsLeft = MAX_ATTEMPTS; JSONObject resp = jobStatus.getJsonData(); String taksStatus = resp.getJSONObject(CFProtocolConstants.V2_KEY_ENTITY).getString(CFProtocolConstants.V2_KEY_STATUS); while (!CFProtocolConstants.V2_KEY_FINISHED.equals(taksStatus) && !CFProtocolConstants.V2_KEY_FAILURE.equals(taksStatus)) { if (CFProtocolConstants.V2_KEY_FAILED.equals(taksStatus)) { /* delete the tmp file */ appPackage.delete(); status.add(new ServerStatus(IStatus.ERROR, HttpServletResponse.SC_BAD_REQUEST, "Upload failed", null)); return status; } if (attemptsLeft == 0) { /* delete the tmp file */ appPackage.delete(); status.add(new ServerStatus(IStatus.ERROR, HttpServletResponse.SC_BAD_REQUEST, "Upload timeout exceeded", null)); return status; } /* two seconds */ Thread.sleep(2000); /* check whether job has finished */ URI jobLocation = targetURI.resolve(resp.getJSONObject(CFProtocolConstants.V2_KEY_METADATA).getString(CFProtocolConstants.V2_KEY_URL)); GetMethod jobRequest = new GetMethod(jobLocation.toString()); ServerStatus confStatus = HttpUtil.configureHttpMethod(jobRequest, target.getCloud()); if (!confStatus.isOK()) return confStatus; /* send request */ jobStatus = HttpUtil.executeMethod(jobRequest); status.add(jobStatus); if (!jobStatus.isOK()) return status; resp = jobStatus.getJsonData(); taksStatus = resp.getJSONObject(CFProtocolConstants.V2_KEY_ENTITY).getString(CFProtocolConstants.V2_KEY_STATUS); --attemptsLeft; } if (CFProtocolConstants.V2_KEY_FAILURE.equals(jobStatus)) { status.add(new ServerStatus(IStatus.ERROR, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "Failed to upload application bits", null)); return status; } /* delete the tmp file */ appPackage.delete(); return status; } catch (Exception e) { String msg = NLS.bind("An error occured when performing operation {0}", commandName); //$NON-NLS-1$ logger.error(msg, e); status.add(new ServerStatus(IStatus.ERROR, HttpServletResponse.SC_INTERNAL_SERVER_ERROR, msg, e)); return status; } } }