NAF
Nuts Application Framework
The core API foundation for modular and dynamic Java applications

What is NAF?
Nuts Application Framework
(NAF
) is a lightweight, modular framework designed to simplify the development of modern Java applications. Built on top of the Nuts
runtime, NAF
provides a unified foundation for configuration, logging, dependency injection, modularity, and extensibility, all while remaining Java 8 compatible and able to leverage the latest Java features when available.
NAF
is non-invasive by design: it integrates seamlessly with existing frameworks and libraries such as Spring, Spring Boot, SLF4J, and more, allowing you to adopt its conventions and APIs without rewriting or restructuring your application. Whether you're building CLI tools, desktop applications, or services, NAF
emphasizes clarity, productivity, and maintainability, giving you a consistent foundation and powerful conventions without imposing complexity or locking you in.
Maven Integration
Nuts can be added to your project with one
single JAR dependency, fully compatible with Maven repositories. Once included, it brings runtime dependency resolution, artifact management, and dynamic execution to your application without additional setup. Just add the dependency, and Nuts takes care of the rest — from fetching artifacts to managing versions, all seamlessly integrated with your existing Maven workflow.
<dependencies>
<dependency><groupId>net.thevpc.nuts</groupId>
<artifactId>nuts</artifactId>
<version>0.8.6</version>
</dependency>
</dependencies>
<repositories>
<repository><id>thevpc</id><url>https://maven.thevpc.net</url></repository>
</repositories>
Easy Onboarding
One line to start. Full runtime at your fingertips. Get started instantly with Nuts — no setup, no configuration, just run. Behind that single line lies a powerful, fully-featured runtime: dependency management, sessions, workspaces, and automation tools ready for anything your application needs. Nuts makes modern Java development simple, composable, and ready to scale.
Nuts.require();
NOut.println("Hello Nuts!");
NMsg in a nutshell
NMsg
allows you to create structured messages with dynamic placeholders, automatically rendering common types such as booleans, numbers, paths, dates, and enums in colors for improved readability. You can also apply custom styles to placeholders or entire messages, and even nest messages within messages to build complex, rich, and expressive content. This makes NMsg
a versatile tool for clear, context-aware, and visually informative output in any application.
// Simple example with automatic coloring
NMsg.ofC("User %s set flag %s on path %s",
"Alice", true, NPath.of("/tmp/data.txt")
);
// Custom styling example
NMsg.ofC("Task %s completed with status %s",
"Upload",
NText.ofStyled("OK", NTextStyle.primary1())
);
// Nested messages example
NMsg.ofV("User $user completed ${task}",
NMaps.of(
"user", "Alice",
"task", NMsg.ofV("task %s in %s", "Upload",
NText.ofStyled("123ms", NTextStyle.secondary1()))
)
);
Placeholder Formats
NMsg
supports multiple placeholder formats to create flexible and dynamic messages. You can use C-style placeholders (%s
, %d
) for traditional printf-style formatting, Java-style placeholders ({}
) similar to MessageFormat or SLF4J, and variable substitution ($name
) for named placeholders. The variable substitution format can take parameters, maps, or functions, making it easy to build messages dynamically and adaptively for your application.
NMsg.ofC("Hello %s, you have %d new notifications", "Alice", 5);
NMsg.ofJ("Downloading {} from {}", "report.pdf", "server-01");
NMsg.ofV("User $user on ${app}", Map.of("user", "Alice", "app", "NAF"));
NMsg.ofV("Threshold=$th, Date=$date", name -> switch (name) {
case "th" -> 0.85;
case "date" -> LocalDate.now();
default -> null;
});
Text Rendering Formats
NMsg
NMsg also provides multiple text rendering formats to make messages visually expressive. You can use plain messages that print as-is, styled messages to highlight errors, warnings, or other emphasis, code blocks for monospaced text with optional language hints, and NTF (Nuts Text Format) for lightweight markup supporting bold, italic, colors, and other rich formatting. These formats, combined with placeholders, allow NMsg to produce rich, dynamic, and visually informative output in any context.
NMsg.ofPlain("This is a plain message");
NMsg.ofStyled("Error: file not found", NTextStyle.error());
NMsg.ofCode("java", "System.out.println(\"Hello NAF\");");
NMsg.ofNtf("##bold## ##:/:italic## ```java public class{} ```");
Commandline
NCmdLine lets you parse and handle command-line arguments with full flexibility, while keeping your code clean and readable. Define flags, options, and non-option arguments, all with automatic type handling and default values. With Nuts, building sophisticated CLI tools becomes straightforward, letting you focus on functionality instead of parsing logic.
NCmdLine cmdLine = NApp.of().getCmdLine(); // or from somewhere else
NRef<Boolean> boolOption = NRef.of(false);
NRef<String> stringOption = NRef.ofNull();
List<String> others = new ArrayList<>();
while (cmdLine.hasNext()) {
cmdLine.matcher()
.with("-o", "--option").matchFlag((v) -> boolOption.set(v.booleanValue()))
.with("-n", "--name").matchEntry((v) -> stringOption.set(v.stringValue()))
.withNonOption().matchAny((v) -> stringOption.set(v.image()))
.requireDefaults()
;
}
NOut.println(NMsg.ofC("boolOption=%s stringOption=%s others=%s", boolOption, stringOption, others));
Universal Path
NPath gives you a unified way to work with both local and remote paths, letting you read, write, and manipulate files from HTTP, SSH, or the local filesystem with the same simple API. It also provides convenient access to standard system and user directories, including home, working, configuration, and application paths, making cross-platform file handling seamless and consistent across environments.
// manipulate local and remote paths
String content=NPath.of("http://myserver/myfile.txt").readString();
String[] lines=NPath.of("ssh://myserver/myfile.txt").lines().toArray(String[]::new);
// access local standard folders
NPath.ofUserHome(); // User home directory
NPath.ofUserDirectory(); // Current working directory
// User store path (~/.config/nuts on linux, C:\Users\{user}\AppData\Local\nuts on windows)
NPath.ofUserStore(NStoreType.CONFIG);
// User store path (/opt/nuts/ on linux, C:\Program Files\nuts on windows)
NPath.ofSystemStore(NStoreType.BIN); // System store path
Structured Console Output with NTF
Nuts
supports NTF
(Nuts Text Format), enabling rich, structured, and styled console output. You can embed variables, apply colors or styles, and produce messages that are both human-readable and machine-friendly. This makes your CLI output more expressive, interactive, and easier to interpret.
NOut.println(
NMsg.ofV("Hello ${user}, your task status is ${status}",
NMaps.of(
"user", "Alice",
"status", NText.ofStyled("OK", NTextStyle.primary1())
)
);
NOut.println(
NMsg.ofC("Hello %s, your task status is %s",
"Bob"
NText.ofStyled("KO", NTextStyle.danger())
)
);
NOut.println(
NMsg.ofC("Hello %s, your task status is ##:danger KO##",
"Meriam"
"KO"
)
);
Unified Logging with NLog
NLog
combines structured messages (NMsg
), styled output with colors and NTF
formatting, and seamless integration with JUL or SLF4J. Messages carry an Intent, similar to logging markers, which allows you to classify, filter, or style logs at runtime. Whether you’re building CLI tools, scripts, or full applications, NLog
makes logs expressive, rich, and easy to understand.
NLog.of("myapp").info(
NMsg.ofV("Hello %s, task %s completed with status %s",
"user","Alice","status",
NText.ofStyled("OK", NTextStyle.primary1()), exception
)
.withIntent(NMsgIntent.CONFIG) // Classifies this log, can be used for filtering or styling
.withThrowable(exception) // Attaches the exception
.withDurationMs(123) // Optional: report task duration
);
Scoped, Context-Aware Logging (Beyond MDC)
Traditional MDC allows you to store key-value pairs for the current thread, but managing nested or dynamic contexts often becomes cumbersome. NLog builds on and extends this concept by allowing nested logging scopes, dynamic placeholders, message prefixes, and custom log handlers — all without touching global configuration or rewriting classes. Logs automatically inherit the correct context, making them structured, expressive, and runtime-aware. With NLog, you get the convenience of MDC plus the power of non-invasive, modular, and scoped logging.
class MyApp {
public void test() {
NLogs.of().runWith(
NLogContext.of()
.withMessagePrefix(NMsg.ofC("[My Application]")) // Prefix added to every log message in this scope
.withPlaceholder("user", "Adam") // Placeholder available to all logs in this scope
.withLog(message -> NOut.println(NMsg.ofC("[SCOPED] %s", message))), // Custom log handler: redirect all messages to stdout with a [SCOPED] prefix
() -> {
OtherClass.doThis(); // Perform actions that generate logs
}
);
}
}
class OtherClass {
private static void doThis() {
// Standard logger: picks up class context but not the scoped stdout handler
NLog.of(LogTest.class).log(NMsg.ofC("hello %s", NMsg.placeholder("user")));
// Scoped logger: inherits context from outer scope (user=Adam) and uses the custom stdout handler
NLog.ofScoped(OtherClass.class).log(NMsg.ofV("hello $user"));
}
}
NElement — Structured Data, Any Format
With NElement
, Nuts
lets you build, parse, and format structured data effortlessly. From plain objects to JSON, XML, or TSON, you can read and write files, parse into Java objects, or print with optional NTF
color formatting — all in a runtime-friendly way.
// Build an element
NElement document = NElement.ofObjectBuilder()
.set("app-id", NApp.of().getId().get())
.set("error", messageString)
.build();
// Parse JSON into Java object
Person person = NElementParser.ofJson().parse(NPath.of("person.json"), Person.class);
// Format and write XML to file
NElementFormat.ofPlainXml(document).println(NPath.of("person.xml"));
// Print TSON to terminal with colors
NElementFormat.ofNtfTson(document).println();
NTextArt — Turn Text into Art
Bring your CLI, logs, or console output to life with NTextArt. Render text as classic ASCII banners, pixel-style visuals, or even image-like representations, with multiple renderers at your fingertips — all workspace-aware and fully embeddable.
NTextArt art = NTextArt.of();
NText text = NText.of("hello world");
NOut.println(art.getTextRenderer("figlet:standard").get().render(text));
NOut.println(art.getImageRenderer("pixel:standard").get()
.setFontSize(20) .setOutputColumns(60) .render(text));
// _ _ _ _ _
// | | | | | | | | | |
// | |__ ___ | | | | ___ __ __ ___ _ __ | | __| |
// | '_ \ / _ \ | | | | / _ \ \ \ /\ / / / _ \ | '__| | | / _` |
// | | | | | __/ | | | | | (_) | \ V V / | (_) | | | | | | (_| |
// |_| |_| \___| |_| |_| \___/ \_/\_/ \___/ |_| |_| \__,_|
//
// █ ░██ ███ ███ █
// █ █ ▓█ ░█ █
// █ █▒ ░██ █ ▓█ █▒ █ █ █▓ ██░█░ ░█ ▒█ █
// █▓▓█░░█ █░ █ ▓█ ░█ ▓▒ █ █ █░█ ▓▓ ██▓▓ ░█ █░▒█
// █ █░█████ █ ▓█ ▓█ ▒█ █▓█ ▓▒█ ░█ ██ ░█ ░█ █
// █ █░ █ ██ ▓█ █ █░ ██░█▓ █ █▒ ██ ░█░ ░█░██
// ▓ ▓░ ░▓▓ ▓▓ ▓▓░ ▓░ ░▓ ▓ ▓▒ ▒▒ ░▓▓ ░▓ ▓
NTextArt — Turn Text into Art
Beyond ASCII banners and pixel-style visuals, NTextArt
also supports structured data rendering. You can display tables with aligned rows and columns, and hierarchical trees where each node can contain multi-line or styled text — even full tables. Branches, indentation, and node formatting are handled automatically, making it easy to visualize complex hierarchical or tabular data directly in the terminal with a clean, readable layout.
class MyNode implements NTreeNode {
int value;
public MyNode(int value) { this.value = value;}
@Override
public NText value() {
return art.getTableRenderer().get().render(NTableModel.of().addRow(NText.of(value)));
}
@Override
public List<NTreeNode> children() {
return (value < 3) ? Arrays.<Integer>asList(value + 1, value + 2).stream().map(MyNode::new).collect(Collectors.toList())
: Collections.emptyList();
}
}
NTreeNode tree = new MyNode(1);
NOut.println(art.getTreeRenderer().get().render(tree));
// ╭─╮
// │1│
// ╰─╯
// ├── ╭─╮
// │ │2│
// │ ╰─╯
// │ ├── ╭─╮
// │ │ │3│
// │ │ ╰─╯
// │ └── ╭─╮
// │ │4│
// │ ╰─╯
// └── ╭─╮
// │3│
// ╰─╯
NExec & NPs — Unified Process Execution
NAF offers a complete abstraction for process execution and monitoring. With NExec, you can run system commands, remote jobs, or even Maven artifacts seamlessly. With NPs, you can introspect and control running processes across platforms. Together, they form a portable, workspace-aware execution toolkit that abstracts OS differences, integrates with Nuts’ runtime, and makes both starting and supervising processes trivial — whether locally or remotely.
// Run a system command and capture output
String out = NExec.of("ls").system().grabAll().run().getGrabbedOutString();
// Run a Maven artifact (auto-resolves if missing)
NExec.of("netbeans-launcher").run();
// List all Java processes on the local machine
NPs.of().setPlatformFamily(NPlatformFamily.JAVA)
.getResultList()
.forEach(System.out::println);
// Kill a process by ID (if supported on the platform)
NPs.of().killProcess("12345");
// Inspect processes on a remote host
NPs.of().at("ssh://myuser@myserver").getResultList();
NCp — Copy with Options & Validation
NCp provides a unified, flexible API to copy resources of various types — files, streams, URLs, or paths — while supporting advanced features like logging, progress monitoring, and validation. You can start with a simple copy, then gradually enable tracing, progress feedback, or integrity checks, all with the same intuitive API.
// --- Basic copy: simple source to target ---
NCp.of()
.from(source) // set source (File, Path, InputStream, etc.)
.to(download_path.resolve(source.getName())) // set target path
.addOptions(NPathOption.LOG, NPathOption.TRACE) // enable logging and tracing
.run(); // execute copy
// --- Copy with progress monitoring ---
NCp.of()
.from(from)
.to(to)
.addOptions(NPathOption.LOG, NPathOption.TRACE)
// --- add validation validation (e.g., SHA-1 integrity check) ---
.setValidator(new NCpValidator() {
@Override
public void validate(InputStream in) throws IOException {
checkSHA1Hash(id.builder().setFace(NConstants.QueryFaces.CONTENT_HASH).build(),
in, "artifact binaries");
}
})
.setProgressMonitor(event -> {
NOut.println(event.getProgress()); // display progress
return true; // continue copy
})
.run();
NCompress / NUncompress — Flexible Compression & Extraction
Nuts provides unified APIs for compressing and uncompressing files, directories, or streams, supporting multiple formats (e.g., ZIP). You can monitor progress, skip root directories, or apply custom options for logging and safety. NCompress and NUncompress make it easy to handle resource packaging in a consistent, OS-aligned manner, while fully integrating with Nuts’ filesystem abstractions.
// --- Compress a file or directory into a ZIP ---
NCompress.of()
.addSource(example) // source to compress
.setTarget(example.resolveSibling(
example.getNameParts(NPathExtensionType.SHORT).getBaseName() + ".zip")) // target zip path
.setPackaging("zip") // compression format
.run(); // execute compression
// --- Uncompress a ZIP file to a folder ---
NUncompress.of()
.from(zipTo) // source zip file
.to(folderTo) // target directory
.setSkipRoot(true) // optionally skip the root folder in zip
.progressMonitor(new OpNInputStreamProgressMonitor(
module.rt().addOperation("Unzipping " + i))) // progress monitoring
.run(); // execute uncompression
NDigest – Hashing Made Simple
NDigest is a fluent I/O command to compute hash digests of one or multiple sources. It supports files, streams, URLs, byte arrays, or Nuts descriptors, and allows combining multiple sources into a single digest. Built on top of Java's MessageDigest, it simplifies hashing in Nuts workflows, integrates seamlessly with download validation, and supports MD5, SHA1, SHA256, or any algorithm provided by MessageDigest.
// Simple SHA256 digest of a file
String hash = NDigest.of()
.sha256()
.addSource(path)
.computeString();
// Digest multiple sources
String combined = NDigest.of()
.sha1()
.addSource(file1)
.addSource(file2)
.addSource(url)
.computeString();
// Digest and get raw bytes
byte[] bytes = NDigest.of()
.md5()
.addSource(stream)
.computeBytes();
NInputSource & NInputSourceBuilder – Flexible Input Abstraction
NInputSource represents a flexible, metadata-aware source of content in Nuts. It can wrap files, paths, URLs, byte arrays, streams, readers, or other providers, offering a unified API for reading, digesting, or streaming content. NInputSourceBuilder allows fine-grained configuration of sources, such as expected length, progress monitoring, interruptibility, multi-read capability, or non-blocking streams. Together, they decouple I/O handling from concrete types and simplify building robust I/O pipelines.
NInputSource src = NInputSource.of(file)
.readBytes(); // get content
NInputSource multi = NInputSource.ofMultiRead(src); // reusable input
NInputSourceBuilder b = NInputSourceBuilder.of(stream)
.setMetadata(metadata)
.setInterruptible(true)
.setCloseBase(true);
InputStream in = b.createInputStream();
NInputSource source = b.createInputSource();
Progress Monitoring with NProgressMonitor
NProgressMonitor provides a flexible and context-aware way to track progress in tasks. You can create incremental, split, and nested monitors, log events to any output, and automatically propagate the current progress context using NProgressMonitor.of(). This allows embedded or nested operations to report progress seamlessly without explicit parameter passing.
// 1. Simple incremental progress
NProgressMonitor mon = NProgressMonitors.of().ofSysOut();
mon.start();
for (int i = 0; i < 10; i++) {
mon.setProgress(i * 1.0 / 10, NMsg.ofC("Step %.1f", i * 1.0 / 10));
}
mon.complete();
// 2. Split progress for subtasks
NProgressMonitor[] split = mon.split(2);
split[0].incremental(5).complete();
split[1].incremental(5).complete();
// 3. Context-aware progress
NProgressHandler handler = event -> System.out.println(event);
NProgressMonitors.of().of(handler).runWith(() -> {
NProgressMonitor inner = NProgressMonitor.of();
inner.start();
inner.setProgress(0.5, NMsg.ofC("Halfway done"));
inner.complete();
});
Expression Parsing & Evaluation with NExpr
NExpr is a powerful expression parser and evaluator designed to handle dynamic, runtime expressions within the Nuts ecosystem. It allows declaration of constants, variables, and functions, supports custom operators, and can evaluate expressions in a context-aware way. This makes it ideal for dynamic queries, runtime computation, scripting, and configuration-driven logic in Java applications — all while remaining type-safe, extensible, and embeddable.
NExprMutableDeclarations d = NExprs.of().newMutableDeclarations();
d.declareConstant("pi", Math.PI);
d.declareFunction("sin", (name, args, ctx) -> {
NExprNodeValue a = args.get(0);
return Math.sin(asDouble(a.eval(ctx), rendererContext));
});
NOptional<NExprNode> ne = d.parse("sin(x*pi)");
if (ne.isPresent()) {
NExprNode node = ne.get();
NDoubleFunction fct = x -> {
NOptional<Object> r = node.eval(new NExprEvaluator() {
@Override
public NOptional<NExprVar> getVar(String varName, NExprDeclarations ctx) {
return "x".equals(varName)
? Optional.of(x)
: NOptional.ofNamedEmpty("var " + varName);
}
});
return NTxExprHelper.asDouble(r, rendererContext);
};
double result = fct.apply(0.5); // evaluates sin(0.5*pi)
}
Working with Workspaces and Session
With Nuts, what starts as a simple one-line setup can grow into a fully controlled runtime environment. Create multiple workspaces, configure sessions with custom flags, manage output formats, and orchestrate complex automation — all while keeping your code clean and portable. Nuts gives you both simplicity for quick experiments and full power for advanced applications.
NWorkspace ws = Nuts.openWorkspace("--workspace="/path/to/ws");
ws.runWith(() -> {
NSession.of()
.copy()
.setDry(true)
.setOutputFormat(NContentType.JSON)
.runWith(() -> {
NOut.println(Map.of("status", "ok"));
});
});