package husacct.analyse.task.reconstruct.algorithms.hu.gateways;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Map;
import java.util.Set;
import org.apache.log4j.Logger;
import husacct.analyse.domain.IModelQueryService;
import husacct.analyse.task.reconstruct.AnalyseReconstructConstants;
import husacct.analyse.task.reconstruct.dto.ReconstructArchitectureDTO;
import husacct.analyse.task.reconstruct.parameters.ReconstructArchitectureParameterDTO;
import husacct.common.dto.DependencyDTO;
import husacct.common.dto.ModuleDTO;
import husacct.common.dto.SoftwareUnitDTO;
import husacct.common.enums.ModuleTypes;
public class GatewayHUSACCT_Root extends AlgorithmHUSACCT{
ModuleDTO selectedModule;
private final Logger logger = Logger.getLogger(GatewayHUSACCT_Root.class);
private ArrayList<SoftwareUnitDTO> softwareUnitsToIncludeInAlgorithm = new ArrayList<SoftwareUnitDTO>();
private HashMap<String, SoftwareUnitDTO> softwareUnitsToExclude = new HashMap<String, SoftwareUnitDTO>();
//Gateway finder.
//Gateway: only has inside-dependencies towards it, so it is located in the bottom layer
//Gateway: is the only class with imports towards an external application
public GatewayHUSACCT_Root (IModelQueryService queryService) {
super(queryService);
}
@Override
public void executeAlgorithm(ReconstructArchitectureDTO dto, IModelQueryService queryService) throws Exception {
try {
selectedModule = dto.getSelectedModule();
this.threshold = dto.getThreshold();
// If the selectedModule is of type Facade or ExternalLibrary, nothing is done.
if ((selectedModule == null) || selectedModule.type.equals(ModuleTypes.EXTERNAL_LIBRARY.toString()) || selectedModule.type.equals(ModuleTypes.FACADE.toString())) {
return;
}
if (!"**".equals(selectedModule.logicalPath)) {
softwareUnitsToIncludeInAlgorithm = getRelevantSoftwareUnits();
}
HashMap<SoftwareUnitDTO, ArrayList<SoftwareUnitDTO>> gateways = identifyGateWays(softwareUnitsToIncludeInAlgorithm);
createModule(gateways,selectedModule);
} catch (Exception e) {
logger.warn(" Exception: " + e );
}
}
private ArrayList<SoftwareUnitDTO> getChildUnitsOutOfPackage(SoftwareUnitDTO softwareUnit){
ArrayList<SoftwareUnitDTO> listOfClassesFound = new ArrayList<SoftwareUnitDTO>();
ArrayList<SoftwareUnitDTO> originalUnit = new ArrayList<SoftwareUnitDTO>();
originalUnit.add(softwareUnit);
if(softwareUnit.type.equals("package")){
SoftwareUnitDTO[] list = queryService.getChildUnitsOfSoftwareUnit(softwareUnit.uniqueName);
for(SoftwareUnitDTO unit: list){
if(unit.type.equals("package")){
for(SoftwareUnitDTO childUnit : queryService.getChildUnitsOfSoftwareUnit(unit.uniqueName)){
listOfClassesFound.add(childUnit);
}
}
listOfClassesFound.add(unit);
}
return listOfClassesFound;
}
return originalUnit;
}
private HashMap<SoftwareUnitDTO, ArrayList<SoftwareUnitDTO>> identifyGateWays(ArrayList<SoftwareUnitDTO> selectedUnits){
ArrayList<SoftwareUnitDTO> gateways = new ArrayList<SoftwareUnitDTO>();
HashMap<SoftwareUnitDTO, ArrayList<SoftwareUnitDTO>> mapOfGateways = new HashMap<SoftwareUnitDTO, ArrayList<SoftwareUnitDTO>>();
Set<SoftwareUnitDTO> chosenClasses = new HashSet<SoftwareUnitDTO>();
SoftwareUnitDTO library = null;
for (SoftwareUnitDTO softwareUnitParent : selectedUnits){
for(SoftwareUnitDTO softwareUnit : getChildUnitsOutOfPackage(softwareUnitParent)){
DependencyDTO[] allDependencies = queryService.getDependenciesFromSoftwareUnitToSoftwareUnit(softwareUnit.uniqueName,"");
Set<SoftwareUnitDTO> set = new HashSet<SoftwareUnitDTO>();
ArrayList<DependencyDTO> unitDependencies = new ArrayList<>();
ArrayList<DependencyDTO> unitExternalDependencies = new ArrayList<>();
for(DependencyDTO dep : allDependencies){
if(dep.from.equals(softwareUnit.uniqueName)){
unitDependencies.add(dep);
SoftwareUnitDTO depTo = queryService.getSoftwareUnitByUniqueName(dep.to);
if (depTo.type.toUpperCase().equals("LIBRARY")){
unitExternalDependencies.add(dep);
library = depTo;
}
}
}
int totalNumberOfDep = unitDependencies.size();
if((totalNumberOfDep * .6) <= unitExternalDependencies.size() && totalNumberOfDep > 0){
set.add(softwareUnit);
}
gateways.addAll(set);
chosenClasses = determineClassWithMostDependencies(library, gateways);
if(chosenClasses.contains(softwareUnit)){
mapOfGateways = addSoftwareUnitToHashMap(softwareUnit, library, mapOfGateways);
}
set = new HashSet<SoftwareUnitDTO>();
}
}
return mapOfGateways;
}
private Set<SoftwareUnitDTO> determineClassWithMostDependencies(SoftwareUnitDTO library, ArrayList<SoftwareUnitDTO> listOfClasses){
HashMap<SoftwareUnitDTO, Integer> classWithNumberOfDependencies = new HashMap<SoftwareUnitDTO, Integer>();
Set<SoftwareUnitDTO> setOfClasses = new HashSet<SoftwareUnitDTO>();
for(SoftwareUnitDTO unit : listOfClasses){
DependencyDTO[] dependencies = queryService.getDependenciesFromSoftwareUnitToSoftwareUnit( unit.uniqueName, library.uniqueName);
classWithNumberOfDependencies.put(unit, dependencies.length);
Map.Entry<SoftwareUnitDTO, Integer> maxEntry = null;
for (Map.Entry<SoftwareUnitDTO, Integer> entry : classWithNumberOfDependencies.entrySet())
{
if (maxEntry == null || entry.getValue().compareTo(maxEntry.getValue()) >= 0)
{
maxEntry = entry;
}
setOfClasses.add(maxEntry.getKey());
}
}
return setOfClasses;
}
private HashMap<SoftwareUnitDTO,ArrayList<SoftwareUnitDTO>> addSoftwareUnitToHashMap(SoftwareUnitDTO softwareUnit, SoftwareUnitDTO keyOfHashMap, HashMap<SoftwareUnitDTO,ArrayList<SoftwareUnitDTO>> hashMap) {
if(!hashMap.containsKey(keyOfHashMap)){
ArrayList<SoftwareUnitDTO> softwareUnitsOfClass = new ArrayList<SoftwareUnitDTO>();
softwareUnitsOfClass.add(softwareUnit);
hashMap.put(keyOfHashMap, softwareUnitsOfClass);
}
else{
ArrayList<SoftwareUnitDTO> softwareUnitsOfClass = hashMap.get(keyOfHashMap);
softwareUnitsOfClass.add(softwareUnit);
hashMap.put(keyOfHashMap, softwareUnitsOfClass);
}
return hashMap;
}
private void createModule(HashMap<SoftwareUnitDTO, ArrayList<SoftwareUnitDTO>> gateways, ModuleDTO selectedModule){
ModuleDTO gatewayModule = new ModuleDTO();
for(HashMap.Entry<SoftwareUnitDTO, ArrayList<SoftwareUnitDTO>> gateway : gateways.entrySet()){
if(!"".equals(gateway.getKey())){
gatewayModule = defineSarService.addModule(gateway.getKey().name + " Gateway", selectedModule.logicalPath, ModuleTypes.SUBSYSTEM.toString(), 0, gateway.getValue());
if(!gatewayModule.logicalPath.equals("")){
createRuleType(gatewayModule,selectedModule);
}
}
}
addToReverseReconstructionList(gatewayModule);
}
private void createRuleType(ModuleDTO libraryModule, ModuleDTO moduleTo){
defineSarService.addMainRule(moduleTo.logicalPath, libraryModule.logicalPath, "IsTheOnlyModuleAllowedToUse");
}
private ArrayList<SoftwareUnitDTO> getSetOfChildSoftwareUnits(SoftwareUnitDTO parentSoftwareUnit) {
ArrayList<SoftwareUnitDTO> childSoftwareUnits = new ArrayList<SoftwareUnitDTO>();
SoftwareUnitDTO softwareUnit = parentSoftwareUnit;
while (childSoftwareUnits.size() < 2) {
SoftwareUnitDTO[] childUnits = (queryService.getChildUnitsOfSoftwareUnit(softwareUnit.uniqueName));
if (childUnits.length == 0) {
if (!softwareUnit.equals(parentSoftwareUnit)) {
childSoftwareUnits.add(softwareUnit);
}
break;
} else if ((childUnits.length == 1)) {
softwareUnit = childUnits[0];
} else if ((childUnits.length >= 2)) {
for (SoftwareUnitDTO childUnit : childUnits) {
childSoftwareUnits.add(childUnit);
}
}
}
return childSoftwareUnits;
}
private ArrayList<SoftwareUnitDTO> getRelevantSoftwareUnits() {
ArrayList<SoftwareUnitDTO> softwareUnitsToReturn = new ArrayList<SoftwareUnitDTO>();
addSoftwareUnitsAssignedToComponentInterface_To_softwareUnitsToExcludeMap();
int numberOfAssignedSoftwareUnits = defineService.getAssignedSoftwareUnitsOfModule(selectedModule.logicalPath).size();
if (numberOfAssignedSoftwareUnits > 1) {
for(String logicalSoftwarePathSelectedModule : defineService.getAssignedSoftwareUnitsOfModule(selectedModule.logicalPath)){
SoftwareUnitDTO suDTO = queryService.getSoftwareUnitByUniqueName(logicalSoftwarePathSelectedModule);
if (!softwareUnitsToExclude.containsKey(suDTO.uniqueName)) {
softwareUnitsToReturn.add(suDTO);
}
}
} else if (numberOfAssignedSoftwareUnits == 1){
SoftwareUnitDTO assignedSU = new SoftwareUnitDTO("", "", "", "");
for(String uniqueNameAssignedSU : defineService.getAssignedSoftwareUnitsOfModule(selectedModule.logicalPath)){
assignedSU = queryService.getSoftwareUnitByUniqueName(uniqueNameAssignedSU);
}
for (SoftwareUnitDTO subModule : getSetOfChildSoftwareUnits(assignedSU)){
if (!softwareUnitsToExclude.containsKey(subModule.uniqueName)) {
softwareUnitsToReturn.add(subModule);
}
}
}
return softwareUnitsToReturn;
}
private void addSoftwareUnitsAssignedToComponentInterface_To_softwareUnitsToExcludeMap() {
if (selectedModule.type.equals(ModuleTypes.COMPONENT.toString())) {
for (ModuleDTO subModule : selectedModule.subModules) {
if (subModule.type.equals(ModuleTypes.FACADE.toString())) {
defineService.getAssignedSoftwareUnitsOfModule(subModule.logicalPath);
for (String assignedUnitUniqueName : defineService.getAssignedSoftwareUnitsOfModule(subModule.logicalPath)) {
SoftwareUnitDTO assignedUnit = queryService.getSoftwareUnitByUniqueName(assignedUnitUniqueName);
if (!assignedUnit.name.isEmpty()) {
softwareUnitsToExclude.put(assignedUnit.uniqueName, assignedUnit);
}
}
}
}
}
}
@Override
public ReconstructArchitectureDTO getAlgorithmParameterSettings() {
ReconstructArchitectureDTO reconstructArchitecture = new ReconstructArchitectureDTO();
reconstructArchitecture.approachId = AnalyseReconstructConstants.Algorithms.Gateways_HUSACCT_Root;
reconstructArchitecture.threshold = 10;
reconstructArchitecture.relationType = AnalyseReconstructConstants.RelationTypes.allDependencies;
reconstructArchitecture.granularity = AnalyseReconstructConstants.Granularities.PackagesAndClasses;
reconstructArchitecture.parameterDTOs = createParameterPanels();
return reconstructArchitecture;
}
private ArrayList<ReconstructArchitectureParameterDTO> createParameterPanels(){
ArrayList<ReconstructArchitectureParameterDTO> parameterDTOs = new ArrayList<>();
parameterDTOs.add(ReconstructArchitectureParameterDTO.DefaultParameterDTOs.createThresholdParameter(10));
parameterDTOs.add(ReconstructArchitectureParameterDTO.DefaultParameterDTOs.createRelationTypeParameter(AnalyseReconstructConstants.RelationTypes.allDependencies));
parameterDTOs.add(ReconstructArchitectureParameterDTO.DefaultParameterDTOs.createGranularityPanel(AnalyseReconstructConstants.Granularities.PackagesAndClasses));
return parameterDTOs;
}
}