/*
* Copyright 2011 - Alistair Rutherford - www.netthreads.co.uk
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package com.netthreads.mavenize.pom;
import com.netthreads.mavenize.model.ProjectFiles;
import java.io.File;
import java.io.IOException;
import java.io.Writer;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;
import org.apache.maven.model.Model;
import org.apache.maven.model.io.xpp3.MavenXpp3Writer;
import org.codehaus.plexus.util.IOUtil;
import org.codehaus.plexus.util.WriterFactory;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* I have borrowed heavily from the Maven And Task.
*
* @author Alistair
*/
public class DefaultPomGenerator implements PomGenerator
{
private static Logger logger = LoggerFactory.getLogger(DefaultPomGenerator.class);
public static final String TEXT_UNKNOWN = "unknown";
/**
* Generate default pom info.
*
/**
* Generate pom from project files.
*
* @param projectFiles
* @param version The version number to assign in the generated pom.
* @param packaging The "packaging" type to assign in the pom.
*/
@Override
public Model generate(ProjectFiles projectFiles, String version, String packaging)
{
// Lets create a simple pom to match the project
Model model = new Model();
model.setModelVersion(DEFAULT_MODEL_VERSION);
model.setVersion(version);
// Packaging name doesn't like upper case letters.
model.setPackaging(packaging.toLowerCase());
populate(projectFiles, model);
writePom(model, projectFiles);
return model;
}
/**
* Populate model.
*
* @param projectFiles
*/
@Override
public void populate(ProjectFiles projectFiles, Model model)
{
trimModel(model);
String groupId = findGroupId(projectFiles);
String artifactId = findArtifactId(projectFiles);
model.setGroupId(groupId);
model.setArtifactId(artifactId);
Properties properties = new Properties();
properties.put("project.build.sourceEncoding", "UTF-8");
model.setProperties(properties);
}
/**
* Write pom to target "src" directory.
*
* @param model
* @param projectFiles
*/
public void writePom(Model model, ProjectFiles projectFiles)
{
String path = projectFiles.getTargetSrc().getParent();
MavenXpp3Writer mavenXpp3Writer = new MavenXpp3Writer();
Writer fileWriter = null;
try
{
File file = new File(path + "/" + POM_NAME);
fileWriter = WriterFactory.newXmlWriter(file);
mavenXpp3Writer.write(fileWriter, model);
}
catch (IOException e)
{
logger.error(e.getMessage());
}
finally
{
IOUtil.close(fileWriter);
}
}
/**
* Generate group id.
*
* This uses the "longest common substring" algorithm to attempt to extract a decent
* package group identifier. The most common string is found then we will attempt to make
* it into a nicer name by shortening it a little.
*
* @param projectFiles
*
* @return The group id.
*/
public String findGroupId(ProjectFiles projectFiles)
{
String groupId = "";
Map<String, Integer> counts = new HashMap<String, Integer>();
List<File> files = projectFiles.getFiles();
int size = files.size();
if (size > 1)
{
int indexA = 0;
int indexB = 1;
while (indexB < size)
{
File fileA = files.get(indexA);
File fileB = files.get(indexB);
String partialA = fileA.getAbsolutePath().substring(projectFiles.getSourceSrc().getAbsolutePath().length());
String partialB = fileB.getAbsolutePath().substring(projectFiles.getSourceSrc().getAbsolutePath().length());
int index = StringHelper.longestSubstr(partialA, partialB);
if (index > 0)
{
String common = partialA.substring(0, index);
logger.debug("common = " + common);
Integer count = counts.get(common);
if (count != null)
{
count++;
counts.put(common, count);
}
else
{
counts.put(common, 1);
}
}
indexA++;
indexB++;
}
if (counts.size() > 0)
{
String target = findMostCommon(counts);
groupId = target.replace('\\', '.').replace('/', '.');
// At this point we mught have something like ".org.gephi.data.attributes.type."
// Lets try and chop it down a bit further and tidy it up
if (groupId.charAt(0) == '.')
{
groupId = groupId.substring(1);
}
if (groupId.charAt(groupId.length() - 1) == '.')
{
groupId = groupId.substring(0, groupId.length() - 1);
}
// Attempt to chop the string up to the stated number of dots.
groupId = StringHelper.chopFromLeft(groupId, '.', 3);
}
else
{
groupId = TEXT_UNKNOWN;
}
}
else
{
groupId = TEXT_UNKNOWN;
}
// Lets's sift through our files for common package name.
return groupId;
}
/**
* Look through the string collected and find the one with the highest number
* of occurrences.
*
* @param counts
*
* @return String from test with highest number of occurrences.
*/
private String findMostCommon(Map<String, Integer> counts)
{
// Find common string with highest count.
Set<String> keys = counts.keySet();
int highest = 0;
String target = "";
for (String key : keys)
{
Integer count = counts.get(key);
if (count > highest)
{
highest = count;
target = key;
}
}
return target;
}
/**
* Generate the artifact id.
*
* @param projectFiles
*
* @return The artifact id.
*/
public String findArtifactId(ProjectFiles projectFiles)
{
String artifactId = "";
// We'll got for a lower case version of our project name.
artifactId = new File(projectFiles.getSourceSrc().getParent()).getName().toLowerCase();
return artifactId;
}
/**
* Removes a lot of unnecessary information from the POM.
* This includes the build section, reporting, repositories, etc.
*/
public void trimModel(Model model)
{
model.setBuild(null);
model.setReporting(null);
model.setProperties(null);
model.setRepositories(null);
model.setPluginRepositories(null);
model.setProfiles(null);
model.setDistributionManagement(null);
model.setModules(null);
}
}