package alien4cloud.tosca.repository;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.Set;
import javax.annotation.Resource;
import org.springframework.expression.EvaluationContext;
import org.springframework.expression.spel.support.StandardEvaluationContext;
import org.springframework.stereotype.Component;
import alien4cloud.component.ICSARRepositorySearchService;
import alien4cloud.exception.NotFoundException;
import org.alien4cloud.tosca.model.CSARDependency;
import org.alien4cloud.tosca.model.Csar;
import org.alien4cloud.tosca.model.types.AbstractToscaType;
import alien4cloud.tosca.context.ToscaContext;
import alien4cloud.tosca.model.ArchiveRoot;
import alien4cloud.tosca.parser.ParsingContextExecution;
import alien4cloud.tosca.parser.ParsingResult;
import alien4cloud.tosca.parser.ToscaArchiveParser;
import lombok.Getter;
import lombok.Setter;
import lombok.SneakyThrows;
/**
* Manages a file-based local archive repository.
*
* Note: You should always access this class through the ToscaContext.
*/
@Getter
@Setter
@Component
public class LocalRepositoryImpl implements ICSARRepositorySearchService {
private static ThreadLocal<Boolean> recursiveCall = new ThreadLocal<>();
@Resource
private ToscaArchiveParser toscaArchiveParser;
/** Path of the local repository. */
private Path localRepositoryPath = Paths.get("target/repository");
public void setPath(String path) {
localRepositoryPath = Paths.get(path);
}
@Override
public Csar getArchive(String archiveName, String archiveVersion) {
CSARDependency dependency = new CSARDependency(archiveName, archiveVersion);
ArchiveRoot root = parse(dependency).getResult();
return root == null ? null : root.getArchive();
}
@Override
public boolean isElementExistInDependencies(Class<? extends AbstractToscaType> elementClass, String elementId, Set<CSARDependency> dependencies) {
return getElementInDependencies(elementClass, elementId, dependencies) != null;
}
@Override
public <T extends AbstractToscaType> T getElementInDependencies(Class<T> elementClass, Set<CSARDependency> dependencies, String... keyValueFilters) {
return (T) ToscaContext.get().getElement(elementClass, element -> {
if (!dependencies.contains(new CSARDependency(element.getArchiveName(), element.getArchiveVersion()))) {
return false;
}
EvaluationContext context = new StandardEvaluationContext(element);
for (int i = 0; i < keyValueFilters.length; i += 2) {
String field = keyValueFilters[0];
String value = keyValueFilters[1];
if (!value.equals(context.lookupVariable(field).toString())) {
return false;
}
}
return true;
}).orElse(null);
}
@Override
public <T extends AbstractToscaType> T getRequiredElementInDependencies(Class<T> elementClass, String elementId, Set<CSARDependency> dependencies)
throws NotFoundException {
T element = getElementInDependencies(elementClass, elementId, dependencies);
if (element == null) {
throw new NotFoundException(
"Element elementId: <" + elementId + "> of type <" + elementClass.getSimpleName() + "> cannot be found in dependencies " + dependencies);
}
return element;
}
@Override
public <T extends AbstractToscaType> T getElementInDependencies(Class<T> elementClass, String elementId, Set<CSARDependency> dependencies) {
if (recursiveCall.get() == null) {
recursiveCall.set(true);
} else {
return null;
}
// ensure that dependencies are loaded in the ToscaContext
for (CSARDependency dependency : dependencies) {
// parse and register the archive from local repository.
parseAndRegister(dependency);
}
T element = ToscaContext.get(elementClass, elementId);
recursiveCall.remove();
return element;
}
@SneakyThrows
private void parseAndRegister(CSARDependency dependency) {
// parse and load archive.
ParsingResult<ArchiveRoot> result = parse(dependency);
ToscaContext.Context context = ToscaContext.get();
context.register(result.getResult());
}
@SneakyThrows
private ParsingResult<ArchiveRoot> parse(CSARDependency dependency) {
String archiveFileName = dependency.getName().concat("-").concat(dependency.getVersion()).concat(".csar");
Path archivePath = localRepositoryPath.resolve(dependency.getName()).resolve(dependency.getVersion()).resolve(archiveFileName);
ParsingContextExecution.Context previousContext = ParsingContextExecution.get();
try {
ParsingContextExecution.init();
return toscaArchiveParser.parse(archivePath);
} finally {
ParsingContextExecution.destroy();
if (previousContext != null) {
ParsingContextExecution.set(previousContext);
}
}
}
}