[maven] IDEA-91662 doesn't take into account mirror repositories as Indexed Maven...
[idea/community.git] / plugins / maven / maven3-server-common / src / org / jetbrains / idea / maven / server / MavenModelConverter.java
1 // Copyright 2000-2021 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
2 package org.jetbrains.idea.maven.server;
3
4 import com.intellij.util.ReflectionUtilRt;
5 import org.apache.maven.archetype.catalog.Archetype;
6 import org.apache.maven.artifact.Artifact;
7 import org.apache.maven.artifact.handler.ArtifactHandler;
8 import org.apache.maven.artifact.repository.ArtifactRepository;
9 import org.apache.maven.artifact.repository.ArtifactRepositoryPolicy;
10 import org.apache.maven.model.*;
11 import org.apache.maven.shared.dependency.tree.DependencyNode;
12 import org.codehaus.plexus.util.xml.Xpp3Dom;
13 import org.jdom.Element;
14 import org.jdom.IllegalNameException;
15 import org.jetbrains.annotations.NotNull;
16 import org.jetbrains.idea.maven.model.*;
17 import org.jetbrains.idea.maven.server.embedder.CustomMaven3Artifact;
18 import org.sonatype.nexus.index.ArtifactInfo;
19
20 import java.io.File;
21 import java.lang.reflect.Field;
22 import java.rmi.RemoteException;
23 import java.util.*;
24
25 public class MavenModelConverter {
26   @NotNull
27   public static MavenModel convertModel(Model model, File localRepository) throws RemoteException {
28     if(model.getBuild() == null) {
29       model.setBuild(new Build());
30     }
31     Build build = model.getBuild();
32     return convertModel(model,
33                         asSourcesList(build.getSourceDirectory()),
34                         asSourcesList(build.getTestSourceDirectory()),
35                         Collections.<Artifact>emptyList(),
36                         Collections.<DependencyNode>emptyList(),
37                         Collections.<Artifact>emptyList(),
38                         localRepository);
39   }
40
41   private static List<String> asSourcesList(String directory) {
42     return directory == null ? Collections.<String>emptyList() : Collections.singletonList(directory);
43   }
44
45   @NotNull
46   public static MavenModel convertModel(Model model,
47                                         List<String> sources,
48                                         List<String> testSources,
49                                         Collection<? extends Artifact> dependencies,
50                                         Collection<? extends DependencyNode> dependencyTree,
51                                         Collection<? extends Artifact> extensions,
52                                         File localRepository) throws RemoteException {
53     MavenModel result = new MavenModel();
54     result.setMavenId(new MavenId(model.getGroupId(), model.getArtifactId(), model.getVersion()));
55
56     Parent parent = model.getParent();
57     if (parent != null) {
58       result.setParent(new MavenParent(new MavenId(parent.getGroupId(), parent.getArtifactId(), parent.getVersion()),
59                                        parent.getRelativePath()));
60     }
61     result.setPackaging(model.getPackaging());
62     result.setName(model.getName());
63     result.setProperties(model.getProperties() == null ? new Properties() : model.getProperties());
64     result.setPlugins(convertPlugins(model));
65
66     Map<Artifact, MavenArtifact> convertedArtifacts = new HashMap<Artifact, MavenArtifact>();
67     result.setExtensions(convertArtifacts(extensions, convertedArtifacts, localRepository));
68     result.setDependencies(convertArtifacts(dependencies, convertedArtifacts, localRepository));
69     result.setDependencyTree(convertDependencyNodes(null, dependencyTree, convertedArtifacts, localRepository));
70
71     result.setRemoteRepositories(convertRepositories(model.getRepositories()));
72     result.setProfiles(convertProfiles(model.getProfiles()));
73     result.setModules(model.getModules());
74
75     convertBuild(result.getBuild(), model.getBuild(), sources, testSources);
76     return result;
77   }
78
79   public static void convertBuild(MavenBuild result, Build build, List<String> sources, List<String> testSources) {
80     convertBuildBase(result, build);
81     result.setOutputDirectory(build.getOutputDirectory());
82     result.setTestOutputDirectory(build.getTestOutputDirectory());
83     result.setSources(sources);
84     result.setTestSources(testSources);
85   }
86
87   private static void convertBuildBase(MavenBuildBase result, BuildBase build) {
88     result.setFinalName(build.getFinalName());
89     result.setDefaultGoal(build.getDefaultGoal());
90     result.setDirectory(build.getDirectory());
91     result.setResources(convertResources(build.getResources()));
92     result.setTestResources(convertResources(build.getTestResources()));
93     result.setFilters(build.getFilters() == null ? Collections.<String>emptyList() : build.getFilters());
94   }
95
96   public static MavenId createMavenId(Artifact artifact) {
97     return new MavenId(artifact.getGroupId(), artifact.getArtifactId(), artifact.getVersion());
98   }
99
100   private static List<MavenResource> convertResources(List<Resource> resources) {
101     if (resources == null) return new ArrayList<MavenResource>();
102
103     List<MavenResource> result = new ArrayList<MavenResource>(resources.size());
104     for (Resource each : resources) {
105       result.add(new MavenResource(each.getDirectory(),
106                                    each.isFiltering(),
107                                    each.getTargetPath(),
108                                    ensurePatterns(each.getIncludes()),
109                                    ensurePatterns(each.getExcludes())));
110     }
111     return result;
112   }
113
114   private static List<String> ensurePatterns(List<String> patterns) {
115     return patterns == null ? Collections.<String>emptyList() : patterns;
116   }
117
118   public static List<MavenRemoteRepository> convertRepositories(List<? extends Repository> repositories) {
119     if (repositories == null) return new ArrayList<MavenRemoteRepository>();
120
121     List<MavenRemoteRepository> result = new ArrayList<MavenRemoteRepository>(repositories.size());
122     for (Repository each : repositories) {
123       result.add(new MavenRemoteRepository(each.getId(),
124                                            each.getName(),
125                                            each.getUrl(),
126                                            each.getLayout(),
127                                            convertPolicy(each.getReleases()),
128                                            convertPolicy(each.getSnapshots())));
129     }
130     return result;
131   }
132
133   public static List<MavenRemoteRepository> convertRemoteRepositories(List<? extends ArtifactRepository> repositories) {
134     if (repositories == null) return new ArrayList<MavenRemoteRepository>();
135
136     List<MavenRemoteRepository> result = new ArrayList<MavenRemoteRepository>(repositories.size());
137     for (ArtifactRepository each : repositories) {
138       result.add(new MavenRemoteRepository(each.getId(),
139                                            each.getId(),
140                                            each.getUrl(),
141                                            each.getLayout() != null ? each.getLayout().getId() : "default",
142                                            convertPolicy(each.getReleases()),
143                                            convertPolicy(each.getSnapshots())));
144     }
145     return result;
146   }
147
148
149   private static MavenRemoteRepository.Policy convertPolicy(RepositoryPolicy policy) {
150     return policy != null
151            ? new MavenRemoteRepository.Policy(policy.isEnabled(), policy.getUpdatePolicy(), policy.getChecksumPolicy())
152            : null;
153   }
154
155   private static MavenRemoteRepository.Policy convertPolicy(ArtifactRepositoryPolicy policy) {
156     return policy != null
157            ? new MavenRemoteRepository.Policy(policy.isEnabled(), policy.getUpdatePolicy(), policy.getChecksumPolicy())
158            : null;
159   }
160
161   public static List<MavenArtifact> convertArtifacts(Collection<? extends Artifact> artifacts,
162                                                      Map<Artifact, MavenArtifact> nativeToConvertedMap,
163                                                      File localRepository) {
164     if (artifacts == null) return new ArrayList<MavenArtifact>();
165
166     Set<MavenArtifact> result = new LinkedHashSet<MavenArtifact>(artifacts.size());
167     for (Artifact each : artifacts) {
168       result.add(convertArtifact(each, nativeToConvertedMap, localRepository));
169     }
170     return new ArrayList<MavenArtifact>(result);
171   }
172
173   public static List<MavenArtifactNode> convertDependencyNodes(MavenArtifactNode parent,
174                                                                Collection<? extends DependencyNode> nodes,
175                                                                Map<Artifact, MavenArtifact> nativeToConvertedMap,
176                                                                File localRepository) {
177     List<MavenArtifactNode> result = new ArrayList<MavenArtifactNode>(nodes.size());
178     for (DependencyNode each : nodes) {
179       Artifact a = each.getArtifact();
180       MavenArtifact ma = convertArtifact(a, nativeToConvertedMap, localRepository);
181
182       MavenArtifactState state = MavenArtifactState.ADDED;
183       switch (each.getState()) {
184         case DependencyNode.INCLUDED:
185           break;
186         case DependencyNode.OMITTED_FOR_CONFLICT:
187           state = MavenArtifactState.CONFLICT;
188           break;
189         case DependencyNode.OMITTED_FOR_DUPLICATE:
190           state = MavenArtifactState.DUPLICATE;
191           break;
192         case DependencyNode.OMITTED_FOR_CYCLE:
193           state = MavenArtifactState.CYCLE;
194           break;
195         default:
196           assert false : "unknown dependency node state: " + each.getState();
197       }
198       MavenArtifact relatedMA = each.getRelatedArtifact() == null ? null
199                                                                   : convertArtifact(each.getRelatedArtifact(), nativeToConvertedMap,
200                                                                                     localRepository);
201       MavenArtifactNode newNode = new MavenArtifactNode(parent, ma, state, relatedMA, each.getOriginalScope(),
202                                                         each.getPremanagedVersion(), each.getPremanagedScope());
203       newNode.setDependencies(convertDependencyNodes(newNode, each.getChildren(), nativeToConvertedMap, localRepository));
204       result.add(newNode);
205     }
206     return result;
207   }
208
209   public static MavenArtifact convertArtifact(Artifact artifact, Map<Artifact, MavenArtifact> nativeToConvertedMap, File localRepository) {
210     MavenArtifact result = nativeToConvertedMap.get(artifact);
211     if (result == null) {
212       result = convertArtifact(artifact, localRepository);
213       nativeToConvertedMap.put(artifact, result);
214     }
215     return result;
216   }
217
218   public static MavenArtifact convertArtifact(Artifact artifact, File localRepository) {
219     return new MavenArtifact(artifact.getGroupId(),
220                              artifact.getArtifactId(),
221                              artifact.getVersion(),
222                              artifact.getBaseVersion(),
223                              artifact.getType(),
224                              artifact.getClassifier(),
225
226                              artifact.getScope(),
227                              artifact.isOptional(),
228
229                              convertExtension(artifact),
230
231                              artifact.getFile(),
232                              localRepository,
233
234                              artifact.isResolved(),
235                              artifact instanceof CustomMaven3Artifact && ((CustomMaven3Artifact)artifact).isStub());
236   }
237
238   private static String convertExtension(Artifact artifact) {
239     ArtifactHandler handler = artifact.getArtifactHandler();
240     String result = null;
241     if (handler != null) result = handler.getExtension();
242     if (result == null) result = artifact.getType();
243     return result;
244   }
245
246   public static List<MavenPlugin> convertPlugins(Model mavenModel) throws RemoteException {
247     List<MavenPlugin> result = new ArrayList<MavenPlugin>();
248     Build build = mavenModel.getBuild();
249
250     if (build != null) {
251       List<Plugin> plugins = build.getPlugins();
252       if (plugins != null) {
253         for (Plugin each : plugins) {
254           result.add(convertPlugin(false, each));
255         }
256       }
257     }
258
259     return result;
260   }
261
262   private static MavenPlugin convertPlugin(boolean isDefault, Plugin plugin) throws RemoteException {
263     List<MavenPlugin.Execution> executions = new ArrayList<MavenPlugin.Execution>(plugin.getExecutions().size());
264     for (PluginExecution each : plugin.getExecutions()) {
265       executions.add(convertExecution(each));
266     }
267
268     List<MavenId> deps = new ArrayList<MavenId>(plugin.getDependencies().size());
269     for (Dependency each : plugin.getDependencies()) {
270       deps.add(new MavenId(each.getGroupId(), each.getArtifactId(), each.getVersion()));
271     }
272
273     return new MavenPlugin(plugin.getGroupId(),
274                            plugin.getArtifactId(),
275                            plugin.getVersion(),
276                            isDefault,
277                            "true".equals(plugin.getExtensions()),
278                            convertConfiguration(plugin.getConfiguration()),
279                            executions, deps);
280   }
281
282   public static MavenPlugin.Execution convertExecution(PluginExecution execution) throws RemoteException {
283     return new MavenPlugin.Execution(execution.getId(), execution.getPhase(), execution.getGoals(), convertConfiguration(execution.getConfiguration()));
284   }
285
286   private static Element convertConfiguration(Object config) throws RemoteException {
287     return config == null ? null : xppToElement((Xpp3Dom)config);
288   }
289
290   private static Element xppToElement(Xpp3Dom xpp) throws RemoteException {
291     Element result;
292     try {
293       result = new Element(xpp.getName());
294     }
295     catch (IllegalNameException e) {
296       Maven3ServerGlobals.getLogger().info(e);
297       return null;
298     }
299
300     Xpp3Dom[] children = xpp.getChildren();
301     if (children == null || children.length == 0) {
302       result.setText(xpp.getValue());
303     }
304     else {
305       for (Xpp3Dom each : children) {
306         Element child = xppToElement(each);
307         if (child != null) result.addContent(child);
308       }
309     }
310     return result;
311   }
312
313   public static List<MavenProfile> convertProfiles(Collection<? extends Profile> profiles) {
314     if (profiles == null) return Collections.emptyList();
315     List<MavenProfile> result = new ArrayList<MavenProfile>();
316     for (Profile each : profiles) {
317       String id = each.getId();
318       if (id == null) continue;
319       MavenProfile profile = new MavenProfile(id, each.getSource());
320       List<String> modules = each.getModules();
321       profile.setModules(modules == null ? Collections.<String>emptyList() : modules);
322       profile.setActivation(convertActivation(each.getActivation()));
323       if (each.getBuild() != null) convertBuildBase(profile.getBuild(), each.getBuild());
324       result.add(profile);
325     }
326     return result;
327   }
328
329   private static MavenProfileActivation convertActivation(Activation activation) {
330     if (activation == null) return null;
331
332     MavenProfileActivation result = new MavenProfileActivation();
333     result.setActiveByDefault(activation.isActiveByDefault());
334     result.setOs(convertOsActivation(activation.getOs()));
335     result.setJdk(activation.getJdk());
336     result.setFile(convertFileActivation(activation.getFile()));
337     result.setProperty(convertPropertyActivation(activation.getProperty()));
338     return result;
339   }
340
341   private static MavenProfileActivationOS convertOsActivation(ActivationOS os) {
342     return os == null ? null : new MavenProfileActivationOS(os.getName(), os.getFamily(), os.getArch(), os.getVersion());
343   }
344
345   private static MavenProfileActivationFile convertFileActivation(ActivationFile file) {
346     return file == null ? null : new MavenProfileActivationFile(file.getExists(), file.getMissing());
347   }
348
349   private static MavenProfileActivationProperty convertPropertyActivation(ActivationProperty property) {
350     return property == null ? null : new MavenProfileActivationProperty(property.getName(), property.getValue());
351   }
352
353   public static Map<String, String> convertToMap(Object object) {
354     try {
355       Map<String, String> result = new HashMap<String, String>();
356       doConvert(object, "", result);
357       return result;
358     }
359     catch (IllegalAccessException e) {
360       throw new RuntimeException(e);
361     }
362   }
363
364   private static boolean isNativeToString(String toStringResult, Object o) {
365     String className = o.getClass().getName();
366     return (toStringResult.startsWith(className) && toStringResult.startsWith("@", className.length()));
367   }
368
369   private static void doConvert(Object object, String prefix, Map<String, String> result) throws IllegalAccessException {
370     for (Field each : ReflectionUtilRt.collectFields(object.getClass())) {
371       Class<?> type = each.getType();
372       if (shouldSkip(type)) continue;
373
374       each.setAccessible(true);
375       Object value = each.get(object);
376
377       if (value != null) {
378         String name = prefix + each.getName();
379
380         String sValue = String.valueOf(value);
381         if (!isNativeToString(sValue, value)) {
382           result.put(name, sValue);
383         }
384
385         Package pack = type.getPackage();
386         if (pack != null && Model.class.getPackage().getName().equals(pack.getName())) {
387           doConvert(value, name + ".", result);
388         }
389       }
390     }
391   }
392
393   public static boolean shouldSkip(Class clazz) {
394     return clazz.isArray()
395            || Collection.class.isAssignableFrom(clazz)
396            || Map.class.isAssignableFrom(clazz)
397            || Xpp3Dom.class.isAssignableFrom(clazz);
398   }
399
400   @NotNull
401   public static Model toNativeModel(MavenModel model) {
402     Model result = new Model();
403     result.setArtifactId(model.getMavenId().getArtifactId());
404     result.setGroupId(model.getMavenId().getGroupId());
405     result.setVersion(model.getMavenId().getVersion());
406     result.setPackaging(model.getPackaging());
407     result.setName(model.getName());
408
409     if (model.getParent() != null) {
410       Parent parent = new Parent();
411       parent.setArtifactId(model.getParent().getMavenId().getArtifactId());
412       parent.setGroupId(model.getParent().getMavenId().getGroupId());
413       parent.setVersion(model.getParent().getMavenId().getVersion());
414       parent.setRelativePath(model.getParent().getRelativePath());
415       result.setParent(parent);
416     }
417     toNativeModelBase(model, result);
418
419     result.setBuild(new Build());
420     MavenBuild modelBuild = model.getBuild();
421     toNativeBuildBase(modelBuild, result.getBuild());
422     result.getBuild().setOutputDirectory(modelBuild.getOutputDirectory());
423     result.getBuild().setTestOutputDirectory(modelBuild.getTestOutputDirectory());
424
425     if (modelBuild.getSources().size() > 1) throw new RuntimeException("too many source directories: " + modelBuild.getSources());
426     if (modelBuild.getTestSources().size() > 1) throw new RuntimeException("too many test directories: " + modelBuild.getTestSources());
427
428     if (modelBuild.getSources().size() == 1) {
429       result.getBuild().setSourceDirectory(modelBuild.getSources().get(0));
430     }
431     if (modelBuild.getTestSources().size() == 1) {
432       result.getBuild().setTestSourceDirectory(modelBuild.getTestSources().get(0));
433     }
434
435     result.setProfiles(toNativeProfiles(model.getProfiles()));
436
437     return result;
438   }
439
440   private static List<Profile> toNativeProfiles(List<MavenProfile> profiles) {
441     List<Profile> result = new ArrayList<Profile>(profiles.size());
442     for (MavenProfile each : profiles) {
443       Profile p = new Profile();
444       p.setId(each.getId());
445       p.setSource(each.getSource());
446       p.setBuild(new Build());
447       p.setActivation(toNativeActivation(each.getActivation()));
448       toNativeModelBase(each, p);
449       toNativeBuildBase(each.getBuild(), p.getBuild());
450       result.add(p);
451     }
452     return result;
453   }
454
455   private static Activation toNativeActivation(MavenProfileActivation activation) {
456     if (activation == null) return null;
457     Activation result = new Activation();
458     result.setActiveByDefault(activation.isActiveByDefault());
459     result.setJdk(activation.getJdk());
460     result.setOs(toNativeOsActivation(activation.getOs()));
461     result.setFile(toNativeFileActivation(activation.getFile()));
462     result.setProperty(toNativePropertyActivation(activation.getProperty()));
463     return result;
464   }
465
466   private static ActivationOS toNativeOsActivation(MavenProfileActivationOS os) {
467     if (os == null) return null;
468     ActivationOS result = new ActivationOS();
469     result.setArch(os.getArch());
470     result.setFamily(os.getFamily());
471     result.setName(os.getName());
472     result.setVersion(os.getVersion());
473     return result;
474   }
475
476   private static ActivationFile toNativeFileActivation(MavenProfileActivationFile file) {
477     if (file == null) return null;
478     ActivationFile result = new ActivationFile();
479     result.setExists(file.getExists());
480     result.setMissing(file.getMissing());
481     return result;
482   }
483
484   private static ActivationProperty toNativePropertyActivation(MavenProfileActivationProperty property) {
485     if (property == null) return null;
486     ActivationProperty result = new ActivationProperty();
487     result.setName(property.getName());
488     result.setValue(property.getValue());
489     return result;
490   }
491
492   private static void toNativeModelBase(MavenModelBase from, ModelBase to) {
493     to.setModules(from.getModules());
494     to.setProperties(from.getProperties());
495   }
496
497   private static void toNativeBuildBase(MavenBuildBase from, BuildBase to) {
498     to.setFinalName(from.getFinalName());
499     to.setDefaultGoal(from.getDefaultGoal());
500     to.setDirectory(from.getDirectory());
501     to.setFilters(from.getFilters());
502     to.setResources(toNativeResources(from.getResources()));
503     to.setTestResources(toNativeResources(from.getTestResources()));
504   }
505
506   private static List<Resource> toNativeResources(List<MavenResource> resources) {
507     List<Resource> result = new ArrayList<Resource>(resources.size());
508     for (MavenResource each : resources) {
509       Resource r = new Resource();
510       r.setDirectory(each.getDirectory());
511       r.setTargetPath(each.getTargetPath());
512       r.setFiltering(each.isFiltered());
513       r.setIncludes(each.getIncludes());
514       r.setExcludes(each.getExcludes());
515       result.add(r);
516     }
517     return result;
518   }
519
520   public static Repository toNativeRepository(MavenRemoteRepository r) {
521     Repository result = new Repository();
522     result.setId(r.getId());
523     result.setName(r.getName());
524     result.setUrl(r.getUrl());
525     result.setLayout(r.getLayout() == null ? "default" : r.getLayout());
526
527     if (r.getReleasesPolicy() != null) result.setReleases(toNativePolicy(r.getReleasesPolicy()));
528     if (r.getSnapshotsPolicy() != null) result.setSnapshots(toNativePolicy(r.getSnapshotsPolicy()));
529
530     return result;
531   }
532
533   private static RepositoryPolicy toNativePolicy(MavenRemoteRepository.Policy policy) {
534     RepositoryPolicy result = new RepositoryPolicy();
535     result.setEnabled(policy.isEnabled());
536     result.setUpdatePolicy(policy.getUpdatePolicy());
537     result.setChecksumPolicy(policy.getChecksumPolicy());
538     return result;
539   }
540
541   public static MavenArtifactInfo convertArtifactInfo(ArtifactInfo a) {
542     return new MavenArtifactInfo(a.groupId, a.artifactId, a.version, a.packaging, a.classifier, a.classNames, a.repository);
543   }
544
545   public static MavenArchetype convertArchetype(Archetype archetype) {
546     return new MavenArchetype(archetype.getGroupId(),
547                               archetype.getArtifactId(),
548                               archetype.getVersion(),
549                               archetype.getRepository(),
550                               archetype.getDescription());
551   }
552 }
553