io.github.microcks.util.ReferenceResolver Maven / Gradle / Ivy
The newest version!
/*
* Copyright The Microcks Authors.
*
* 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 io.github.microcks.util;
import io.github.microcks.domain.Secret;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.file.Files;
import java.util.HashMap;
import java.util.Map;
/**
* Helper object that can be used to fully resolved references that are placed within a specification or a schema (think
* of the $ref within OpenAPI or AsyncAPI documents). A resolver is built with a base repository URL (that should point
* to a "folder") and some security parameters on how to access this repository. It then takes care of retrieving
* reference content using their relative path from base repository URL.
* @author laurent
*/
public class ReferenceResolver {
/** A simple logger for diagnostic messages. */
private static final Logger log = LoggerFactory.getLogger(ReferenceResolver.class);
private String baseRepositoryUrl;
private final Secret repositorySecret;
private final boolean disableSSLValidation;
private boolean cleanResolvedFiles = true;
private RelativeReferenceURLBuilder urlBuilder;
private Map resolvedReferences = new HashMap<>();
private Map relativeResolvedReferences = new HashMap<>();
/**
* Build a new reference resolver.
* @param baseRepositoryUrl The root folder representing a remote repository we want to resolved references to
* @param repositorySecret An optional Secret containing connection credentials to the repository
* @param disableSSLValidation Whether to disable or enable the SSL trusting of certificates
*/
public ReferenceResolver(String baseRepositoryUrl, Secret repositorySecret, boolean disableSSLValidation) {
this.setBaseRepositoryUrl(baseRepositoryUrl);
this.repositorySecret = repositorySecret;
this.disableSSLValidation = disableSSLValidation;
this.urlBuilder = new SimpleReferenceURLBuilder();
}
/**
* Build a new reference resolver.
* @param baseRepositoryUrl The root folder representing a remote repository we want to resolved references to
* @param repositorySecret An optional Secret containing connection credentials to the repository
* @param disableSSLValidation Whether to disable or enable the SSL trusting of certificates
*/
public ReferenceResolver(String baseRepositoryUrl, Secret repositorySecret, boolean disableSSLValidation,
RelativeReferenceURLBuilder urlBuilder) {
this.setBaseRepositoryUrl(baseRepositoryUrl);
this.repositorySecret = repositorySecret;
this.disableSSLValidation = disableSSLValidation;
this.urlBuilder = urlBuilder;
}
/** @return the current base repository url. */
public String getBaseRepositoryUrl() {
return baseRepositoryUrl;
}
/**
* Update the base repository url to use as root for relative reference resolution.
* @param baseRepositoryUrl The new base repository url.
*/
public void setBaseRepositoryUrl(String baseRepositoryUrl) {
// Remove trailing / to ease things later.
if (baseRepositoryUrl.endsWith("/")) {
this.baseRepositoryUrl = baseRepositoryUrl.substring(0, baseRepositoryUrl.length() - 1);
} else {
this.baseRepositoryUrl = baseRepositoryUrl;
}
}
/**
* Check if resolved files should be cleaned up after usage. Default behavior is true.
* @return The current value for this flag.
*/
public boolean isCleanResolvedFiles() {
return cleanResolvedFiles;
}
/**
* Set if resolved files should be cleaned up after usage. If set to false, resolvedReferences map will be clear but
* files will not be deleted from the local filesystem.
* @param cleanResolvedFiles The new value for this flag.
*/
public void setCleanResolvedFiles(boolean cleanResolvedFiles) {
this.cleanResolvedFiles = cleanResolvedFiles;
}
/**
* Get the full URL corresponding to a reference relative path
* @param referenceRelativePath The reference relative path to resolve
* @return The absolute URL if a relative path, the orginal path/URL otherwise.
*/
public String getReferenceURL(String referenceRelativePath) {
String remoteUrl = referenceRelativePath;
if (!referenceRelativePath.startsWith("http")) {
remoteUrl = urlBuilder.buildRemoteURL(this.baseRepositoryUrl, referenceRelativePath);
}
return remoteUrl;
}
/**
* Retrieve a reference content from remote repository using its relative path?
* @param relativePath The relative path of the reference to retrieve
* @param encoding The encoding to use for building a string representation of content.
* @return A string representation of reference content.
* @throws IOException if access to remote reference fails (not found or connection issues)
*/
public String getReferenceContent(String relativePath, Charset encoding) throws IOException {
// Check the file first.
String remoteUrl = getReferenceURL(relativePath);
File referenceFile = resolvedReferences.get(remoteUrl);
if (referenceFile == null) {
log.info("Downloading a reference file at {}", remoteUrl);
if (remoteUrl.startsWith("http")) {
// We have a remote URL, let's download it.
referenceFile = HTTPDownloader.handleHTTPDownloadToFile(remoteUrl, repositorySecret, disableSSLValidation);
} else {
// We have a local file, let's just use it.
if (remoteUrl.startsWith("file://")) {
remoteUrl = remoteUrl.substring("file://".length());
}
log.debug("Reading local file {}", remoteUrl);
referenceFile = new File(remoteUrl);
}
// Store this relative reference into the cache.
resolvedReferences.put(remoteUrl, referenceFile);
}
// Keep track on how we resolved this relativePath.
relativeResolvedReferences.put(relativePath, referenceFile);
return Files.readString(referenceFile.toPath(), encoding);
}
/**
* Get resolved references map.
* @return The map of resolved references with keys being absolute paths.
*/
public Map getResolvedReferences() {
return resolvedReferences;
}
/**
* Get relative resolved references map.
* @return The map of resolved references with keys being relative paths.
*/
public Map getRelativeResolvedReferences() {
return relativeResolvedReferences;
}
/** Cleans up already resolved references. */
public void cleanResolvedReferences() {
if (cleanResolvedFiles) {
for (File referenceFile : resolvedReferences.values()) {
referenceFile.delete();
}
}
resolvedReferences.clear();
relativeResolvedReferences.clear();
}
}