### Complete Stream Resilience Setup (Java) Source: https://github.com/legacylands/legacy-lands-library/blob/main/player/README.md This Java example demonstrates setting up a resilient stream processing system. It configures a hybrid retry policy, a failure handler with monitoring capabilities, and a resilient task that utilizes virtual threads. The setup includes starting the resilient task and a monitoring loop to check system status. Dependencies include LegacyPlayerDataService, RedissonClient, and various retry/failure handling components from the library. ```java public class CompleteIntegrationExample { public void completeStreamResilienceSetup( LegacyPlayerDataService playerService, RedissonClient redissonClient) { // 1. Configure retry policy with hybrid counting RetryPolicy hybridPolicy = RetryPolicy.builder() .maxAttempts(5) .baseDelay(Duration.ofSeconds(1)) .exponentialBackoff(true) .retryCounterType(RetryCounterType.HYBRID) .distributedKeyPattern("critical:.*|payment:.*|inventory:.*") .useDistributedPredicate(key -> { // Custom logic for distributed vs local counting return key.contains("critical") || key.contains("payment") || key.contains("transaction"); }) .retryCondition(exception -> { // Comprehensive retry condition return exception instanceof IOException || exception instanceof ConnectException || exception instanceof RedisCommandTimeoutException || (exception instanceof RuntimeException && exception.getCause() instanceof SocketTimeoutException); }) .build(); // 2. Create failure handler with monitoring FailureHandler monitoringHandler = context -> { RetryPolicy policy = RetryPolicy.defaultPolicy(); if (context.getAttemptNumber() <= policy.getMaxAttempts() && policy.shouldRetry(context.getException())) { // Log retry attempt Log.warn("Retrying operation (attempt {}/{})", context.getAttemptNumber(), policy.getMaxAttempts()); return FailureHandlingResult.retry( policy.calculateDelay(context.getAttemptNumber()) ); } // Log final failure and compensate Log.error("Operation failed permanently after {} attempts", context.getAttemptNumber(), context.getException()); return FailureHandlingResult.giveUp( CompensationAction.composite( CompensationAction.LOG_FAILURE, CompensationAction.REMOVE_MESSAGE, customNotificationAction(context) ) ); }; // 3. Create resilient task with virtual threads TaskInterface virtualThreadInterface = new TaskInterface() { }; ResilientRStreamAccepterInvokeTask resilientTask = ResilientRStreamAccepterInvokeTask.create( playerService, List.of("your.package", "net.legacy.library.player"), List.of(PlayerLauncher.class.getClassLoader()), Duration.ofSeconds(2), monitoringHandler, virtualThreadInterface ); // 4. Start the resilient processing resilientTask.start(); // 5. Monitor the system CompletableFuture.runAsync(() -> { while (true) { try { Thread.sleep(30000); // Check every 30 seconds // Monitor retry counters if needed Log.info("Resilient stream processing is running"); } catch (InterruptedException e) { Thread.currentThread().interrupt(); break; } } }); } private CompensationAction customNotificationAction(FailureContext context) { return ctx -> { // Send notification to monitoring system notifyOperationFailure( ctx.getMessageId().toString(), ctx.getException().getClass().getSimpleName(), ctx.getAttemptNumber() ); }; } private void notifyOperationFailure(String messageId, String errorType, int attempts) { // Implementation for failure notification } } ``` -------------------------------- ### Java Basic Service Configuration Example Source: https://github.com/legacylands/legacy-lands-library/blob/main/player/README.md A Java code example demonstrating the basic initialization of the LegacyPlayerDataService. It shows the creation of MongoDB and Redis connection configurations and the service instantiation. ```java public class ServiceInitExample { public static void main(String[] args) { // 1. Create MongoDB connection config MongoDBConnectionConfig mongoConfig = MongoDBConnectionConfigFactory.create( "playerdb", // Database name "mongodb://localhost:27017/", // MongoDB connection URI UuidRepresentation.STANDARD // UUID representation ); // 2. Create Redis config Config redisConfig = new Config(); redisConfig.useSingleServer() .setAddress("redis://127.0.0.1:6379") .setDatabase(0) .setConnectionMinimumIdleSize(5) .setConnectionPoolSize(10); // 3. Create player data service (using default configuration) LegacyPlayerDataService service = LegacyPlayerDataService.of( "player-data-service", // Service name, used to distinguish multiple service instances mongoConfig, // MongoDB configuration redisConfig, // Redis configuration // List of packages to scan, for auto-discovering RStreamAccepter implementations List.of("your.package", "net.legacy.library.player"), // List of ClassLoaders for scanning annotations List.of(PlayerLauncher.class.getClassLoader()) ); } } ``` -------------------------------- ### Basic Resilience Setup for Stream Accepters (Java) Source: https://github.com/legacylands/legacy-lands-library/blob/main/player/README.md Demonstrates how to enable the resilience framework for discovered stream accepters with default settings. It initializes a resilient task with a specified duration for stream operations and starts it. Dependencies include the LegacyPlayerDataService and custom classes for package and classloader scanning. ```java public class ResilienceExample { public void basicResilience(LegacyPlayerDataService playerService) { // Enable resilience for all discovered stream accepters List basePackages = List.of("your.package", "net.legacy.library.player"); List classLoaders = List.of(PlayerLauncher.class.getClassLoader()); // Create resilient task with default settings (3 retries, exponential backoff) ResilientRStreamAccepterInvokeTask resilientTask = ResilientRStreamAccepterInvokeTask.ofResilient( playerService, basePackages, classLoaders, Duration.ofSeconds(5) ); resilientTask.start(); } } ``` -------------------------------- ### Starting the Task Scheduler Server (Bash) Source: https://github.com/legacylands/legacy-lands-library/blob/main/experimental/third-party-schedulers/task-scheduler-rust/README.md Provides command-line instructions for building and running the task scheduler server using Cargo. It covers basic startup, specifying a custom library directory, enabling TLS with server certificates, and configuring mutual TLS (mTLS) with client certificate authentication. Also includes options for starting in interactive CLI mode. ```bash cargo build --release # Without TLS, default library dir ('./libraries') ./target/release/task-scheduler --addr "0.0.0.0:50051" # Specify a custom library directory ./target/release/task-scheduler --addr "0.0.0.0:50051" --library-dir /path/to/custom/plugins # With TLS (server cert only) ./target/release/task-scheduler --addr "0.0.0.0:50051" --tls-cert path/to/server.crt --tls-key path/to/server.key # With TLS and Client Certificate Authentication (mTLS) ./target/release/task-scheduler --addr "0.0.0.0:50051" --tls-cert path/to/server.crt --tls-key path/to/server.key --tls-ca-cert path/to/client_ca.crt # Start in interactive CLI mode ./target/release/task-scheduler --cli # Or using cargo run (example with TLS and CLI): # cargo run --release -- --addr "0.0.0.0:50051" --tls-cert path/to/server.crt --tls-key path/to/server.key --cli ``` -------------------------------- ### TaskAutoStartAnnotation: Automatically Starting Tasks in Java Source: https://github.com/legacylands/legacy-lands-library/blob/main/commons/README.md Shows how to use `TaskAutoStartAnnotation` to automatically start a task upon application initialization. This simplifies task management by removing the need for manual instantiation and calling. ```java @TaskAutoStartAnnotation(isFromFairyIoC = false) public class Example implements TaskInterface> { @Override public ScheduledTask start() { // This is a simple example of a task that prints "Hello, world!" every second. return scheduleAtFixedRate(() -> System.out.println("Hello, world!"), 0, 20); } } ``` -------------------------------- ### Create SimplixBuilder and Yaml Instance (Java) Source: https://github.com/legacylands/legacy-lands-library/blob/main/configuration/README.md Demonstrates how to create a SimplixBuilder instance using the factory mode and then obtain a Yaml instance for data manipulation. This setup is thread-safe and prepares for data storage operations. ```java public class Example extends Plugin { @Override public void onPluginEnable() { SimplixBuilder simplixBuilder = SimplixBuilderFactory.createSimplixBuilder("example", "D:/"); Yaml yaml = simplixBuilder.createYaml(); // json / toml / yaml // do something eg: yaml.set("example", "test"); // thread safety // more about SimplixStorage: https://github.com/Simplix-Softworks/SimplixStorage/wiki } } ``` -------------------------------- ### Configure and Use Multi-Level Cache (Java) Source: https://github.com/legacylands/legacy-lands-library/blob/main/cache/README.md Demonstrates the setup and usage of a FlexibleMultiLevelCacheService by combining different cache levels, such as Caffeine and Redis. It shows how to define cache tiers and initialize the multi-level cache service. ```java /* * Multi-Level Cache */ Set> tiers = Set.of( // L1 cache is caffeine TieredCacheLevel.of("L1", caffeineCache.getResource()), // L2 cache is redis TieredCacheLevel.of("L2", redisCache.getResource()) ); FlexibleMultiLevelCacheService multiLevelCache = CacheServiceFactory.createFlexibleMultiLevelCacheService(tiers); // get cache ``` -------------------------------- ### MongoDB Usage Example (Java) Source: https://github.com/legacylands/legacy-lands-library/blob/main/mongodb/README.md This Java example demonstrates how to use `MongoDBConnectionFactory` to establish a connection, save `Person` objects, and query them using filters. It highlights thread safety considerations for iterators. ```java public class Example { public static void main(String[] args) { // test object Person person = new Person(); person.setUuid(UUID.randomUUID()); person.setName("Alice"); person.setAge(20); Person person2 = new Person(); person2.setUuid(UUID.randomUUID()); person2.setName("Alice"); person2.setAge(45); // create connection MongoDBConnectionConfig mongoConfig = MongoDBConnectionFactory.create( "example", "mongodb://localhost:27017/", UuidRepresentation.STANDARD ); // get datastore Datastore datastore = mongoConfig.getDatastore(); // save object datastore.save(person); datastore.save(person2); // find object, its thread safety @Cleanup MorphiaCursor iterator = datastore.find(Person.class) .filter(Filters.and( Filters.eq("_id", "2135ef6b-8915-4d4c-a677-b1f5482ed2aa"), // _id eq Filters.eq("name", "Alice"), // name eq Filters.gt("age", 35) // age > 35, it's time to lay off employees lol )) // It should be noted that iterators are not thread-safe .iterator(); // get iterator // just print for (Person person1 : iterator.toList()) { System.out.println(person1.getAge()); } } } @Data @Entity("persons") class Person { @Id private UUID uuid; private String name; private int age; } ``` -------------------------------- ### Initialize and Use Redis Cache (Java) Source: https://github.com/legacylands/legacy-lands-library/blob/main/cache/README.md Demonstrates initializing a Redis cache service using a provided configuration and performing basic cache operations like getting and setting values. It also shows how to acquire a lock for thread-safe operations on the Redis client. ```java public class CacheLauncher { public static void main(String[] args) { Config config = new Config(); config.useSingleServer().setAddress("redis://127.0.0.1:6379"); /* * Redis cache example */ RedisCacheServiceInterface redisCache = CacheServiceFactory.createRedisCache(config); // get method will return object type, getWithType can specify the return type int integer = redisCache.getWithType( // get cache value by key cache -> cache.getBucket("key").get(), // if cache miss, do this, like query from database () -> 1, // if cacheAfterQuery is true, do this, store to cache (cache, queryValue) -> cache.getBucket("key").set(queryValue), // cacheAfterQuery true ); // string String string = redisCache.getWithType( // get cache value by key cache -> cache.getBucket("key2").get(), // if cache miss, do this, like query from database () -> "qwq", // if cacheAfterQuery is true, do this, store to cache (cache, queryValue) -> cache.getBucket("key2").set(queryValue), // cacheAfterQuery true ); // for redisCacheService, it is recommended to use redissonClient to acquire the lock redisCache.execute( // get lock redissonClient -> redissonClient.getLock("a"), // do something redissonClient -> redissonClient.getBucket("a").get(), // lock settings LockSettings.of(1, 1, TimeUnit.MINUTES) ); } } ``` -------------------------------- ### Basic TaskChain Execution with Java Source: https://github.com/legacylands/legacy-lands-library/blob/main/commons/README.md Demonstrates the basic usage of the TaskChain builder to define, execute, and retrieve results from a sequence of tasks. It shows how to set execution modes, run tasks immediately or asynchronously, and access results by name or index. This example relies on the TaskChain class and associated builder methods. ```java public class TaskChainExample { public static void main(String[] args) { // Create task chain and execute multiple tasks TaskChain taskChain = TaskChain.builder() // Define the execution mode for the first task and execute immediately .withMode((taskInterface, task) -> { Log.info("Executing task: " + task); return "Result: " + task; }) // the task field in withMode method is: Task1 (can be null) .execute("Task1") // Continue adding the second task .then() .withMode((taskInterface, task) -> { Log.info("Executing task: " + task); return "Result: " + task; }) .run("Task2") // run is equivalent to execute, just more intuitive naming // Add named task for later access .then() .withMode((taskInterface, task) -> // task here is the second parameter of execute below CompletableFuture.supplyAsync(() -> { try { Thread.sleep(1000); } catch (InterruptedException e) { Thread.currentThread().interrupt(); } return "Calculation complete: " + Math.random(); })) // Task name: CalculationTask, the task field in withMode method above is: AsyncCalculation (can be null) .execute("CalculationTask", "AsyncCalculation") // Build the final task chain .build(); // Wait for all tasks to complete taskChain.join().get(5, TimeUnit.SECONDS); // Get result by name String result = taskChain.getResult("CalculationTask"); System.out.println("Calculation result: " + result); // Get result by index String indexResult = taskChain.getResult(2); System.out.println("Index 2 result: " + indexResult); System.out.println("Task chain contains " + taskChain.size() + " tasks"); } } ``` -------------------------------- ### Create and Execute Scheduled Task Chains in Java Source: https://github.com/legacylands/legacy-lands-library/blob/main/commons/README.md This Java example demonstrates how to build and execute a chain of scheduled tasks. It includes immediate execution tasks, delayed tasks with a specified delay, and tasks scheduled to run on virtual threads. The code shows how to configure task execution modes and retrieve results. ```java public class ScheduledTaskExample { public static void main(String[] args) { long startTime = System.currentTimeMillis(); TaskChain taskChain = TaskChain.builder() // Immediate execution task .withMode((taskInterface, task) -> { Log.info("Immediate execution: " + System.currentTimeMillis()); return "Immediate execution result"; }) .execute("ImmediateTask") // Task with 1-second delay .then() .withMode((taskInterface, task) -> taskInterface.schedule(() -> { Log.info("Delayed task execution: " + task); }, 20L)) // 1 seconds delay (20 ticks) .execute("DelayedTask", "DelayedTask") // Virtual thread scheduled task .then() .withMode((taskInterface, task) -> taskInterface.scheduleWithVirtualThread(() -> { Log.info("Virtual thread delayed task execution: " + task); }, 100, TimeUnit.MILLISECONDS)) .run("VirtualThreadDelayed", "VirtualThreadDelayedTask") .build(); // Wait for all tasks to complete taskChain.join().get(10, TimeUnit.SECONDS); // You can get the original Mode return values for advanced control ScheduledTask scheduledTask = taskChain.getModeResult("DelayedTask"); Object vtScheduledFuture = taskChain.getModeResult("VirtualThreadDelayed"); long executionTime = System.currentTimeMillis() - startTime; System.out.println("Total execution time: " + executionTime + "ms"); } } ``` -------------------------------- ### Thread-Safe Resource Management with AbstractLockable (Java) Source: https://github.com/legacylands/legacy-lands-library/blob/main/cache/README.md This Java example demonstrates how to use the `AbstractLockable` class for thread-safe resource management. It shows creating a lockable database connection, executing an operation under lock protection with specified lock settings, and retrieving a user. ```java public class CacheLauncher { public static void main(String[] args) { // Create an instance of the lockable resource (e.g., a database connection) DatabaseConnection dbConnection = new DatabaseConnection(); LockableInterface lockableDb = AbstractLockable.of(dbConnection); // Execute operations under lock protection User user = lockableDb.execute( // get lock conn -> new ReentrantLock(), // the operation to be performed under lock protection conn -> conn.queryUserById(123), // lock settings LockSettings.of(1, 1, TimeUnit.MINUTES) ); } } ``` -------------------------------- ### Initialize and Use Caffeine Cache (Java) Source: https://github.com/legacylands/legacy-lands-library/blob/main/cache/README.md Illustrates how to create and utilize a Caffeine cache service. It covers getting values, handling cache misses, storing new values, and performing thread-safe operations with locks. ```java /* * Caffeine cache example * * Cache * - cache key and cache value type */ CacheServiceInterface, String> caffeineCache = CacheServiceFactory.createCaffeineCache(); // get String qwq = caffeineCache.get( // get cache value by key cache -> cache.getIfPresent(1), // if cache miss, do this, like query from database () -> "qwq", // if cacheAfterQuery is true, do this, store to cache (cache, queryValue) -> cache.put(1, queryValue), // cacheAfterQuery true ); // get with lock String qwq2 = caffeineCache.get( // get lock cache -> new ReentrantLock(), // get cache value by key cache -> cache.getIfPresent(1), // if cache miss, do this, like query from database () -> "qwq", // if cacheAfterQuery is true, do this, store to cache (cache, queryValue) -> cache.put(1, queryValue), // cacheAfterQuery true, // lock settings LockSettings.of(1, 1, TimeUnit.MINUTES) ); // thread-safe execution of something caffeineCache.execute( // get lock cache -> new ReentrantLock(), // do something cache -> cache.getIfPresent(1), // lock settings LockSettings.of(1, 1, TimeUnit.MINUTES) ); /* * Most of caffeine's methods are thread-safe, * we can directly use getResource() to operate these methods. */ caffeineCache.getResource().put(2, "hi"); ``` -------------------------------- ### Main Binary Entry Point for Task Scheduler Source: https://github.com/legacylands/legacy-lands-library/blob/main/experimental/third-party-schedulers/task-scheduler-rust/README.md This Rust code snippet represents the main binary entry point for the Task Scheduler. It handles command-line argument parsing, initializes logging, starts the gRPC server using `tonic`, configures TLS if needed, and ensures built-in tasks are linked. It's the primary startup routine for the scheduler service. ```Rust mod logger; mod server; mod tasks; #[tokio::main] async fn main() -> Result<(), Box> { // 1. Parse command-line arguments (server address, TLS options) // let config = parse_args(); // 2. Initialize logging // logger::init_logger(); // 3. Start the gRPC server // let addr = config.server_address.parse().unwrap(); // let task_service = server::service::TaskSchedulerImpl::new(); // let mut builder = tonic::transport::Server::builder(); // if config.tls { /* configure TLS */ } // builder.add_service(task_service.into_grpc_server()) // .serve(addr) // .await?; // 4. Ensure built-in tasks are linked (handled by ctor and macros) Ok(()) } ``` -------------------------------- ### Java Object Validation Examples Source: https://github.com/legacylands/legacy-lands-library/blob/main/commons/README.md Demonstrates the usage of various object validation methods provided by a utility class. These include checking for null values, ensuring objects are not null with custom exceptions, and comparing object equality. ```java public class ObjectValidationExample { public static void main(String[] args) { Object obj = null; Object obj2 = "Hello"; if (ValidationUtil.isNull(obj)) { System.out.println("obj is null"); // Output: obj is null } ValidationUtil.requireNonNull(obj2, "obj2 cannot be null"); try { ValidationUtil.requireNonNull(obj, () -> new IllegalStateException("Object must not be null here.")); } catch (IllegalStateException exception) { System.err.println(exception.getMessage()); // Output: Object must not be null here. } String s1 = "test"; String s2 = new String("test"); // Same content, different object String s3 = "different"; // Compare content using Objects.equals if (ValidationUtil.equals(s1, s2)) { System.out.println("s1 and s2 are equal (content-wise)"); // Output: s1 and s2 are equal (content-wise) } ValidationUtil.requireEquals(s1, s2, "s1 and s2 must be equal"); try { ValidationUtil.requireEquals(s1, s3, () -> new RuntimeException("Strings must match")); } catch (RuntimeException exception) { System.err.println(exception.getMessage()); // Output: Strings must match } } } ``` -------------------------------- ### Protobuf Definition for Task Request and Response Source: https://github.com/legacylands/legacy-lands-library/blob/main/experimental/third-party-schedulers/task-scheduler-rust/README.md This example shows a simplified Protocol Buffers definition for the gRPC service. It includes `TaskRequest` which specifies the task to run, its arguments (as `Any` messages), and any dependencies. The `TaskResponse` returns the status and result of the executed task. ```protobuf syntax = "proto3"; import "google/protobuf/any.proto"; message TaskRequest { string method = 1; repeated google.protobuf.Any args = 2; repeated string dependencies = 3; } message TaskResponse { string task_id = 1; enum Status { SUCCESS = 0; FAILURE = 1; RUNNING = 2; } Status status = 2; string result = 3; } ``` -------------------------------- ### Java String Validation Examples Source: https://github.com/legacylands/legacy-lands-library/blob/main/commons/README.md Demonstrates the usage of various string validation methods provided by the ValidationUtil class. This includes checking for empty and blank strings, ensuring strings are not blank, validating length constraints, and verifying against regular expressions. It also shows how to use custom exceptions with the require methods. ```java public class StringValidationExample { public static void main(String[] args) { String emptyStr = ""; String blankStr = " "; String validStr = " example "; String numberStr = "12345"; Pattern numberPattern = Pattern.compile("\\d+"); if (ValidationUtil.isEmpty(emptyStr)) { System.out.println("emptyStr is empty"); // Output: emptyStr is empty } if (ValidationUtil.isBlank(blankStr)) { System.out.println("blankStr is blank"); // Output: blankStr is blank } if (ValidationUtil.notBlank(validStr)) { System.out.println("validStr is not blank"); // Output: validStr is not blank } ValidationUtil.requireNotBlank(validStr, "String must not be blank"); ValidationUtil.requireLengthBetween(validStr.trim(), 5, 10, "Trimmed length (example) must be between 5 and 10"); // "example" has length 7 ValidationUtil.requireMatches(numberStr, numberPattern, "String must contain only digits"); try { ValidationUtil.requireNotEmpty(emptyStr, () -> new NoSuchElementException("String is required.")); } catch (NoSuchElementException exception) { System.err.println(exception.getMessage()); // Output: String is required. } } } ``` -------------------------------- ### Initialize and Use Custom Cache (Java) Source: https://github.com/legacylands/legacy-lands-library/blob/main/cache/README.md Shows how to create a custom cache service, using a provided implementation like ConcurrentHashMap. It demonstrates how to obtain the underlying resource for direct manipulation. ```java /* * Custom cache example * * CacheServiceInterface, String> customCache * - value type * - impl cache type, e.g. Map * * CacheServiceFactory.createCustomCache(new ConcurrentHashMap<>()) * - impl cache, e.g. ConcurrentHashMap<> */ CacheServiceInterface, String> customCache = CacheServiceFactory.createCustomCache(new ConcurrentHashMap<>()); // get impl cache, we can use get, execute, and more method like other cache service Map cache = customCache.getResource(); ``` -------------------------------- ### Resilience Framework Configuration in Java Source: https://github.com/legacylands/legacy-lands-library/blob/main/player/README.md Illustrates how to configure the resilience framework, including setting up a resilient stream accepter with default or custom settings. It shows how to define custom retry policies with hybrid counting and failure handlers with compensation actions. ```java public class ResilienceConfigurationExample { public void configureResilience(LegacyPlayerDataService playerService) { // 1. Basic resilient stream accepter with default settings List basePackages = List.of("your.package", "net.legacy.library.player"); List classLoaders = List.of(PlayerLauncher.class.getClassLoader()); ResilientRStreamAccepterInvokeTask resilientTask = ResilientRStreamAccepterInvokeTask.ofResilient( playerService, basePackages, classLoaders, Duration.ofSeconds(5) ); resilientTask.start(); // 2. Custom retry policy with hybrid counting RetryPolicy hybridPolicy = RetryPolicy.builder() .maxAttempts(5) .baseDelay(Duration.ofSeconds(1)) .exponentialBackoff(true) .retryCounterType(RetryCounterType.HYBRID) .distributedKeyPattern("critical:.*") .retryCondition(ex -> ex instanceof IOException || ex instanceof ConnectException) .build(); // 3. Custom failure handler with compensation FailureHandler customHandler = FailureHandler.withPolicy( hybridPolicy, CompensationAction.composite( CompensationAction.LOG_FAILURE, CompensationAction.REMOVE_MESSAGE ) ); // 4. Create resilient accepter with custom configuration RStreamAccepterInterface originalAccepter = new YourCustomAccepter(); ResilientRStreamAccepter resilientAccepter = new ResilientRStreamAccepter( originalAccepter, customHandler, redissonClient ); } } ``` -------------------------------- ### TaskInterface: Scheduling Fixed-Rate Tasks in Java Source: https://github.com/legacylands/legacy-lands-library/blob/main/commons/README.md Illustrates how to use the TaskInterface to schedule a recurring task that prints a message every second. This example utilizes `scheduleAtFixedRate` for standard Java execution. ```java public class Example { public static void main(String[] args) { TaskInterface> taskInterface = new TaskInterface<>() { @Override public ScheduledTask start() { // This is a simple example of a task that prints "Hello, world!" every second. return scheduleAtFixedRate(() -> System.out.println("Hello, world!"), 0, 20); } }; // start the task taskInterface.start(); } } ``` -------------------------------- ### Java: Create and Manage SimplixStorage Configurations Source: https://context7.com/legacylands/legacy-lands-library/llms.txt Shows how to create and manage configurations using the SimplixStorage library, including setting and retrieving primitive values and custom serializable objects. It requires the `de.leonhard.storage` library and demonstrates automatic registration of serializers. ```java import net.legacy.library.configuration.factory.SimplixBuilderFactory; import net.legacy.library.configuration.annotation.SimplixSerializerSerializableAutoRegister; import de.leonhard.storage.Yaml; import de.leonhard.storage.SimplixBuilder; import de.leonhard.storage.internal.serialize.SimplixSerializable; import java.util.HashMap; import java.util.Map; // Custom serializable object class ItemStack { private String type; private int amount; private Map metadata; // Constructors, getters, setters... public void setType(String type) { this.type = type; } public String getType() { return type; } public void setAmount(int amount) { this.amount = amount; } public int getAmount() { return amount; } public void setMetadata(Map metadata) { this.metadata = metadata; } public Map getMetadata() { return metadata; } } // Auto-register serializer @SimplixSerializerSerializableAutoRegister class ItemStackSerializer implements SimplixSerializable { @Override public ItemStack deserialize(Object object) { if (!(object instanceof Map)) { return null; } Map map = (Map) object; ItemStack item = new ItemStack(); item.setType((String) map.get("type")); item.setAmount((Integer) map.get("amount")); item.setMetadata((Map) map.get("metadata")); return item; } @Override public Object serialize(ItemStack item) { Map map = new HashMap<>(); map.put("type", item.getType()); map.put("amount", item.getAmount()); map.put("metadata", item.getMetadata()); return map; } @Override public Class getClazz() { return ItemStack.class; } } // Use configuration public class ConfigManager { private final Yaml config; public ConfigManager() { SimplixBuilder builder = SimplixBuilderFactory.createSimplixBuilder( "config.yml", "plugins/MyPlugin" ); this.config = builder.createYaml(); } public void saveAndLoadData() { // Save primitive values config.set("server.port", 25565); config.set("server.name", "My Server"); config.set("features.pvp", true); // Save custom objects (uses registered serializer) ItemStack diamond = new ItemStack(); diamond.setType("DIAMOND"); diamond.setAmount(64); config.set("rewards.daily", diamond); // Read values int port = config.getInt("server.port"); String name = config.getString("server.name"); boolean pvp = config.getBoolean("features.pvp"); // Read custom objects ItemStack reward = config.get("rewards.daily", ItemStack.class); System.out.println("Daily reward: " + reward.getAmount() + "x " + reward.getType()); // Save to file config.write(); } } ``` -------------------------------- ### VarHandleReflectionInjector: Assigning VarHandle Fields in Java Source: https://github.com/legacylands/legacy-lands-library/blob/main/commons/README.md Demonstrates the usage of VarHandleReflectionInjector to set values for fields managed by VarHandle. This example shows how to assign a value to a `tField` using its associated `TField_HANDLE`. ```java public class Example { public static void main(String[] args) { Test test = new Test(); // we can use TField_HANDLE Test.TField_HANDLE.set(test, 2); // prints 2 System.out.println(test.getTField()); } } ``` ```java @Getter @Setter public class Test { private volatile int tField = 100; @VarHandleAutoInjection(fieldName = "tField") public static VarHandle TField_HANDLE; static { /* * This class is a singleton and is managed by Fairy IoC. * Of course, it is also allowed to create it directly using the factory or directly creating it. * This is not so strict. */ InjectorFactory.createVarHandleReflectionInjector().inject(Test.class); } } ``` -------------------------------- ### Serialize and Deserialize Objects using SimplixSerializer (Java) Source: https://github.com/legacylands/legacy-lands-library/blob/main/configuration/README.md Provides examples of using the SimplixSerializer utility class for serializing a 'plant' object to a string and deserializing a string back into a 'Plant' object. This assumes the necessary serializable implementation is in place. ```java public class Example { public static void main(String[] args) { SimplixSerializer.serialize(plant).toString(); SimplixSerializer.deserialize(plantString, Plant.class); } } ``` -------------------------------- ### Manage Script Variables with Scopes Source: https://github.com/legacylands/legacy-lands-library/blob/main/script/README.md Illustrates how to use ScriptScope to isolate variable environments and manage script variables. This includes setting, getting, and removing variables within a script execution context. Note that V8ScriptEngine does not support ScriptScope and will ignore it. ```java public class Example { public static void main(String[] args) { RhinoScriptEngine scriptEngine = new RhinoScriptEngine(); try { // Create a script scope RhinoScriptScope scriptScope = RhinoScriptScope.of(scriptEngine); // Set variables scriptScope.setVariable("x", 10); scriptScope.setVariable("name", "Legacy"); // Execute a script in the scope Object result = scriptEngine.execute("'Hello, ' + name + '! x = ' + x", scriptScope); System.out.println(result); // Output: Hello, Legacy! x = 10 // Get a variable Object value = scriptScope.getVariable("name"); System.out.println(value); // Output: Legacy // Remove a variable scriptScope.removeVariable("name"); } catch (ScriptException exception) { exception.printStackTrace(); } } } ``` -------------------------------- ### Build Multi-Tier Cache with Redis and Caffeine (Java) Source: https://context7.com/legacylands/legacy-lands-library/llms.txt Illustrates the construction of a flexible multi-level cache system combining an in-memory Caffeine cache (L1) with a distributed Redis cache (L2). It shows how to configure Redis using Redisson and integrate different cache tiers using `TieredCacheLevel` and `FlexibleMultiLevelCacheService`. Accessing data from specific tiers is also demonstrated. ```java import net.legacy.library.cache.factory.CacheServiceFactory; import net.legacy.library.cache.service.CacheServiceInterface; import net.legacy.library.cache.service.multi.FlexibleMultiLevelCacheService; import net.legacy.library.cache.service.multi.TieredCacheLevel; import net.legacy.library.cache.service.redis.RedisCacheServiceInterface; import com.github.benmanes.caffeine.cache.Cache; import org.redisson.config.Config; import org.redisson.api.RedissonClient; import java.util.Set; import java.util.Optional; public class MultiTierCacheSystem { private final FlexibleMultiLevelCacheService multiLevelCache; public MultiTierCacheSystem() { // Create L1 (Caffeine) cache CacheServiceInterface, String> l1Cache = CacheServiceFactory.createCaffeineCache(); // Create L2 (Redis) cache Config redisConfig = new Config(); redisConfig.useSingleServer() .setAddress("redis://localhost:6379") .setDatabase(0); RedisCacheServiceInterface l2Cache = CacheServiceFactory.createRedisCache(redisConfig); // Build multi-level cache Set> tiers = Set.of( TieredCacheLevel.of("L1-Local", l1Cache.getResource()), TieredCacheLevel.of("L2-Redis", l2Cache.getResource()) ); this.multiLevelCache = CacheServiceFactory.createFlexibleMultiLevelCacheService(tiers); } public void useMultiTierCache(String key) { // Access L1 cache Optional> l1 = multiLevelCache.getCacheLevel("L1-Local"); if (l1.isPresent()) { CacheServiceInterface, String> l1Service = l1.get().getCacheWithType(); String value = l1Service.getResource().getIfPresent(key); System.out.println("L1 value: " + value); } // Access L2 cache Optional> l2 = multiLevelCache.getCacheLevel("L2-Redis"); if (l2.isPresent()) { RedisCacheServiceInterface l2Service = l2.get().getCacheWithType(); RedissonClient client = l2Service.getResource(); String value = client.getBucket(key).get(); System.out.println("L2 value: " + value); } } } ``` -------------------------------- ### Basic Retry Counter Usage in Java Source: https://github.com/legacylands/legacy-lands-library/blob/main/player/README.md Demonstrates the creation and basic operations of different retry counter types: local (in-memory), distributed (Redis-based), and hybrid. It shows how to increment, get, check existence, and reset counters, with operations returning CompletableFuture. ```java public class RetryCounterExample { public void basicRetryCounters(RedissonClient redissonClient) { // 1. Local retry counter (in-memory, high performance) RetryCounter localCounter = LocalRetryCounter.create(); // 2. Distributed retry counter (Redis-based, globally consistent) RetryCounter distributedCounter = DistributedRetryCounter.create(redissonClient); // 3. Hybrid retry counter (intelligent selection) RetryCounter hybridCounter = HybridRetryCounter.create( redissonClient, key -> key.startsWith("critical:") // Use distributed for critical operations ); // Basic operations (all methods return CompletableFuture) CompletableFuture count = localCounter.increment("operation:123"); CompletableFuture countWithTTL = localCounter.increment("operation:123", Duration.ofMinutes(5)); CompletableFuture currentCount = localCounter.get("operation:123"); CompletableFuture exists = localCounter.exists("operation:123"); CompletableFuture reset = localCounter.reset("operation:123"); } } ``` -------------------------------- ### Java: Pre-compile Scripts for Optimal Performance with Rhino Source: https://context7.com/legacylands/legacy-lands-library/llms.txt Demonstrates how to pre-compile JavaScript scripts using the Rhino engine to significantly improve execution speed. This is useful for frequently used or computationally intensive scripts. It includes a benchmark comparing compiled vs. uncompiled script execution. ```java import javax.script.ScriptException; import jdk.nashorn.api.scripting.ScriptEngineFactory; import jdk.nashorn.api.scripting.ScriptEngineInterface; public class OptimizedScriptExecution { private final ScriptEngineInterface engine; private final Object compiledDamageCalc; public OptimizedScriptExecution() throws ScriptException { this.engine = ScriptEngineFactory.createRhinoScriptEngine(); // Pre-compile frequently-used script String damageScript = """ function calculateDamage(base, modifier) { return base * modifier * (1 + Math.random() * 0.2); } """; this.compiledDamageCalc = engine.compile(damageScript); } public void performanceBenchmark() throws ScriptException { // Without compilation - slow long start1 = System.nanoTime(); for (int i = 0; i < 1000; i++) { engine.execute("function calc(x) { return x * 2; }"); engine.invokeFunction("calc", i); } long time1 = (System.nanoTime() - start1) / 1_000_000; // With compilation - 30x faster String script = "function calc(x) { return x * 2; }"; Object compiled = engine.compile(script); long start2 = System.nanoTime(); for (int i = 0; i < 1000; i++) { engine.executeCompiled(compiled, null); engine.invokeCompiledFunction(compiled, "calc", null, i); } long time2 = (System.nanoTime() - start2) / 1_000_000; System.out.println("Without compilation: " + time1 + "ms"); System.out.println("With compilation: " + time2 + "ms"); System.out.println("Speedup: " + (time1 / time2) + "x"); } public double calculateDamage(double base, double modifier) throws ScriptException { // Execute pre-compiled script - extremely fast engine.executeCompiled(compiledDamageCalc, null); return (Double) engine.invokeCompiledFunction( compiledDamageCalc, "calculateDamage", base, modifier ); } } ``` -------------------------------- ### Initialize Legacy Entity Service Source: https://github.com/legacylands/legacy-lands-library/blob/main/player/README.md Demonstrates how to initialize the LegacyEntityDataService. This involves providing service name, MongoDB and Redis configurations, and package scan lists for entity discovery. Dependencies include MongoDB and Redis client configurations. ```java public class EntityServiceExample { public void initEntityService() { // Create entity data service LegacyEntityDataService entityService = LegacyEntityDataService.of( "game-entity-service", // Service name mongoConfig, // MongoDB configuration redisConfig, // Redis configuration List.of("your.package", "net.legacy.library.player"), // Package scan list List.of(PlayerLauncher.class.getClassLoader()) // ClassLoader list ); } } ``` -------------------------------- ### Retry Policy Patterns in Java Source: https://github.com/legacylands/legacy-lands-library/blob/main/player/README.md Showcases various patterns for configuring retry policies, including policies for specific exception types, conservative retries, fast retries, and hybrid or distributed counting strategies. It also includes an example of disabling retries for a fail-fast approach. ```java public class RetryPolicyPatternsExample { public void demonstratePolicyPatterns() { // 1. Network error retry (exponential backoff for IO operations) RetryPolicy networkPolicy = RetryPolicy.forExceptionTypes( IOException.class, ConnectException.class, SocketTimeoutException.class ); // 2. Conservative retry (fewer attempts, longer delays) RetryPolicy conservativePolicy = RetryPolicy.builder() .maxAttempts(2) .baseDelay(Duration.ofSeconds(5)) .exponentialBackoff(true) .maxDelay(Duration.ofMinutes(2)) .build(); // 3. Fast retry (more attempts, shorter delays) RetryPolicy fastPolicy = RetryPolicy.builder() .maxAttempts(5) .baseDelay(Duration.ofMillis(500)) .exponentialBackoff(true) .maxDelay(Duration.ofSeconds(10)) .build(); // 4. Hybrid counting with distributed coordination RetryPolicy hybridPolicy = RetryPolicy.withHybridCounting("payment:.*|inventory:.*"); // 5. Distributed counting for all operations RetryPolicy distributedPolicy = RetryPolicy.withDistributedCounting(); // 6. No retry policy (fail fast) RetryPolicy noRetryPolicy = RetryPolicy.noRetry(); } } ``` -------------------------------- ### Build and Execute Task Chains with Named Results (Java) Source: https://context7.com/legacylands/legacy-lands-library/llms.txt Demonstrates building a task chain using TaskChain.builder(). Each stage can have a defined mode for execution (e.g., virtual thread, scheduled tasks). Results from each task can be retrieved by their assigned name. ```java import net.legacy.library.commons.task.TaskChain; import net.legacy.library.commons.task.TaskInterface; import io.fairyproject.mc.scheduler.MCSchedulers; import java.util.concurrent.TimeUnit; public class DataProcessingPipeline { public void processUserData(UUID userId) throws Exception { // Build a task chain with multiple stages TaskChain chain = TaskChain.builder() .withMode((ti, task) -> ti.submitWithVirtualThreadAsync(() -> { return fetchUserFromDatabase(task); })) .execute("fetchUser", userId) .then() .withMode((ti, task) -> ti.scheduleAtFixedRate(() -> { return enrichUserData(task); }, 0, 20)) .execute("enrichData", userId) .then() .withMode((ti, task) -> ti.schedule(() -> { return validateAndSave(task); }, 40)) .run("saveData", userId) .build(); // Wait for all tasks with timeout chain.join().get(10, TimeUnit.SECONDS); // Retrieve results by name User user = chain.getResult("fetchUser"); EnrichedData enriched = chain.getResult("enrichData"); Boolean saved = chain.getResult("saveData"); System.out.println("Processed user: " + user.getName()); System.out.println("Enrichment level: " + enriched.getLevel()); System.out.println("Save successful: " + saved); // Access all results List allResults = chain.getAllModeResults(); System.out.println("Total tasks executed: " + chain.size()); } private User fetchUserFromDatabase(UUID userId) { // Simulate database fetch return new User(userId, "PlayerName"); } private EnrichedData enrichUserData(UUID userId) { // Enrich with additional data return new EnrichedData(userId, "gold", 50); } private Boolean validateAndSave(UUID userId) { // Validate and save to storage return true; } } ``` -------------------------------- ### Configure Advanced LegacyPlayerDataService Source: https://github.com/legacylands/legacy-lands-library/blob/main/player/README.md Demonstrates creating a LegacyPlayerDataService instance with custom configurations, including auto-save intervals, package scanning for entity discovery, and Redis stream polling intervals. This allows fine-tuning of the service's behavior beyond default settings. ```java public class AdvancedServiceInitExample { public static void main(String[] args) { // Create service with custom configuration LegacyPlayerDataService customService = LegacyPlayerDataService.of( "custom-player-service", mongoConfig, redisConfig, Duration.ofMinutes(15), // Auto-save interval (default 2 hours) List.of("your.package", "net.legacy.library.player"), List.of(PlayerLauncher.class.getClassLoader()), Duration.ofSeconds(1) // Redis Stream polling interval (default 2 seconds) ); } } ```