package org.jfrog.wharf.ivy.repository;
import org.apache.ivy.core.IvyContext;
import org.apache.ivy.plugins.repository.AbstractRepository;
import org.apache.ivy.plugins.repository.RepositoryCopyProgressListener;
import org.apache.ivy.plugins.repository.Resource;
import org.apache.ivy.plugins.repository.TransferEvent;
import org.apache.ivy.util.url.ApacheURLLister;
import org.jfrog.wharf.ivy.checksum.ChecksumType;
import org.jfrog.wharf.ivy.resource.WharfUrlResource;
import org.jfrog.wharf.ivy.util.WharfUtils;
import java.io.File;
import java.io.IOException;
import java.net.MalformedURLException;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.util.*;
/**
* @author Tomer Cohen
*/
public class WharfURLRepository extends AbstractRepository {
private static final ApacheURLLister lister = new ApacheURLLister();
public static final String ALWAYS_CHECK_RESOURCES = "wharf.alwaysCheckResources";
private final Map<String, WharfUrlResource> resourcesCache;
private final RepositoryCopyProgressListener progressListener;
private EnumSet<ChecksumType> checksums;
public WharfURLRepository() {
this.progressListener = new RepositoryCopyProgressListener(this);
this.resourcesCache = new HashMap<String, WharfUrlResource>();
// Only SHA1 by default
checkOnlySha1();
}
public RepositoryCopyProgressListener getProgressListener() {
return progressListener;
}
public EnumSet<ChecksumType> getChecksums() {
return checksums;
}
public void noChecksumCheck() {
checksums.clear();
}
public void checkOnlySha1() {
checksums = EnumSet.of(ChecksumType.sha1);
}
public void checkOnlyMd5() {
checksums = EnumSet.of(ChecksumType.sha1);
}
public void checkAny() {
checksums = EnumSet.allOf(ChecksumType.class);
}
public boolean supportsWrongSha1() {
return checksums.size() != 1 || checksums.contains(ChecksumType.md5);
}
public String[] getChecksumAlgorithms() {
String[] result = new String[checksums.size()];
int i = 0;
for (ChecksumType checksum : checksums) {
result[i] = checksum.alg();
i++;
}
return result;
}
/**
* Fill the checksums algorithm that need to be verified to accept an artifact.
*
* @param checksumsList a comma separated list of checksum algorithms to use with this repository
*/
public void setChecksums(String checksumsList) {
checksums.clear();
String[] checks = checksumsList.split(",");
for (String check : checks) {
String cs = check.trim();
if (!"".equals(cs) && !"none".equals(cs)) {
checksums.add(ChecksumType.valueOf(cs));
}
}
}
public static boolean isAlwaysCheck() {
Boolean alwaysCheck = (Boolean) IvyContext.getContext().get(ALWAYS_CHECK_RESOURCES);
return alwaysCheck != null && alwaysCheck;
}
public static void setAlwaysCheck(boolean alwaysCheck) {
IvyContext.getContext().set(ALWAYS_CHECK_RESOURCES, alwaysCheck);
}
public Resource getResource(String source) throws IOException {
return getWharfResource(source);
}
public WharfUrlResource getWharfResource(String source) throws IOException {
WharfUrlResource res = resourcesCache.get(source);
if (res == null || isAlwaysCheck()) {
URL url;
try {
url = new URL(source);
} catch (MalformedURLException e) {
url = new File(source).toURI().toURL();
}
res = new WharfUrlResource(url);
resourcesCache.put(source, res);
resourcesCache.put(url.toExternalForm(), res);
if (isAlwaysCheck()) {
setAlwaysCheck(false);
}
}
return res;
}
public void get(String source, File destination) throws IOException {
WharfUrlResource res = getWharfResource(source);
get(res, destination);
}
public void get(WharfUrlResource res, File destination) throws IOException {
fireTransferInitiated(res, TransferEvent.REQUEST_GET);
try {
long totalLength = res.getContentLength();
if (totalLength > 0) {
getProgressListener().setTotalLength(totalLength);
}
WharfUtils.getWharfUrlHandler().download(res, destination, getProgressListener());
} catch (IOException ex) {
fireTransferError(ex);
throw ex;
} catch (RuntimeException ex) {
fireTransferError(ex);
throw ex;
} finally {
getProgressListener().setTotalLength(null);
}
}
public void put(File source, String destination, boolean overwrite) throws IOException {
throw new UnsupportedOperationException("put in not supported by " + getName());
}
public List list(String parent) throws IOException {
if (parent.startsWith("http")) {
List urls = lister.listAll(new URL(parent));
if (urls != null) {
List ret = new ArrayList(urls.size());
for (ListIterator iter = urls.listIterator(); iter.hasNext(); ) {
URL url = (URL) iter.next();
ret.add(url.toExternalForm());
}
return ret;
}
} else {
File file;
String path;
if (parent.startsWith("file")) {
try {
path = new URI(parent).getPath();
file = new File(path);
} catch (URISyntaxException e) {
IOException ioe = new IOException("Couldn't list content of '" + parent + "'");
ioe.initCause(e);
throw ioe;
}
} else {
file = new File(parent);
URI uri = file.toURI();
path = uri.getPath();
parent = uri.toURL().toExternalForm();
}
if (file.exists() && file.isDirectory()) {
String[] files = file.list();
List ret = new ArrayList(files.length);
URL context = path.endsWith("/") ? new URL(parent) : new URL(parent + "/");
for (int i = 0; i < files.length; i++) {
ret.add(new URL(context, files[i]).toExternalForm());
}
return ret;
} else {
return Collections.EMPTY_LIST;
}
}
return null;
}
public void checkChecksums(WharfUrlResource wharfUrlResource) throws IOException {
if (checksums.isEmpty()) {
return;
}
boolean oneGood = false;
for (ChecksumType checksumType : checksums) {
if (checkResourceChecksum(wharfUrlResource, checksumType)) {
oneGood = true;
}
}
if (!oneGood) {
throw new IOException("Resource " + wharfUrlResource.toString() + " has a wrong checksum for " + checksums);
}
}
private boolean checkResourceChecksum(WharfUrlResource wharfUrlResource, ChecksumType checksumType) {
String actualChecksum = wharfUrlResource.getActual().get(checksumType);
String remoteChecksum = wharfUrlResource.getRemote().get(checksumType);
return actualChecksum != null && remoteChecksum != null && actualChecksum.equals(remoteChecksum);
}
}