Java tutorial
/** * Copyright (C) 2015 Red Hat, Inc. (jcasey@redhat.com) * * 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.redhat.red.build.koji; import com.redhat.red.build.koji.config.KojiConfig; import com.redhat.red.build.koji.model.ImportFile; import com.redhat.red.build.koji.model.KojiImportResult; import com.redhat.red.build.koji.model.json.KojiImport; import com.redhat.red.build.koji.model.json.util.KojiObjectMapper; import com.redhat.red.build.koji.model.xmlrpc.KojiBuildInfo; import com.redhat.red.build.koji.model.xmlrpc.KojiNVR; import com.redhat.red.build.koji.model.xmlrpc.KojiPermission; import com.redhat.red.build.koji.model.xmlrpc.KojiSessionInfo; import com.redhat.red.build.koji.model.xmlrpc.KojiTagInfo; import com.redhat.red.build.koji.model.xmlrpc.KojiTagQuery; import com.redhat.red.build.koji.model.xmlrpc.KojiUploaderResult; import com.redhat.red.build.koji.model.xmlrpc.KojiUserInfo; import com.redhat.red.build.koji.model.xmlrpc.KojiXmlRpcBindery; import com.redhat.red.build.koji.model.xmlrpc.messages.AllPermissionsRequest; import com.redhat.red.build.koji.model.xmlrpc.messages.AllPermissionsResponse; import com.redhat.red.build.koji.model.xmlrpc.messages.ApiVersionRequest; import com.redhat.red.build.koji.model.xmlrpc.messages.ApiVersionResponse; import com.redhat.red.build.koji.model.xmlrpc.messages.CGImportRequest; import com.redhat.red.build.koji.model.xmlrpc.messages.CheckPermissionRequest; import com.redhat.red.build.koji.model.xmlrpc.messages.ConfirmationResponse; import com.redhat.red.build.koji.model.xmlrpc.messages.CreateTagRequest; import com.redhat.red.build.koji.model.xmlrpc.messages.GetBuildByIdOrNameRequest; import com.redhat.red.build.koji.model.xmlrpc.messages.GetBuildByNVRObjRequest; import com.redhat.red.build.koji.model.xmlrpc.messages.GetBuildResponse; import com.redhat.red.build.koji.model.xmlrpc.messages.GetTagIdRequest; import com.redhat.red.build.koji.model.xmlrpc.messages.IdResponse; import com.redhat.red.build.koji.model.xmlrpc.messages.ListBuildsRequest; import com.redhat.red.build.koji.model.xmlrpc.messages.ListBuildsResponse; import com.redhat.red.build.koji.model.xmlrpc.messages.ListTagsRequest; import com.redhat.red.build.koji.model.xmlrpc.messages.ListTagsResponse; import com.redhat.red.build.koji.model.xmlrpc.messages.LoggedInUserRequest; import com.redhat.red.build.koji.model.xmlrpc.messages.LoginRequest; import com.redhat.red.build.koji.model.xmlrpc.messages.LoginResponse; import com.redhat.red.build.koji.model.xmlrpc.messages.LogoutRequest; import com.redhat.red.build.koji.model.xmlrpc.messages.StatusResponse; import com.redhat.red.build.koji.model.xmlrpc.messages.TagRequest; import com.redhat.red.build.koji.model.xmlrpc.messages.TagResponse; import com.redhat.red.build.koji.model.xmlrpc.messages.UploadResponse; import com.redhat.red.build.koji.model.xmlrpc.messages.UserRequest; import com.redhat.red.build.koji.model.xmlrpc.messages.UserResponse; import org.apache.http.client.methods.CloseableHttpResponse; import org.apache.http.client.methods.HttpPost; import org.apache.http.entity.InputStreamEntity; import org.apache.http.impl.client.CloseableHttpClient; import org.commonjava.maven.atlas.ident.ref.ProjectVersionRef; import org.commonjava.rwx.binding.error.BindException; import org.commonjava.rwx.error.XmlRpcException; import org.commonjava.rwx.http.RequestModifier; import org.commonjava.rwx.http.UrlBuildResult; import org.commonjava.rwx.http.UrlBuilder; import org.commonjava.rwx.http.httpclient4.HC4SyncObjectClient; import org.commonjava.util.jhttpc.HttpFactory; import org.commonjava.util.jhttpc.JHttpCException; import org.commonjava.util.jhttpc.auth.MemoryPasswordManager; import org.commonjava.util.jhttpc.auth.PasswordManager; import org.commonjava.util.jhttpc.util.UrlUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.io.ByteArrayInputStream; import java.io.ByteArrayOutputStream; import java.io.Closeable; import java.io.IOException; import java.io.InputStream; import java.io.UnsupportedEncodingException; import java.net.MalformedURLException; import java.net.URLEncoder; import java.text.SimpleDateFormat; import java.util.Collections; import java.util.Date; import java.util.HashMap; import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; import java.util.concurrent.Callable; import java.util.concurrent.ExecutionException; import java.util.concurrent.ExecutorCompletionService; import java.util.concurrent.ExecutorService; import java.util.concurrent.Future; import java.util.concurrent.atomic.AtomicInteger; import java.util.function.Consumer; import java.util.function.Supplier; import static com.redhat.red.build.koji.model.xmlrpc.KojiXmlRpcConstants.ACCEPT_ENCODING_HEADER; import static com.redhat.red.build.koji.model.xmlrpc.KojiXmlRpcConstants.ADLER_32_CHECKSUM; import static com.redhat.red.build.koji.model.xmlrpc.KojiXmlRpcConstants.CALL_NUMBER_PARAM; import static com.redhat.red.build.koji.model.xmlrpc.KojiXmlRpcConstants.EMBEDDED_ERROR_PARAM; import static com.redhat.red.build.koji.model.xmlrpc.KojiXmlRpcConstants.IDENTITY_ENCODING_VALUE; import static com.redhat.red.build.koji.model.xmlrpc.KojiXmlRpcConstants.METADATA_JSON_FILE; import static com.redhat.red.build.koji.model.xmlrpc.KojiXmlRpcConstants.SESSION_ID_PARAM; import static com.redhat.red.build.koji.model.xmlrpc.KojiXmlRpcConstants.SESSION_KEY_PARAM; import static com.redhat.red.build.koji.model.xmlrpc.KojiXmlRpcConstants.SSL_LOGIN_PATH; import static com.redhat.red.build.koji.model.xmlrpc.KojiXmlRpcConstants.UPLOAD_CHECKSUM_TYPE_PARAM; import static com.redhat.red.build.koji.model.xmlrpc.KojiXmlRpcConstants.UPLOAD_DIR_PARAM; import static com.redhat.red.build.koji.model.xmlrpc.KojiXmlRpcConstants.UPLOAD_FILENAME_PARAM; import static com.redhat.red.build.koji.model.xmlrpc.KojiXmlRpcConstants.UPLOAD_OFFSET_PARAM; import static com.redhat.red.build.koji.model.xmlrpc.KojiXmlRpcConstants.UPLOAD_OVERWRITE_PARAM; import static org.apache.commons.lang.StringUtils.isEmpty; import static org.apache.commons.lang.StringUtils.isNotEmpty; import static org.apache.http.client.utils.HttpClientUtils.closeQuietly; /** * Created by jdcasey on 12/3/15. */ public class KojiClient implements Closeable { private HC4SyncObjectClient xmlrpcClient; private HttpFactory httpFactory; private ExecutorService executorService; private ExecutorCompletionService<KojiUploaderResult> uploadService; private KojiObjectMapper objectMapper; private KojiConfig config; private KojiXmlRpcBindery bindery; private AtomicInteger callCount = new AtomicInteger(0); private static final RequestModifier STANDARD_REQUEST_MODIFIER = (request) -> { request.setHeader(ACCEPT_ENCODING_HEADER, IDENTITY_ENCODING_VALUE); Logger logger = LoggerFactory.getLogger(KojiClient.class); logger.debug("\n\n\n\nTarget URI: {}\n\n\n\n", request.getURI()); }; private static final UrlBuilder NO_OP_URL_BUILDER = (url) -> new UrlBuildResult(url); private UrlBuilder sessionUrlBuilder(KojiSessionInfo session) { return sessionUrlBuilder(session, null); } private UrlBuilder sessionUrlBuilder(KojiSessionInfo session, Supplier<Map<String, Object>> paramEditor) { return (url) -> { if (session == null) { return new UrlBuildResult(url); } Map<String, String> params = new HashMap<>(); params.put(SESSION_ID_PARAM, Integer.toString(session.getSessionId())); params.put(SESSION_KEY_PARAM, session.getSessionKey()); params.put(CALL_NUMBER_PARAM, Integer.toString(callCount.getAndIncrement())); if (paramEditor != null) { Map<String, Object> extraParams = paramEditor.get(); if (extraParams != null) { MalformedURLException error = (MalformedURLException) extraParams.get(EMBEDDED_ERROR_PARAM); if (error != null) { return new UrlBuildResult(error); } else { extraParams.forEach((key, value) -> { params.put(key, String.valueOf(value)); }); } } } String result = UrlUtils.buildUrl(url, params); Logger logger = LoggerFactory.getLogger(KojiClient.class); logger.debug("\n\n\n\nBuild URL: {}\n\n\n\n", result); return new UrlBuildResult(result); }; } public KojiClient(KojiConfig config, PasswordManager passwordManager, ExecutorService executorService) throws BindException { this.config = config; this.bindery = new KojiXmlRpcBindery(); this.httpFactory = new HttpFactory(passwordManager); this.executorService = executorService; setup(); } public synchronized void close() { if (xmlrpcClient != null) { xmlrpcClient.close(); xmlrpcClient = null; } } public void setup() { uploadService = new ExecutorCompletionService<KojiUploaderResult>(executorService); objectMapper = new KojiObjectMapper(); Logger logger = LoggerFactory.getLogger(getClass()); logger.debug("SETUP: Starting KojiClient for: " + config.getKojiURL()); try { xmlrpcClient = new HC4SyncObjectClient(httpFactory, bindery, config.getKojiSiteConfig()); } catch (IOException e) { logger.error("Cannot construct koji HTTP site-config: " + e.getMessage(), e); xmlrpcClient.close(); xmlrpcClient = null; } if (xmlrpcClient != null) { try { ApiVersionResponse response = xmlrpcClient.call(new ApiVersionRequest(), ApiVersionResponse.class, NO_OP_URL_BUILDER, STANDARD_REQUEST_MODIFIER); if (1 != response.getApiVersion()) { logger.error("Cannot connect to koji at: " + config.getKojiURL() + ". API Version reported is '" + response.getApiVersion() + "' but this client only supports version 1."); xmlrpcClient.close(); xmlrpcClient = null; } } catch (XmlRpcException e) { logger.error("Cannot retrieve koji API version from: " + config.getKojiURL() + ". (Reason: " + e.getMessage() + ")", e); xmlrpcClient.close(); xmlrpcClient = null; } } } public int getApiVersion() throws KojiClientException { checkConnection(); Logger logger = LoggerFactory.getLogger(getClass()); try { ApiVersionResponse response = xmlrpcClient.call(new ApiVersionRequest(), ApiVersionResponse.class, NO_OP_URL_BUILDER, STANDARD_REQUEST_MODIFIER); return response.getApiVersion(); } catch (XmlRpcException e) { throw new KojiClientException("Cannot retrieve koji API version from: %s. (Reason: %s)", e, config.getKojiURL(), e.getMessage()); } } public KojiSessionInfo login() throws KojiClientException { checkConnection(); try { UrlBuilder urlBuilder = (url) -> new UrlBuildResult(UrlUtils.buildUrl(url, SSL_LOGIN_PATH)); RequestModifier requestModifier = (request) -> request.setHeader(ACCEPT_ENCODING_HEADER, IDENTITY_ENCODING_VALUE); LoginResponse loginResponse = xmlrpcClient.call(new LoginRequest(), LoginResponse.class, urlBuilder, requestModifier); return loginResponse == null ? null : loginResponse.getSessionInfo(); } catch (XmlRpcException e) { throw new KojiClientException("Failed to login: %s", e, e.getMessage()); } } public <T> T withKojiSession(KojiCustomCommand<T> command) throws KojiClientException { KojiSessionInfo session = null; T result = null; try { session = login(); result = command.execute(session); } catch (Exception e) { Logger logger = LoggerFactory.getLogger(getClass()); logger.error("Lambda failed", e); if (e instanceof KojiClientException) { throw e; } else { throw new KojiClientException("Lambda command failed: %s", e, e.getMessage()); } } finally { logout(session); } return result; } public KojiUserInfo getLoggedInUserInfo(String username) throws KojiClientException { checkConnection(); try { UserResponse response = xmlrpcClient.call(new UserRequest(username), UserResponse.class, NO_OP_URL_BUILDER, STANDARD_REQUEST_MODIFIER); return response == null ? null : response.getUserInfo(); } catch (XmlRpcException e) { throw new KojiClientException("Failed to retrieve current user info: %s", e, e.getMessage()); } } public KojiUserInfo getLoggedInUserInfo(KojiSessionInfo session) throws KojiClientException { checkConnection(); try { UserResponse response = xmlrpcClient.call(new LoggedInUserRequest(), UserResponse.class, sessionUrlBuilder(session), STANDARD_REQUEST_MODIFIER); return response == null ? null : response.getUserInfo(); } catch (XmlRpcException e) { throw new KojiClientException("Failed to retrieve current user info: %s", e, e.getMessage()); } } public void logout(KojiSessionInfo session) { if (session == null) { return; } if (xmlrpcClient != null) { try { StatusResponse response = xmlrpcClient.call(new LogoutRequest(), StatusResponse.class, sessionUrlBuilder(session), STANDARD_REQUEST_MODIFIER); if (isNotEmpty(response.getError())) { Logger logger = LoggerFactory.getLogger(getClass()); logger.error("Failed to logout from Koji: {}", response.getError()); } } catch (XmlRpcException e) { Logger logger = LoggerFactory.getLogger(getClass()); logger.error(String.format("Failed to logout: %s", e.getMessage()), e); } } } private void checkConnection() throws KojiClientException { if (xmlrpcClient == null) { throw new KojiClientException("Connection to koji at %s is closed. Perhaps it failed to initialize?", config.getKojiURL()); } } public Set<KojiPermission> getAllPermissions(KojiSessionInfo session) throws KojiClientException { checkConnection(); try { AllPermissionsResponse response = xmlrpcClient.call(new AllPermissionsRequest(), AllPermissionsResponse.class, sessionUrlBuilder(session), STANDARD_REQUEST_MODIFIER); return response.getPermissions(); } catch (XmlRpcException e) { throw new KojiClientException("Failed to retrieve listing of koji permissions: %s", e, e.getMessage()); } } public boolean hasPermission(String permission, KojiSessionInfo session) throws KojiClientException { checkConnection(); try { ConfirmationResponse response = xmlrpcClient.call(new CheckPermissionRequest(permission), ConfirmationResponse.class, sessionUrlBuilder(session), STANDARD_REQUEST_MODIFIER); return response.isSuccess(); } catch (XmlRpcException e) { throw new KojiClientException("Failed to check whether logged-in user has permission: %s. Reason: %s", e, permission, e.getMessage()); } } public int createTag(CreateTagRequest request, KojiSessionInfo session) throws KojiClientException { checkConnection(); try { IdResponse response = xmlrpcClient.call(request, IdResponse.class, sessionUrlBuilder(session), STANDARD_REQUEST_MODIFIER); return response.getId(); } catch (XmlRpcException e) { throw new KojiClientException("Failed to create tag: %s. Reason: %s", e, request, e.getMessage()); } } public KojiTagInfo getTag(int tagId, KojiSessionInfo session) throws KojiClientException { checkConnection(); try { TagResponse response = xmlrpcClient.call(new TagRequest(tagId), TagResponse.class, sessionUrlBuilder(session), STANDARD_REQUEST_MODIFIER); return response.getTagInfo(); } catch (XmlRpcException e) { throw new KojiClientException("Failed to retrieve tag: %s. Reason: %s", e, tagId, e.getMessage()); } } public KojiTagInfo getTag(String tagName, KojiSessionInfo session) throws KojiClientException { checkConnection(); try { TagResponse response = xmlrpcClient.call(new TagRequest(tagName), TagResponse.class, sessionUrlBuilder(session), STANDARD_REQUEST_MODIFIER); return response.getTagInfo(); } catch (XmlRpcException e) { throw new KojiClientException("Failed to retrieve tag: %s. Reason: %s", e, tagName, e.getMessage()); } } public Integer getTagId(String tagName, KojiSessionInfo session) throws KojiClientException { checkConnection(); try { IdResponse response = xmlrpcClient.call(new GetTagIdRequest(tagName), IdResponse.class, sessionUrlBuilder(session), STANDARD_REQUEST_MODIFIER); return response.getId(); } catch (XmlRpcException e) { throw new KojiClientException("Failed to retrieve tag: %s. Reason: %s", e, tagName, e.getMessage()); } } public Integer getPackageId(String packageName, KojiSessionInfo session) throws KojiClientException { checkConnection(); try { IdResponse response = xmlrpcClient.call(new GetTagIdRequest(packageName), IdResponse.class, sessionUrlBuilder(session), STANDARD_REQUEST_MODIFIER); return response.getId(); } catch (XmlRpcException e) { throw new KojiClientException("Failed to retrieve package: %s. Reason: %s", e, packageName, e.getMessage()); } } public KojiImportResult importBuild(KojiImport buildInfo, Supplier<Iterable<ImportFile>> outputSupplier, KojiSessionInfo session) throws KojiClientException { checkConnection(); String dirname = generateUploadDirname(session); Map<String, KojiClientException> uploadErrors = uploadForImport(buildInfo, outputSupplier, dirname, session); if (!uploadErrors.isEmpty()) { return new KojiImportResult(buildInfo).withUploadErrors(uploadErrors); } try { StatusResponse response = xmlrpcClient.call(new CGImportRequest(dirname), StatusResponse.class, sessionUrlBuilder(session), STANDARD_REQUEST_MODIFIER); if (!isEmpty(response.getError())) { throw new KojiClientException("Error response from Koji server: %s", response.getError()); } KojiBuildInfo build = getBuildInfo(buildInfo.getBuildNVR(), session); return new KojiImportResult(buildInfo).withBuildInfo(build); } catch (XmlRpcException e) { throw new KojiClientException("Failed to execute content-generator import. Reason: %s", e, e.getMessage()); } } public List<KojiTagInfo> listTags(KojiBuildInfo buildInfo, KojiSessionInfo session) throws KojiClientException { checkConnection(); try { ListTagsResponse response = xmlrpcClient.call(new ListTagsRequest(new KojiTagQuery(buildInfo)), ListTagsResponse.class, sessionUrlBuilder(session), STANDARD_REQUEST_MODIFIER); List<KojiTagInfo> tags = response.getTags(); return tags == null ? Collections.emptyList() : tags; } catch (XmlRpcException e) { throw new KojiClientException("Failed to retrieve list of tags for build: %s. Reason: %s", e, buildInfo, e.getMessage()); } } public List<KojiTagInfo> listTags(KojiNVR nvr, KojiSessionInfo session) throws KojiClientException { checkConnection(); try { ListTagsResponse response = xmlrpcClient.call(new ListTagsRequest(new KojiTagQuery(nvr)), ListTagsResponse.class, sessionUrlBuilder(session), STANDARD_REQUEST_MODIFIER); List<KojiTagInfo> tags = response.getTags(); return tags == null ? Collections.emptyList() : tags; } catch (XmlRpcException e) { throw new KojiClientException("Failed to retrieve list of tags for build: %s. Reason: %s", e, nvr, e.getMessage()); } } public List<KojiTagInfo> listTags(String nvr, KojiSessionInfo session) throws KojiClientException { checkConnection(); try { ListTagsResponse response = xmlrpcClient.call(new ListTagsRequest(new KojiTagQuery(nvr)), ListTagsResponse.class, sessionUrlBuilder(session), STANDARD_REQUEST_MODIFIER); List<KojiTagInfo> tags = response.getTags(); return tags == null ? Collections.emptyList() : tags; } catch (XmlRpcException e) { throw new KojiClientException("Failed to retrieve list of tags for build: %s. Reason: %s", e, nvr, e.getMessage()); } } public List<KojiTagInfo> listTags(int buildId, KojiSessionInfo session) throws KojiClientException { checkConnection(); try { ListTagsResponse response = xmlrpcClient.call(new ListTagsRequest(new KojiTagQuery(buildId)), ListTagsResponse.class, sessionUrlBuilder(session), STANDARD_REQUEST_MODIFIER); List<KojiTagInfo> tags = response.getTags(); return tags == null ? Collections.emptyList() : tags; } catch (XmlRpcException e) { throw new KojiClientException("Failed to retrieve list of tags for build: %s. Reason: %s", e, buildId, e.getMessage()); } } public List<KojiBuildInfo> listBuilds(ProjectVersionRef gav, KojiSessionInfo session) throws KojiClientException { checkConnection(); try { ListBuildsResponse response = xmlrpcClient.call(new ListBuildsRequest(gav), ListBuildsResponse.class, sessionUrlBuilder(session), STANDARD_REQUEST_MODIFIER); List<KojiBuildInfo> builds = response.getBuilds(); return builds == null ? Collections.emptyList() : builds; } catch (XmlRpcException e) { throw new KojiClientException("Failed to retrieve list of builds for: %s. Reason: %s", e, gav, e.getMessage()); } } public KojiBuildInfo getBuildInfo(KojiNVR nvr, KojiSessionInfo session) throws KojiClientException { checkConnection(); try { GetBuildResponse response = xmlrpcClient.call(new GetBuildByNVRObjRequest(nvr), GetBuildResponse.class, sessionUrlBuilder(session), STANDARD_REQUEST_MODIFIER); return response.getBuildInfo(); } catch (XmlRpcException e) { throw new KojiClientException("Failed to retrieve build info for: %s. Reason: %s", e, nvr, e.getMessage()); } } public KojiBuildInfo getBuildInfo(String nvr, KojiSessionInfo session) throws KojiClientException { checkConnection(); try { GetBuildResponse response = xmlrpcClient.call(new GetBuildByIdOrNameRequest(nvr), GetBuildResponse.class, sessionUrlBuilder(session), STANDARD_REQUEST_MODIFIER); return response.getBuildInfo(); } catch (XmlRpcException e) { throw new KojiClientException("Failed to retrieve build info for: %s. Reason: %s", e, nvr, e.getMessage()); } } public KojiBuildInfo getBuildInfo(int buildId, KojiSessionInfo session) throws KojiClientException { checkConnection(); try { GetBuildResponse response = xmlrpcClient.call(new GetBuildByIdOrNameRequest(buildId), GetBuildResponse.class, sessionUrlBuilder(session), STANDARD_REQUEST_MODIFIER); return response.getBuildInfo(); } catch (XmlRpcException e) { throw new KojiClientException("Failed to retrieve build info for: %s. Reason: %s", e, buildId, e.getMessage()); } } protected String generateUploadDirname(KojiSessionInfo session) throws KojiClientException { KojiUserInfo userInfo = getLoggedInUserInfo(session); return String.format("kojiji-upload/%s-%s/", new SimpleDateFormat("yyyymmdd-hhMM").format(new Date()), userInfo.getKerberosPrincipal()); } protected Map<String, KojiClientException> uploadForImport(KojiImport buildInfo, Supplier<Iterable<ImportFile>> outputSupplier, String dirname, KojiSessionInfo session) throws KojiClientException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); try { objectMapper.writeValue(baos, buildInfo); } catch (IOException e) { throw new KojiClientException("Failed to serialize import info to JSON. Reason: %s", e, e.getMessage()); } AtomicInteger count = new AtomicInteger(0); uploadService.submit( newUploader(new ImportFile(METADATA_JSON_FILE, new ByteArrayInputStream(baos.toByteArray())), dirname, session)); count.incrementAndGet(); outputSupplier.get().forEach((importFile) -> { uploadService.submit(newUploader(importFile, dirname, session)); count.incrementAndGet(); }); Logger logger = LoggerFactory.getLogger(getClass()); Map<String, KojiClientException> uploadErrors = new HashMap<>(); Set<UploadResponse> responses = new HashSet<>(); int total = count.get(); do { logger.debug("Waiting for %d uploads.", count.get()); try { Future<KojiUploaderResult> future = uploadService.take(); KojiUploaderResult result = future.get(); KojiClientException error = result.getError(); if (error != null) { uploadErrors.put(result.getImportFile().getFilePath(), error); } else { responses.add(result.getResponse()); } } catch (InterruptedException e) { logger.debug("Interrupted while uploading. Aborting upload."); break; } catch (ExecutionException e) { throw new KojiClientException("Failed to execute %d uploads for: %s. Reason: %s", e, total, buildInfo, e.getMessage()); } } while (count.decrementAndGet() > 0); return uploadErrors; } protected Callable<KojiUploaderResult> newUploader(ImportFile importFile, String dirname, KojiSessionInfo session) { return () -> { KojiUploaderResult result = new KojiUploaderResult(importFile); try { result.setResponse(upload(importFile.getStream(), importFile.getFilePath(), dirname, session)); } catch (KojiClientException e) { result.setError(e); } return result; }; } protected UploadResponse upload(InputStream stream, String filepath, String uploadDir, KojiSessionInfo session) throws KojiClientException { CloseableHttpClient client = null; try { client = httpFactory.createClient(config.getKojiSiteConfig()); String url = sessionUrlBuilder(session, () -> { Map<String, Object> params = new HashMap<>(); try { params.put(UPLOAD_DIR_PARAM, encodeParam(UPLOAD_DIR_PARAM, uploadDir)); params.put(UPLOAD_CHECKSUM_TYPE_PARAM, ADLER_32_CHECKSUM); params.put(UPLOAD_FILENAME_PARAM, encodeParam(UPLOAD_FILENAME_PARAM, filepath)); params.put(UPLOAD_OFFSET_PARAM, Integer.toString(0)); params.put(UPLOAD_OVERWRITE_PARAM, Integer.toString(1)); } catch (MalformedURLException e) { params.put(EMBEDDED_ERROR_PARAM, e); } return params; }).buildUrl(config.getKojiURL()).throwError().get(); HttpPost request = new HttpPost(url); request.setEntity(new InputStreamEntity(stream)); CloseableHttpResponse response = client.execute(request); if (response.getStatusLine().getStatusCode() == 200) { return bindery.parse(response.getEntity().getContent(), UploadResponse.class); } else { throw new KojiClientException("Failed to upload: %s to dir: %s. Server response: %s", filepath, uploadDir, response.getStatusLine()); } } catch (IOException | JHttpCException | XmlRpcException e) { throw new KojiClientException("Failed to upload: %s to dir: %s. Reason: %s", e, filepath, uploadDir, e.getMessage()); } finally { closeQuietly(client); } } private String encodeParam(String param, String value) throws MalformedURLException { try { return URLEncoder.encode(value, "UTF-8"); } catch (UnsupportedEncodingException e) { String msg = String.format("Failed to encode %s parameter: %s. Reason: %s", param, value, e.getMessage()); Logger logger = LoggerFactory.getLogger(getClass()); logger.error(msg, e); throw new MalformedURLException(msg); } } }