### Visualize Action Flow Diagram Source: https://github.com/neowu/core-ng-project/blob/master/CHANGELOG_2021.md Example URL to visualize the action flow diagram for a given action ID. Requires the log-processor module. ```URL https://localhost:8443/diagram/action?actionId=7A356AA3B1A5C6740794 ``` -------------------------------- ### Test Database Initialization Source: https://github.com/neowu/core-ng-project/blob/master/CHANGELOG_2017.md Added support for testing database initialization, running scripts, and creating schemas. This facilitates automated testing of database setup and migrations. ```java support test initDB(), runscript and createSchema ``` -------------------------------- ### Job Implementation Example Source: https://context7.com/neowu/core-ng-project/llms.txt Implement the `Job` interface for background tasks. Access job context to retrieve scheduled time and perform business logic. ```java public class DailyReportJob implements Job { @Inject ReportService reportService; @Inject EmailService emailService; @Override public void execute(JobContext context) throws Exception { // context.scheduledTime() gives the intended trigger time (not actual wall clock) LocalDate reportDate = context.scheduledTime().toLocalDate().minusDays(1); byte[] report = reportService.generateDailyReport(reportDate); emailService.sendReport("reports@example.com", reportDate, report); } } ``` -------------------------------- ### Forwarding Actions Based on Result in Java Source: https://github.com/neowu/core-ng-project/blob/master/CHANGELOG_2022.md Example of forwarding actions based on their result, such as only forwarding 'OK' actions. ```java log-processor: action forward supports by result > e.g. only forward OK actions ``` -------------------------------- ### Core-NG as a Scripting Application Source: https://github.com/neowu/core-ng-project/blob/master/CHANGELOG_2017.md Create `Application.configure()` and `Application.start()` methods to enable Core-NG to be used as a script for testing or scripting purposes. This simplifies the setup and execution of Core-NG in non-server environments. ```java create Application.configure()/start(), to make core-ng be used as script for testing/scripting ``` -------------------------------- ### SQL Multiply Operator Example Source: https://github.com/neowu/core-ng-project/blob/master/CHANGELOG_2021.md Example of using the 'multiply operator' (not wildcard) in SQL queries, such as selecting a column multiplied by a number. ```sql select column*3 from table ``` -------------------------------- ### Configure Log Forwarding to Kafka Source: https://github.com/neowu/core-ng-project/blob/master/CHANGELOG_2021.md Configure log forwarding to another Kafka instance for data warehouse sinks. Environment variables must start with APP_. ```yaml - name: APP_LOG_FORWARD_CONFIG value: | { "kafkaURI": "kafka-0.kafka", "action": { "topic": "action", "apps": ["website", "mobile-api"], "ignoreErrorCodes": ["FORBIDDEN", "PATH_NOT_FOUND", "UNAUTHORIZED", "METHOD_NOT_ALLOWED"] } } ``` -------------------------------- ### API Config JSON Schema Change Source: https://github.com/neowu/core-ng-project/blob/master/CHANGELOG_2021.md Example of the new API configuration JSON schema, changed from a map to a List for simplification. Requires the latest framework. ```JSON { "api": { "services": ["https://website", "https://backoffice"] } } ``` -------------------------------- ### RabbitMQ Default Credentials Source: https://github.com/neowu/core-ng-project/blob/master/CHANGELOG_2017.md Set the default RabbitMQ user and password to `rabbitmq/rabbitmq`. This simplifies initial setup and testing of RabbitMQ integration. ```java rabbitmq: make default user/password to rabbitmq/rabbitmq ``` -------------------------------- ### Update Rate Control Configuration in Java Source: https://github.com/neowu/core-ng-project/blob/master/CHANGELOG_2022.md Provides an intuitive API for rate control configuration. Example: add("group", 10, 5, Duration.ofSeconds(1)) keeps 10 permits and fills 5 permits every second. ```java add("group", 10, 5, Duration.ofSeconds(1)) ``` ```java add("group", 20, 10, Duration.ofMinutes(5)) ``` -------------------------------- ### ProductService API Source: https://context7.com/neowu/core-ng-project/llms.txt Defines the typed REST service interface for product-related operations, including methods for getting, creating, deleting, and searching products. This interface can be used on both the server side as an implementation and on the client side as a type-safe proxy. ```APIDOC ## ProductService API ### Description Defines the typed REST service interface for product-related operations, including methods for getting, creating, deleting, and searching products. This interface can be used on both the server side as an implementation and on the client side as a type-safe proxy. ### Methods #### Get Product ##### Method GET ##### Endpoint /api/products/:id ##### Parameters ###### Path Parameters - **id** (String) - Required - The ID of the product to retrieve. #### Create Product ##### Method POST ##### Endpoint /api/products ##### Request Body - **request** (CreateProductRequest) - Required - The product details to create. ##### Response ###### Success Response (201 Created) - **ProductResponse** - The created product details. #### Delete Product ##### Method DELETE ##### Endpoint /api/products/:id ##### Parameters ###### Path Parameters - **id** (String) - Required - The ID of the product to delete. ##### Response ###### Success Response (204 No Content) - No content is returned. #### Search Products ##### Method GET ##### Endpoint /api/products ##### Parameters ###### Query Parameters - **category** (String) - Optional - The category to filter products by. - **page** (Integer) - Optional - The page number for search results. ##### Response ###### Success Response (200 OK) - **List** - A list of product responses matching the search criteria. ``` -------------------------------- ### Notification Channel Configuration Source: https://github.com/neowu/core-ng-project/blob/master/CHANGELOG_2021.md Example of the updated alert configuration for notification channels, supporting multiple matchers per channel. This change affects how alerts are routed based on severity, indices, error codes, and applications. ```JSON "notifications": [ {"channel": "backendWarnChannel", "matcher": {"severity": "WARN", "indices": ["trace", "stat"]}}, {"channel": "backendErrorChannel", "matcher": {"severity": "ERROR", "indices": ["trace", "stat"]}}, {"channel": "frontendWarnChannel", "matcher": {"severity": "WARN", "indices": ["event"]}}, {"channel": "frontendWarnChannel", "matcher": {"severity": "WARN", "errorCodes": ["API_CHANGED"], "indices": ["stat"]}}, {"channel": "frontendErrorChannel", "matcher": {"severity": "ERROR", "indices": ["event"]}}, {"channel": "frontendErrorChannel", "matcher": {"severity": "ERROR", "errorCodes": ["API_CHANGED"], "indices": ["stat"]}}, {"channel": "additionalErrorCodeChannel", "matcher": {"apps": ["product-service"], "errorCodes": ["PRODUCT_ERROR"]}} ] ``` -------------------------------- ### Application Bootstrapping with Core NG Source: https://context7.com/neowu/core-ng-project/llms.txt Demonstrates how to bootstrap a Core NG application by extending the App class and configuring subsystems within the initialize() method. Load properties, configure the HTTP server, register routes, and load sub-modules. ```java public class Main { public static void main(String[] args) { new CustomerApp().start(); } } ``` ```java public class CustomerApp extends App { @Override protected void initialize() { loadProperties("app.properties"); // configure HTTP server http().listenHTTP("8080"); http().gzip(); http().maxProcessTime(Duration.ofSeconds(25)); // register a route http().route(HTTPMethod.GET, "/health", request -> Response.text("ok")); // load sub-modules load(new CustomerModule()); load(new OrderModule()); } } ``` ```java public class CustomerModule extends Module { @Override protected void initialize() { // configure DB db().url(requiredProperty("db.url")); db().user(requiredProperty("db.user")); db().password(requiredProperty("db.password")); db().poolSize(5, 20); Repository customerRepo = db().repository(Customer.class); // bind service bean and inject the repo CustomerService service = bind(CustomerService.class); // service gets @Inject fields populated automatically } } ``` -------------------------------- ### Measure Startup and DB Schema Creation Time Source: https://github.com/neowu/core-ng-project/blob/master/CHANGELOG_2017.md Added measurements for startup time and the time taken for test database schema creation. This helps in identifying performance bottlenecks during application startup and testing. ```java measure startup time measure time on test db schema creation ``` -------------------------------- ### Enable Java 16 Native Library Loading Source: https://github.com/neowu/core-ng-project/blob/master/CHANGELOG_2021.md To use adoptopenjdk/openjdk16:alpine-jre, add 'RUN apk add --no-cache gcompat' to your Dockerfile. This is required for the kafka/snappy library to load native libraries. ```dockerfile RUN apk add --no-cache gcompat ``` -------------------------------- ### Core-NG Project Directory Structure Source: https://github.com/neowu/core-ng-project/wiki/Project Illustrates the standard directory layout for core-ng applications using Gradle, including configuration, main, and test directories. ```plaintext /gradle /application |-conf |-${env}/resources |-main |-java |-resources |-test |-java |-resources build.gradle ``` -------------------------------- ### YAML Loading for DB Initialization Source: https://github.com/neowu/core-ng-project/blob/master/CHANGELOG_2017.md Load database initialization data using `YAML.load(ClasspathResources.text())` instead of `module.loadYML()`. For batch inserts, load a list from YAML and then call `repository.batchInsert()`. ```java removed module.loadYML(), use YAML.load(ClasspathResources.text()) instead, for db init data, use YAML loadlist then call repository.batchInsert ``` -------------------------------- ### MongoCollection Operations Source: https://context7.com/neowu/core-ng-project/llms.txt Offers CRUD and aggregation functionalities for MongoDB documents. Supports insert, get, findOne, find, forEach, aggregate, replace, update, and bulk delete operations. ```APIDOC ## MongoCollection ### Description Provides CRUD and aggregation operations for MongoDB documents, including insert, get, findOne, find, forEach, aggregate, replace, update, and bulk delete. ### Methods - **insert(T document)**: Inserts a single document. - **get(String id)**: Retrieves a document by its ID. - **find(Filter filter)**: Finds documents matching the given filter. - **findOne(FindOne findOneConfig)**: Finds a single document based on filter and sort criteria. - **count(Filter filter)**: Counts the number of documents matching the filter. - **delete(Filter filter)**: Deletes documents matching the filter. - **aggregate(Aggregate aggregateConfig)**: Performs an aggregation pipeline on the collection. ``` -------------------------------- ### Create Product Controller Source: https://context7.com/neowu/core-ng-project/llms.txt Handles HTTP requests to create a product. It deserializes a typed JSON body, accesses query parameters and session data, calls business logic, and returns a JSON response. ```java public class CreateProductController implements Controller { @Inject ProductService productService; @Override public Response execute(Request request) throws Exception { // deserialize typed JSON body with validation CreateProductRequest body = request.bean(CreateProductRequest.class); // access query params String category = request.queryParams().getOrDefault("category", "default"); // access session Session session = request.session(); String userId = session.get("userId").orElseThrow(() -> new ForbiddenException()); // call business logic ProductResponse product = productService.create(userId, body); // return JSON response with 201 return Response.bean(product).status(HTTPStatus.CREATED); } } // Bean definitions (used with @Property for JSON field names) public class CreateProductRequest { @NotNull @Property(name = "name") public String name; @NotNull @Min(0) @Property(name = "price") public BigDecimal price; } public class ProductResponse { @Property(name = "id") public String id; @Property(name = "name") public String name; } ``` -------------------------------- ### MongoCollection CRUD and Aggregation for MongoDB Source: https://context7.com/neowu/core-ng-project/llms.txt Provides methods for interacting with MongoDB collections, including insert, get, find, aggregate, update, and delete operations. Requires core-ng-mongo module configuration. ```java // Document class @Collection(name = "events") public class EventDocument { @Id public String id; @Field(name = "user_id") public String userId; @Field(name = "event_type") public String eventType; @Field(name = "created_time") public LocalDateTime createdTime; } ``` ```java // Usage public class EventRepository { @Inject MongoCollection events; public void save(EventDocument event) { events.insert(event); } public Optional findById(String id) { return events.get(id); } public List findByUser(String userId) { return events.find(Filters.eq("user_id", userId)); } public Optional findLatestLogin(String userId) { var findOne = new FindOne(); findOne.filter = Filters.and(Filters.eq("user_id", userId), Filters.eq("event_type", "login")); findOne.sort = Sorts.descending("created_time"); return events.findOne(findOne); } public long countUserEvents(String userId) { return events.count(Filters.eq("user_id", userId)); } public void deleteOldEvents(LocalDateTime before) { events.delete(Filters.lt("created_time", before)); } public List aggregateByType(String userId) { var agg = new Aggregate(); agg.pipeline = List.of( Aggregates.match(Filters.eq("user_id", userId)), Aggregates.group("$event_type", Accumulators.sum("count", 1)) ); agg.resultClass = EventSummary.class; return events.aggregate(agg); } } ``` -------------------------------- ### Gradle Environment Variable Configuration Source: https://github.com/neowu/core-ng-project/wiki/Project Demonstrates how to pass environment variables to Gradle builds for configuring application settings. ```bash gradle -Penv=${env} clean build ``` -------------------------------- ### HTTPClient Usage Source: https://context7.com/neowu/core-ng-project/llms.txt Demonstrates how to build and use an HTTPClient for making outbound HTTP requests, including setting timeouts, retries, and authentication. ```APIDOC ## HTTPClient / HTTPRequest / HTTPResponse — Outbound HTTP calls `HTTPClient` (built via `HTTPClientBuilder`) wraps OkHttp with retries, connection pooling, SSL configuration, and per-request timeouts. ### Building an HTTPClient ```java // Build a client (typically in a module, bound as singleton) public class ExternalApiModule extends Module { @Override protected void initialize() { HTTPClient httpClient = HTTPClient.builder() .userAgent("MyService/1.0") .connectTimeout(Duration.ofSeconds(5)) .timeout(Duration.ofSeconds(30)) .keepAlive(Duration.ofMinutes(1)) .maxRetries(3) .retryWaitTime(Duration.ofMillis(500)) .trustAll() // or .trust(pemCert) for specific CA .build(); bind(httpClient); } } ``` ### Making an HTTP Request ```java // Usage public class PaymentGatewayClient { @Inject HTTPClient httpClient; public PaymentResponse charge(ChargeRequest chargeRequest) { var request = new HTTPRequest(HTTPMethod.POST, "https://api.payment-gateway.com/v1/charges"); request.accept(ContentType.APPLICATION_JSON); request.bearerAuth("api-key-here"); request.body(JSON.toJSON(chargeRequest), ContentType.APPLICATION_JSON); request.timeout = Duration.ofSeconds(45); // per-request override HTTPResponse response = httpClient.execute(request); if (response.statusCode != 200) { throw new RuntimeException("payment failed, status=" + response.statusCode + ", body=" + response.text()); } return JSON.fromJSON(PaymentResponse.class, response.text()); } public void downloadReport(String url, Path outputPath) { var request = new HTTPRequest(HTTPMethod.GET, url); request.params.put("format", "csv"); request.params.put("date", "2024-01-01"); // requestURI() produces: url?format=csv&date=2024-01-01 HTTPResponse response = httpClient.execute(request); // process response.body ... } } ``` ``` -------------------------------- ### Environment Property Renaming and Aggregation Preparation Source: https://github.com/neowu/core-ng-project/blob/master/CHANGELOG_2017.md Renamed the `-Dcore.web` property to `-Dcore.webPath` and added `-Dcore.appName`. This prepares the system for log aggregation by providing a more specific path and application name. ```java internal: renamed -Dcore.web to -Dcore.webPath, added -Dcore.appName, prepare for log aggregating ``` -------------------------------- ### Configure and Use Direct Redis Access Source: https://context7.com/neowu/core-ng-project/llms.txt Set up a pooled Redis client using redis().host(), redis().password(), redis().poolSize(), and redis().timeout(). The Redis interface provides access to string, hash, list, set, sorted-set, and admin operations. Use set with expiration for timed keys, and set with NX flag for acquiring locks. ```java // Configuration public class RedisModule extends Module { @Override protected void initialize() { redis().host(requiredProperty("redis.host")); redis().password(requiredProperty("redis.password")); redis().poolSize(5, 20); redis().timeout(Duration.ofSeconds(2)); } } // Usage public class SessionStore { @Inject Redis redis; public void saveSession(String sessionId, String userId) { // set with expiration redis.set("session:" + sessionId, userId, Duration.ofHours(2)); } public Optional getSession(String sessionId) { return Optional.ofNullable(redis.get("session:" + sessionId)); } public void extendSession(String sessionId) { redis.expire("session:" + sessionId, Duration.ofHours(2)); } public void deleteSession(String sessionId) { redis.del("session:" + sessionId); } public void saveUserAttributes(String userId, Map attributes) { redis.hash().multiSet("user:" + userId, attributes); } public Map getUserAttributes(String userId) { return redis.hash().getAll("user:" + userId); } public long increment(String key) { return redis.increaseBy(key, 1); } public boolean acquireLock(String lockKey, String token) { // set only if absent (NX) return redis.set(lockKey, token, Duration.ofSeconds(30), true); } public void iterateKeys(String pattern) { redis.forEach(pattern, key -> System.out.println("found: " + key)); } } ``` -------------------------------- ### Build HTTPClient with custom configuration Source: https://context7.com/neowu/core-ng-project/llms.txt Builds an HTTPClient instance with specific configurations like user agent, timeouts, keep-alive, retries, and trust settings. Typically bound as a singleton in a module. ```java public class ExternalApiModule extends Module { @Override protected void initialize() { HTTPClient httpClient = HTTPClient.builder() .userAgent("MyService/1.0") .connectTimeout(Duration.ofSeconds(5)) .timeout(Duration.ofSeconds(30)) .keepAlive(Duration.ofMinutes(1)) .maxRetries(3) .retryWaitTime(Duration.ofMillis(500)) .trustAll() // or .trust(pemCert) for specific CA .build(); bind(httpClient); } } ``` -------------------------------- ### Configure and Use Typed Cache (Local or Redis) Source: https://context7.com/neowu/core-ng-project/llms.txt Configure local or Redis-backed caches using cache().redis() or cache().local(). Add cache entries with specific types and durations. The Cache interface supports get-with-loader, put, evict, and getAll operations. ```java // Configuration public class CacheModule extends Module { @Override protected void initialize() { // Option 1: Redis-backed cache().redis(requiredProperty("redis.host")); // Option 2: local in-memory // cache().local(); // cache().maxLocalSize(5000); cache().add(ProductResponse.class, Duration.ofMinutes(10)); cache().add(UserProfile.class, Duration.ofHours(1)); } } // Usage public class ProductCacheService { @Inject Cache productCache; @Inject ProductRepository productRepository; public ProductResponse getProduct(String id) { // loader is called only on cache miss; must not return null return productCache.get(id, key -> productRepository.findById(key) .orElseThrow(() -> new NotFoundException("product not found, id=" + key))); } public Map getProducts(List ids) { return productCache.getAll(ids, key -> productRepository.findById(key).orElseThrow()); } public void invalidate(String id) { productCache.evict(id); } public void updateProduct(String id, ProductResponse updated) { productCache.put(id, updated); } } ``` -------------------------------- ### Product Service Client-Side Configuration Source: https://context7.com/neowu/core-ng-project/llms.txt Configures the ProductService client by providing the URL of the service. This allows other services to inject and use the ProductService as a type-safe HTTP proxy. ```java // Client side — create proxy in consuming service public class OrderModule extends Module { @Override protected void initialize() { api().client(ProductService.class, requiredProperty("product.serviceURL")); // ProductService is now injectable in OrderService } } // Inject and use the client public class OrderService { @Inject ProductService productService; // transparent HTTP proxy public void placeOrder(String productId) { ProductResponse product = productService.get(productId); // use product ... } } ``` -------------------------------- ### Database Repository SelectAll Source: https://github.com/neowu/core-ng-project/blob/master/CHANGELOG_2017.md Added the `selectAll()` method to the database repository. This allows for retrieving all records from a table easily. ```java db repository, added selectAll() ``` -------------------------------- ### D3.js Graph Rendering and Interaction Source: https://github.com/neowu/core-ng-project/blob/master/ext/log-processor/src/main/dist/web/template/diagram.html Initializes Graphviz rendering and sets up event listeners for node clicks to display tooltips. Ensure the DOM has elements with IDs 'graph' and 'tooltip'. ```javascript const graphviz = d3.select("#graph").graphviz(); const tooltipDiv = d3.select("#tooltip"); let selected = null; let selectedStyle = {}; function render(dot) { graphviz.renderDot(dot) .on("end", () => { d3.selectAll(".edge, .node").on("click mousedown", function (event) { event.preventDefault(); event.stopPropagation(); const element = d3.select(this); select(element); const tooltip = element.select("a"); if (!tooltip.empty()) { tooltipDiv.html(tooltip.attr("title")); // lgtm[js/xss-through-dom] tooltipDiv.style("visibility", "visible"); } else { tooltipDiv.style("visibility", "hidden"); } }); }); } function select(element) { if (selected != null) { selected.selectAll("path, polygon, ellipse").attr("stroke-width", selectedStyle[\"stroke-width\"]); } selected = element; let shape = selected.selectAll("path, polygon, ellipse"); selectedStyle = {"stroke-width": shape.attr("stroke-width")}; shape.attr("stroke-width", "5"); } const dot = d3.select("#dot").text(); render(dot); ``` -------------------------------- ### Kafka Configuration and Message Publishing Source: https://context7.com/neowu/core-ng-project/llms.txt Configure Kafka producers and consumers, define message classes, and bind publishers. Use `kafka().publish()` for producing messages and `kafka().subscribe()` for consuming. ```java public class MessagingModule extends Module { @Override protected void initialize() { kafka().uri(requiredProperty("kafka.uri")); // e.g. kafka-0.kafka:9092 // producer MessagePublisher publisher = kafka().publish("order-created", OrderCreatedMessage.class); bind(MessagePublisher.class, OrderCreatedMessage.class, publisher); // consumer OrderCreatedHandler handler = bind(OrderCreatedHandler.class); kafka().subscribe("order-created", OrderCreatedMessage.class, handler); kafka().concurrency(4); kafka().maxPoll(200, 1024 * 1024); } } ``` ```java public class OrderCreatedMessage { @NotNull @Property(name = "order_id") public String orderId; @NotNull @Property(name = "customer_id") public String customerId; @Property(name = "total") public BigDecimal total; } ``` ```java public class OrderService { @Inject MessagePublisher orderPublisher; public void createOrder(Order order) { // ... save order ... OrderCreatedMessage msg = new OrderCreatedMessage(); msg.orderId = order.id.toString(); msg.customerId = order.customerId.toString(); msg.total = order.total; // publish with partition key (routes same customer to same partition) orderPublisher.publish(order.customerId.toString(), msg); } } ``` -------------------------------- ### Configure Relational Database with DBConfig Source: https://context7.com/neowu/core-ng-project/llms.txt Sets database connection URL, credentials, pool size, and timeout. Registers entity and view classes. Supports multiple named databases. ```java public class DatabaseModule extends Module { @Override protected void initialize() { db().url("jdbc:mysql://localhost:3306/mydb?useSSL=false"); db().user("appuser"); db().password("secret"); db().poolSize(5, 20); db().timeout(Duration.ofSeconds(15)); db().isolationLevel(IsolationLevel.READ_COMMITTED); db().repository(Customer.class); // binds Repository db().view(CustomerSummaryView.class); // read-only projection } } // Entity definition @Table(name = "customer") public class Customer { @PrimaryKey(autoIncrement = true) @Column(name = "id") public Long id; @Column(name = "name") public String name; @Column(name = "email") public String email; @Column(name = "status") public CustomerStatus status; @Column(name = "created_time") public LocalDateTime createdTime; } // Usage in service public class CustomerService { @Inject Repository customerRepository; @Inject Database database; public Optional findById(long id) { return customerRepository.get(id); } public List findActive(int limit) { return customerRepository.select("status = ?", CustomerStatus.ACTIVE) // or use fluent Query API: // Query q = customerRepository.select(); // q.where("status = ?", CustomerStatus.ACTIVE); // q.limit(limit); // q.orderBy("created_time DESC"); // return q.fetch(); ; } public void createCustomer(Customer customer) { customerRepository.insert(customer); // returns OptionalLong with generated key } public void bulkUpsert(List customers) { customerRepository.batchUpsert(customers); } public void deactivateOldCustomers() { try (Transaction tx = database.beginTransaction()) { List old = customerRepository.select("created_time < ?", LocalDateTime.now().minusYears(2)); old.forEach(c -> { c.status = CustomerStatus.INACTIVE; customerRepository.partialUpdate(c); }); tx.commit(); } } } ``` -------------------------------- ### Move Repository into DB Module Source: https://github.com/neowu/core-ng-project/blob/master/CHANGELOG_2017.md Moved the `repository()` method into the `db()` module and registered the DB entity class for viewing. This consolidates database-related functionalities. ```java move repository() into db() and register db entity class to view. ``` -------------------------------- ### Generate System Architecture Diagram Source: https://github.com/neowu/core-ng-project/blob/master/CHANGELOG_2021.md Generate a system architecture diagram by calling the log-processor endpoint. The 'hours' parameter is optional. ```http https://log-processor:8443/diagram/arch?hours=24 ``` -------------------------------- ### Configure Kafka Monitor Disk Size Threshold Source: https://github.com/neowu/core-ng-project/blob/master/CHANGELOG_2021.md Add 'highDiskSizeThreshold' to Kafka monitor configuration to set an absolute size limit for disk usage, not a percentage. ```json "highDiskSizeThreshold" ``` -------------------------------- ### String Formatting and Manipulation Source: https://context7.com/neowu/core-ng-project/llms.txt Utilize String helpers for template formatting with SLF4J-style placeholders, checking for blank strings, splitting strings by a delimiter, truncating strings, and converting strings to byte arrays. ```java String msg = Strings.format("hello {}, you have {} messages", "Alice", 3); // "hello Alice, you have 3 messages" boolean blank = Strings.isBlank(" "); // true String[] parts = Strings.split("a,b,c", ','); // ["a", "b", "c"] String truncated = Strings.truncate("long text...", 4); // "long" byte[] bytes = Strings.bytes("UTF-8 text"); ``` -------------------------------- ### Execute Raw SQL Queries with Database Source: https://context7.com/neowu/core-ng-project/llms.txt Use the Database class for multi-table joins, complex aggregations, DDL, and batch DML. The select method returns a list of objects, while batchExecute is for bulk DML operations. Transactions can be managed using beginTransaction. ```java public class ReportService { @Inject Database database; public List getSalesSummary(LocalDate from, LocalDate to) { String sql = "SELECT date(created_time) AS sale_date, SUM(total) AS total_sales, COUNT(*) AS order_count " + "FROM orders WHERE created_time BETWEEN ? AND ? GROUP BY date(created_time)"; return database.select(sql, SalesSummary.class, from, to); } public void archiveOrders(List ids) { // batchExecute for bulk DML List params = ids.stream().map(id -> new Object[]{id}).toList(); database.batchExecute("UPDATE orders SET archived = true WHERE id = ?", params); } public void runInTransaction(Runnable work) { try (Transaction tx = database.beginTransaction()) { work.run(); tx.commit(); } } } ``` -------------------------------- ### Create Customer Record Source: https://github.com/neowu/core-ng-project/wiki/Database Inserts a new customer record into the database. Instantiate a Customer object, populate its properties, and use the repository's insert method. ```java Customer customer = new Customer(); customer.email = request.email; customer.firstName = request.firstName; customer.lastName = request.lastName; customer.updatedTime = LocalDateTime.now(); customer.id = customerRepository.insert(customer).get(); ``` -------------------------------- ### ActionLogContext for Logging and Observability Source: https://context7.com/neowu/core-ng-project/llms.txt Enriches the current action log with custom context, numeric stats, and manual performance tracking for better observability. ```APIDOC ## Logging and Observability ### ActionLogContext — Structured per-request logging and metrics `ActionLogContext` enriches the current action log (one per HTTP request / Kafka message / scheduled job) with custom context, numeric stats, and manual performance tracking. #### Using ActionLogContext ```java public class OrderController implements Controller { @Override public Response execute(Request request) throws Exception { String orderId = request.pathParam("id"); // add structured context visible in trace logs ActionLogContext.put("orderId", orderId); ActionLogContext.put("customerId", request.header("X-Customer-Id").orElse("unknown")); // record a numeric metric (aggregated in Kibana) ActionLogContext.stat("order_items_count", 5); // track an external operation manually long start = System.nanoTime(); callExternalService(orderId); ActionLogContext.track("external_api", System.nanoTime() - start, 1, 0); // force full trace capture for this action ActionLogContext.triggerTrace(false); // increase allowed process time for long operations ActionLogContext.maxProcessTime(Duration.ofMinutes(2)); return Response.bean(Map.of("orderId", orderId)); } } ``` ``` -------------------------------- ### Configure HTTP Max Forwarded IPs in Java Source: https://github.com/neowu/core-ng-project/blob/master/CHANGELOG_2022.md Allows configuration of http().maxForwardedIPs() by reading the 'sys.http.maxForwardedIPs' property, making it configurable via environment variables. ```java log-collector: make http().maxForwardedIPs() read property "sys.http.maxForwardedIPs" ``` -------------------------------- ### Query Projection with Limit and Skip in Java Source: https://github.com/neowu/core-ng-project/blob/master/CHANGELOG_2022.md Demonstrates how query.limit(1).projectOne("col1, col2", View.class) results in 'select col1, col2 from table limit 1'. Note that skip/limit/orderBy should not be set before query.count(). ```java query.limit(1); query.projectOne("col1, col2", View.class); ``` -------------------------------- ### Monitor Deployment Configuration Source: https://github.com/neowu/core-ng-project/wiki/Ext This YAML defines a Kubernetes ServiceAccount, ClusterRoleBinding, and Deployment for a monitor application. It specifies the image, environment variables for Kafka, Slack, alerting, and monitoring configurations, as well as readiness probes and resource limits. ```yaml apiVersion: v1 kind: ServiceAccount metadata: name: monitor namespace: platform --- apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRoleBinding metadata: name: platform:monitor subjects: - kind: ServiceAccount name: monitor namespace: platform roleRef: kind: ClusterRole name: view apiGroup: rbac.authorization.k8s.io --- apiVersion: apps/v1 kind: Deployment metadata: name: monitor namespace: platform spec: replicas: 1 selector: matchLabels: app: monitor revisionHistoryLimit: 10 strategy: rollingUpdate: maxUnavailable: 0 maxSurge: 1 template: metadata: labels: app: monitor spec: nodeSelector: pool: ops serviceAccountName: monitor containers: - name: monitor image: neowu/monitor:7.5.7 env: - name: JAVA_OPTS value: "-XX:+UseG1GC -XX:MaxRAMPercentage=85 -Xss256k" - name: SYS_KAFKA_URI value: "log-kafka-0.log-kafka:9092" - name: APP_SLACK_TOKEN value: "xxxxxxx" - name: APP_ALERT_CONFIG value: | { "ignoreErrors": [ {"apps": ["backoffice", "log-collector"], "severity": "WARN", "errorCodes": ["FORBIDDEN", "PATH_NOT_FOUND", "UNAUTHORIZED", "METHOD_NOT_ALLOWED"]} ], "criticalErrors": [ {"errorCodes": ["FAILED_TO_START", "POD_FAILURE"]}, {"errorCodes": ["RUNTIME_ERROR", "LIFECYCLE_ERROR", "API_VALIDATION_ERROR"]} ], "site": "dev / platform", "kibanaURL": "http://kube.example.com:30101", "channels": { "xxx": {"severity": "ERROR", "indices": ["trace", "stat"]}, "xxx": {"severity": "WARN", "indices": ["trace", "stat"]}, "xxx": {"severity": "ERROR", "indices": ["event"]}, "xxx": {"severity": "WARN", "indices": ["event"]} } } - name: APP_MONITOR_CONFIG value: | { "redis": { "cache": { "hosts": ["cache"] }, "session": { "hosts": ["session-0.session"] } }, "es": { "log": { "host": "log-es-0.log-es", "highHeapUsageThreshold": 0.8 } }, "kafka": { "log": { "host": "log-kafka-0.log-kafka", "highHeapUsageThreshold": 0.8 } }, "kube": { "namespaces": ["platform", "ops"] } } readinessProbe: httpGet: path: /health-check scheme: HTTPS port: 8443 initialDelaySeconds: 10 periodSeconds: 10 resources: limits: memory: 256Mi ``` -------------------------------- ### Webservice Client Source: https://github.com/neowu/core-ng-project/blob/master/CHANGELOG_2017.md Introduced a webservice client. This module likely provides functionality for making requests to external webservices. ```java webservice client ``` -------------------------------- ### HTTP Server Configuration with Core NG Source: https://context7.com/neowu/core-ng-project/llms.txt Configure the embedded Undertow HTTP server using HTTPConfig. Set listen ports, enable gzip, set entity size limits, register routes with lambda controllers or custom classes, and configure global interceptors or error handlers. ```java public class WebModule extends Module { @Override protected void initialize() { http().listenHTTP("8080"); http().listenHTTPS("8443"); http().gzip(); http().maxEntitySize(10 * 1024 * 1024); // 10 MB upload limit http().maxForwardedIPs(2); // plain Controller (lambda) http().route(HTTPMethod.GET, "/api/products", request -> Response.bean(List.of())); http().route(HTTPMethod.POST, "/api/products", new CreateProductController()); http().route(HTTPMethod.GET, "/api/products/:id", request -> { String id = request.pathParam("id"); return Response.bean(Map.of("id", id)); }); // global interceptor for auth http().intercept(new AuthInterceptor()); // custom error handler http().errorHandler(new AppErrorHandler()); // register bean classes for /_sys/api metadata http().bean(CreateProductRequest.class); http().bean(ProductResponse.class); } } ``` -------------------------------- ### Product Service Server-Side Registration Source: https://context7.com/neowu/core-ng-project/llms.txt Registers an implementation of the ProductService interface on the server side. This makes the service available for clients to consume. ```java // Server side — register implementation public class ProductModule extends Module { @Override protected void initialize() { ProductServiceImpl impl = bind(ProductServiceImpl.class); api().service(ProductService.class, impl); } } ``` -------------------------------- ### Scheduler Configuration for Background Jobs Source: https://context7.com/neowu/core-ng-project/llms.txt Configure various job triggers including fixed-rate, daily, hourly, weekly, and monthly schedules. Set the time zone for all scheduled jobs. ```java public class SchedulerModule extends Module { @Override protected void initialize() { schedule().timeZone(ZoneId.of("America/New_York")); // fixed rate schedule().fixedRate("refresh-cache", bind(CacheRefreshJob.class), Duration.ofMinutes(5)); // daily at specific time schedule().dailyAt("send-daily-report", bind(DailyReportJob.class), LocalTime.of(8, 0)); // hourly at minute 30 schedule().hourlyAt("hourly-sync", bind(HourlySyncJob.class), 30, 0); // weekly on Monday at 02:00 schedule().weeklyAt("weekly-cleanup", bind(WeeklyCleanupJob.class), DayOfWeek.MONDAY, LocalTime.of(2, 0)); // monthly on the 1st at midnight schedule().monthlyAt("monthly-billing", bind(MonthlyBillingJob.class), 1, LocalTime.MIDNIGHT); } } ``` -------------------------------- ### ElasticSearchType Configuration and Usage Source: https://context7.com/neowu/core-ng-project/llms.txt Demonstrates how to configure and use ElasticSearchType for document indexing, searching, updating, and iteration. Requires core-ng-search module configuration. ```java // Entity @Index(name = "product", type = "_doc") public class ProductDocument { @Property(name = "id") public String id; @Property(name = "name") public String name; @Property(name = "category") public String category; @Property(name = "price") public Double price; } ``` ```java // Configuration (in module using core-ng-search) public class SearchModule extends Module { @Override protected void initialize() { // ElasticSearchConfig is registered via SystemModule; here we bind the type ElasticSearch elasticSearch = bean(ElasticSearch.class); ElasticSearchType productType = elasticSearch.type(ProductDocument.class); bind(ElasticSearchType.class, ProductDocument.class, productType); } } ``` ```java // Usage public class ProductSearchService { @Inject ElasticSearchType productIndex; public void indexProduct(ProductDocument doc) { productIndex.index(doc.id, doc); } public void bulkIndex(Map docs) { productIndex.bulkIndex(docs); } public SearchResponse search(String keyword, String category) { var request = new SearchRequest(); request.query = QueryBuilders.bool() .must(QueryBuilders.match(m -> m.field("name").query(keyword))) .filter(QueryBuilders.term(t -> t.field("category").value(category))) ._build(); request.limit = 20; request.skip = 0; return productIndex.search(request); } public List autocomplete(String prefix) { return productIndex.complete(prefix, "name.suggest"); } public void updatePrice(String id, double newPrice) { productIndex.update(id, "ctx._source.price = params.price", Map.of("price", newPrice)); } public void iterateAll(Consumer consumer) { var forEach = new ForEach(); forEach.consumer = consumer; forEach.batchSize = 500; productIndex.forEach(forEach); } } ``` -------------------------------- ### Composite Queue Publisher Source: https://github.com/neowu/core-ng-project/blob/master/CHANGELOG_2017.md Introduced a composite queue publisher for enhanced message queuing capabilities. This allows for more flexible message publishing strategies. ```java queue: composite queue publisher ``` -------------------------------- ### MessagePublisher Publish with Routing Key Source: https://github.com/neowu/core-ng-project/blob/master/CHANGELOG_2017.md Implemented `MessagePublisher.publish` with a `routingKey` parameter, specifically for RabbitMQ. This allows messages to be routed to specific queues based on the provided key. ```java queue: MessagePublisher.publish with routingKey, only support for RabbitMQ ``` -------------------------------- ### Register Entity Repository Source: https://github.com/neowu/core-ng-project/wiki/Database Register an entity's repository within a module. This allows for dependency injection of the repository in other classes. ```java db().repository(Entity.class); ``` -------------------------------- ### Rename StandardAppModule and Add JDBC Properties Source: https://github.com/neowu/core-ng-project/blob/master/CHANGELOG_2017.md Renamed `StandardAppModule` to `SystemModule` and added JDBC pool properties. This improves the organization of application modules and provides configuration options for the JDBC pool. ```java renamed StandardAppModule to SystemModule, and added jdbc pool properties ```