/*******************************************************************************
* Copyright (c) 2012-2017 Codenvy, S.A.
* 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:
* Codenvy, S.A. - initial API and implementation
*******************************************************************************/
package org.eclipse.che.plugin.maven.server.core.project;
import org.eclipse.che.commons.lang.Pair;
import org.eclipse.che.commons.xml.XMLTreeException;
import org.eclipse.che.ide.maven.tools.Activation;
import org.eclipse.che.ide.maven.tools.ActivationFile;
import org.eclipse.che.ide.maven.tools.ActivationOS;
import org.eclipse.che.ide.maven.tools.ActivationProperty;
import org.eclipse.che.ide.maven.tools.Build;
import org.eclipse.che.ide.maven.tools.Dependency;
import org.eclipse.che.ide.maven.tools.Model;
import org.eclipse.che.ide.maven.tools.Parent;
import org.eclipse.che.ide.maven.tools.Plugin;
import org.eclipse.che.ide.maven.tools.Profile;
import org.eclipse.che.ide.maven.tools.Resource;
import org.eclipse.che.maven.data.MavenActivation;
import org.eclipse.che.maven.data.MavenActivationFile;
import org.eclipse.che.maven.data.MavenActivationOS;
import org.eclipse.che.maven.data.MavenActivationProperty;
import org.eclipse.che.maven.data.MavenArtifact;
import org.eclipse.che.maven.data.MavenBuild;
import org.eclipse.che.maven.data.MavenExplicitProfiles;
import org.eclipse.che.maven.data.MavenKey;
import org.eclipse.che.maven.data.MavenModel;
import org.eclipse.che.maven.data.MavenParent;
import org.eclipse.che.maven.data.MavenPlugin;
import org.eclipse.che.maven.data.MavenProblemType;
import org.eclipse.che.maven.data.MavenProfile;
import org.eclipse.che.maven.data.MavenProjectProblem;
import org.eclipse.che.maven.data.MavenResource;
import org.eclipse.che.maven.server.MavenProjectInfo;
import org.eclipse.che.maven.server.MavenServerResult;
import org.eclipse.che.maven.server.ProfileApplicationResult;
import org.eclipse.che.plugin.maven.server.MavenServerManager;
import org.eclipse.che.plugin.maven.server.MavenServerWrapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import java.util.stream.Collectors;
import static com.google.common.base.Strings.isNullOrEmpty;
import static java.lang.Boolean.parseBoolean;
import static java.util.Collections.emptyList;
import static java.util.Collections.singletonList;
import static org.eclipse.che.plugin.maven.shared.MavenAttributes.DEFAULT_RESOURCES_FOLDER;
import static org.eclipse.che.plugin.maven.shared.MavenAttributes.DEFAULT_SOURCE_FOLDER;
import static org.eclipse.che.plugin.maven.shared.MavenAttributes.DEFAULT_TEST_RESOURCES_FOLDER;
import static org.eclipse.che.plugin.maven.shared.MavenAttributes.DEFAULT_TEST_SOURCE_FOLDER;
/**
* @author Evgen Vidolob
*/
public class MavenModelReader {
private static final Logger LOG = LoggerFactory.getLogger(MavenModelReader.class);
public MavenModelReaderResult resolveMavenProject(File pom, MavenServerWrapper mavenServer, List<String> activeProfiles,
List<String> inactiveProfiles, MavenServerManager serverManager) {
try {
MavenServerResult resolveProject = mavenServer.resolveProject(pom, activeProfiles, inactiveProfiles);
MavenProjectInfo projectInfo = resolveProject.getProjectInfo();
if (projectInfo != null) {
return new MavenModelReaderResult(projectInfo.getMavenModel(),
projectInfo.getActiveProfiles(),
emptyList(),
resolveProject.getProblems(),
resolveProject.getUnresolvedArtifacts());
} else {
MavenModelReaderResult readMavenProject = readMavenProject(pom, serverManager);
readMavenProject.getProblems().addAll(resolveProject.getProblems());
readMavenProject.getUnresolvedArtifacts().addAll(resolveProject.getUnresolvedArtifacts());
return readMavenProject;
}
} catch (Throwable t) {
String message = t.getMessage();
LOG.info(message, t);
MavenModelReaderResult readMavenProject = readMavenProject(pom, serverManager);
if (message != null) {
readMavenProject.getProblems().add(MavenProjectProblem.newStructureProblem(pom.getPath(), message));
} else {
readMavenProject.getProblems().add(MavenProjectProblem.newSyntaxProblem(pom.getPath(), MavenProblemType.SYNTAX));
}
return readMavenProject;
}
}
public MavenModelReaderResult readMavenProject(File pom, MavenServerManager serverManager) {
Pair<ModelReadingResult, Pair<List<String>, List<String>>> readResult = readModel(pom, serverManager);
MavenModel model = readResult.first.model;
model = serverManager.interpolateModel(model, pom.getParentFile());
Pair<List<String>, List<String>> profilesPair = readResult.second;
return new MavenModelReaderResult(model,
profilesPair.first,
profilesPair.second,
readResult.first.problems,
Collections.emptySet());
}
private Pair<ModelReadingResult, Pair<List<String>, List<String>>> readModel(File pom, MavenServerManager serverManager) {
ModelReadingResult readingResult = doRead(pom);
//TODO resolve parent pom
ProfileApplicationResult applied = serverManager.applyProfiles(readingResult.model,
pom.getParentFile(),
MavenExplicitProfiles.NONE,
emptyList());
final MavenModel model = applied.getModel();
updateModelBody(model);
final MavenExplicitProfiles activatedProfiles = applied.getActivatedProfiles();
final ArrayList<String> disabledProfiles = new ArrayList<>(activatedProfiles.getDisabledProfiles().size());
disabledProfiles.addAll(activatedProfiles.getDisabledProfiles());
final ArrayList<String> enableProfiles = new ArrayList<>(activatedProfiles.getEnabledProfiles().size());
enableProfiles.addAll(activatedProfiles.getEnabledProfiles());
return Pair.of(new ModelReadingResult(model, readingResult.problems, readingResult.enabledProfiles),
Pair.of(enableProfiles, disabledProfiles));
}
private ModelReadingResult doRead(File pom) {
List<MavenProjectProblem> problems = new ArrayList<>();
Set<String> enabledProfiles = new HashSet<>();
MavenModel result = new MavenModel();
fillModelByDefaults(result);
Model model = null;
try {
model = Model.readFrom(pom);
} catch (IOException e) {
problems.add(MavenProjectProblem.newProblem(pom.getPath(), e.getMessage(), MavenProblemType.SYNTAX));
} catch (XMLTreeException xmlExc) {
problems.add(MavenProjectProblem.newProblem(pom.getPath(), xmlExc.getMessage(), MavenProblemType.STRUCTURE));
}
if (model == null) {
return new ModelReadingResult(result, problems, enabledProfiles);
}
final MavenKey parentKey;
if (model.getParent() == null) {
parentKey = result.getParent().getMavenKey();
} else {
Parent modelParent = model.getParent();
parentKey = new MavenKey(modelParent.getGroupId(), modelParent.getArtifactId(), modelParent.getVersion());
MavenParent parent = new MavenParent(parentKey, modelParent.getRelativePath());
result.setParent(parent);
}
final MavenKey mavenKey = new MavenKey(getNotNull(model.getGroupId(), parentKey.getGroupId()),
model.getArtifactId(),
getNotNull(model.getVersion(), parentKey.getVersion()));
result.setMavenKey(mavenKey);
if (model.getPackaging() != null) {
result.setPackaging(model.getPackaging());
}
result.setName(model.getName());
final List<String> modules = model.getModules();
if (modules != null) {
result.setModules(new ArrayList<>(model.getModules()));
}
Map<String, String> properties = model.getProperties();
Properties prop = new Properties();
if (properties != null) {
prop.putAll(properties);
}
result.setProperties(prop);
final Build build = model.getBuild();
if (build != null) {
final String sourceDirectory = build.getSourceDirectory();
if (sourceDirectory != null) {
result.getBuild().setSources(singletonList(sourceDirectory));
}
final String testSourceDirectory = build.getTestSourceDirectory();
if (testSourceDirectory != null) {
result.getBuild().setTestSources(singletonList(testSourceDirectory));
}
result.getBuild().setResources(convertResources(build.getResources()));
}
List<Profile> profiles = model.getProfiles();
if (profiles != null && !profiles.isEmpty()) {
List<MavenProfile> resultProfiles = new ArrayList<>(profiles.size());
for (Profile profile : profiles) {
enabledProfiles.add(profile.getId());
MavenProfile resultProfile = new MavenProfile(profile.getId(), Profile.SOURCE_POM);
setProfileActivation(resultProfile, profile);
setProfileProperties(resultProfile, profile);
setProfileModules(resultProfile, profile);
setProfileBuild(resultProfile, profile);
setProfileDependencies(resultProfile, profile);
resultProfiles.add(resultProfile);
}
result.setProfiles(resultProfiles);
}
return new ModelReadingResult(result, problems, enabledProfiles);
}
private void setProfileProperties(MavenProfile resultProfile, Profile profile) {
Properties resultProperties = new Properties();
resultProperties.putAll(profile.getProperties());
resultProfile.setProperties(resultProperties);
}
private void updateModelBody(MavenModel model) {
MavenBuild build = model.getBuild();
if (build == null) {
return;
}
if (isNullOrEmpty(build.getFinalName())) {
build.setFinalName("${project.artifactId}-${project.version}");
}
if (build.getSources().isEmpty()) {
build.setSources(singletonList("src/main/java"));
}
if (build.getTestSources().isEmpty()) {
build.setTestSources(singletonList("src/test/java"));
}
build.setResources(updateResources(build.getResources(), "src/main/resources"));
build.setTestResources(updateResources(build.getTestResources(), "src/test/resources"));
build.setDirectory(isNullOrEmpty(build.getDirectory()) ? "target" : build.getDirectory());
build.setOutputDirectory(isNullOrEmpty(build.getOutputDirectory()) ? "${project.build.directory}/classes"
: build.getOutputDirectory());
build.setTestOutputDirectory(isNullOrEmpty(build.getTestOutputDirectory()) ? "${project.build.directory}/test-classes"
: build.getTestOutputDirectory());
}
private List<MavenResource> updateResources(List<MavenResource> resources, String defaultDir) {
List<MavenResource> result = new ArrayList<>();
if (resources.isEmpty()) {
result.add(createResource(defaultDir));
return result;
}
for (MavenResource each : resources) {
if (isNullOrEmpty(each.getDirectory())) continue;
result.add(each);
}
return result;
}
private MavenResource createResource(String directory) {
return new MavenResource(directory, false, null, emptyList(), emptyList());
}
private void setProfileDependencies(MavenProfile resultProfile, Profile profile) {
final List<Dependency> dependencies = profile.getDependencies();
final List<MavenArtifact> mavenArtifacts = dependencies.stream()
.map(dependency -> new MavenArtifact(dependency.getGroupId(),
dependency.getArtifactId(),
dependency.getVersion(),
dependency.getVersion(),
dependency.getType(),
dependency.getClassifier(),
dependency.getScope(),
dependency.isOptional(),
dependency.getType(),
null,
null,
false,
false
)).collect(Collectors.toList());
resultProfile.setDependencies(mavenArtifacts);
}
private void setProfileActivation(MavenProfile resultProfile, Profile profile) {
final Activation activation = profile.getActivation();
if (activation != null) {
resultProfile.setActivation(convertActivation(activation));
}
}
private void setProfileBuild(MavenProfile resultProfile, Profile profile) {
final Build build = profile.getBuild();
if (build == null) {
return;
}
final List<Plugin> plugins = build.getPlugins();
if (plugins != null && !plugins.isEmpty()) {
List<MavenPlugin> mavenPlugins = new ArrayList<>(plugins.size());
for (Plugin plugin : plugins) {
mavenPlugins.add(new MavenPlugin(plugin.getGroupId(),
plugin.getArtifactId(),
plugin.getVersion(),
false,
null, emptyList(), emptyList()));
}
resultProfile.setPlugins(mavenPlugins);
resultProfile.getBuild().setFinalName(build.getFinalName());
resultProfile.getBuild().setDefaultGoal(build.getDefaultGoal());
resultProfile.getBuild().setOutputDirectory(build.getOutputDirectory());
resultProfile.getBuild().setTestOutputDirectory(build.getTestOutputDirectory());
resultProfile.getBuild().setTestOutputDirectory(build.getTestOutputDirectory());
}
}
private void setProfileModules(MavenProfile resultProfile, Profile profile) {
final List<String> profileModules = profile.getModules();
if (profileModules != null) {
resultProfile.setModules(profileModules);
}
}
private void fillModelByDefaults(MavenModel model) {
model.setMavenKey(new MavenKey("unknown", "unknown", "unknown"));
final MavenKey parentKey = new MavenKey("unknown", "unknown", "unknown");
model.setParent(new MavenParent(parentKey, "../pom.xml"));
model.setPackaging("jar");
model.setModules(emptyList());
final MavenBuild build = model.getBuild();
build.setSources(singletonList(DEFAULT_SOURCE_FOLDER));
build.setTestSources(singletonList(DEFAULT_TEST_SOURCE_FOLDER));
build.setResources(singletonList(new MavenResource(DEFAULT_RESOURCES_FOLDER,
false,
null,
emptyList(),
emptyList())));
build.setTestResources(singletonList(new MavenResource(DEFAULT_TEST_RESOURCES_FOLDER,
false,
null,
emptyList(),
emptyList())));
}
private String getNotNull(String value, String defaultValue) {
return value == null ? defaultValue : value;
}
private List<MavenResource> convertResources(List<Resource> resources) {
return resources.stream()
.map(resource -> new MavenResource(resource.getDirectory(),
resource.isFiltering(),
resource.getTargetPath(),
resource.getIncludes(),
resource.getExcludes()))
.collect(Collectors.toList());
}
private MavenActivation convertActivation(Activation activation) {
MavenActivation mavenActivation = new MavenActivation();
final ActivationOS activationOs = activation.getOs();
final ActivationFile activationFile = activation.getFile();
final ActivationProperty activationProperty = activation.getProperty();
if (activationOs != null) {
mavenActivation.setOs(new MavenActivationOS(activationOs.getName(),
activationOs.getFamily(),
activationOs.getArch(),
activationOs.getVersion()));
}
if (activationFile != null) {
mavenActivation.setFile(new MavenActivationFile(activationFile.getExist(), activationFile.getMissing()));
}
if (activationProperty != null) {
mavenActivation.setProperty(new MavenActivationProperty(activationProperty.getName(), activationProperty.getValue()));
}
mavenActivation.setJdk(activation.getJdk());
mavenActivation.setActiveByDefault(parseBoolean(activation.isActiveByDefault()));
return mavenActivation;
}
private static class ModelReadingResult {
MavenModel model;
List<MavenProjectProblem> problems;
Set<String> enabledProfiles;
public ModelReadingResult(MavenModel model, List<MavenProjectProblem> problems, Set<String> enabledProfiles) {
this.model = model;
this.problems = problems;
this.enabledProfiles = enabledProfiles;
}
}
}