Skip to main content
aboutsummaryrefslogtreecommitdiffstats
blob: dac28f716bc25d6bbf46e61f99cc07a6d6d26c23 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
/*******************************************************************************
 * Copyright (c) 2008-2010 Sonatype, Inc.
 * All rights reserved. This program and the accompanying materials
 * are made available under the terms of the Eclipse Public License v1.0
 * which accompanies this distribution, and is available at
 * http://www.eclipse.org/legal/epl-v10.html
 *
 * Contributors:
 *      Sonatype, Inc. - initial API and implementation
 *******************************************************************************/

package org.eclipse.m2e.jdt.internal;

import java.io.File;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import org.eclipse.core.resources.IProject;
import org.eclipse.core.resources.ResourcesPlugin;
import org.eclipse.core.runtime.CoreException;
import org.eclipse.core.runtime.IProgressMonitor;
import org.eclipse.core.runtime.IStatus;
import org.eclipse.core.runtime.MultiStatus;
import org.eclipse.core.runtime.OperationCanceledException;
import org.eclipse.core.runtime.Status;
import org.eclipse.core.runtime.jobs.ISchedulingRule;
import org.eclipse.core.runtime.jobs.Job;
import org.eclipse.jdt.core.IPackageFragmentRoot;

import org.apache.maven.artifact.Artifact;
import org.apache.maven.artifact.repository.ArtifactRepository;
import org.apache.maven.project.MavenProject;

import org.eclipse.m2e.core.MavenPlugin;
import org.eclipse.m2e.core.embedder.ArtifactKey;
import org.eclipse.m2e.core.embedder.IMaven;
import org.eclipse.m2e.core.internal.jobs.IBackgroundProcessingQueue;
import org.eclipse.m2e.core.project.IMavenProjectFacade;
import org.eclipse.m2e.core.project.IMavenProjectRegistry;
import org.eclipse.m2e.jdt.MavenJdtPlugin;


/**
 * DownloadSourcesJob
 * 
 * @author igor
 */
class DownloadSourcesJob extends Job implements IBackgroundProcessingQueue {
  private static Logger log = LoggerFactory.getLogger(DownloadSourcesJob.class);

  private static final long SCHEDULE_INTERVAL = 1000L;

  private static class DownloadRequest {
    final IProject project;

    final IPackageFragmentRoot fragment;

    final ArtifactKey artifact;

    final boolean downloadSources;

    final boolean downloadJavaDoc;

    public DownloadRequest(IProject project, IPackageFragmentRoot fragment, ArtifactKey artifact,
        boolean downloadSources, boolean downloadJavaDoc) {
      this.project = project;
      this.fragment = fragment;
      this.artifact = artifact;
      this.downloadSources = downloadSources;
      this.downloadJavaDoc = downloadJavaDoc;
    }

    public int hashCode() {
      int hash = 17;
      hash = hash * 31 + project.hashCode();
      hash = hash * 31 + (fragment != null ? fragment.hashCode() : 0);
      hash = hash * 31 + (artifact != null ? artifact.hashCode() : 0);
      hash = hash * 31 + (downloadSources ? 1 : 0);
      hash = hash * 31 + (downloadJavaDoc ? 1 : 0);
      return hash;
    }

    public boolean equals(Object o) {
      if(this == o) {
        return true;
      }
      if(!(o instanceof DownloadRequest)) {
        return false;
      }
      DownloadRequest other = (DownloadRequest) o;

      return project.equals(other.project)
          && (fragment != null ? fragment.equals(other.fragment) : other.fragment == null)
          && (artifact != null ? artifact.equals(other.artifact) : other.artifact == null)
          && downloadSources == other.downloadSources && downloadJavaDoc == other.downloadJavaDoc;
    }
  }

  private final IMaven maven;

  private final BuildPathManager manager;

  private final IMavenProjectRegistry projectManager;

  private final ArrayList<DownloadRequest> queue = new ArrayList<DownloadRequest>();

  public DownloadSourcesJob(BuildPathManager manager) {
    super(Messages.DownloadSourcesJob_job_download);
    this.manager = manager;

    this.maven = MavenPlugin.getMaven();

    this.projectManager = MavenPlugin.getMavenProjectRegistry();
  }

  public IStatus run(IProgressMonitor monitor) {
    ArrayList<DownloadRequest> downloadRequests;

    synchronized(this.queue) {
      downloadRequests = new ArrayList<DownloadRequest>(this.queue);
      this.queue.clear();
    }

    ArrayList<IStatus> exceptions = new ArrayList<IStatus>();

    Set<IProject> mavenProjects = new LinkedHashSet<IProject>();
    Map<IPackageFragmentRoot, File[]> nonMavenProjects = new LinkedHashMap<IPackageFragmentRoot, File[]>();

    for(DownloadRequest request : downloadRequests) {
      try {
        IMavenProjectFacade projectFacade = projectManager.create(request.project, monitor);
        if(projectFacade != null) {
          downloadMaven(projectFacade, request.artifact, request.downloadSources, request.downloadJavaDoc, monitor);
          mavenProjects.add(request.project);
        } else if(request.artifact != null) {
          List<ArtifactRepository> repositories = maven.getArtifactRepositories();
          File[] files = downloadAttachments(request.artifact, repositories, request.downloadSources,
              request.downloadJavaDoc, monitor);
          nonMavenProjects.put(request.fragment, files);
        }
      } catch(CoreException ex) {
        exceptions.add(ex.getStatus());
      }
    }

    if(!mavenProjects.isEmpty() || !nonMavenProjects.isEmpty()) {
      ISchedulingRule schedulingRule = ResourcesPlugin.getWorkspace().getRuleFactory().buildRule();
      getJobManager().beginRule(schedulingRule, monitor);
      try {
        for(IProject mavenProject : mavenProjects) {
          manager.updateClasspath(mavenProject, monitor);
        }

        for(Map.Entry<IPackageFragmentRoot, File[]> entry : nonMavenProjects.entrySet()) {
          File[] files = entry.getValue();
          manager.attachSourcesAndJavadoc(entry.getKey(), files[0], files[1], monitor);
        }
      } finally {
        getJobManager().endRule(schedulingRule);
      }
    }

    if(!exceptions.isEmpty()) {
      IStatus[] problems = exceptions.toArray(new IStatus[exceptions.size()]);
      return new MultiStatus(MavenJdtPlugin.PLUGIN_ID, -1, problems, "Could not download sources or javadoc", null);
    }

    return Status.OK_STATUS;
  }

  private void downloadMaven(IMavenProjectFacade projectFacade, ArtifactKey artifact, boolean downloadSources,
      boolean downloadJavadoc, IProgressMonitor monitor) throws CoreException {
    MavenProject mavenProject = projectFacade.getMavenProject(monitor);
    List<ArtifactRepository> repositories = mavenProject.getRemoteArtifactRepositories();

    if(artifact != null) {
      downloadAttachments(artifact, repositories, downloadSources, downloadJavadoc, monitor);
    } else {
      for(Artifact a : mavenProject.getArtifacts()) {
        ArtifactKey aKey = new ArtifactKey(a.getGroupId(), a.getArtifactId(), a.getBaseVersion(), a.getClassifier());
        downloadAttachments(aKey, repositories, downloadSources, downloadJavadoc, monitor);
      }
    }
  }

  private File[] downloadAttachments(ArtifactKey artifact, List<ArtifactRepository> repositories,
      boolean downloadSources, boolean downloadJavadoc, IProgressMonitor monitor) throws CoreException {
    if(monitor != null && monitor.isCanceled()) {
      String message = "Downloading of sources/javadocs was canceled"; //$NON-NLS-1$
      log.debug(message);
      synchronized(queue) {
        queue.clear();
      }
      throw new OperationCanceledException(message);
    }
    ArtifactKey[] attached = manager.getAttachedSourcesAndJavadoc(artifact, repositories, downloadSources,
        downloadJavadoc);

    File[] files = new File[2];

    if(attached[0] != null) {
      try {
        files[0] = download(attached[0], repositories, monitor);
        log.info("Downloaded sources for " + artifact.toString());
      } catch(CoreException e) {
        log.error("Could not download sources for " + artifact.toString(), e); //$NON-NLS-1$
      }
    }

    if(attached[1] != null) {
      try {
        files[1] = download(attached[1], repositories, monitor);
        log.info("Downloaded javadoc for " + artifact.toString());
      } catch(CoreException e) {
        log.error("Could not download sources for " + artifact.toString(), e); //$NON-NLS-1$
      }
    }

    return files;
  }

  private File download(ArtifactKey artifact, List<ArtifactRepository> repositories, IProgressMonitor monitor)
      throws CoreException {
    Artifact resolved = maven.resolve(artifact.getGroupId(), //
        artifact.getArtifactId(), //
        artifact.getVersion(), //
        "jar" /*type*/, // //$NON-NLS-1$
        artifact.getClassifier(), // 
        repositories, //
        monitor);
    return resolved.getFile();
  }

  private void scheduleDownload(IProject project, IPackageFragmentRoot fragment, ArtifactKey artifact,
      boolean downloadSources, boolean downloadJavadoc) {
    if(project == null || !project.isAccessible()) {
      return;
    }

    synchronized(this.queue) {
      queue.add(new DownloadRequest(project, fragment, artifact, downloadSources, downloadJavadoc));
    }

    schedule(SCHEDULE_INTERVAL);
  }

  /**
   * If artifact is not null, download sources and/or javadoc of this artifact. If artifact is null, download sources
   * and/or javadoc of all project dependencies. Entire project classpath is updated after download. Does nothing if
   * both downloadSources and downloadJavadoc are false.
   */
  public void scheduleDownload(IProject project, ArtifactKey artifact, boolean downloadSources, boolean downloadJavadoc) {
    scheduleDownload(project, null, artifact, downloadSources, downloadJavadoc);
  }

  public void scheduleDownload(IPackageFragmentRoot fragment, ArtifactKey artifact, boolean downloadSources,
      boolean downloadJavadoc) {
    IProject project = fragment.getJavaProject().getProject();
    scheduleDownload(project, fragment, artifact, downloadSources, downloadJavadoc);
  }

  public boolean isEmpty() {
    synchronized(queue) {
      return queue.isEmpty();
    }
  }
}

Back to the top