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); } } } }