IDEA-97324 Maven support cannot handle skinny wars for EAR deployments

This commit is contained in:
Vladislav.Soroka
2015-08-17 17:18:39 +03:00
parent 2bae715966
commit 3d2373ae28
8 changed files with 173 additions and 15 deletions
@@ -16,26 +16,43 @@
package org.jetbrains.jps.maven.compiler;
import com.intellij.openapi.diagnostic.Logger;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.util.io.FileUtil;
import com.intellij.openapi.util.io.StreamUtil;
import com.intellij.openapi.util.text.StringUtil;
import com.intellij.util.Base64;
import com.intellij.util.Function;
import com.intellij.util.Processor;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import org.jetbrains.jps.builders.BuildRootDescriptor;
import org.jetbrains.jps.builders.artifacts.ArtifactBuildTaskProvider;
import org.jetbrains.jps.builders.storage.BuildDataPaths;
import org.jetbrains.jps.cmdline.ProjectDescriptor;
import org.jetbrains.jps.incremental.BuildTask;
import org.jetbrains.jps.incremental.CompileContext;
import org.jetbrains.jps.incremental.ProjectBuildException;
import org.jetbrains.jps.incremental.artifacts.impl.JpsArtifactUtil;
import org.jetbrains.jps.maven.model.JpsMavenExtensionService;
import org.jetbrains.jps.maven.model.impl.MavenModuleResourceConfiguration;
import org.jetbrains.jps.maven.model.impl.MavenProjectConfiguration;
import org.jetbrains.jps.model.artifact.JpsArtifact;
import org.jetbrains.jps.model.artifact.elements.JpsArtifactRootElement;
import org.jetbrains.jps.model.artifact.elements.JpsFileCopyPackagingElement;
import org.jetbrains.jps.model.artifact.elements.JpsPackagingElement;
import java.io.ByteArrayInputStream;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.util.Collection;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.jar.Attributes;
import java.util.jar.JarFile;
import java.util.jar.Manifest;
/**
* @author nik
@@ -72,6 +89,7 @@ public class MavenManifestGenerationBuildTaskProvider extends ArtifactBuildTaskP
try {
File output = new File(myArtifact.getOutputPath(), JarFile.MANIFEST_NAME);
FileUtil.writeToFile(output, Base64.decode(moduleResourceConfiguration.manifest));
handleSkinnyWars(context, projectConfiguration, moduleResourceConfiguration);
}
// do not fail the whole 'Make' if there is an invalid manifest cached (e.g. non encoded string generated by previous IDEA version)
catch (Exception e) {
@@ -80,6 +98,82 @@ public class MavenManifestGenerationBuildTaskProvider extends ArtifactBuildTaskP
}
}
private void handleSkinnyWars(final CompileContext context,
final MavenProjectConfiguration projectConfiguration,
MavenModuleResourceConfiguration moduleResourceConfiguration) {
if (!"ear".equals(moduleResourceConfiguration.modelMap.get("packaging"))) return;
if (!Boolean.parseBoolean(moduleResourceConfiguration.modelMap.get("build.plugin.maven-ear-plugin.skinnyWars"))) return;
final String earClasspath = moduleResourceConfiguration.classpath;
if (earClasspath == null) return;
final Map<String, String> earClasspathMap = ContainerUtil.map2Map(
StringUtil.split(earClasspath, " "), new Function<String, Pair<String, String>>() {
@Override
public Pair<String, String> fun(String s) {
final int idx = s.lastIndexOf("/");
return Pair.create(s.substring(idx == -1 ? 0 : idx + 1), s);
}
});
JpsArtifactUtil.processPackagingElements(myArtifact.getRootElement(), new Processor<JpsPackagingElement>() {
@Override
public boolean process(JpsPackagingElement element) {
if (!(element instanceof JpsFileCopyPackagingElement)) return true;
final String filePath = ((JpsFileCopyPackagingElement)element).getFilePath();
final File skinnyManifest = new File(filePath);
if (!"SKINNY_MANIFEST.MF".equals(skinnyManifest.getName())) return true;
final String skinnyWarModuleName = skinnyManifest.getParentFile().getParentFile().getName();
final MavenModuleResourceConfiguration warConfiguration = projectConfiguration.moduleConfigurations.get(skinnyWarModuleName);
if (warConfiguration == null || warConfiguration.classpath == null) return true;
try {
final byte[] warManifestData = Base64.decode(warConfiguration.manifest);
Manifest warManifest = new Manifest(new ByteArrayInputStream(warManifestData));
List<String> skinnyWarClasspath = ContainerUtil.newArrayList();
for (String entry : StringUtil.split(warConfiguration.classpath, " ")) {
final int idx = entry.lastIndexOf("/");
final String entryName = entry.substring(idx == -1 ? 0 : idx + 1);
final String earEntryPath = earClasspathMap.get(entryName);
skinnyWarClasspath.add(earEntryPath == null ? entry : earEntryPath);
}
final Attributes warManifestMainAttributes = warManifest.getMainAttributes();
warManifestMainAttributes.putValue("Class-Path", StringUtil.join(skinnyWarClasspath, " "));
FileUtil.createParentDirs(skinnyManifest);
FileOutputStream outputStream = new FileOutputStream(skinnyManifest);
try {
warManifest.write(outputStream);
final ProjectDescriptor projectDescriptor = context.getProjectDescriptor();
final Collection<BuildRootDescriptor> descriptors =
projectDescriptor.getBuildRootIndex().findAllParentDescriptors(skinnyManifest, context);
for (BuildRootDescriptor descriptor : descriptors) {
try {
projectDescriptor.fsState.markDirty(context, skinnyManifest, descriptor, projectDescriptor.timestamps.getStorage());
}
catch (IOException e) {
LOG.debug(e);
}
}
}
finally {
StreamUtil.closeStream(outputStream);
}
}
catch (IOException e) {
LOG.debug(e);
}
return true;
}
});
}
@Nullable
private static String getModuleName(@NotNull String artifactName) {
return StringUtil.substringBefore(artifactName, ":");
@@ -45,6 +45,10 @@ public class MavenModuleResourceConfiguration {
@Tag("manifest")
public String manifest;
@Nullable
@Tag("classpath")
public String classpath;
@NotNull
@Tag("delimiters-pattern")
public String delimitersPattern;
@@ -110,6 +114,7 @@ public class MavenModuleResourceConfiguration {
result = 31 * result + (parentId != null ? parentId.hashCode() : 0);
result = 31 * result + directory.hashCode();
result = 31 * result + (manifest != null ? manifest.hashCode() : 0);
result = 31 * result + (classpath != null ? classpath.hashCode() : 0);
result = 31 * result + delimitersPattern.hashCode();
result = 31 * result + modelMap.hashCode();
result = 31 * result + properties.hashCode();
@@ -50,7 +50,7 @@ public abstract class ManifestImporter {
String classpathPrefix = getClasspathPrefix(manifestConfiguration);
for (MavenArtifact mavenArtifact : mavenProject.getDependencies()) {
final DependencyScope scope = MavenModuleImporter.selectScope(mavenArtifact.getScope());
if (scope.isForProductionRuntime()) {
if (scope.isForProductionCompile() || scope.isForProductionRuntime()) {
if (classpath.length() > 0) {
classpath.append(" ");
}
@@ -149,6 +149,12 @@ public abstract class MavenImporter {
Map<MavenProject, String> mavenProjectToModuleName,
List<MavenProjectsProcessorTask> postTasks);
public void postProcess(Module module,
MavenProject mavenProject,
MavenProjectChanges changes,
MavenModifiableModelsProvider modifiableModelsProvider) {
}
public boolean processChangedModulesOnly() {
return true;
}
@@ -159,6 +159,31 @@ public class MavenModuleImporter {
});
}
public void postConfigFacets() {
MavenUtil.invokeAndWaitWriteAction(myModule.getProject(), new Runnable() {
public void run() {
if (myModule.isDisposed()) return;
final ModuleType moduleType = ModuleType.get(myModule);
for (final MavenImporter importer : getSuitableImporters()) {
final MavenProjectChanges changes;
if (myMavenProjectChanges == null) {
if (importer.processChangedModulesOnly()) continue;
changes = MavenProjectChanges.NONE;
}
else {
changes = myMavenProjectChanges;
}
if (importer.getModuleType() == moduleType) {
importer.postProcess(myModule, myMavenProject, changes, myModifiableModelsProvider);
}
}
}
});
}
private List<MavenImporter> getSuitableImporters() {
return myMavenProject.getSuitableImporters();
}
@@ -431,7 +431,7 @@ public class MavenProjectImporter {
javacOptions.ADDITIONAL_OPTIONS_STRING = options;
}
private void importModules(final List<MavenProjectsProcessorTask> postTasks) {
private void importModules(final List<MavenProjectsProcessorTask> tasks) {
Map<MavenProject, MavenProjectChanges> projectsWithChanges = myProjectsToImportWithChanges;
Set<MavenProject> projectsWithNewlyCreatedModules = new THashSet<MavenProject>();
@@ -471,7 +471,11 @@ public class MavenProjectImporter {
}
for (MavenModuleImporter importer : importers) {
importer.configFacets(postTasks);
importer.configFacets(tasks);
}
for (MavenModuleImporter importer : importers) {
importer.postConfigFacets();
}
setMavenizedModules(modulesToMavenize, true);
@@ -129,6 +129,8 @@ public class MavenResourceCompilerConfigurationGenerator {
}
}
addEarModelMapEntries(mavenProject, resourceConfig.modelMap);
Element pluginConfiguration = mavenProject.getPluginConfiguration("org.apache.maven.plugins", "maven-resources-plugin");
resourceConfig.outputDirectory = getResourcesPluginGoalOutputDirectory(mavenProject, pluginConfiguration, "resources");
@@ -190,6 +192,12 @@ public class MavenResourceCompilerConfigurationGenerator {
});
}
private static void addEarModelMapEntries(@NotNull MavenProject mavenProject, @NotNull Map<String, String> modelMap) {
Element pluginConfiguration = mavenProject.getPluginConfiguration("org.apache.maven.plugins", "maven-ear-plugin");
final String skinnyWars = MavenJDOMUtil.findChildValueByPath(pluginConfiguration, "skinnyWars", "false");
modelMap.put("build.plugin.maven-ear-plugin.skinnyWars", skinnyWars);
}
@Nullable
private static String getResourcesPluginGoalOutputDirectory(@NotNull MavenProject mavenProject,
@Nullable Element pluginConfiguration,
@@ -234,6 +242,7 @@ public class MavenResourceCompilerConfigurationGenerator {
finally {
StreamUtil.closeStream(outputStream);
}
resourceConfig.classpath = ManifestBuilder.getClasspath(mavenProject);
}
catch (ManifestBuilder.ManifestBuilderException e) {
LOG.warn("Unable to generate artifact manifest", e);
@@ -67,18 +67,7 @@ public class ManifestBuilder {
@NotNull
public java.util.jar.Manifest build() throws ManifestBuilderException {
try {
Element mavenPackagingPluginConfiguration = null;
final String packaging = myMavenProject.getPackaging();
if (StringUtil.isEmpty(packaging)) {
mavenPackagingPluginConfiguration = myMavenProject.getPluginConfiguration("org.apache.maven.plugins", "maven-jar-plugin");
}
else {
final String pluginArtifactId = PACKAGING_PLUGINS.get(StringUtil.toLowerCase(packaging));
if (pluginArtifactId != null) {
mavenPackagingPluginConfiguration = myMavenProject.getPluginConfiguration("org.apache.maven.plugins", pluginArtifactId);
}
}
Element mavenPackagingPluginConfiguration = getMavenPackagingPluginConfiguration(myMavenProject);
final Element mavenArchiveConfiguration =
mavenPackagingPluginConfiguration != null ? mavenPackagingPluginConfiguration.getChild("archive") : null;
@@ -110,6 +99,16 @@ public class ManifestBuilder {
}
}
@NotNull
public static String getClasspath(@NotNull MavenProject mavenProject) {
Element mavenPackagingPluginConfiguration = getMavenPackagingPluginConfiguration(mavenProject);
final Element mavenArchiveConfiguration =
mavenPackagingPluginConfiguration != null ? mavenPackagingPluginConfiguration.getChild("archive") : null;
final Element manifestConfiguration = mavenArchiveConfiguration != null ? mavenArchiveConfiguration.getChild("manifest") : null;
final ManifestImporter manifestImporter = ManifestImporter.getManifestImporter(mavenProject.getPackaging());
return manifestImporter.getClasspath(mavenProject, manifestConfiguration);
}
@NotNull
public static String getClasspathPrefix(@Nullable Element manifestConfiguration) {
String classpathPrefix = MavenJDOMUtil.findChildValueByPath(manifestConfiguration, "classpathPrefix", "").replaceAll("\\\\", "/");
@@ -119,6 +118,22 @@ public class ManifestBuilder {
return classpathPrefix;
}
@Nullable
private static Element getMavenPackagingPluginConfiguration(@NotNull MavenProject mavenProject) {
Element mavenPackagingPluginConfiguration = null;
final String packaging = mavenProject.getPackaging();
if (StringUtil.isEmpty(packaging)) {
mavenPackagingPluginConfiguration = mavenProject.getPluginConfiguration("org.apache.maven.plugins", "maven-jar-plugin");
}
else {
final String pluginArtifactId = PACKAGING_PLUGINS.get(StringUtil.toLowerCase(packaging));
if (pluginArtifactId != null) {
mavenPackagingPluginConfiguration = mavenProject.getPluginConfiguration("org.apache.maven.plugins", pluginArtifactId);
}
}
return mavenPackagingPluginConfiguration;
}
private static Map<String, String> getManifestEntries(Element manifestEntries) {
boolean hasManifestEntries = manifestEntries != null && manifestEntries.getContentSize() > 0;