package fr.openwide.maven.artifact.notifier.core.business.sync.service;
import java.io.IOException;
import java.util.List;
import org.apache.http.Header;
import org.apache.http.HttpResponse;
import org.apache.http.client.methods.HttpHead;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.protocol.HTTP;
import org.apache.solr.common.util.DateUtil;
import org.jsoup.Jsoup;
import org.jsoup.nodes.Document;
import org.jsoup.nodes.Element;
import org.jsoup.select.Elements;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import com.google.common.collect.Lists;
import fr.openwide.core.jpa.exception.ServiceException;
import fr.openwide.core.spring.util.StringUtils;
import fr.openwide.maven.artifact.notifier.core.business.search.model.ArtifactVersionBean;
import fr.openwide.maven.artifact.notifier.core.config.application.MavenArtifactNotifierConfigurer;
//@Service("artifactVersionProviderService")
public class MavenRepositoryArtifactVersionProviderServiceImpl implements IArtifactVersionProviderService {
private static final Logger LOGGER = LoggerFactory.getLogger(MavenRepositoryArtifactVersionProviderServiceImpl.class);
private static final String LAST_MODIFIED_HEADER = "Last-Modified";
@Autowired
private MavenArtifactNotifierConfigurer configurer;
@Override
public List<ArtifactVersionBean> getArtifactVersions(String groupId, String artifactId) throws ServiceException {
String url = String.format(configurer.getArtifactRepositoryMetadataUrl(), groupId.replace(".", "/"), artifactId);
Document doc;
try {
doc = Jsoup.connect(url).header(HTTP.CONN_DIRECTIVE, HTTP.CONN_CLOSE).get();
} catch (IOException e) {
throw new ServiceException("IOException: " + e.getMessage(), e);
}
return parseMavenMetadata(doc);
}
private List<ArtifactVersionBean> parseMavenMetadata(Document doc) {
String groupId = doc.getElementsByTag("groupId").text();
String artifactId = doc.getElementsByTag("artifactId").text();
if (!StringUtils.hasText(groupId) || !StringUtils.hasText(artifactId)) {
return Lists.newArrayListWithCapacity(0);
}
Elements versions = doc.getElementsByTag("version");
List<ArtifactVersionBean> artifactList = Lists.newArrayList();
for (Element version : versions) {
ArtifactVersionBean artifactVersionBean = new ArtifactVersionBean();
artifactVersionBean.setGroupId(groupId);
artifactVersionBean.setArtifactId(artifactId);
artifactVersionBean.setVersion(version.text());
artifactVersionBean.setId(groupId + ":" + artifactId + ":" + version.text());
// Gets and convert the last update date
Long lastUpdateDate = retrieveLastUpdateDate(artifactVersionBean);
if (lastUpdateDate == null) {
continue;
}
artifactVersionBean.setTimestamp(lastUpdateDate);
artifactList.add(artifactVersionBean);
}
return artifactList;
}
private Long retrieveLastUpdateDate(ArtifactVersionBean artifactVersionBean) {
CloseableHttpClient client = null;
try {
client = HttpClientBuilder.create().setUserAgent(configurer.getUserAgent()).build();
String url = String.format(configurer.getArtifactVersionRepositoryPomUrl(),
artifactVersionBean.getGroupId().replace(".", "/"),
artifactVersionBean.getArtifactId(),
artifactVersionBean.getVersion());
HttpHead httpHead = new HttpHead(url);
httpHead.addHeader(HTTP.CONN_DIRECTIVE, HTTP.CONN_CLOSE);
// The possible errors here are considered as secondary and will not be seen by the user
// We may want to reconsider it
HttpResponse response = client.execute(httpHead);
Header lastUpdateDate = response.getFirstHeader(LAST_MODIFIED_HEADER);
if (lastUpdateDate != null) {
return DateUtil.parseDate(lastUpdateDate.getValue()).getTime();
}
LOGGER.error("An error occurred while retrieving the last update date for " + artifactVersionBean.getId());
} catch (Exception e) {
LOGGER.error("An error occurred while retrieving the last update date for " + artifactVersionBean.getId(), e);
} finally {
if (client != null) {
try {
client.close();
} catch (IOException e) {
LOGGER.error("Unable to close the HTTP client", e);
}
}
}
return null;
}
}