11/*******************************************************************************
2- * Copyright (c) 2020 Christoph Läubrich and others.
2+ * Copyright (c) 2020, 2025 Christoph Läubrich and others.
33 * This program and the accompanying materials
44 * are made available under the terms of the Eclipse Public License 2.0
55 * which accompanies this distribution, and is available at
1818import java .io .FileNotFoundException ;
1919import java .io .IOException ;
2020import java .io .InputStream ;
21+ import java .net .URI ;
22+ import java .net .URISyntaxException ;
2123import java .net .URL ;
2224import java .net .URLConnection ;
25+ import java .util .Hashtable ;
2326import java .util .List ;
27+ import java .util .stream .Collectors ;
2428
29+ import org .osgi .framework .BundleContext ;
30+ import org .osgi .framework .ServiceRegistration ;
31+ import org .osgi .service .component .annotations .Activate ;
2532import org .osgi .service .component .annotations .Component ;
33+ import org .osgi .service .component .annotations .Deactivate ;
2634import org .osgi .service .component .annotations .Reference ;
2735import org .osgi .service .url .AbstractURLStreamHandlerService ;
2836import org .osgi .service .url .URLConstants ;
4048import org .eclipse .core .runtime .IProgressMonitor ;
4149import org .eclipse .core .runtime .NullProgressMonitor ;
4250import org .eclipse .core .runtime .Status ;
51+ import org .eclipse .osgi .service .debug .DebugOptions ;
52+ import org .eclipse .osgi .service .debug .DebugOptionsListener ;
53+ import org .eclipse .osgi .service .debug .DebugTrace ;
4354
4455import org .apache .maven .RepositoryUtils ;
4556import org .apache .maven .artifact .repository .ArtifactRepository ;
5061
5162
5263@ Component (service = URLStreamHandlerService .class , property = URLConstants .URL_HANDLER_PROTOCOL + "=mvn" )
53- public class MvnProtocolHandlerService extends AbstractURLStreamHandlerService {
64+ public class MvnProtocolHandlerService extends AbstractURLStreamHandlerService implements DebugOptionsListener {
5465
55- @ Reference
56- IMaven maven ;
66+ private static final String ID = "org.eclipse.m2e.core" ;
67+
68+ private static final String OPTION = "/mvnProtocolHandler" ;
69+
70+ private final IMaven maven ;
71+
72+ private volatile DebugTrace debugTrace ;
73+
74+ private final ServiceRegistration <DebugOptionsListener > serviceRegistration ;
75+
76+ @ Activate
77+ public MvnProtocolHandlerService (@ Reference IMaven maven , BundleContext bundleContext ) {
78+ this .maven = maven ;
79+ //We need to register this manually here to we are lazy as otherwise it would activate this component immediately
80+ Hashtable <String , Object > hashtable = new Hashtable <>();
81+ hashtable .put (DebugOptions .LISTENER_SYMBOLICNAME , ID );
82+ serviceRegistration = bundleContext .registerService (DebugOptionsListener .class , this , hashtable );
83+ }
84+
85+ @ Deactivate
86+ void shutdown () {
87+ serviceRegistration .unregister ();
88+ }
89+ @ Override
90+ public void optionsChanged (DebugOptions options ) {
91+ if (options .getBooleanOption (ID + OPTION , false )) {
92+ this .debugTrace = options .newDebugTrace (ID , MvnProtocolHandlerService .class );
93+ } else {
94+ this .debugTrace = null ;
95+ }
96+ }
5797
5898 @ Override
5999 public URLConnection openConnection (URL url ) {
60- //TODO replace reference with IMaven maven = MavenPlugin.getMaven();
61- //this is required to make the component active even if m2e itself is not running at the moment
62- //that will make the m2e protocol available from the start of eclipse
63- //See https://github.com/eclipse-equinox/equinox/pull/290
64- return new MavenURLConnection (url , maven );
100+ return new MavenURLConnection (url , maven , debugTrace );
65101 }
66102
67103 private static final class MavenURLConnection extends URLConnection {
@@ -70,11 +106,14 @@ private static final class MavenURLConnection extends URLConnection {
70106
71107 private ArtifactResult artifactResult ;
72108
73- private IMaven maven ;
109+ private final IMaven maven ;
110+
111+ private final DebugTrace debugTrace ;
74112
75- protected MavenURLConnection (URL url , IMaven maven ) {
113+ protected MavenURLConnection (URL url , IMaven maven , DebugTrace debugTrace ) {
76114 super (url );
77115 this .maven = maven ;
116+ this .debugTrace = debugTrace ;
78117 }
79118
80119 @ Override
@@ -86,6 +125,9 @@ public void connect() throws IOException {
86125 if (path == null ) {
87126 throw new IOException ("maven coordinates are missing" );
88127 }
128+ if (debugTrace != null ) {
129+ debugTrace .trace (OPTION , "connect to " + url );
130+ }
89131 int subPathIndex = path .indexOf ('/' );
90132
91133 String [] coordinates ;
@@ -104,8 +146,18 @@ public void connect() throws IOException {
104146 try {
105147 RepositorySystem repoSystem = maven .lookup (RepositorySystem .class );
106148 IMavenExecutionContext context = maven .createExecutionContext ();
149+ boolean isSnapshot = artifact .getBaseVersion ().endsWith ("-SNAPSHOT" );
150+ if (isSnapshot && !context .getExecutionRequest ().isUpdateSnapshots ()) {
151+ //if a snapshot version is requested, always force an update!
152+ context .getExecutionRequest ().setUpdateSnapshots (true );
153+ }
107154 List <ArtifactRepository > artifactRepositories = maven .getArtifactRepositories ();
108155 List <RemoteRepository > remoteRepositories = RepositoryUtils .toRepos (artifactRepositories );
156+ if (debugTrace != null ) {
157+ debugTrace .trace (OPTION , "Fetching artifact " + artifact + " using "
158+ + remoteRepositories .stream ().map (rp -> rp .getUrl ()).collect (Collectors .joining (", " ))
159+ + " with update snapshots = " + context .getExecutionRequest ().isUpdateSnapshots ());
160+ }
109161 artifactResult = context .execute (new ICallable <ArtifactResult >() {
110162
111163 @ Override
@@ -115,6 +167,9 @@ public ArtifactResult call(IMavenExecutionContext context, IProgressMonitor moni
115167 try {
116168 return repoSystem .resolveArtifact (session , artifactRequest );
117169 } catch (ArtifactResolutionException e ) {
170+ if (debugTrace != null ) {
171+ debugTrace .trace (OPTION , "resolving of artifact " + artifact + " failed!" , e );
172+ }
118173 throw new CoreException (Status .error ("Resolving artifact failed" , e ));
119174 }
120175 }
@@ -132,17 +187,27 @@ public InputStream getInputStream() throws IOException {
132187 }
133188 File location = artifactResult .getArtifact ().getFile ();
134189 if (subPath == null ) {
190+ if (debugTrace != null ) {
191+ debugTrace .trace (OPTION , "Open stream to artifact file " + location );
192+ }
135193 return new FileInputStream (location );
136194 }
137195 String urlSpec = "jar:" + location .toURI () + "!" + subPath ;
138- return new URL (urlSpec ).openStream ();
196+ try {
197+ if (debugTrace != null ) {
198+ debugTrace .trace (OPTION , "Open stream to subpath in artifact file " + urlSpec );
199+ }
200+ return new URI (urlSpec ).toURL ().openStream ();
201+ } catch (URISyntaxException ex ) {
202+ throw new IOException (ex );
203+ }
139204 }
140205
141206 @ Override
142207 public long getLastModified () {
143208 try {
144209 connect ();
145- } catch (IOException e ) {
210+ } catch (IOException e ) {
146211 return 0 ;
147212 }
148213 if (artifactResult == null || artifactResult .isMissing ()) {
0 commit comments