ThemisSolverPackage.java
/*
* Themis: Java Project Framework
* Copyright 2012-2026. Tony Washer
*
* 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 io.github.tonywasher.joceanus.themis.solver.proj;
import io.github.tonywasher.joceanus.themis.parser.base.ThemisChar;
import io.github.tonywasher.joceanus.themis.parser.proj.ThemisFile;
import io.github.tonywasher.joceanus.themis.parser.proj.ThemisPackage;
import io.github.tonywasher.joceanus.themis.solver.proj.ThemisSolverDef.ThemisSolverModuleDef;
import io.github.tonywasher.joceanus.themis.solver.proj.ThemisSolverDef.ThemisSolverPackageDef;
import java.util.ArrayList;
import java.util.List;
/**
* Solver Package.
*/
public class ThemisSolverPackage
implements ThemisSolverPackageDef, Comparable<ThemisSolverPackage> {
/**
* The owning module.
*/
private final ThemisSolverModuleDef theModule;
/**
* The underlying package.
*/
private final ThemisPackage thePackage;
/**
* The shortName.
*/
private final String theShortName;
/**
* The files.
*/
private final List<ThemisSolverFile> theFiles;
/**
* The list of child packages.
*/
private final List<ThemisSolverPackage> theChildren;
/**
* The referenceMap.
*/
private final ThemisSolverReference theReferenceMap;
/**
* The referenced sibling packages in local package.
*/
private final List<ThemisSolverPackageDef> theLocalReferences;
/**
* The implied referenced sibling packages in local package.
*/
private final List<ThemisSolverPackageDef> theImpliedReferences;
/**
* Is this a standard package?
*/
private final boolean isStandard;
/**
* The parent package.
*/
private ThemisSolverPackage theParent;
/**
* Is the reference list circular?
*/
private boolean isCircular;
/**
* Is the package incestuous viz. its parent?
*/
private boolean isIncestuous;
/**
* Constructor.
*
* @param pModule the owning module
* @param pPackage the parsed package
*/
ThemisSolverPackage(final ThemisSolverModuleDef pModule,
final ThemisPackage pPackage) {
/* Store the package and register with parser */
theModule = pModule;
thePackage = pPackage;
isStandard = pPackage.isStandard();
/* Determine the short name */
final String myName = getPackageName();
final int iIndex = myName.lastIndexOf(ThemisChar.PERIOD);
theShortName = iIndex == -1 ? myName : myName.substring(iIndex + 1);
/* Create the referenceMap and lists */
theReferenceMap = new ThemisSolverReference();
theLocalReferences = new ArrayList<>();
theImpliedReferences = new ArrayList<>();
/* Populate the fileList */
theFiles = new ArrayList<>();
theChildren = new ArrayList<>();
for (ThemisFile myFile : thePackage.getFiles()) {
final ThemisSolverFile mySolverFile = new ThemisSolverFile(this, myFile);
theFiles.add(mySolverFile);
}
}
@Override
public ThemisSolverModuleDef getOwningModule() {
return theModule;
}
@Override
public ThemisPackage getUnderlyingPackage() {
return thePackage;
}
@Override
public String getPackageName() {
return thePackage.getPackage();
}
/**
* Obtain the short package name.
*
* @return the shirt package name
*/
public String getShortName() {
return theShortName;
}
/**
* Obtain the file list.
*
* @return the file list
*/
public List<ThemisSolverFile> getFiles() {
return theFiles;
}
/**
* Obtain the list of child packages.
*
* @return the list of child packages
*/
public List<ThemisSolverPackage> getChildren() {
return theChildren;
}
/**
* Obtain the referenceMap.
*
* @return the referenceMap
*/
public ThemisSolverReference getReferenceMap() {
return theReferenceMap;
}
@Override
public List<ThemisSolverPackageDef> getLocalReferences() {
return theLocalReferences;
}
/**
* Obtain the implied references.
*
* @return the implied references
*/
public List<ThemisSolverPackageDef> getImpliedReferences() {
return theImpliedReferences;
}
/**
* Add the child package.
*
* @param pChild the child package
*/
public void addChild(final ThemisSolverPackage pChild) {
theChildren.add(pChild);
pChild.setParent(this);
}
/**
* Set parent package.
*
* @param pParent the parent package
*/
private void setParent(final ThemisSolverPackage pParent) {
theParent = pParent;
}
/**
* Obtain the parent package.
*
* @return the parent
*/
public ThemisSolverPackage getParent() {
return theParent;
}
@Override
public boolean isStandard() {
return isStandard;
}
/**
* Is the reference list circular?
*
* @return true/false
*/
public boolean isCircular() {
return isCircular;
}
/**
* Mark the package as incestuous.
*/
public void markIncestuous() {
isIncestuous = true;
}
/**
* Is the reference list incestuous?
*
* @return true/false
*/
public boolean isIncestuous() {
return isIncestuous;
}
/**
* Is the package a placeHolder?
*
* @return true/false
*/
public boolean isPlaceHolder() {
return thePackage.isPlaceHolder();
}
/**
* Set the referenced classes.
*
* @param pReferenced the referenced classes
*/
public void setReferenced(final List<ThemisSolverPackageDef> pReferenced) {
/* Add all references except for a self-reference */
theLocalReferences.addAll(pReferenced.stream().filter(s -> !s.equals(this)).toList());
}
/**
* process local references.
*/
public void processLocalReferences() {
/* Loop through the referenced local classes */
for (ThemisSolverPackageDef myPackage : theLocalReferences) {
/* Process the class */
processLocalReferences(myPackage);
}
/* Determine whether we are circular */
isCircular = theImpliedReferences.contains(this);
}
/**
* process local references.
*
* @param pPackage the class to process local references for
*/
private void processLocalReferences(final ThemisSolverPackageDef pPackage) {
/* If this is not already in the local reference list */
if (!theImpliedReferences.contains(pPackage)) {
/* Add the class */
theImpliedReferences.add(pPackage);
/* Only process further if we have not found circularity */
if (!pPackage.equals(this)) {
/* Loop through the local references */
for (ThemisSolverPackageDef myPackage : pPackage.getLocalReferences()) {
/* Process the local references */
processLocalReferences(myPackage);
}
}
}
}
@Override
public boolean equals(final Object pThat) {
/* Handle the trivial cases */
if (this == pThat) {
return true;
}
if (pThat == null) {
return false;
}
/* Make sure that the object is a Package */
if (!(pThat instanceof ThemisSolverPackage myThat)) {
return false;
}
/* Check name of package */
return getPackageName().equals(myThat.getPackageName());
}
@Override
public int hashCode() {
return getPackageName().hashCode();
}
@Override
public String toString() {
return thePackage.toString();
}
@Override
public int compareTo(final ThemisSolverPackage pThat) {
/* Handle simple dependency */
if (theImpliedReferences.contains(pThat)
&& !pThat.getImpliedReferences().contains(this)) {
return -1;
}
if (pThat.getImpliedReferences().contains(this)
&& !theImpliedReferences.contains(pThat)) {
return 1;
}
/* Sort on number of dependencies */
final int iDiff = pThat.theImpliedReferences.size()
- theImpliedReferences.size();
if (iDiff != 0) {
return iDiff;
}
/* If all else fails rely on alphabetical */
return getPackageName().compareTo(pThat.getPackageName());
}
}