/*
* Copyright 2009 NCHOVY
*
* 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 org.krakenapps.pkg;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.MalformedURLException;
import java.net.URISyntaxException;
import java.net.URL;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.UnrecoverableKeyException;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import javax.net.ssl.KeyManagerFactory;
import javax.net.ssl.TrustManagerFactory;
import org.krakenapps.api.BundleRepository;
import org.krakenapps.api.KeyStoreManager;
import org.krakenapps.api.MavenArtifact;
import org.krakenapps.api.MavenResolveException;
import org.krakenapps.api.ProgressMonitor;
import org.krakenapps.api.Version;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class MavenResolver {
private final Logger logger = LoggerFactory.getLogger(MavenResolver.class.getName());
private File localRepository;
private List<BundleRepository> repositories;
private ProgressMonitor monitor;
private KeyStoreManager keyStoreManager;
public MavenResolver(File localRepository, List<BundleRepository> repositories, ProgressMonitor monitor,
KeyStoreManager keyStoreManager) {
this.localRepository = localRepository;
this.repositories = repositories;
this.monitor = monitor;
this.keyStoreManager = keyStoreManager;
}
public File resolve(MavenArtifact artifact) throws MavenResolveException {
File localJar = download(artifact);
if (localJar == null)
throw new MavenResolveException(artifact);
return localJar;
}
private String getRelativePath(MavenArtifact artifact) {
return String.format("%s/%s/%s/%s-%s", artifact.getGroupId().replace(".", "/"), artifact.getArtifactId(),
artifact.getVersion(), artifact.getArtifactId(), artifact.getVersion());
}
private File getLocalPom(BundleRepository repo, MavenArtifact artifact) {
String relativePath = getRelativePath(artifact);
if (repo.getUrl().getProtocol().equals("file")) {
try {
return new File(new File(repo.getUrl().toURI()), relativePath + ".pom");
} catch (URISyntaxException e) {
throw new RuntimeException(e);
}
}
return new File(localRepository, relativePath + ".pom");
}
private File getLocalJar(BundleRepository repo, MavenArtifact artifact) {
String relativePath = getRelativePath(artifact);
if (repo.getUrl().getProtocol().equals("file")) {
try {
return new File(new File(repo.getUrl().toURI()), relativePath + ".jar");
} catch (URISyntaxException e) {
throw new RuntimeException(e);
}
}
return new File(localRepository, relativePath + ".jar");
}
private File download(MavenArtifact artifact) {
Collections.sort(repositories, new Comparator<BundleRepository>() {
@Override
public int compare(BundleRepository o1, BundleRepository o2) {
if (o1 == null && o2 == null) {
return 1;
} else if (o1 == null) {
return -1;
} else if (o2 == null) {
return 1;
} else {
return o2.getPriority() - o1.getPriority();
}
}
});
for (BundleRepository repo : repositories) {
File downloadedJar = null;
if (artifact.getVersion() == null) {
try {
MavenMetadata metadata = new MavenMetadata(repo, keyStoreManager, artifact.getGroupId(),
artifact.getArtifactId());
if (metadata.getRelease() != null) {
artifact.setVersion(metadata.getRelease());
downloadedJar = tryDownload(repo, artifact);
}
if (downloadedJar == null && metadata.getLatest() != null) {
artifact.setVersion(metadata.getLatest());
downloadedJar = tryDownload(repo, artifact);
}
if (downloadedJar == null) {
for (Version version : metadata.getVersions()) {
artifact.setVersion(version);
downloadedJar = tryDownload(repo, artifact);
if (downloadedJar != null)
break;
}
}
} catch (Exception e) {
String metadataUrl = normalize(repo.getUrl())
+ String.format("%s/%s/maven-metadata.xml", artifact.getGroupId().replace(".", "/"),
artifact.getArtifactId());
logger.info("maven resolver: failed to get {} {}", metadataUrl, e.getMessage());
}
} else
downloadedJar = tryDownload(repo, artifact);
if (downloadedJar != null)
return downloadedJar;
}
return null;
}
private File tryDownload(BundleRepository repo, MavenArtifact artifact) {
File localPom = getLocalPom(repo, artifact);
File localJar = getLocalJar(repo, artifact);
localPom.getParentFile().mkdirs();
FileOutputStream pomStream = null;
FileOutputStream jarStream = null;
try {
URL pomUrl = getPomUrl(repo.getUrl(), artifact);
URL jarUrl = getJarUrl(repo.getUrl(), artifact);
if (monitor != null)
monitor.writeln(" -> trying to download from " + repo);
byte[] b = new byte[8096];
// download pom
InputStream is = null;
if (localPom.exists() == false) {
try {
is = download(repo, pomUrl);
pomStream = new FileOutputStream(localPom, false);
while (is != null) {
int read = is.read(b);
if (read <= 0)
break;
pomStream.write(b, 0, read);
}
} catch (Exception e) {
logger.info("maven resolver: failed to get {} {}", pomUrl, e.getMessage());
return null;
} finally {
ensureClose(is);
}
}
if (localJar.getAbsolutePath().replace("\\", "/").equals(jarUrl.getPath().substring(1)))
return localJar;
// download jar
is = null;
try {
is = download(repo, jarUrl);
jarStream = new FileOutputStream(localJar, false);
while (is != null) {
int read = is.read(b);
if (read <= 0)
break;
jarStream.write(b, 0, read);
}
} catch (Exception e) {
logger.info("maven resolver: failed to get {} {}", jarUrl, e.getMessage());
return null;
} finally {
ensureClose(is);
}
return localJar;
} catch (MalformedURLException e) {
logger.info("maven resolver: malformed url", e);
return null;
} finally {
ensureClose(pomStream);
ensureClose(jarStream);
}
}
private void ensureClose(InputStream is) {
if (is != null) {
try {
is.close();
} catch (IOException e) {
}
}
}
private void ensureClose(OutputStream os) {
if (os != null) {
try {
os.close();
} catch (IOException e) {
}
}
}
private InputStream download(BundleRepository repository, URL url) throws IOException, KeyStoreException,
KeyManagementException, UnrecoverableKeyException {
if (repository.isHttps() && keyStoreManager != null) { // https
try {
String trustStoreAlias = repository.getTrustStoreAlias();
String keyStoreAlias = repository.getKeyStoreAlias();
TrustManagerFactory tmf = keyStoreManager.getTrustManagerFactory(trustStoreAlias, "SunX509");
KeyManagerFactory kmf = keyStoreManager.getKeyManagerFactory(keyStoreAlias, "SunX509");
return HttpWagon.openDownloadStream(url, tmf, kmf);
} catch (NoSuchAlgorithmException e) {
return null;
}
} else if (repository.isAuthRequired()) // http auth
return HttpWagon.openDownloadStream(url, true, repository.getAccount(), repository.getPassword());
else if (url.getProtocol().equals("file")) {
try {
File file = new File(url.toURI());
return new FileInputStream(file);
} catch (URISyntaxException e) {
return null;
}
} else
// plain http
return HttpWagon.openDownloadStream(url);
}
private URL getPomUrl(URL repository, MavenArtifact artifact) throws MalformedURLException {
String relativePath = getRelativePath(artifact);
return new URL(normalize(repository) + relativePath + ".pom");
}
private URL getJarUrl(URL repository, MavenArtifact artifact) throws MalformedURLException {
String relativePath = getRelativePath(artifact);
return new URL(normalize(repository) + relativePath + ".jar");
}
private URL normalize(URL url) {
String urlStr = url.toString();
if (urlStr.lastIndexOf('/') == urlStr.length() - 1)
return url;
try {
return new URL(url + "/");
} catch (MalformedURLException e) {
return null; // ignore
}
}
}