/******************************************************************************* * Copyright (c) 2012-2015 Codenvy, S.A. * 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: * Codenvy, S.A. - initial API and implementation *******************************************************************************/ package org.eclipse.che.api.builder; import org.eclipse.che.api.builder.dto.BuildTaskDescriptor; import org.eclipse.che.api.builder.internal.Constants; import org.eclipse.che.api.core.ConflictException; import org.eclipse.che.api.core.ForbiddenException; import org.eclipse.che.api.core.NotFoundException; import org.eclipse.che.api.core.ServerException; import org.eclipse.che.api.core.UnauthorizedException; import org.eclipse.che.api.core.rest.HttpJsonHelper; import org.eclipse.che.api.core.rest.HttpOutputMessage; import org.eclipse.che.api.core.rest.shared.dto.Link; import org.eclipse.che.dto.server.DtoFactory; import com.google.common.io.ByteStreams; import com.google.common.io.Closer; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.IOException; import java.io.InputStream; import java.net.HttpURLConnection; import java.net.URL; /** * Representation of remote builder's task. * * @author andrew00x */ public class RemoteTask { private static final Logger LOG = LoggerFactory.getLogger(RemoteTask.class); private final String baseUrl; private final String builder; private final Long taskId; private final long created; /* Package visibility, not expected to be created by api users. They should use RemoteBuilder instead and get an instance of remote task. */ RemoteTask(String baseUrl, String builder, Long taskId) { this.baseUrl = baseUrl; this.builder = builder; this.taskId = taskId; created = System.currentTimeMillis(); } /** * Get unique id of this task. * * @return unique id of this task */ public Long getId() { return taskId; } /** Get date when this task was created. */ public long getCreationTime() { return created; } public String getBaseRemoteUrl() { return baseUrl; } public String getBuilder() { return builder; } /** * Get actual status of remote build process. * * @return status of remote build process * @throws BuilderException * if an error occurs * @throws NotFoundException * if can't get status of remote task because isn't available anymore, e.g. its already removed on remote server */ public BuildTaskDescriptor getBuildTaskDescriptor() throws BuilderException, NotFoundException { try { return HttpJsonHelper.get(BuildTaskDescriptor.class, String.format("%s/status/%s/%d", baseUrl, builder, taskId)); } catch (IOException e) { throw new BuilderException(e); } catch (ServerException | UnauthorizedException | ForbiddenException | ConflictException e) { throw new BuilderException(e.getServiceError()); } } /** * Cancel a remote build process. * * @return status of remote build process after the call * @throws BuilderException * if an error occurs * @throws NotFoundException * if can't cancel remote task because isn't available anymore, e.g. its already removed on remote server */ public BuildTaskDescriptor cancel() throws BuilderException, NotFoundException { final BuildTaskDescriptor descriptor = getBuildTaskDescriptor(); final Link link = descriptor.getLink(Constants.LINK_REL_CANCEL); if (link == null) { switch (descriptor.getStatus()) { case SUCCESSFUL: case FAILED: case CANCELLED: LOG.debug("Can't cancel build, status is {}", descriptor.getStatus()); return descriptor; default: throw new BuilderException("Can't cancel task. Cancellation link is not available"); } } try { return HttpJsonHelper.request(BuildTaskDescriptor.class, DtoFactory.getInstance().clone(link)); } catch (IOException e) { throw new BuilderException(e); } catch (ServerException | UnauthorizedException | ForbiddenException | ConflictException e) { throw new BuilderException(e.getServiceError()); } } /** * Copy logs of build process to specified {@code output}. * * @param output * output for logs content * @throws IOException * if an i/o error occurs * @throws BuilderException * if other error occurs */ public void readLogs(HttpOutputMessage output) throws IOException, BuilderException, NotFoundException { final BuildTaskDescriptor descriptor = getBuildTaskDescriptor(); final Link link = descriptor.getLink(Constants.LINK_REL_VIEW_LOG); if (link == null) { throw new BuilderException("Logs are not available."); } readFromUrl(link.getHref(), output); } /** * Copy report file of build process to specified {@code output}. * * @param output * output for report * @throws IOException * if an i/o error occurs * @throws BuilderException * if other error occurs * @see org.eclipse.che.api.builder.internal.BuildResult#getBuildReport() */ public void readReport(HttpOutputMessage output) throws IOException, BuilderException, NotFoundException { final BuildTaskDescriptor descriptor = getBuildTaskDescriptor(); final Link link = descriptor.getLink(Constants.LINK_REL_VIEW_REPORT); if (link == null) { throw new BuilderException("Report is not available."); } readFromUrl(link.getHref(), output); } /** * Download file to specified {@code output}. * * @param path * path to build artifact * @param output * output for download content * @throws IOException * if an i/o error occurs * @throws BuilderException * if other error occurs * @see org.eclipse.che.api.builder.internal.SlaveBuilderService#downloadFile(String, Long, String) * @see org.eclipse.che.api.builder.internal.BuildResult#getResults() */ public void downloadFile(String path, HttpOutputMessage output) throws IOException, BuilderException { readFromUrl(String.format("%s/download/%s/%d?path=%s", baseUrl, builder, taskId, path), output); } /** * Read file to specified {@code output}. * * @param path * path to build artifact * @param output * output for download content * @throws IOException * if an i/o error occurs * @throws BuilderException * if other error occurs * @see org.eclipse.che.api.builder.internal.SlaveBuilderService#viewFile(String, Long, String) * @see org.eclipse.che.api.builder.internal.BuildResult#getResults() */ public void readFile(String path, HttpOutputMessage output) throws IOException, BuilderException { readFromUrl(String.format("%s/view/%s/%d?path=%s", baseUrl, builder, taskId, path), output); } public void browseDirectory(String path, HttpOutputMessage output) throws IOException, BuilderException { readFromUrl(String.format("%s/browse/%s/%d?path=%s", baseUrl, builder, taskId, path), output); } public void listDirectory(String path, HttpOutputMessage output) throws IOException, BuilderException { readFromUrl(String.format("%s/tree/%s/%d?path=%s", baseUrl, builder, taskId, path), output); } public void downloadResultArchive(String archType, HttpOutputMessage output) throws IOException, BuilderException, NotFoundException { final BuildTaskDescriptor descriptor = getBuildTaskDescriptor(); Link link = null; if (archType.equals("zip")) { link = descriptor.getLink(Constants.LINK_REL_DOWNLOAD_RESULTS_ZIPBALL); } else if (archType.equals("tar")) { link = descriptor.getLink(Constants.LINK_REL_DOWNLOAD_RESULTS_TARBALL); } if (link == null) { throw new BuilderException(String.format("%s archive with build result is not available.", archType)); } readFromUrl(link.getHref(), output); } private void readFromUrl(String url, final HttpOutputMessage output) throws IOException { final HttpURLConnection conn = (HttpURLConnection)new URL(url).openConnection(); conn.setConnectTimeout(60 * 1000); conn.setReadTimeout(60 * 1000); conn.setRequestMethod("GET"); try { output.setStatus(conn.getResponseCode()); final String contentType = conn.getContentType(); if (contentType != null) { output.setContentType(contentType); } // for download files final String contentDisposition = conn.getHeaderField("Content-Disposition"); if (contentDisposition != null) { output.addHttpHeader("Content-Disposition", contentDisposition); } Closer closer = Closer.create(); try { InputStream errorStream = closer.register(conn.getErrorStream()); InputStream in = errorStream != null ? errorStream : closer.register(conn.getInputStream()); ByteStreams.copy(in, closer.register(output.getOutputStream())); } catch (Throwable e) { throw closer.rethrow(e); } finally { closer.close(); } } finally { conn.disconnect(); } } }