View Javadoc
1   /*
2    * #%L
3    * wcm.io
4    * %%
5    * Copyright (C) 2018 wcm.io
6    * %%
7    * Licensed under the Apache License, Version 2.0 (the "License");
8    * you may not use this file except in compliance with the License.
9    * You may obtain a copy of the License at
10   *
11   *      http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing, software
14   * distributed under the License is distributed on an "AS IS" BASIS,
15   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   * See the License for the specific language governing permissions and
17   * limitations under the License.
18   * #L%
19   */
20  package io.wcm.devops.conga.tooling.maven.plugin;
21  
22  import java.io.IOException;
23  import java.util.ArrayList;
24  import java.util.Collection;
25  import java.util.Enumeration;
26  import java.util.List;
27  import java.util.TreeSet;
28  import java.util.function.Function;
29  import java.util.stream.Collectors;
30  import java.util.zip.ZipEntry;
31  import java.util.zip.ZipFile;
32  
33  import org.apache.commons.lang3.StringUtils;
34  import org.apache.maven.model.Dependency;
35  import org.eclipse.aether.artifact.Artifact;
36  
37  import io.wcm.devops.conga.generator.GeneratorException;
38  import io.wcm.devops.conga.generator.GeneratorOptions;
39  import io.wcm.devops.conga.generator.spi.context.PluginContextOptions;
40  import io.wcm.devops.conga.generator.util.FileUtil;
41  import io.wcm.devops.conga.model.environment.Environment;
42  import io.wcm.devops.conga.tooling.maven.plugin.util.MavenArtifactHelper;
43  import io.wcm.devops.conga.tooling.maven.plugin.util.MavenContext;
44  import io.wcm.devops.conga.tooling.maven.plugin.util.VersionInfoUtil;
45  
46  class DependencyVersionBuilder implements Function<Environment, Collection<String>> {
47  
48    private final MavenContext mavenContext;
49    private final PluginContextOptions pluginContextOptions;
50  
51    DependencyVersionBuilder(PluginContextOptions pluginContextOptions) {
52      this.mavenContext = (MavenContext)pluginContextOptions.getContainerContext();
53      this.pluginContextOptions = pluginContextOptions;
54    }
55  
56    @Override
57    public Collection<String> apply(Environment environment) {
58      MavenArtifactHelper mavenArtifactHelper = new MavenArtifactHelper(environment, pluginContextOptions);
59  
60      try {
61        List<Artifact> dependencyArtifacts = new ArrayList<>();
62        dependencyArtifacts.addAll(getCompileDependencyArtifacts(mavenArtifactHelper));
63        dependencyArtifacts.addAll(getEnvironmentDependencyArtifacts(environment, mavenArtifactHelper));
64  
65        return new TreeSet<>(
66            dependencyArtifacts.stream()
67                // include only dependencies with a CONGA-INF/ directory
68                .filter(this::hasCongaDefinitions)
69                // transform to string
70                .map(this::toArtifactCoordsPaxUrlStyle)
71                .collect(Collectors.toSet()));
72      }
73      catch (IOException ex) {
74        throw new GeneratorException(ex.getMessage(), ex);
75      }
76    }
77  
78    @SuppressWarnings("deprecation")
79    private List<Artifact> getCompileDependencyArtifacts(MavenArtifactHelper mavenArtifactHelper) throws IOException {
80      List<Artifact> artifacts = new ArrayList<>();
81      for (Dependency dependency : mavenContext.getProject().getCompileDependencies()) {
82        artifacts.add(mavenArtifactHelper.resolveArtifact(
83            dependency.getGroupId(),
84            dependency.getArtifactId(),
85            dependency.getType(),
86            dependency.getClassifier(),
87            dependency.getVersion()));
88      }
89      return artifacts;
90    }
91  
92    private List<Artifact> getEnvironmentDependencyArtifacts(Environment environment, MavenArtifactHelper mavenArtifactHelper) throws IOException {
93      return mavenArtifactHelper.dependencyUrlsToArtifactsWithTransitiveDependencies(environment.getDependencies());
94    }
95  
96    /**
97     * Checks if the JAR file of the given dependency has a CONGA-INF/ directory.
98     * @param artifact Dependency
99     * @return true if configuration definitions found
100    */
101   private boolean hasCongaDefinitions(Artifact artifact) {
102     if (!StringUtils.equalsAny(artifact.getExtension(), "jar")) {
103       return false;
104     }
105     String fileInfo = artifact.toString();
106     try {
107       fileInfo = FileUtil.getCanonicalPath(artifact.getFile());
108       try (ZipFile zipFile = new ZipFile(artifact.getFile())) {
109         Enumeration<? extends ZipEntry> entries = zipFile.entries();
110         while (entries.hasMoreElements()) {
111           ZipEntry entry = entries.nextElement();
112           if (StringUtils.startsWith(entry.getName(), GeneratorOptions.CLASSPATH_PREFIX)) {
113             return true;
114           }
115         }
116       }
117     }
118     catch (IOException ex) {
119       throw new GeneratorException("Unable to read from JAR file: " + fileInfo, ex);
120     }
121     return false;
122   }
123 
124   /**
125    * Build artifact coords string.
126    * @param artifact Artifact
127    * @return Artifact coords
128    */
129   private String toArtifactCoordsPaxUrlStyle(Artifact artifact) {
130     return artifact.getGroupId() + "/" + artifact.getArtifactId()
131         + "/" + VersionInfoUtil.cleanupSnapshotVersion(artifact.getVersion())
132         + (StringUtils.isNotEmpty(artifact.getClassifier()) ? "/" + artifact.getExtension() + "/" + artifact.getClassifier() : "");
133   }
134 
135 }