package org.jboss.windup.rules.apps.mavenize;
import java.util.HashMap;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.logging.Logger;
import org.apache.commons.lang3.StringUtils;
import org.jboss.windup.graph.GraphContext;
import org.jboss.windup.graph.frames.TypeAwareFramedGraphQuery;
import org.jboss.windup.graph.model.ProjectModel;
import org.jboss.windup.graph.model.WindupVertexFrame;
import org.jboss.windup.rules.apps.java.config.ScanPackagesOption;
import org.jboss.windup.rules.apps.java.model.JavaClassFileModel;
import org.jboss.windup.rules.apps.java.model.project.MavenProjectModel;
import org.jboss.windup.util.Logging;
import com.thinkaurelius.titan.core.attribute.Text;
import com.tinkerpop.blueprints.Vertex;
import com.tinkerpop.gremlin.java.GremlinPipeline;
import com.tinkerpop.pipes.PipeFunction;
import com.tinkerpop.pipes.branch.CopySplitPipe;
import com.tinkerpop.pipes.filter.PropertyFilterPipe;
import com.tinkerpop.pipes.sideeffect.AggregatePipe;
import com.tinkerpop.pipes.sideeffect.GroupCountPipe;
import com.tinkerpop.pipes.transform.OutPipe;
import com.tinkerpop.pipes.transform.PropertyPipe;
/**
* Contains methods for assistance in analyzing modules
*
* @author <a href="http://ondra.zizka.cz/">Ondrej Zizka, ozizka at seznam.cz</a>
*/
public class ModuleAnalysisHelper
{
public static final String LAST_RESORT_DEFAULT_GROUP_ID = "com.mycompany.mavenized";
private static final Logger LOG = Logging.get(ModuleAnalysisHelper.class);
protected GraphContext graphContext;
public ModuleAnalysisHelper(GraphContext context)
{
this.graphContext = context;
}
String deriveGroupId(ProjectModel projectModel)
{
if (projectModel instanceof MavenProjectModel)
{
MavenProjectModel mavenProject = (MavenProjectModel) projectModel;
mavenProject.getGroupId();
}
// User can set this via --mavenizeGroupId.
{
String groupId = (String) graphContext.getOptionMap().get(MavenizeGroupIdOption.NAME);
if (groupId != null)
{
if (groupId.matches(MavenizeGroupIdOption.REGEX_GROUP_ID))
return groupId;
LOG.severe(MavenizeGroupIdOption.NAME + " doesn't match the groupId pattern, ignoring: " + groupId);
}
}
// Try to take what the user put to --packages.
{
List<String> scanPackages = (List<String>) graphContext.getOptionMap().get(ScanPackagesOption.NAME);
if (scanPackages != null && !scanPackages.isEmpty() && scanPackages.get(0).contains("."))
return scanPackages.get(0);
}
// FIXME TODO - If this is unused, it should be removed.
// Get shared prefix of all packages in this application. Can result to "".
//String fromPackages = new ModuleAnalysisHelper(graphContext).deriveGroupIdFromPackages(projectModel);
//if (fromPackages != null)
//return fromPackages;
return LAST_RESORT_DEFAULT_GROUP_ID;
}
/**
* Counts the packages prefixes appearing in this project and if some of them make more than half of the total of existing packages, this prefix
* is returned. Otherwise, returns null.
*
* This is just a helper, it isn't something really hard-setting the package. It's something to use if the user didn't specify using
* --mavenize.groupId, and the archive or project name is something insane, like few sencences paragraph (a description) or a number or such.
*/
String deriveGroupIdFromPackages(ProjectModel projectModel)
{
Map<String, Integer> pkgsMap = new HashMap<>();
Set<String> pkgs = new HashSet<>(1000);
GremlinPipeline<Vertex, Vertex> pipeline = new GremlinPipeline<>(projectModel);
PipeFunction<String, String> upToThirdDot = new PipeFunction<String, String>()
{
@Override
public String compute(String pkgName)
{
int upToThirdDot = StringUtils.ordinalIndexOf(pkgName, ".", 3);
return StringUtils.substring(pkgName, 0, upToThirdDot);
}
};
PipeFunction<String, String> identity = new PipeFunction<String, String>()
{
@Override
public String compute(String pkgName)
{
return pkgName;
}
};
pipeline
.add(new OutPipe(ProjectModel.PROJECT_MODEL_TO_FILE))
.add(new TypePipe(JavaClassFileModel.class))
// .add(new GroupByPipe(identity, identity)
.add(new PropertyPipe(JavaClassFileModel.PROPERTY_PACKAGE_NAME))
.add(new CopySplitPipe(
new AggregatePipe(pkgs, upToThirdDot),
new GroupCountPipe(pkgsMap)))
// .add(new AggregatePipe(pkgs, upToThirdDot))
;
Map.Entry<String, Integer> biggest = null;
for (Map.Entry<String, Integer> entry : pkgsMap.entrySet())
{
if (biggest == null || biggest.getValue() < entry.getValue())
biggest = entry;
}
// More than a half is of this package.
if (biggest != null && biggest.getValue() > pkgsMap.size() / 2)
return biggest.getKey();
return null;
}
public class TypePipe extends PropertyFilterPipe<Vertex, Vertex>
{
public TypePipe(Class<? extends WindupVertexFrame> clazz)
{
super(WindupVertexFrame.TYPE_PROP, Text.CONTAINS, TypeAwareFramedGraphQuery.getTypeValue(clazz));
}
}
}