001/** 002 * Copyright (C) 2006-2025 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.net.URI; 019import java.nio.charset.StandardCharsets; 020import java.nio.file.Files; 021import java.nio.file.Path; 022import java.nio.file.Paths; 023import java.util.Objects; 024import java.util.Optional; 025import java.util.regex.Matcher; 026import java.util.stream.Stream; 027 028import org.talend.sdk.component.runtime.manager.service.path.PathHandler; 029import org.talend.sdk.component.runtime.manager.service.path.PathHandlerImpl; 030 031import lombok.Data; 032import lombok.NoArgsConstructor; 033import lombok.extern.slf4j.Slf4j; 034 035/** 036 * m2 discovery process is used for plugins/connectors loading. 037 * 038 * The default discovery process is at it follows: 039 * <ul> 040 * <li>read {@code talend.component.manager.m2.repository} system property</li> 041 * <li>check if we're running in studio and uses its m2 if system property is not set to maven.repository=global</li> 042 * <li>parse maven's {@code settings.xml} (or if provided {@code talend.component.manager.m2.settings}) for checking if 043 * a property localRepository is defined</li> 044 * <li>checking for maven env properties (ie $M2_HOME)</li> 045 * <li>fallbacks to ${user.home}/.m2/repository</li> 046 * </ul> 047 */ 048@Slf4j 049@NoArgsConstructor 050@Data 051public class MavenRepositoryDefaultResolver implements MavenRepositoryResolver { 052 053 private PathHandler handler = new PathHandlerImpl(); 054 055 @Override 056 public Path discover() { 057 return Stream 058 .of(fromSystemProperties(), fromStudioConfiguration(), fromMavenSettings(), fromEnvironmentVariables()) 059 .filter(Objects::nonNull) 060 .findFirst() 061 .orElseGet(this::fallback); 062 } 063 064 @Override 065 public Path fallback() { 066 log.debug("[fallback] default to user's default repository."); 067 return Paths.get(USER_HOME).resolve(M2_REPOSITORY); 068 } 069 070 public Path fromSystemProperties() { 071 final String m2 = System.getProperty(TALEND_COMPONENT_MANAGER_M2_REPOSITORY); 072 if (m2 != null) { 073 return handler.get(m2); 074 } 075 log.debug("[fromSystemProperties] Could not get m2 from System property."); 076 return null; 077 } 078 079 private Path fromStudioConfiguration() { 080 // check if we are in the studio process if so just grab the studio config 081 final String m2Repo = System.getProperty(STUDIO_MVN_REPOSITORY); 082 if (!"global".equals(m2Repo)) { 083 final String osgi = System.getProperty("osgi.configuration.area", ""); 084 try { 085 return osgi != null && osgi.startsWith("file") ? handler.get(Paths.get(new URI(osgi)).toString()) 086 : handler.get(Paths.get(osgi, M2_REPOSITORY).toString()); 087 } catch (java.net.URISyntaxException e) { 088 log.debug("[fromStudioConfiguration] Could not get m2 from studio config." + e.getMessage()); 089 return null; 090 } 091 } 092 log.debug("[fromStudioConfiguration] Could not get m2 from studio config."); 093 return null; 094 } 095 096 private static String parseSettings(final Path settings) { 097 log.debug("[fromMavenSettings] searching for localRepository location in {}", settings); 098 try { 099 String localM2RepositoryFromSettings = null; 100 // do not introduce a xml parser so will do with what we have... 101 final String content = new String(java.nio.file.Files.readAllBytes(settings), StandardCharsets.UTF_8); 102 // some cleanups 103 String stripped = XML_COMMENTS_PATTERN.matcher(content).replaceAll(""); 104 stripped = XML_EMPTY_LINES_PATTERN.matcher(stripped).replaceAll(""); 105 // localRepository present? 106 final Matcher m = XML_LOCAL_REPO_PATTERN.matcher(stripped); 107 if (!m.matches()) { 108 log.debug("[fromMavenSettings] localRepository not defined in settings.xml"); 109 } else { 110 localM2RepositoryFromSettings = m.group(1).trim(); 111 if (localM2RepositoryFromSettings != null && !localM2RepositoryFromSettings.isEmpty()) { 112 return localM2RepositoryFromSettings; 113 } 114 } 115 } catch (final Exception ignore) { 116 // fallback on default local path 117 } 118 return null; 119 } 120 121 public Path fromMavenSettings() { 122 return Stream.of( 123 Optional.ofNullable(System.getProperty(TALEND_COMPONENT_MANAGER_M2_SETTINGS)) 124 .map(Paths::get) 125 .orElse(null), // 126 Optional.ofNullable(System.getProperty("user.home")).map(it -> Paths.get(it, M2_SETTINGS)).orElse(null), 127 Optional.ofNullable(System.getenv(MAVEN_HOME)).map(it -> Paths.get(it, CONF_SETTINGS)).orElse(null), 128 Optional.ofNullable(System.getenv(M2_HOME)).map(it -> Paths.get(it, CONF_SETTINGS)).orElse(null)) 129 .filter(Objects::nonNull) 130 .filter(Files::exists) 131 .map(MavenRepositoryDefaultResolver::parseSettings) 132 .filter(Objects::nonNull) 133 .map(handler::get) 134 .filter(Objects::nonNull) 135 .findFirst() 136 .orElse(null); 137 } 138 139 public Path fromEnvironmentVariables() { 140 final String vm2 = System.getenv(M2_HOME); 141 log.debug("[fromEnvironmentVariables] M2_HOME={}", vm2); 142 if (vm2 != null) { 143 return handler.get(Paths.get(vm2, "repository").toString()); 144 } 145 log.debug("[fromEnvironmentVariables] Could not get m2 from environment."); 146 return null; 147 } 148 149}