CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/maven-org-apereo-cas--cas-server-core-util-api

Apereo CAS Core Utilities - A comprehensive utility library providing functional programming constructs, encryption utilities, configuration helpers, and core infrastructure components for the Central Authentication Service framework

Pending
Overview
Eval results
Files

functional-programming.mddocs/

Functional Programming

Advanced functional programming utilities with enhanced exception handling, conditional operations, retry mechanisms, and composable functions for robust and elegant code patterns.

Core Imports

import org.apereo.cas.util.function.FunctionUtils;
import org.jooq.lambda.fi.util.function.CheckedFunction;
import org.jooq.lambda.fi.util.function.CheckedConsumer;
import org.jooq.lambda.fi.util.function.CheckedSupplier;
import org.springframework.retry.RetryCallback;
import java.util.function.*;
import java.util.List;

FunctionUtils

Comprehensive utility class providing functional programming constructs with exception handling and conditional execution patterns.

@UtilityClass
public class FunctionUtils {
    
    // Conditional Functions - Return modified values based on conditions
    public static <T, R> Function<T, R> doIf(Predicate<Object> condition, 
                                           Supplier<R> trueFunction, 
                                           Supplier<R> falseFunction);
    
    public static <T, R> Function<T, R> doIf(Predicate<T> condition,
                                           CheckedFunction<T, R> trueFunction,
                                           CheckedFunction<T, R> falseFunction);
    
    // Conditional Consumers - Execute actions based on conditions
    public static <T> Consumer<T> doIf(boolean condition, 
                                     Consumer<T> trueFunction,
                                     Consumer<T> falseFunction);
    
    public static <T> Consumer<T> doIf(boolean condition, 
                                     Consumer<T> trueFunction);
    
    // Conditional Suppliers - Supply values based on conditions
    public static <R> Supplier<R> doIf(boolean condition, 
                                      Supplier<R> trueFunction, 
                                      Supplier<R> falseFunction);
    
    // String-specific conditional operations
    public static <T> void doIfBlank(CharSequence input, CheckedConsumer<T> trueFunction);
    
    public static <T> T doIfNotBlank(CharSequence input, 
                                   CheckedSupplier<T> trueFunction,
                                   CheckedSupplier<T> falseFunction);
    
    public static <T extends CharSequence> void doIfNotBlank(T input, CheckedConsumer<T> trueFunction);
    
    // Null-safe operations
    public static <R> R doIfNotNull(Object input, CheckedSupplier<R> trueFunction);
    
    public static <R> Supplier<R> doIfNotNull(Object input,
                                            CheckedSupplier<R> trueFunction,
                                            CheckedSupplier<R> falseFunction);
    
    public static <T> void doIfNotNull(T input, CheckedConsumer<T> trueFunction);
    
    public static <T> void doIfNotNull(T input,
                                     CheckedConsumer<T> trueFunction,
                                     CheckedConsumer<T> falseFunction);
    
    // Null condition operations
    public static <T> void doIfNull(T input, CheckedConsumer<T> trueFunction);
    
    public static <T> void doIfNull(T input,
                                  CheckedConsumer<T> trueFunction,
                                  CheckedConsumer<T> falseFunction);
    
    public static <R> Supplier<R> doIfNull(Object input,
                                         Supplier<R> trueFunction,
                                         Supplier<R> falseFunction);
    
    public static <T> void doIfNotNull(T obj, Consumer<T> consumer);
    
    public static <T> void doIfNull(T obj, Runnable action);
    
    // Exception handling with functions
    public static <T, R> Function<T, R> doAndHandle(CheckedFunction<T, R> function,
                                                   CheckedFunction<Throwable, R> errorHandler);
    
    public static <R> Consumer<R> doAndHandle(CheckedConsumer<R> function,
                                            CheckedFunction<Throwable, R> errorHandler);
    
    public static <R> R doAndHandle(CheckedSupplier<R> function);
    
    public static <R> void doAndHandle(CheckedConsumer<R> function);
    
    public static <R> Supplier<R> doAndHandle(CheckedSupplier<R> function, 
                                            CheckedFunction<Throwable, R> errorHandler);
    
    // Conditional execution with predicates
    public static <T> void doWhen(T obj, Predicate<T> condition, Consumer<T> consumer);
    
    // Exception-safe operations
    public static boolean doWithoutThrows(Runnable action);
    
    // Unchecked exception handling
    public static <T> T doUnchecked(Supplier<T> supplier);
    
    public static void doUnchecked(Runnable action);
    
    // Retry operations
    public static <T> T doAndRetry(RetryCallback<T, Exception> callback) throws Exception;
    
    public static <T> T doAndRetry(RetryCallback<T, Exception> callback, int maximumAttempts) throws Exception;
    
    public static <T> T doAndRetry(List<Class<? extends Throwable>> clazzes,
                                 RetryCallback<T, Exception> callback) throws Exception;
    
    public static <T> T doAndRetry(List<Class<? extends Throwable>> clazzes,
                                 RetryCallback<T, Exception> callback,
                                 int maximumAttempts) throws Exception;
    
    // Validation helpers
    public static String throwIfBlank(String str, String message);
    
    public static <T> T throwIfNull(T obj, String message);
    
    public static void throwIf(BooleanSupplier condition, String message);
    
    // Return value helpers
    public static <T> T doAndReturn(Runnable action, T returnValue);
    
    public static <T> T doAndThrow(Runnable action, RuntimeException exception);
    
    public static <T> T doAndThrowUnchecked(Runnable action, Exception exception);
}

Usage Examples

Conditional operations with enhanced readability:

@Service
public class UserServiceImpl implements UserService {
    
    private final UserRepository userRepository;
    private final EmailService emailService;
    
    public void processUserRegistration(UserRegistrationRequest request) {
        // Conditional validation with clear semantics
        String email = FunctionUtils.throwIfBlank(request.getEmail(), "Email is required");
        String username = FunctionUtils.throwIfBlank(request.getUsername(), "Username is required");
        
        // Conditional processing based on user type
        Function<UserRegistrationRequest, User> userCreator = FunctionUtils.doIf(
            req -> req.getAccountType() == AccountType.PREMIUM,
            req -> createPremiumUser(req),
            req -> createStandardUser(req)
        );
        
        User user = userCreator.apply(request);
        userRepository.save(user);
        
        // Conditional email sending
        Consumer<User> emailSender = FunctionUtils.doIf(
            u -> u.isEmailNotificationEnabled(),
            u -> emailService.sendWelcomeEmail(u.getEmail())
        );
        
        emailSender.accept(user);
    }
    
    public Optional<UserProfile> getUserProfile(String userId) {
        return FunctionUtils.doIfNotBlank(userId, id -> {
            User user = userRepository.findById(id);
            return FunctionUtils.doIfNotNull(user, this::createUserProfile);
        });
    }
}

Exception handling with graceful degradation:

@Service
public class ExternalApiService {
    
    private final HttpClient httpClient;
    private final CacheManager cacheManager;
    
    public ApiResponse fetchUserData(String userId) {
        // Primary operation with exception handling and fallback
        Function<String, ApiResponse> fetchFromApi = FunctionUtils.doAndHandle(
            id -> callExternalApi(id),
            IOException.class,
            ex -> {
                log.warn("API call failed, trying cache", ex);
                return getCachedResponse(id);
            }
        );
        
        // Retry mechanism for critical operations
        return FunctionUtils.doAndRetry(
            () -> fetchFromApi.apply(userId),
            3,                    // Max retries
            1000,                 // Delay between retries
            IOException.class,    // Retryable exceptions
            TimeoutException.class
        );
    }
    
    public UserPreferences getUserPreferences(String userId) {
        // Multiple fallback strategies
        Supplier<UserPreferences> preferenceSupplier = FunctionUtils.doIf(
            () -> isUserCacheEnabled(),
            () -> getCachedPreferences(userId),
            () -> getDefaultPreferences()
        );
        
        return FunctionUtils.doAndHandle(
            preferenceSupplier,
            Exception.class,
            ex -> {
                log.error("Failed to load user preferences", ex);
                return UserPreferences.getDefaults();
            }
        );
    }
    
    public void updateUserSettings(String userId, Map<String, Object> settings) {
        // Conditional processing with validation
        FunctionUtils.doWhen(settings, 
            s -> !s.isEmpty(),
            s -> {
                validateSettings(s);
                persistSettings(userId, s);
                clearUserCache(userId);
            }
        );
        
        // Null-safe notification
        FunctionUtils.doIfNotNull(settings.get("email"), 
            email -> notificationService.updateEmailPreference(userId, (String) email)
        );
    }
}

Advanced retry patterns with exponential backoff:

@Component
public class ResilientDataService {
    
    public <T> T executeWithRetry(Supplier<T> operation, String operationName) {
        return FunctionUtils.doAndRetry(
            () -> {
                log.debug("Executing operation: {}", operationName);
                T result = operation.get();
                log.debug("Operation completed successfully: {}", operationName);
                return result;
            },
            5,                           // Max retries
            1000,                        // Base delay
            SQLException.class,          // Database exceptions
            ConnectException.class,      // Network exceptions
            SocketTimeoutException.class // Timeout exceptions
        );
    }
    
    public CompletableFuture<String> processDataAsync(String dataId) {
        return CompletableFuture.supplyAsync(() -> 
            FunctionUtils.doAndHandle(
                () -> processData(dataId),
                Exception.class,
                ex -> {
                    log.error("Async data processing failed for: {}", dataId, ex);
                    return "ERROR: " + ex.getMessage();
                }
            )
        );
    }
    
    public void batchProcess(List<String> dataIds) {
        dataIds.parallelStream()
            .forEach(id -> 
                FunctionUtils.doWhen(id,
                    Objects::nonNull,
                    dataId -> FunctionUtils.doWithoutThrows(() -> processData(dataId))
                )
            );
    }
}

Validation and transformation pipelines:

@Service
public class DataValidationService {
    
    public ProcessedData validateAndTransform(RawData rawData) {
        // Validation pipeline with early returns
        RawData validated = FunctionUtils.doAndReturn(
            () -> FunctionUtils.throwIfNull(rawData, "Raw data cannot be null"),
            rawData
        );
        
        // Transformation pipeline with conditional steps
        Function<RawData, ProcessedData> transformationPipeline = data -> {
            // Step 1: Basic sanitization
            data = FunctionUtils.doIfNotNull(data, this::sanitizeData);
            
            // Step 2: Conditional enrichment
            Function<RawData, RawData> enricher = FunctionUtils.doIf(
                d -> d.requiresEnrichment(),
                d -> enrichData(d),
                d -> d  // No enrichment needed
            );
            data = enricher.apply(data);
            
            // Step 3: Format conversion
            return convertToProcessedData(data);
        };
        
        // Execute with error handling
        return FunctionUtils.doAndHandle(
            () -> transformationPipeline.apply(validated),
            ValidationException.class,
            ex -> {
                log.error("Validation failed", ex);
                throw new ProcessingException("Data validation failed", ex);
            }
        );
    }
    
    public ValidationResult validateBusinessRules(ProcessedData data) {
        List<ValidationError> errors = new ArrayList<>();
        
        // Conditional validation rules
        Consumer<ProcessedData> validator = FunctionUtils.doIf(
            d -> d.getType() == DataType.FINANCIAL,
            d -> validateFinancialRules(d, errors)
        ).andThen(FunctionUtils.doIf(
            d -> d.hasPersonalInfo(),
            d -> validatePrivacyRules(d, errors)
        )).andThen(FunctionUtils.doIf(
            d -> d.isExternalSource(),
            d -> validateExternalSourceRules(d, errors)
        ));
        
        validator.accept(data);
        
        return errors.isEmpty() ? ValidationResult.success() : ValidationResult.failure(errors);
    }
}

ComposableFunction Interface

Interface extending Function for composable operations with enhanced chaining capabilities.

@FunctionalInterface
public interface ComposableFunction<T, R> extends Function<T, R> {
    
    // Enhanced composition methods
    default <V> ComposableFunction<T, V> andThenComposable(Function<? super R, ? extends V> after);
    
    default <V> ComposableFunction<V, R> composeComposable(Function<? super V, ? extends T> before);
    
    // Conditional composition
    default ComposableFunction<T, R> composeIf(Predicate<T> condition, 
                                             Function<T, T> preprocessor);
    
    // Exception-safe composition
    default ComposableFunction<T, Optional<R>> safely();
    
    // Retry composition
    default ComposableFunction<T, R> withRetry(int maxRetries, long delayMillis);
    
    // Factory methods
    static <T, R> ComposableFunction<T, R> of(Function<T, R> function);
    
    static <T> ComposableFunction<T, T> identity();
}

Usage Examples

Composable function pipelines:

@Service
public class DataProcessingPipeline {
    
    public ProcessingResult processUserData(UserInput input) {
        // Create composable processing pipeline
        ComposableFunction<UserInput, ProcessingResult> pipeline = ComposableFunction
            .<UserInput>identity()
            .andThenComposable(this::validateInput)
            .andThenComposable(this::sanitizeInput) 
            .andThenComposable(this::enrichInput)
            .andThenComposable(this::transformInput)
            .andThenComposable(this::persistInput)
            .andThenComposable(this::createResult);
        
        // Execute pipeline with error handling
        return pipeline.safely()
            .withRetry(3, 1000)
            .apply(input)
            .orElse(ProcessingResult.failed("Processing pipeline failed"));
    }
    
    public ComposableFunction<String, User> createUserPipeline() {
        return ComposableFunction
            .<String>of(this::validateUserId)
            .composeIf(Objects::nonNull, this::normalizeUserId)
            .andThenComposable(this::fetchUserFromRepository)
            .andThenComposable(this::enrichUserData)
            .safely(); // Make the entire pipeline safe
    }
}

Advanced composition with conditions:

@Component
public class ConditionalProcessingService {
    
    public String processMessage(Message message, ProcessingContext context) {
        // Build conditional processing pipeline
        ComposableFunction<Message, String> processor = ComposableFunction
            .<Message>identity()
            .composeIf(msg -> msg.isEncrypted(), this::decryptMessage)
            .composeIf(msg -> msg.needsSanitization(), this::sanitizeMessage)
            .andThenComposable(msg -> applyBusinessRules(msg, context))
            .composeIf(msg -> context.isAuditEnabled(), this::auditMessage)
            .andThenComposable(this::formatOutput);
        
        return processor.apply(message);
    }
    
    public ComposableFunction<Request, Response> createAuthenticationPipeline() {
        return ComposableFunction
            .<Request>of(this::extractCredentials)
            .andThenComposable(this::validateCredentials)
            .composeIf(creds -> creds.isMfaRequired(), this::validateMfaToken)
            .andThenComposable(this::createAuthenticationResult)
            .andThenComposable(this::generateTokens)
            .andThenComposable(this::createResponse)
            .withRetry(2, 500); // Retry on transient failures
    }
}

Complete Integration Examples

Functional Configuration Service

@Service
@Slf4j
public class FunctionalConfigurationService {
    
    private final Map<String, Supplier<Object>> configurationSuppliers;
    
    public FunctionalConfigurationService() {
        this.configurationSuppliers = new ConcurrentHashMap<>();
        initializeDefaultSuppliers();
    }
    
    private void initializeDefaultSuppliers() {
        // Database configuration with fallback
        registerConfigSupplier("database.url", 
            FunctionUtils.doIf(
                () -> isDatabaseAvailable(),
                () -> getDatabaseUrl(),
                () -> getDefaultDatabaseUrl()
            )
        );
        
        // Cache configuration with validation
        registerConfigSupplier("cache.enabled",
            FunctionUtils.doAndHandle(
                () -> Boolean.parseBoolean(getProperty("cache.enabled", "true")),
                Exception.class,
                ex -> {
                    log.warn("Failed to parse cache.enabled, using default", ex);
                    return true;
                }
            )
        );
        
        // External service URLs with retry
        registerConfigSupplier("external.api.url",
            () -> FunctionUtils.doAndRetry(
                () -> validateAndGetExternalUrl(),
                3,
                2000,
                ConnectException.class
            )
        );
    }
    
    public <T> T getConfiguration(String key, Class<T> type) {
        Supplier<Object> supplier = configurationSuppliers.get(key);
        
        return FunctionUtils.doIfNotNull(supplier,
            s -> FunctionUtils.doAndHandle(
                () -> type.cast(s.get()),
                ClassCastException.class,
                ex -> {
                    log.error("Configuration cast failed for key: {}", key, ex);
                    return null;
                }
            )
        );
    }
    
    public void registerConfigSupplier(String key, Supplier<Object> supplier) {
        configurationSuppliers.put(key, supplier);
    }
    
    // Functional configuration validation
    public ValidationResult validateAllConfigurations() {
        List<String> errors = configurationSuppliers.entrySet()
            .parallelStream()
            .map(entry -> validateConfiguration(entry.getKey(), entry.getValue()))
            .filter(Optional::isPresent)
            .map(Optional::get)
            .collect(Collectors.toList());
        
        return errors.isEmpty() ? 
            ValidationResult.success() : 
            ValidationResult.failure(errors);
    }
    
    private Optional<String> validateConfiguration(String key, Supplier<Object> supplier) {
        return FunctionUtils.doAndHandle(
            () -> {
                Object value = supplier.get();
                FunctionUtils.throwIfNull(value, "Configuration value is null");
                return Optional.<String>empty();
            },
            Exception.class,
            ex -> Optional.of("Configuration '" + key + "' failed: " + ex.getMessage())
        );
    }
}

Functional Event Processing System

@Component
public class FunctionalEventProcessor {
    
    private final Map<EventType, ComposableFunction<Event, ProcessingResult>> processors;
    
    public FunctionalEventProcessor() {
        this.processors = new HashMap<>();
        initializeProcessors();
    }
    
    private void initializeProcessors() {
        // User event processor
        processors.put(EventType.USER_ACTION, 
            ComposableFunction
                .<Event>of(this::validateUserEvent)
                .composeIf(e -> e.requiresAuthentication(), this::authenticateEvent)
                .andThenComposable(this::enrichUserEvent)
                .composeIf(e -> e.isAuditable(), this::auditEvent)
                .andThenComposable(this::processUserAction)
                .safely()
                .withRetry(2, 1000)
        );
        
        // System event processor  
        processors.put(EventType.SYSTEM_EVENT,
            ComposableFunction
                .<Event>of(this::validateSystemEvent)
                .andThenComposable(this::enrichSystemEvent)
                .andThenComposable(this::processSystemEvent)
                .safely()
        );
        
        // Security event processor
        processors.put(EventType.SECURITY_EVENT,
            ComposableFunction
                .<Event>of(this::validateSecurityEvent)
                .andThenComposable(this::enrichSecurityEvent)
                .composeIf(e -> e.isCritical(), this::alertSecurityTeam)
                .andThenComposable(this::processSecurityEvent)
                .safely()
                .withRetry(5, 500) // More aggressive retry for security events
        );
    }
    
    public CompletableFuture<ProcessingResult> processEventAsync(Event event) {
        return CompletableFuture.supplyAsync(() -> 
            FunctionUtils.doIfNotNull(event,
                e -> {
                    ComposableFunction<Event, ProcessingResult> processor = 
                        processors.get(e.getType());
                    
                    return FunctionUtils.doIfNotNull(processor,
                        p -> p.apply(e)
                    );
                }
            )
        );
    }
    
    public void processEventBatch(List<Event> events) {
        events.parallelStream()
            .forEach(event -> 
                FunctionUtils.doWhen(event,
                    Objects::nonNull,
                    e -> FunctionUtils.doWithoutThrows(() -> 
                        processEventAsync(e).get(5, TimeUnit.SECONDS)
                    )
                )
            );
    }
}

This functional programming library provides powerful abstractions for writing clean, composable, and resilient code with comprehensive error handling and conditional logic support, essential for building robust CAS applications.

Install with Tessl CLI

npx tessl i tessl/maven-org-apereo-cas--cas-server-core-util-api

docs

core-utilities.md

cryptography.md

functional-programming.md

generators.md

http-clients.md

index.md

jwt-utilities.md

serialization.md

specialized-utilities.md

spring-integration.md

text-processing.md

tile.json