Differences From Previous APIs
Though JNX largely hews to the same overall concept of an NSF as the LSXBE and related APIs like ODA, there are some important conceptual differences.
View Data
Reading data from views and folders is done by way of “collections” and queries upon them. This is based partially on the C API terminology and partially on more modern programmatic-query-based APIs.
View queries are based around specifying keys, directions, start points, and the explicit data to read. For example, to look up a category entry:
DominoCollection view = database.openCollection("Lastname Birthyear Categorized");
CollectionEntry categoryEntry = view
.query()
.direction(Navigate.CURRENT)
.readColumnValues()
.readSpecialValues(SpecialValue.INDEXPOSITION)
.startAtCategory(category)
.firstEntry();
Or, to select a subset of documents based on a DQL query:
DominoCollection sortView = database.openCollection("Lastname Firstname Flat");
sortView.resortView("lastname", Direction.Descending);
DQLTerm dql = DQL
.item("Firstname")
.isEqualTo("Nathan");
LinkedHashSet<Integer> sortedIdsOfDQLMatches = sortView
.query()
.select(
SelectedEntries
.deselectAll()
.select(dql)
)
.collectIds(0, Integer.MAX_VALUE);
There exists a View
interface, but it’s specifically for working with the design of the view.
Callbacks
There are several areas where the best way to perform an operation on a set of entities is via a callback function, such as Database#forEachCollection
or Document#forEachItem
. These are often implemented on top of similar callback structures at the C API level and are more efficient than other looping mechanisms available.
Session Usernames
Like the C API, JNX does not have the inherent restrictions on session creation that the LSXBE classes do (particularly on the Java side with the agent security manager). By default, a newly-created DominoClient
will use the name from the underlying Notes ID file from the active server or client runtime.
A DominoClient
object can also be created with an arbitrary username:
DominoClient fooClient = DominoClientBuilder.newDominoClient()
.asUser("CN=Foo Bar/O=Baz")
.build();
In this case, that username will be used to open any databases and perform related actions, and its access will be enforced locally and by trust-configured remote servers.
In practice, this should generally be done with a pre-verified username from the environment, such as the authenticated user in a servlet container or a configured “run as” user for a scheduled task.
It is also possible to perform password authentication against the environment’s configured NSF-based directories during DominoClient
creation:
DominoClientBuilder.newDominoClient()
.authenticateUser(someServer, username, password)
.build();
This mechanism will throw a DominoException
caused by a javax.naming.NamingException
subclass when the user doesn’t exist or the password is incorrect.
Dates/Times
There exists a DominoDateTime
type, but the intent is to integrate heavily into the Java 8+ java.time
system. To that end, DominoDateTime
implements the Temporal
interface and can be used anywhere a Temporal
or TemporalAccessor
is needed. For example:
DominoDateTime dominoDt = someMethod();
OffsetDateTime dt = OffsetDateTime.from(dominoDt);
String output = DateTimeFormatter.ISO_OFFSET_DATE_TIME.format(dominoDt);
DominoDateTime
has convenience methods for toOffsetDateTime
, toLocalDate
, and toLocalTime
to explicitly convert or extract date/time to JDK types. Note that, when the Domino value represents a time-only or date-only value, the inapplicable methods will throw exceptions.
It also has a toTemporal
method that converts to the version of those that most closely matches the underlying data.
DominoDateTime
does not include named time zone data, as this is not representable at the native layer. Instead, it stores just the time zone offset, and so it’s a direct conceptual match for the OffsetDateTime
type when it contains both a date and time, LocalDate
when it’s date-only, and LocalTime
when it’s time-only.
Garbage Collection
JNX objects have their backing Notes handles and memory freed when they are collected by the Java garbage collector, and it is not the programmer’s responsibility to keep track of them. It is good to call DominoClient#close
when done (or use try-with-resources), but those clients can be long-lived and persist across threads.
Some interfaces, such as Database
, also extend AutoCloseable
, but that is for when you wish to more-explicitly manage your memory use, and are optional to call.