ThemisMavenPom.java
/*
* Themis: Java Project Framework
* Copyright 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.parser.maven;
import io.github.tonywasher.joceanus.metis.field.MetisFieldItem;
import io.github.tonywasher.joceanus.metis.field.MetisFieldSet;
import io.github.tonywasher.joceanus.oceanus.base.OceanusException;
import io.github.tonywasher.joceanus.oceanus.format.OceanusDataFormatter;
import io.github.tonywasher.joceanus.themis.exc.ThemisDataException;
import io.github.tonywasher.joceanus.themis.parser.base.ThemisDataResource;
import java.io.File;
import java.util.ArrayList;
import java.util.List;
/**
* Maven Pom.
*/
public class ThemisMavenPom
implements MetisFieldItem {
/**
* The controller.
*/
interface ThemisXMavenControl {
/**
* Load a pom via its id.
*
* @param pId the id of the pom
* @return the loaded pom
* @throws OceanusException on error
*/
ThemisMavenPom loadPomViaId(ThemisMavenId pId) throws OceanusException;
/**
* Load a pom at the location.
*
* @param pLocation the location of the pom
* @return the loaded pom
*/
ThemisMavenPom loadPomAtLocation(File pLocation) throws OceanusException;
}
/**
* Report fields.
*/
private static final MetisFieldSet<ThemisMavenPom> FIELD_DEFS = MetisFieldSet.newFieldSet(ThemisMavenPom.class);
/*
* Declare Fields.
*/
static {
FIELD_DEFS.declareLocalField(ThemisDataResource.DATA_ID, ThemisMavenPom::getId);
FIELD_DEFS.declareLocalField(ThemisDataResource.DATA_PARENT, ThemisMavenPom::getParent);
FIELD_DEFS.declareLocalField(ThemisDataResource.DATA_PROPERTIES, ThemisMavenPom::getProperties);
FIELD_DEFS.declareLocalField(ThemisDataResource.DATA_XTRADIRS, ThemisMavenPom::getXtraDirs);
FIELD_DEFS.declareLocalField(ThemisDataResource.DATA_MODULES, ThemisMavenPom::getModules);
FIELD_DEFS.declareLocalField(ThemisDataResource.DATA_VERSIONS, ThemisMavenPom::getTheVersions);
FIELD_DEFS.declareLocalField(ThemisDataResource.DATA_DIRECTDEPENDENCIES, ThemisMavenPom::getTheDirectDependencies);
FIELD_DEFS.declareLocalField(ThemisDataResource.DATA_DEPENDENCIES, ThemisMavenPom::getTheDependencies);
}
/**
* The controller.
*/
private final ThemisXMavenControl theControl;
/**
* The location.
*/
private final File theLocation;
/**
* The parser.
*/
private final ThemisMavenPomParser theParser;
/**
* The Maven Id.
*/
private final ThemisMavenId theId;
/**
* The parent.
*/
private final ThemisMavenPom theParent;
/**
* The property cache.
*/
private final ThemisMavenPropertyCache theProperties;
/**
* The list of extra directories.
*/
private final List<String> theXtraDirs;
/**
* The list of modules.
*/
private final List<ThemisMavenPom> theModules;
/**
* Is this a jar package.
*/
private final boolean isJarPackage;
/**
* The version cache.
*/
private ThemisMavenVersionCache theVersions;
/**
* The list of direct dependencies.
*/
private List<ThemisMavenPom> theDirectDependencies;
/**
* The full list of dependencies.
*/
private List<ThemisMavenId> theDependencies;
/**
* Constructor.
*
* @param pController the controller
* @param pLocation the location
* @throws OceanusException on error
*/
ThemisMavenPom(final ThemisXMavenControl pController,
final File pLocation) throws OceanusException {
/* Store the controller and location */
theControl = pController;
theLocation = new File(pLocation.getParent());
/* Create the caches */
theProperties = new ThemisMavenPropertyCache();
/* Create the parser */
theParser = new ThemisMavenPomParser(pLocation, theProperties);
/* Create the various lists */
theModules = new ArrayList<>();
theXtraDirs = new ArrayList<>();
/* Access the parent Pom */
final ThemisMavenId myParentId = theParser.getParent();
/* If we have a parent */
if (myParentId != null) {
/* Access pom details */
theParent = theControl.loadPomViaId(myParentId);
/* Inherit the parent properties and read own properties */
theProperties.setParent(theParent.getProperties());
} else {
theParent = null;
}
/* Read the properties */
theParser.readProperties();
/* Load the id */
theId = theParser.getId(theParent == null ? null : theParent.getId());
/* Determine jar packaging */
isJarPackage = theParser.isJarPackaging();
}
/**
* Constructor.
*
* @param pId the id
* @throws OceanusException on error
*/
ThemisMavenPom(final ThemisMavenId pId) throws OceanusException {
/* Store the id */
theId = pId;
/* Store the controller and location */
theControl = null;
theLocation = null;
theParent = null;
/* Create the cache */
theProperties = new ThemisMavenPropertyCache();
theVersions = new ThemisMavenVersionCache();
/* Create the parser */
theParser = null;
/* Set Pom packaging */
isJarPackage = false;
/* Create the various lists */
theModules = new ArrayList<>();
theXtraDirs = new ArrayList<>();
theDirectDependencies = new ArrayList<>();
theDependencies = new ArrayList<>();
}
@Override
public MetisFieldSet<ThemisMavenPom> getDataFieldSet() {
return FIELD_DEFS;
}
@Override
public String formatObject(final OceanusDataFormatter pFormatter) {
return getId().formatObject(pFormatter);
}
/**
* Obtain the id.
*
* @return the id
*/
public ThemisMavenId getId() {
return theId;
}
/**
* Obtain the artifactId.
*
* @return the id
*/
public String getArtifactId() {
return theId.getArtifactId();
}
/**
* Obtain the location.
*
* @return the parent
*/
public File getLocation() {
return theLocation;
}
/**
* Obtain the parent.
*
* @return the parent
*/
private ThemisMavenPom getParent() {
return theParent;
}
/**
* Is this jar packaging?
*
* @return true/false
* @throws OceanusException on error
*/
public boolean isJarPackaging() throws OceanusException {
return isJarPackage;
}
/**
* Obtain the modules.
*
* @return the modules
*/
public List<ThemisMavenPom> getModules() {
return theModules;
}
/**
* Obtain the dependencies.
*
* @return the dependencies
* @throws OceanusException on error
*/
public List<ThemisMavenPom> getDirectDependencies() throws OceanusException {
/* If we have not processed dependencies */
if (theDirectDependencies == null) {
/* Process dependencies */
theDirectDependencies = processDependencies();
}
/* Return the dependencies */
return theDirectDependencies;
}
/**
* Obtain the direct dependencies.
*
* @return the dependencies
*/
private List<ThemisMavenPom> getTheDirectDependencies() {
/* Return the dependencies */
return theDirectDependencies;
}
/**
* Obtain the dependencies.
*
* @return the dependencies
* @throws OceanusException on error
*/
public List<ThemisMavenId> getDependencies() throws OceanusException {
/* If we have not combined dependencies */
if (theDependencies == null) {
/* Combine dependencies */
theDependencies = combineDependencies();
}
/* Return the dependencies */
return theDependencies;
}
/**
* Obtain the dependencies.
*
* @return the dependencies
*/
public List<ThemisMavenId> getTheDependencies() {
/* Return the dependencies */
return theDependencies;
}
/**
* Obtain the extraDirectories.
*
* @return the extra Directories
*/
public List<String> getXtraDirs() {
return theXtraDirs;
}
/**
* Obtain the versions.
*
* @return the versions
* @throws OceanusException on error
*/
public ThemisMavenVersionCache getVersions() throws OceanusException {
/* If we have not processed versions */
if (theVersions == null) {
/* Process dependencies */
theVersions = processDependencyManagement();
}
/* Return the versions */
return theVersions;
}
/**
* Obtain the versions.
*
* @return the versions
*/
private ThemisMavenVersionCache getTheVersions() {
/* Return the versions */
return theVersions;
}
/**
* Obtain the properties.
*
* @return the properties
*/
ThemisMavenPropertyCache getProperties() {
return theProperties;
}
/**
* Process local details.
*
* @throws OceanusException on error
*/
void processLocalDetails() throws OceanusException {
/* Look up any modules */
final List<String> myModules = theParser.getModules();
for (String myModule : myModules) {
/* Load the file at the location */
final ThemisMavenPom myLoaded = theControl.loadPomAtLocation(new File(theLocation, myModule));
theModules.add(myLoaded);
}
/* Look up any extra directories */
final List<String> myXtraDirs = theParser.getXtraDirs();
theXtraDirs.addAll(myXtraDirs);
}
/**
* Process dependencies.
*
* @return the dependencies
* @throws OceanusException on error
*/
private ThemisMavenVersionCache processDependencyManagement() throws OceanusException {
/* Allocate the cache */
final ThemisMavenVersionCache myCache = new ThemisMavenVersionCache();
/* Attach to parent if present */
if (theParent != null) {
myCache.setParent(theParent.getVersions());
}
/* Look up any dependencyManagement */
final List<ThemisMavenId> myDependencyMgmt = theParser.getDependencyManagement();
for (ThemisMavenId myDependency : myDependencyMgmt) {
/* If this is a BOM */
if ("import".equals(myDependency.getScope())) {
final ThemisMavenPom myLoaded = theControl.loadPomViaId(myDependency);
myCache.importDependencies(myLoaded.getVersions());
} else {
myCache.addToCache(myDependency);
}
}
/* Return the cache */
return myCache;
}
/**
* Process dependencies.
*
* @return the dependencies
* @throws OceanusException on error
*/
private List<ThemisMavenPom> processDependencies() throws OceanusException {
/* Allocate the dependencies */
final List<ThemisMavenPom> myPoms = new ArrayList<>();
/* Look up any dependencies */
final List<ThemisMavenId> myDependencies = theParser.getDependencies();
for (ThemisMavenId myDependency : myDependencies) {
/* Load the dependency via its id */
final ThemisMavenId myId = theVersions.lookUpVersion(myDependency);
final ThemisMavenPom myLoaded = theControl.loadPomViaId(myId);
myPoms.add(myLoaded);
}
/* Return the poms */
return myPoms;
}
/**
* Combine direct dependencies.
*
* @return the dependencies
* @throws OceanusException on error
*/
private List<ThemisMavenId> combineDependencies() throws OceanusException {
/* Allocate the dependencies */
final List<ThemisMavenId> myIds = new ArrayList<>();
/* Combine dependencies for this pom */
combineDependencies(myIds, this);
/* Return the id */
return myIds;
}
/**
* Combine direct dependencies.
*
* @param pIds the list to populate
* @param pPom the pom to process
* @throws OceanusException on error
*/
private static void combineDependencies(final List<ThemisMavenId> pIds,
final ThemisMavenPom pPom) throws OceanusException {
/* Loop through direct dependencies */
for (ThemisMavenPom myDependency : pPom.getDirectDependencies()) {
/* If we have not processed this dependency before */
final ThemisMavenId myId = myDependency.getId();
if (checkDependencyId(pIds, myId)) {
/* Combine underlying dependencies */
combineDependencies(pIds, myDependency);
}
}
}
/**
* Check id.
*
* @param pDependencies the list of existing dependencies
* @param pId to id to check
* @return was the id added true/false
* @throws OceanusException on error
*/
static boolean checkDependencyId(final List<ThemisMavenId> pDependencies,
final ThemisMavenId pId) throws OceanusException {
/* Loop through the existing dependencies */
for (ThemisMavenId myDependency : pDependencies) {
/* If we have a match */
if (myDependency.equalsPrefix(pId)) {
/* OK as long as version matches */
if (myDependency.getVersion().equals(pId.getVersion())) {
return false;
}
/* Reject mismatch of versions */
throw new ThemisDataException("Mismatch of dependency versions " + myDependency + " vs " + pId);
}
}
/* No match, so add to list */
pDependencies.add(pId);
return true;
}
}