CmsLoader.java
package com.cloudforgeci.api.compute;
import com.cloudforge.core.interfaces.ApplicationSpec;
import com.cloudforge.core.interfaces.CmsSpec;
import com.cloudforge.core.annotation.CmsPlugin;
import java.util.*;
import java.util.stream.Collectors;
/**
* Auto-discovery utility for CmsSpec implementations using Java ServiceLoader.
*
* <p>This class discovers all CmsSpec implementations registered via
* META-INF/services/com.cloudforge.core.interfaces.ApplicationSpec and provides
* convenient access methods for deployment tools.</p>
*
* <p>CMS platforms are discovered from:</p>
* <ul>
* <li>Built-in CMS applications in cloudforge-api module</li>
* <li>External plugins providing META-INF/services registration</li>
* </ul>
*
* <h2>Usage Example:</h2>
* <pre>{@code
* // Discover all CMS platforms
* Map<String, CmsSpec> platforms = CmsLoader.discover();
*
* // Get CMS by category
* List<CmsSpec> ecommerceApps = CmsLoader.discoverByCategory("ecommerce");
* List<CmsSpec> socialApps = CmsLoader.discoverByCategory("social");
*
* // Find specific CMS
* Optional<CmsSpec> wordpress = CmsLoader.findById("wordpress");
*
* // Get all e-commerce platforms
* List<CmsSpec> ecommerce = CmsLoader.discoverEcommerce();
* }</pre>
*
* @since 3.1.0
* @see CmsSpec
* @see CmsPlugin
*/
public final class CmsLoader {
private CmsLoader() {
// Utility class
}
/**
* Discover all CmsSpec implementations via ServiceLoader.
*
* <p>Returns a map of CMS ID to CmsSpec instance. The CMS ID
* is obtained from {@link CmsSpec#applicationId()}.</p>
*
* <p>CmsSpec implementations are discovered from the ApplicationSpec
* ServiceLoader registration and filtered to include only those
* that implement CmsSpec.</p>
*
* @return map of CMS ID to CmsSpec (never null, may be empty)
*/
public static Map<String, CmsSpec> discover() {
ServiceLoader<ApplicationSpec> loader = ServiceLoader.load(ApplicationSpec.class);
Map<String, CmsSpec> platforms = new LinkedHashMap<>();
for (ApplicationSpec spec : loader) {
if (spec instanceof CmsSpec cmsSpec) {
String id = cmsSpec.applicationId();
if (platforms.containsKey(id)) {
System.err.println("WARNING: Duplicate CMS ID '" + id + "' - using first registration");
continue;
}
platforms.put(id, cmsSpec);
}
}
return platforms;
}
/**
* Discover all CmsSpec implementations as a list.
*
* <p>CMS platforms are sorted alphabetically by application ID for consistent ordering.</p>
*
* @return list of CmsSpec instances (never null, may be empty)
*/
public static List<CmsSpec> discoverAsList() {
return discover().values().stream()
.sorted(Comparator.comparing(CmsSpec::applicationId))
.collect(Collectors.toList());
}
/**
* Discover CmsSpec implementations filtered by CMS category.
*
* <p>CMS categories include:</p>
* <ul>
* <li>cms - Content management systems (WordPress, Joomla, Drupal)</li>
* <li>ecommerce - E-commerce platforms (WooCommerce, Magento, PrestaShop)</li>
* <li>social - Social networking (Dolphin/UNA, HumHub, Elgg)</li>
* <li>forum - Forum software (phpBB, Discourse, Flarum)</li>
* <li>wiki - Wiki platforms (MediaWiki, DokuWiki, BookStack)</li>
* <li>lms - Learning management (Moodle, Canvas, Chamilo)</li>
* </ul>
*
* @param category the CMS category to filter by
* @return list of CmsSpec instances in this category
*/
public static List<CmsSpec> discoverByCategory(String category) {
return discoverAsList().stream()
.filter(spec -> spec.cmsCategory().equals(category))
.collect(Collectors.toList());
}
/**
* Discover all content management systems (category: "cms").
*
* <p>Includes: WordPress, Joomla, Drupal, TYPO3, Concrete5, etc.</p>
*
* @return list of CMS platforms
*/
public static List<CmsSpec> discoverCms() {
return discoverByCategory("cms");
}
/**
* Discover all e-commerce platforms (category: "ecommerce").
*
* <p>Includes: WooCommerce, Magento, PrestaShop, OpenCart, Shopware, etc.</p>
*
* @return list of e-commerce platforms
*/
public static List<CmsSpec> discoverEcommerce() {
return discoverByCategory("ecommerce");
}
/**
* Discover all social networking platforms (category: "social").
*
* <p>Includes: Dolphin/UNA, HumHub, Elgg, phpFox, etc.</p>
*
* @return list of social networking platforms
*/
public static List<CmsSpec> discoverSocial() {
return discoverByCategory("social");
}
/**
* Discover all forum platforms (category: "forum").
*
* <p>Includes: phpBB, Discourse, Flarum, MyBB, XenForo, etc.</p>
*
* @return list of forum platforms
*/
public static List<CmsSpec> discoverForums() {
return discoverByCategory("forum");
}
/**
* Discover all wiki platforms (category: "wiki").
*
* <p>Includes: MediaWiki, DokuWiki, BookStack, Wiki.js, etc.</p>
*
* @return list of wiki platforms
*/
public static List<CmsSpec> discoverWikis() {
return discoverByCategory("wiki");
}
/**
* Discover all learning management systems (category: "lms").
*
* <p>Includes: Moodle, Canvas, Chamilo, ILIAS, etc.</p>
*
* @return list of LMS platforms
*/
public static List<CmsSpec> discoverLms() {
return discoverByCategory("lms");
}
/**
* Discover all available CMS categories.
*
* <p>Returns a sorted list of unique categories from all discovered platforms.</p>
*
* @return sorted list of category names
*/
public static List<String> discoverCategories() {
return discoverAsList().stream()
.map(CmsSpec::cmsCategory)
.distinct()
.sorted()
.collect(Collectors.toList());
}
/**
* Find a specific CmsSpec by CMS ID.
*
* @param cmsId the CMS identifier (e.g., "wordpress", "magento", "dolphin")
* @return Optional containing the CmsSpec if found
*/
public static Optional<CmsSpec> findById(String cmsId) {
return Optional.ofNullable(discover().get(cmsId));
}
/**
* Get CMS platforms grouped by category.
*
* <p>Returns a map where keys are category names and values are lists of
* CmsSpec instances in that category.</p>
*
* @return map of category to list of CMS platforms
*/
public static Map<String, List<CmsSpec>> discoverGroupedByCategory() {
return discoverAsList().stream()
.collect(Collectors.groupingBy(
CmsSpec::cmsCategory,
TreeMap::new,
Collectors.toList()
));
}
/**
* Discover CMS platforms that support OIDC integration.
*
* @return list of CmsSpec instances supporting OIDC
*/
public static List<CmsSpec> discoverOidcEnabled() {
return discoverAsList().stream()
.filter(CmsSpec::supportsOidcIntegration)
.collect(Collectors.toList());
}
/**
* Discover CMS platforms that support S3 media storage.
*
* @return list of CmsSpec instances supporting S3 media
*/
public static List<CmsSpec> discoverS3MediaSupported() {
return discoverAsList().stream()
.filter(CmsSpec::supportsS3MediaStorage)
.collect(Collectors.toList());
}
/**
* Discover CMS platforms that support object caching (Redis/Memcached).
*
* @return list of CmsSpec instances supporting object caching
*/
public static List<CmsSpec> discoverObjectCacheSupported() {
return discoverAsList().stream()
.filter(CmsSpec::supportsObjectCache)
.collect(Collectors.toList());
}
/**
* Discover CMS platforms that support multi-site/multi-store.
*
* @return list of CmsSpec instances supporting multi-site
*/
public static List<CmsSpec> discoverMultisiteSupported() {
return discoverAsList().stream()
.filter(CmsSpec::supportsMultisite)
.collect(Collectors.toList());
}
/**
* Discover CMS platforms by PHP version requirement.
*
* @param phpVersion the PHP version to filter by (e.g., "8.2", "8.1")
* @return list of CmsSpec instances requiring this PHP version
*/
public static List<CmsSpec> discoverByPhpVersion(String phpVersion) {
return discoverAsList().stream()
.filter(spec -> spec.phpVersion().equals(phpVersion))
.collect(Collectors.toList());
}
/**
* Discover CMS platforms that support Fargate deployment.
*
* @return list of CmsSpec instances supporting Fargate
*/
public static List<CmsSpec> discoverFargateSupported() {
return discoverAsList().stream()
.filter(CmsSpec::supportsFargate)
.collect(Collectors.toList());
}
/**
* Discover CMS platforms that support EC2 deployment.
*
* @return list of CmsSpec instances supporting EC2
*/
public static List<CmsSpec> discoverEc2Supported() {
return discoverAsList().stream()
.filter(CmsSpec::supportsEc2)
.collect(Collectors.toList());
}
/**
* Print a formatted catalog of all discovered CMS platforms.
*
* <p>Useful for debugging and displaying available platforms to users.</p>
*
* @return formatted string containing CMS catalog
*/
public static String printCatalog() {
StringBuilder sb = new StringBuilder();
sb.append("CloudForge CMS Platform Catalog\n");
sb.append("===============================\n\n");
Map<String, List<CmsSpec>> grouped = discoverGroupedByCategory();
for (Map.Entry<String, List<CmsSpec>> entry : grouped.entrySet()) {
String category = entry.getKey();
List<CmsSpec> platforms = entry.getValue();
sb.append(categoryDisplayName(category)).append(":\n");
for (CmsSpec cms : platforms) {
sb.append(" - ").append(cms.applicationId())
.append(" (").append(cms.displayName()).append(")");
if (!cms.description().isEmpty()) {
sb.append("\n ").append(cms.description());
}
sb.append("\n PHP ").append(cms.phpVersion());
List<String> features = new ArrayList<>();
if (cms.supportsOidcIntegration()) features.add("OIDC");
if (cms.supportsS3MediaStorage()) features.add("S3 Media");
if (cms.supportsObjectCache()) features.add("Redis Cache");
if (cms.supportsMultisite()) features.add("Multi-site");
if (cms.supportsFargate()) features.add("Fargate");
if (cms.supportsEc2()) features.add("EC2");
if (!features.isEmpty()) {
sb.append(" | ").append(String.join(", ", features));
}
sb.append("\n");
}
sb.append("\n");
}
return sb.toString();
}
/**
* Get display name for a category.
*
* @param category the category key
* @return human-readable category name
*/
private static String categoryDisplayName(String category) {
return switch (category) {
case "cms" -> "CONTENT MANAGEMENT SYSTEMS";
case "ecommerce" -> "E-COMMERCE PLATFORMS";
case "social" -> "SOCIAL NETWORKING";
case "forum" -> "FORUM SOFTWARE";
case "wiki" -> "WIKI PLATFORMS";
case "lms" -> "LEARNING MANAGEMENT SYSTEMS";
default -> category.toUpperCase();
};
}
}