001/** 002 * Copyright (C) 2006-2024 Talend Inc. - www.talend.com 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016package org.talend.sdk.component.runtime.manager.service; 017 018import java.nio.charset.StandardCharsets; 019import java.nio.file.Files; 020import java.nio.file.Path; 021import java.nio.file.Paths; 022import java.util.Objects; 023import java.util.Optional; 024import java.util.regex.Matcher; 025import java.util.stream.Stream; 026 027import org.talend.sdk.component.runtime.manager.service.path.PathHandler; 028import org.talend.sdk.component.runtime.manager.service.path.PathHandlerImpl; 029 030import lombok.Data; 031import lombok.NoArgsConstructor; 032import lombok.extern.slf4j.Slf4j; 033 034/** 035 * m2 discovery process is used for plugins/connectors loading. 036 * 037 * The default discovery process is at it follows: 038 * <ul> 039 * <li>read {@code talend.component.manager.m2.repository} system property</li> 040 * <li>check if we're running in studio and uses its m2 if system property is not set to maven.repository=global</li> 041 * <li>parse maven's {@code settings.xml} (or if provided {@code talend.component.manager.m2.settings}) for checking if 042 * a property localRepository is defined</li> 043 * <li>checking for maven env properties (ie $M2_HOME)</li> 044 * <li>fallbacks to ${user.home}/.m2/repository</li> 045 * </ul> 046 */ 047@Slf4j 048@NoArgsConstructor 049@Data 050public class MavenRepositoryDefaultResolver implements MavenRepositoryResolver { 051 052 private PathHandler handler = new PathHandlerImpl(); 053 054 @Override 055 public Path discover() { 056 return Stream 057 .of(fromSystemProperties(), fromStudioConfiguration(), fromMavenSettings(), fromEnvironmentVariables()) 058 .filter(Objects::nonNull) 059 .findFirst() 060 .orElseGet(this::fallback); 061 } 062 063 @Override 064 public Path fallback() { 065 log.debug("[fallback] default to user's default repository."); 066 return Paths.get(USER_HOME).resolve(M2_REPOSITORY); 067 } 068 069 public Path fromSystemProperties() { 070 final String m2 = System.getProperty(TALEND_COMPONENT_MANAGER_M2_REPOSITORY); 071 if (m2 != null) { 072 return handler.get(m2); 073 } 074 log.debug("[fromSystemProperties] Could not get m2 from System property."); 075 return null; 076 } 077 078 private Path fromStudioConfiguration() { 079 // check if we are in the studio process if so just grab the studio config 080 final String m2Repo = System.getProperty(STUDIO_MVN_REPOSITORY); 081 if (!"global".equals(m2Repo)) { 082 return handler.get(Paths.get(System.getProperty("osgi.configuration.area", ""), M2_REPOSITORY).toString()); 083 } 084 log.debug("[fromStudioConfiguration] Could not get m2 from studio config."); 085 return null; 086 } 087 088 private static String parseSettings(final Path settings) { 089 log.debug("[fromMavenSettings] searching for localRepository location in {}", settings); 090 try { 091 String localM2RepositoryFromSettings = null; 092 // do not introduce a xml parser so will do with what we have... 093 final String content = new String(java.nio.file.Files.readAllBytes(settings), StandardCharsets.UTF_8); 094 // some cleanups 095 String stripped = XML_COMMENTS_PATTERN.matcher(content).replaceAll(""); 096 stripped = XML_EMPTY_LINES_PATTERN.matcher(stripped).replaceAll(""); 097 // localRepository present? 098 final Matcher m = XML_LOCAL_REPO_PATTERN.matcher(stripped); 099 if (!m.matches()) { 100 log.debug("[fromMavenSettings] localRepository not defined in settings.xml"); 101 } else { 102 localM2RepositoryFromSettings = m.group(1).trim(); 103 if (localM2RepositoryFromSettings != null && !localM2RepositoryFromSettings.isEmpty()) { 104 return localM2RepositoryFromSettings; 105 } 106 } 107 } catch (final Exception ignore) { 108 // fallback on default local path 109 } 110 return null; 111 } 112 113 public Path fromMavenSettings() { 114 return Stream.of( 115 Optional.ofNullable(System.getProperty(TALEND_COMPONENT_MANAGER_M2_SETTINGS)) 116 .map(Paths::get) 117 .orElse(null), // 118 Optional.ofNullable(System.getProperty("user.home")).map(it -> Paths.get(it, M2_SETTINGS)).orElse(null), 119 Optional.ofNullable(System.getenv(MAVEN_HOME)).map(it -> Paths.get(it, CONF_SETTINGS)).orElse(null), 120 Optional.ofNullable(System.getenv(M2_HOME)).map(it -> Paths.get(it, CONF_SETTINGS)).orElse(null)) 121 .filter(Objects::nonNull) 122 .filter(Files::exists) 123 .map(MavenRepositoryDefaultResolver::parseSettings) 124 .filter(Objects::nonNull) 125 .map(handler::get) 126 .filter(Objects::nonNull) 127 .findFirst() 128 .orElse(null); 129 } 130 131 public Path fromEnvironmentVariables() { 132 final String vm2 = System.getenv(M2_HOME); 133 log.debug("[fromEnvironmentVariables] M2_HOME={}", vm2); 134 if (vm2 != null) { 135 return handler.get(Paths.get(vm2, "repository").toString()); 136 } 137 log.debug("[fromEnvironmentVariables] Could not get m2 from environment."); 138 return null; 139 } 140 141}