package org.carlspring.strongbox.client; import org.carlspring.maven.commons.util.ArtifactUtils; import java.io.IOException; import java.io.InputStream; import java.net.URI; import org.apache.commons.io.IOUtils; import org.apache.maven.artifact.Artifact; import org.apache.maven.artifact.repository.metadata.Metadata; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.core.io.Resource; import org.springframework.http.*; import org.springframework.security.authentication.AuthenticationServiceException; import org.springframework.util.LinkedMultiValueMap; import org.springframework.util.MultiValueMap; import org.springframework.web.client.RestTemplate; import org.springframework.web.util.UriComponents; import org.springframework.web.util.UriComponentsBuilder; import static org.apache.http.HttpStatus.SC_FORBIDDEN; import static org.apache.http.HttpStatus.SC_UNAUTHORIZED; /** * @author yury */ public class ArtifactSpringClient { private static final Logger logger = LoggerFactory.getLogger(ArtifactSpringClient.class); protected String username = "maven"; protected String password = "password"; private String protocol = "http"; private String host = System.getProperty("strongbox.host") != null ? System.getProperty("strongbox.host") : "localhost"; private int port = System.getProperty("strongbox.port") != null ? Integer.parseInt(System.getProperty("strongbox.port")) : 48080; private String contextBaseUrl; private RestTemplate restTemplate = new RestTemplate(); public static ArtifactSpringClient getTestInstance() { return getTestInstance("maven", "password"); } public static ArtifactSpringClient getTestInstanceLoggedInAsAdmin() { return getTestInstance("admin", "password"); } public static ArtifactSpringClient getTestInstance(String username, String password) { String host = System.getProperty("strongbox.host") != null ? System.getProperty("strongbox.host") : "localhost"; int port = System.getProperty("strongbox.port") != null ? Integer.parseInt(System.getProperty("strongbox.port")) : 48080; ArtifactSpringClient client = new ArtifactSpringClient(); client.setUsername(username); client.setPassword(password); client.setPort(port); client.setContextBaseUrl("http://" + host + ":" + client.getPort()); return client; } /* Not checked*/ public void addArtifact(Artifact artifact, String storageId, String repositoryId, InputStream is) throws ArtifactOperationException { String url = getContextBaseUrl() + "/storages/" + storageId + "/" + repositoryId; logger.debug("Deploying " + url + "..."); String fileName = ArtifactUtils.getArtifactFileName(artifact); String path = ArtifactUtils.convertArtifactToPath(artifact); deployFile(is, url, path, fileName); } public void addMetadata(Metadata metadata, String path, String storageId, String repositoryId, InputStream is) throws ArtifactOperationException { String url = getContextBaseUrl() + "/storages/" + storageId + "/" + repositoryId + "/" + path; logger.debug("Deploying " + url + "..."); deployMetadata(is, url, path, path.substring(path.lastIndexOf("/"))); } public void deployFile(InputStream is, String url, String path, String fileName) throws ArtifactOperationException { put(is, url, path, fileName, MediaType.APPLICATION_OCTET_STREAM); } public void deployMetadata(InputStream is, String url, String path, String fileName) throws ArtifactOperationException { put(is, url, path, fileName, MediaType.APPLICATION_XML); } public void put(InputStream is, String url, String path, String fileName, MediaType mediaType) throws ArtifactOperationException { String contentDisposition = "attachment; filename=\"" + fileName + "\""; HttpHeaders headers = new HttpHeaders(); headers.setContentType(mediaType); headers.add("Content-Disposition", contentDisposition); byte[] bytes; try { bytes = IOUtils.toByteArray(is); } catch (IOException e) { throw new RuntimeException("Parse error on put method, class ArtifactSpringClient...", e); } HttpEntity<byte[]> entity = new HttpEntity<>(bytes, headers); path = "/" + path; MultiValueMap<String, String> params = new LinkedMultiValueMap<>(); try { params.add("path", path); } catch (Exception e) { logger.error(e.getMessage(), e); } UriComponents uriComponents = UriComponentsBuilder.fromHttpUrl(url).queryParams(params).build(); URI uri = uriComponents.toUri(); ResponseEntity<String> response = restTemplate.exchange(uri, HttpMethod.PUT, entity, String.class); handleFailures(response, "Failed to upload file!"); } public void getArtifact(Artifact artifact, String repository) throws ArtifactTransportException, IOException { String url = getContextBaseUrl() + "/" + repository + "/" + ArtifactUtils.convertArtifactToPath(artifact); logger.debug("Getting " + url + "..."); HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.TEXT_PLAIN); HttpEntity<Integer> entity = new HttpEntity<Integer>(headers); ResponseEntity<Resource> response = restTemplate.exchange(url, HttpMethod.GET, entity, Resource.class); java.io.InputStream is; try { is = response.getBody().getInputStream(); } catch (IOException e) { throw new RuntimeException(e); } int total = 0; int len; final int size = 4096; byte[] bytes = new byte[size]; while ((len = is.read(bytes, 0, size)) != -1) { total += len; } logger.debug("Response code: " + response.getStatusCode() + ". Read: " + total + " bytes."); int status = response.getStatusCode().value(); if (status != 200) { throw new ArtifactTransportException("Failed to resolve artifact!"); } if (total == 0) { throw new ArtifactTransportException("Artifact size was zero!"); } } public java.io.InputStream getResource(String path, String url) throws ArtifactTransportException, IOException { return getResource(path, url, 0); } public ResponseEntity getResourceWithResponse(String pathVar) throws ArtifactTransportException, IOException { String path = "/storages/storage0/releases"; String url = getContextBaseUrl() + (!path.startsWith("/") ? "/" : "") + path + ("?path=" + pathVar); logger.debug("Getting " + url + "..."); HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.TEXT_PLAIN); HttpEntity<String> entity = new HttpEntity<String>(headers); ResponseEntity<String> response = restTemplate.exchange(url, HttpMethod.GET, entity, String.class); return response; } public java.io.InputStream getResource(String path, String url, long offset) throws ArtifactTransportException, IOException { path = (!path.startsWith("/") ? "/" : "") + path; url = getContextBaseUrl() + url + ("?path=" + path); logger.debug("Getting " + url + "..."); ResponseEntity<Resource> response; if (offset > 0) { HttpHeaders headers = new HttpHeaders(); headers.add("Range", "bytes=" + offset + "-"); HttpEntity<String> entity = new HttpEntity<String>(headers); response = restTemplate.exchange(url, HttpMethod.GET, entity, Resource.class); } else { HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.TEXT_PLAIN); HttpEntity<String> entity = new HttpEntity<String>(headers); response = restTemplate.exchange(url, HttpMethod.GET, entity, Resource.class); } java.io.InputStream is; try { is = response.getBody().getInputStream(); } catch (IOException e) { throw new RuntimeException(e); } return is; } // Not checked** public void deleteArtifact(Artifact artifact, String storageId, String repositoryId) throws ArtifactOperationException { String url = getUrlForArtifact(artifact, storageId, repositoryId); HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.TEXT_PLAIN); HttpEntity<String> entity = new HttpEntity<String>(headers); ResponseEntity response = restTemplate.exchange(url, HttpMethod.DELETE, entity, String.class); handleFailures(response, "Failed to delete artifact!"); } public void delete(String storageId, String repositoryId, String path) throws ArtifactOperationException { delete(storageId, repositoryId, path, false); } public void delete(String storageId, String repositoryId, String path, boolean force) throws ArtifactOperationException { @SuppressWarnings("ConstantConditions") String url = getContextBaseUrl() + "/storages/" + storageId + "/" + repositoryId + "?path=" + path + (force ? "?force=" + force : ""); HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.TEXT_PLAIN); HttpEntity<String> entity = new HttpEntity<String>(headers); ResponseEntity response = restTemplate.exchange(url, HttpMethod.DELETE, entity, String.class); handleFailures(response, "Failed to delete artifact!"); } public void deleteTrash(String storageId, String repositoryId) throws ArtifactOperationException { String url = getUrlForTrash(storageId, repositoryId); HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.TEXT_PLAIN); HttpEntity<String> entity = new HttpEntity<String>(headers); ResponseEntity response = restTemplate.exchange(url, HttpMethod.DELETE, entity, String.class); handleFailures(response, "Failed to delete the trash for " + storageId + ":" + repositoryId + "!"); } public void deleteTrash() throws ArtifactOperationException { String url = getContextBaseUrl() + "/trash"; HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.TEXT_PLAIN); HttpEntity<String> entity = new HttpEntity<String>(headers); ResponseEntity response = restTemplate.exchange(url, HttpMethod.DELETE, entity, String.class); handleFailures(response, "Failed to delete trash for all repositories!"); } public String getUrlForArtifact(Artifact artifact, String storageId, String repositoryId) { return getContextBaseUrl() + "/storages/" + storageId + "/" + repositoryId + "/" + ArtifactUtils.convertArtifactToPath(artifact); } public String getUrlForTrash(String storageId, String repositoryId) { return getContextBaseUrl() + "/trash/" + storageId + "/" + repositoryId; } public boolean pathExists(String path, String url) { path = (path.startsWith("/") ? path : '/' + path); url = getContextBaseUrl() + "/" + url + ("?path=" + path); logger.debug("Path to artifact: " + path + " URL " + url); HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.TEXT_PLAIN); HttpEntity<Integer> entity = new HttpEntity<Integer>(headers); ResponseEntity response = restTemplate.exchange(url, HttpMethod.GET, entity, String.class); return response.getStatusCode().value() == 200; } public void undelete(String storageId, String repositoryId, String path) throws ArtifactOperationException { @SuppressWarnings("ConstantConditions") String url = getUrlForTrash(storageId, repositoryId) + "?path=" + path; HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.TEXT_PLAIN); HttpEntity<String> entity = new HttpEntity<String>("Undelete", headers); ResponseEntity response = restTemplate.exchange(url, HttpMethod.PUT, entity, String.class); handleFailures(response, "Failed to delete the trash for " + storageId + ":" + repositoryId + "!"); } // Not checked** public void undeleteTrash(String storageId, String repositoryId) throws ArtifactOperationException { String url = getUrlForTrash(storageId, repositoryId); HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.TEXT_PLAIN); HttpEntity<String> entity = new HttpEntity<String>("Undelete", headers); ResponseEntity response = restTemplate.exchange(url, HttpMethod.PUT, entity, String.class); handleFailures(response, "Failed to delete the trash for " + storageId + ":" + repositoryId + "!"); } // НУЖНО ПРОТЕСТИТЬ public void undeleteTrash() throws ArtifactOperationException { String url = getContextBaseUrl() + "/trash"; HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.TEXT_PLAIN); HttpEntity<String> entity = new HttpEntity<String>(headers); ResponseEntity response = restTemplate.exchange(url, HttpMethod.POST, entity, String.class); handleFailures(response, "Failed to delete the trash!"); } public boolean artifactExists(Artifact artifact, String storageId, String repositoryId) throws ResponseException { ResponseEntity response = artifactExistsStatusCode(artifact, storageId, repositoryId); if (response.getStatusCode().value() == 200) { return true; } else if (response.getStatusCode().value() == 404) { return false; } else { throw new ResponseException(response.getStatusCode().toString(), response.getStatusCode().value()); } } public ResponseEntity artifactExistsStatusCode(Artifact artifact, String storageId, String repositoryId) throws ResponseException { String url = getUrlForArtifact(artifact, storageId, repositoryId); logger.debug("Path to artifact: " + url); HttpHeaders headers = new HttpHeaders(); headers.setContentType(MediaType.TEXT_PLAIN); HttpEntity<String> entity = new HttpEntity<String>(headers); ResponseEntity response = restTemplate.exchange(url, HttpMethod.GET, entity, String.class); return response; } private void handleFailures(ResponseEntity response, String message) throws ArtifactOperationException, AuthenticationServiceException { int status = response.getStatusCode().value(); if (status == SC_UNAUTHORIZED || status == SC_FORBIDDEN) { // TODO Handle authentication exceptions in a right way throw new AuthenticationServiceException(message + "\nUser is unauthorized to execute that operation. " + "Check assigned roles and privileges."); } else if (status != 200) { StringBuilder messageBuilder = new StringBuilder(); messageBuilder.append("\n ERROR ").append(status).append(" ").append(message).append("\n"); Object entity = response.getBody().toString(); if (entity != null) { messageBuilder.append(entity.toString()); } logger.error(messageBuilder.toString()); } } public String getProtocol() { return protocol; } public void setProtocol(String protocol) { this.protocol = protocol; } public String getHost() { return host; } public void setHost(String host) { this.host = host; } public int getPort() { return port; } public void setPort(int port) { this.port = port; } public String getContextBaseUrl() { if (contextBaseUrl == null) { contextBaseUrl = protocol + "://" + host + ":" + port; } return contextBaseUrl; } public void setContextBaseUrl(String contextBaseUrl) { this.contextBaseUrl = contextBaseUrl; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } }