/*
* DBeaver - Universal Database Manager
* Copyright (C) 2010-2017 Serge Rider (serge@jkiss.org)
*
* 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.jkiss.dbeaver.registry.maven;
import org.eclipse.core.runtime.IConfigurationElement;
import org.eclipse.core.runtime.Platform;
import org.jkiss.code.NotNull;
import org.jkiss.code.Nullable;
import org.jkiss.dbeaver.Log;
import org.jkiss.dbeaver.core.DBeaverActivator;
import org.jkiss.dbeaver.model.access.DBAAuthInfo;
import org.jkiss.dbeaver.model.runtime.DBRProgressMonitor;
import org.jkiss.dbeaver.registry.encode.PasswordEncrypter;
import org.jkiss.dbeaver.registry.encode.SimpleStringEncrypter;
import org.jkiss.dbeaver.utils.GeneralUtils;
import org.jkiss.utils.CommonUtils;
import org.jkiss.utils.xml.XMLBuilder;
import org.jkiss.utils.xml.XMLUtils;
import org.w3c.dom.Document;
import org.w3c.dom.Element;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.OutputStream;
import java.util.*;
public class MavenRegistry
{
private static final Log log = Log.getLog(MavenRegistry.class);
public static final String MAVEN_LOCAL_REPO_ID = "local";
public static final String MAVEN_LOCAL_REPO_NAME = "Local Repository";
public static final String MAVEN_LOCAL_REPO_FOLDER = "maven-local";
private static MavenRegistry instance = null;
private final List<String> ignoredArtifactVersions = new ArrayList<>();
public synchronized static MavenRegistry getInstance()
{
if (instance == null) {
instance = new MavenRegistry();
instance.init();
}
return instance;
}
private final List<MavenRepository> repositories = new ArrayList<>();
private MavenRepository localRepository;
// Cache for not found artifact ids. Avoid multiple remote metadata reading
private final Set<String> notFoundArtifacts = new HashSet<>();
private static final PasswordEncrypter ENCRYPTOR = new SimpleStringEncrypter();
private MavenRegistry()
{
}
boolean isVersionIgnored(String ref) {
for (String ver : ignoredArtifactVersions) {
if (ref.startsWith(ver)) {
return true;
}
}
return false;
}
private void init() {
loadStandardRepositories();
loadCustomRepositories();
sortRepositories();
}
private void loadStandardRepositories() {
// Load repositories info
{
IConfigurationElement[] extElements = Platform.getExtensionRegistry().getConfigurationElementsFor(MavenRepository.EXTENSION_ID);
for (IConfigurationElement ext : extElements) {
if ("repository".equals(ext.getName())) {
MavenRepository repository = new MavenRepository(ext);
repositories.add(repository);
} else if ("ignoreArtifactVersion".equals(ext.getName())) {
ignoredArtifactVersions.add(ext.getAttribute("id"));
}
}
}
// Create local repository
String localRepoURL;
try {
localRepoURL = Platform.getInstallLocation().getDataArea(MAVEN_LOCAL_REPO_FOLDER).toString();
} catch (IOException e) {
localRepoURL = Platform.getInstallLocation().getURL().toString() + "/" + MAVEN_LOCAL_REPO_FOLDER;
}
localRepository = new MavenRepository(
MAVEN_LOCAL_REPO_ID,
MAVEN_LOCAL_REPO_NAME,
localRepoURL,
MavenRepository.RepositoryType.LOCAL);
}
public void setCustomRepositories(List<MavenRepository> customRepositories) {
// Clear not-found cache
notFoundArtifacts.clear();
// Remove old custom repos
for (Iterator<MavenRepository> iter = this.repositories.iterator(); iter.hasNext(); ) {
if (iter.next().getType() == MavenRepository.RepositoryType.CUSTOM) {
iter.remove();
}
}
// Add new and reorder
this.repositories.addAll(customRepositories);
sortRepositories();
}
public void loadCustomRepositories() {
final File cfgFile = getConfigurationFile();
if (cfgFile.exists()) {
try {
final Document reposDocument = XMLUtils.parseDocument(cfgFile);
for (Element repoElement : XMLUtils.getChildElementList(reposDocument.getDocumentElement(), "repository")) {
String repoID = repoElement.getAttribute("id");
MavenRepository repo = findRepository(repoID);
if (repo == null) {
String repoName = repoElement.getAttribute("name");
String repoURL = repoElement.getAttribute("url");
repo = new MavenRepository(
repoID,
repoName,
repoURL,
MavenRepository.RepositoryType.CUSTOM);
List<String> scopes = new ArrayList<>();
for (Element scopeElement : XMLUtils.getChildElementList(repoElement, "scope")) {
scopes.add(scopeElement.getAttribute("group"));
}
repo.setScopes(scopes);
repositories.add(repo);
}
repo.setOrder(CommonUtils.toInt(repoElement.getAttribute("order")));
repo.setEnabled(CommonUtils.toBoolean(repoElement.getAttribute("enabled")));
final String authUser = repoElement.getAttribute("auth-user");
if (!CommonUtils.isEmpty(authUser)) {
repo.getAuthInfo().setUserName(authUser);
String authPassword = repoElement.getAttribute("auth-password");
if (!CommonUtils.isEmpty(authPassword)) {
repo.getAuthInfo().setUserPassword(ENCRYPTOR.decrypt(authPassword));
}
}
}
} catch (Exception e) {
log.error("Error parsing maven repositories configuration", e);
}
}
}
@NotNull
public List<MavenRepository> getRepositories() {
return repositories;
}
@Nullable
public MavenArtifactVersion findArtifact(@NotNull DBRProgressMonitor monitor, @Nullable MavenArtifactVersion owner, @NotNull MavenArtifactReference ref) {
String fullId = ref.getId();
if (notFoundArtifacts.contains(fullId)) {
return null;
}
MavenArtifactVersion artifact = findInRepositories(monitor, owner, ref);
if (artifact != null) {
return artifact;
}
// Not found
notFoundArtifacts.add(fullId);
return null;
}
public void resetArtifactInfo(MavenArtifactReference artifactReference) {
notFoundArtifacts.remove(artifactReference.getId());
for (MavenRepository repository : repositories) {
repository.resetArtifactCache(artifactReference);
}
localRepository.resetArtifactCache(artifactReference);
}
@Nullable
private MavenArtifactVersion findInRepositories(@NotNull DBRProgressMonitor monitor, MavenArtifactVersion owner, @NotNull MavenArtifactReference ref) {
MavenRepository currentRepository = owner == null ? null : owner.getArtifact().getRepository();
if (currentRepository != null) {
MavenArtifactVersion artifact = currentRepository.findArtifact(monitor, ref);
if (artifact != null) {
return artifact;
}
}
// Try all available repositories (without resolve)
for (MavenRepository repository : repositories) {
if (!repository.isEnabled()) {
continue;
}
if (repository != currentRepository) {
if (!repository.getScopes().isEmpty()) {
// Check scope (group id)
if (!repository.getScopes().contains(ref.getGroupId())) {
continue;
}
}
MavenArtifactVersion artifact = repository.findArtifact(monitor, ref);
if (artifact != null) {
return artifact;
}
}
}
if (owner != null) {
// Try context repositories
for (MavenRepository repository : owner.getActiveRepositories()) {
if (repository != currentRepository) {
MavenArtifactVersion artifact = repository.findArtifact(monitor, ref);
if (artifact != null) {
return artifact;
}
}
}
}
if (localRepository != currentRepository) {
MavenArtifactVersion artifact = localRepository.findArtifact(monitor, ref);
if (artifact != null) {
return artifact;
}
}
log.warn("Maven artifact '" + ref + "' not found in any available repository.");
return null;
}
public MavenRepository findRepository(String id) {
for (MavenRepository repository : repositories) {
if (repository.getId().equals(id)) {
return repository;
}
}
return null;
}
public void saveConfiguration() {
sortRepositories();
try (OutputStream is = new FileOutputStream(getConfigurationFile())) {
XMLBuilder xml = new XMLBuilder(is, GeneralUtils.UTF8_ENCODING);
xml.setButify(true);
try (final XMLBuilder.Element e1 = xml.startElement("maven")) {
for (MavenRepository repository : repositories) {
try (final XMLBuilder.Element e2 = xml.startElement("repository")) {
xml.addAttribute("id", repository.getId());
xml.addAttribute("order", repository.getOrder());
xml.addAttribute("enabled", repository.isEnabled());
if (repository.getType() != MavenRepository.RepositoryType.GLOBAL) {
xml.addAttribute("url", repository.getUrl());
xml.addAttribute("name", repository.getName());
if (!CommonUtils.isEmpty(repository.getDescription())) {
xml.addAttribute("description", repository.getDescription());
}
for (String scope : repository.getScopes()) {
try (final XMLBuilder.Element e3 = xml.startElement("scope")) {
xml.addAttribute("group", scope);
}
}
final DBAAuthInfo authInfo = repository.getAuthInfo();
if (!CommonUtils.isEmpty(authInfo.getUserName())) {
xml.addAttribute("auth-user", authInfo.getUserName());
if (!CommonUtils.isEmpty(authInfo.getUserPassword())) {
xml.addAttribute("auth-password", ENCRYPTOR.encrypt(authInfo.getUserPassword()));
}
}
}
}
}
}
xml.flush();
} catch (Exception e) {
log.error("Error saving Maven registry", e);
}
}
private void sortRepositories() {
Collections.sort(repositories, new Comparator<MavenRepository>() {
@Override
public int compare(MavenRepository o1, MavenRepository o2) {
return o1.getOrder() - o2.getOrder();
}
});
}
private static File getConfigurationFile()
{
return DBeaverActivator.getConfigurationFile("maven-repositories.xml");
}
}