All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.avsystem.anjay.Anjay Maven / Gradle / Ivy

The newest version!
/*
 * Copyright 2020-2021 AVSystem 
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.avsystem.anjay;

import com.avsystem.anjay.impl.NativeAnjay;
import com.avsystem.anjay.impl.NativeLog;
import java.nio.channels.SelectableChannel;
import java.time.Duration;
import java.util.Arrays;
import java.util.EnumSet;
import java.util.List;
import java.util.Objects;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

/** Anjay object containing all information required for LwM2M communication. */
public final class Anjay implements AutoCloseable {
    private NativeAnjay anjay;

    /**
     * A constant that may be used in {@link #scheduleRegistrationUpdate(int)} call instead of Short
     * Server ID to send Update messages to all connected servers.
     */
    public static final int SSID_ANY = NativeAnjay.getSsidAny();

    /**
     * An SSID value reserved by LwM2M to refer to the Bootstrap Server.
     *
     * 

NOTE: The value of a "Short Server ID" Resource in the Security Object Instance referring * to the Bootstrap Server is irrelevant and cannot be used to identify the Bootstrap Server. */ public static final int SSID_BOOTSTRAP = NativeAnjay.getSsidBootstrap(); /** * Value reserved by the LwM2M spec for all kinds of IDs (Object IDs, Object Instance IDs, * Resource IDs, Resource Instance IDs, Short Server IDs). */ public static final int ID_INVALID = NativeAnjay.getIdInvalid(); /** Initial configuration used when creating an Anjay object. */ public static final class Configuration { /** * Endpoint name as presented to the LwM2M server. Must be non-null, or otherwise {@link * Anjay#Anjay} will fail. */ public String endpointName; /** * UDP port number that all listening sockets will be bound to. It may be left at 0 - in * that case, connection with each server will use a freshly generated ephemeral port * number. */ public int udpListenPort; /** * DTLS version to use for communication. {@link DtlsVersion#DEFAULT} will be automatically * mapped to {@link DtlsVersion#TLSv1_2}, which is the version mandated by LwM2M * specification. */ public Optional dtlsVersion = Optional.empty(); /** * Maximum size of a single incoming CoAP message. Decreasing this value reduces memory * usage, but packets bigger than this value will be dropped. */ public long inBufferSize; /** * Maximum size of a single outgoing CoAP message. If the message exceeds this size, the * library performs the block-wise CoAP transfer (https://tools.ietf.org/html/rfc7959). * *

NOTE: in case of block-wise transfers, this value limits the payload size for a single * block, not the size of a whole packet. */ public long outBufferSize; /** * Number of bytes reserved for caching CoAP responses. If not 0, the library looks up * recently generated responses and reuses them to handle retransmitted packets (ones with * identical CoAP message ID). * *

NOTE: while a single cache is used for all LwM2M servers, cached responses are tied to * a particular server and not reused for other ones. */ public long msgCacheSize; /** * Socket configuration to use when creating TCP/UDP sockets. * *

Note that: * *

    *
  • reuse_addr will be forced to true. *
  • Value pointed to by the preferred_endpoint will be ignored. *
*/ // TODO: avs_net_socket_configuration_t socket_config; /** * Configuration of the CoAP transmission params for UDP connection, as per RFC 7252. * *

The default configuration is {@link CoapUdpTxParams#DEFAULT}. */ public Optional udpTxParams = Optional.empty(); /** * Configuration of the DTLS handshake retransmission timeouts for UDP connection. * *

If not set, the default configuration ANJAY_DTLS_DEFAULT_UDP_HS_TX_PARAMS * will be selected internally. * *

NOTE: Parameters are copied during {@link Anjay#Anjay} and cannot be modified later * on. * *

IMPORTANT: In case of a need to adjust DTLS retransmission params to match the CoAP * retransmission params, the udpDtlsHsTxParams shall be initialized as * dtlsHsParams is in the following code snippet: * *

         *  final CoapUdpTxParams coapTxParams = ... // some initialization
         *
         *  // Without ACK_RANDOM_FACTOR = 1.0, it is impossible to create a DTLS
         *  // configuration that matches CoAP retransmission configuration perfectly.
         *  if (coapTxParams.ackRandomFactor != 1.0) {
         *      throw new IllegalStateException();
         *  }
         *
         *  final DtlsHandhshakeTimeouts = new DtlsHandshakeTimeouts(
         *      coapTxParams.ackTimeout,
         *      coapTxParams.ackTimeout.multipliedBy(1 << coapTxParams.ackTimeout.maxRetransmit)
         *  );
         * 
*/ public Optional udpDtlsHsTxParams = Optional.empty(); /** * Controls whether Notify operations are conveyed using Confirmable CoAP messages by * default. */ public boolean confirmableNotifications; /** * If set to true, connection to the Bootstrap Server will be closed immediately after * making a successful connection to any regular LwM2M Server and only opened again if * (re)connection to a regular server is rejected. * *

If set to false, legacy Server-Initiated Bootstrap is possible, i.e. the Bootstrap * Server can reach the client at any time to re-initiate the bootstrap sequence. * *

NOTE: This parameter controls a legacy Server-Initiated Bootstrap mechanism based on * an interpretation of LwM2M 1.0 TS that is not universally accepted. Server-Initiated * Bootstrap as specified in LwM2M 1.1 TS is always supported, regardless of this setting. */ public boolean disableLegacyServerInitiatedBootstrap; /** * If "Notification Storing When Disabled or Offline" resource is set to true and either the * client is in offline mode, or uses Queue Mode, Notify messages are enqueued and sent * whenever the client is online again. This value allows one to limit the size of said * notification queue. The limit applies to notifications queued for all servers. * *

If set to 0, size of the stored notification queue is only limited by the amount of * available RAM. * *

If set to a positive value, that much most recent notifications are * stored. Attempting to add a notification to the queue while it is already full drops the * oldest one to make room for new one. */ public long storedNotificationLimit; /** * Sets the preference of the library for Content-Format used when responding to a request * without Accept option. * *

If set to true, the formats used would be: * *

    *
  • for LwM2M 1.0: TLV, *
  • for LwM2M 1.1: SenML CBOR, or if not compiled in, SenML JSON, or if not compiled in * TLV. *
*/ public boolean preferHierarchicalFormats; /** Enables support for DTLS connection_id extension for all DTLS connections. */ public boolean useConnectionId; /** * (D)TLS ciphersuites to use if the "DTLS/TLS Ciphersuite" Resource (/0/x/16) is not * available or empty. * *

Passing an empty array or not setting at all will cause defaults of the TLS backend * library to be used. */ public Optional defaultTlsCiphersuites = Optional.empty(); } /** DTLS handshake retransmission timeout limits for UDP connection. */ public static class DtlsHandshakeTimeouts { public final Duration min; public final Duration max; public DtlsHandshakeTimeouts(Duration min, Duration max) { this.min = Objects.requireNonNull(min, "min duration MUST NOT be null"); this.max = Objects.requireNonNull(max, "min duration MUST NOT be null"); } } /** Enum defining available LwM2M versions to use. */ public static enum Lwm2mVersion { /** * Lightweight Machine to Machine Technical Specification, Approved Version 1.0.2 - 09 Feb * 2018 (OMA-TS-LightweightM2M-V1_0_2-20180209-A). */ VERSION_1_0("1.0"), /** * Lightweight Machine to Machine Technical Specification, Approved Version 1.1 - * 2018-07-10; Core (OMA-TS-LightweightM2M_Core-V1_1-20180710-A) and Transport Bindings * (OMA-TS-LightweightM2M_Transport-V1_1-20180710-A). */ VERSION_1_1("1.1"); private final String stringValue; private Lwm2mVersion(String stringValue) { this.stringValue = stringValue; } @Override public String toString() { return this.stringValue; } } /** * Configuration of LwM2M protocol versions to use when attempting to register to LwM2M servers. * *

    *
  • Restricting the set of supported versions may speed up the Register operation, as less * versions will be attempted for registration. *
  • If {@link #minimumVersion} is set to a higher value than {@link #maximumVersion}, * {@link Anjay#Anjay} will fail. *
  • If {@link #minimumVersion} is set to a version higher than LwM2M 1.0, {@link * Configuration#disableLegacyServerInitiatedBootstrap} will be effectively implied even * if that field is set to false. *
*/ public static final class Lwm2mVersionConfig { /** The lowest version to attempt using when registering to LwM2M Servers. */ public final Lwm2mVersion minimumVersion; /** * The highest version to attempt using when registering to LwM2M Servers. This is also the * version number sent in reponse to Bootstrap Discover. */ public final Lwm2mVersion maximumVersion; /** * Constructor for LwM2M version configuration. * * @param minimum Minimum LwM2M version to use. * @param maximum Maximum LwM2M version to use. */ public Lwm2mVersionConfig(Lwm2mVersion minimum, Lwm2mVersion maximum) { this.minimumVersion = Objects.requireNonNull(minimum, "minimum LwM2M version MUST NOT be null"); this.maximumVersion = Objects.requireNonNull(maximum, "maximum LwM2M version MUST NOT be null"); } } /** * CoAP transmission params object. * * @see RFC7252: Transmission * Parameters */ public static final class CoapUdpTxParams { /** RFC 7252: ACK_TIMEOUT */ public final Duration ackTimeout; /** RFC 7252: ACK_RANDOM_FACTOR */ public final double ackRandomFactor; /** RFC 7252: MAX_RETRANSMIT */ public final int maxRetransmit; /** RFC 7252: NSTART */ public final int nstart; /** Default transmission params recommended by the CoAP specification (RFC 7252). */ public static final CoapUdpTxParams DEFAULT = new CoapUdpTxParams(Duration.ofSeconds(2, 0), 1.5, 4, 1); /** * Constructor for transmission params object. * * @param ackTimeout RFC 7252: ACK_TIMEOUT. Must not be null. * @param ackRandomFactor RFC 7252: ACK_RANDOM_FACTOR * @param maxRetransmit RFC 7252: MAX_RETRANSMIT * @param nstart RFC 7252: NSTART */ public CoapUdpTxParams( Duration ackTimeout, double ackRandomFactor, int maxRetransmit, int nstart) { this.ackTimeout = Objects.requireNonNull(ackTimeout, "ackTimeout MUST NOT be null"); this.ackRandomFactor = ackRandomFactor; this.maxRetransmit = maxRetransmit; this.nstart = nstart; } } /** Object Link value referencing an Object Instance */ public static final class Objlnk { /** Object ID */ public final int oid; /** Instance ID */ public final int iid; /** * Constructor for Object Link value. * * @param oid Object ID. * @param iid Instance ID. */ public Objlnk(int oid, int iid) { this.oid = oid; this.iid = iid; } /** Checks if two Object Links are equal. */ @Override public boolean equals(Object other) { if (other == this) { return true; } else if (other == null || !(other instanceof Objlnk)) { return false; } return ((Objlnk) other).oid == oid && ((Objlnk) other).iid == iid; } /** Calculates hash of the Object Link. */ @Override public int hashCode() { final int pair[] = {oid, iid}; return Arrays.hashCode(pair); } } /** Type of transport used in connection to server. */ public static enum Transport { /** UDP */ UDP, /** TCP */ TCP; } /** Available SSL versions that can be used by SSL sockets. */ public static enum DtlsVersion { DEFAULT, SSLv2_OR_3, SSLv2, SSLv3, TLSv1, TLSv1_1, TLSv1_2 } /** Details about established connection to the LwM2M Server. */ public static final class SocketEntry { /** Channel used to communicate with server. */ public final SelectableChannel channel; /** Used transport. */ public final Transport transport; /** SSID of the server. */ public final int ssid; /** Indicates if Queue Mode is enabled. */ public final boolean queueMode; /** Used port. */ public final int port; /** Constructor for SocketEntry - it is not intended to be called by user. */ public SocketEntry( SelectableChannel channel, Transport transport, int ssid, boolean queueMode, int port) { this.channel = channel; this.transport = transport; this.ssid = ssid; this.queueMode = queueMode; this.port = port; } } /** * Creates a new Anjay object. * * @param config Initial configuration. */ public Anjay(Configuration config) { NativeLog.initialize(); this.anjay = new NativeAnjay(config); } /** Closes the Anjay object and deregisters the client from the servers. */ @Override public void close() { this.anjay.close(); } /** * Function returning the library version. * * @return String representing current version of the library. */ public static String getVersion() { return NativeAnjay.getVersion(); } /** * Runs all scheduled events which need to be invoked at or before the time of this function * invocation. */ public void schedRun() { this.anjay.schedRun(); } /** * Retrieves a list of sockets used for communication with LwM2M servers. * *

Example usage: Selector-based application loop * *

{@code
     * try (Selector selector = Selector.open()) {
     *     while (true) {
     *         List sockets = anjay.getSockets();
     *         for (SelectionKey key : selector.keys()) {
     *             if (!sockets.contains(key.channel())) {
     *                 key.cancel();
     *             }
     *         }
     *         for (SelectableChannel socket : sockets) {
     *             if (socket.keyFor(selector) == null) {
     *                 socket.register(selector, SelectionKey.OP_READ);
     *             }
     *         }
     *         selector.select(1000);
     *         for (Iterator it = selector.selectedKeys().iterator();
     *                 it.hasNext(); ) {
     *             anjay.serve(it.next().channel());
     *             it.remove();
     *         }
     *     }
     * }
     * }
* * @throws IllegalStateException If {@link #close()} has already been called on this object. * @return A list of SelectableChannels that correspond to valid server sockets. */ public List getSockets() { return this.getSocketEntries().stream() .map(entry -> entry.channel) .collect(Collectors.toList()); } /** * Retrieves a list of objects that describe sockets used for communication with LwM2M servers. * *

The returned data is equivalent to the one that can be retrieved using {@link * #getSockets()} - but includes additional data that describes the socket in addition to the * socket itself. * * @return A list of valid server socket entries on success. If the the device is not connected * to any server, the list is empty. */ public List getSocketEntries() { return this.anjay.getSocketEntries(); } /** * Reads a message from given channel and handles it appropriately. * *

Initially, the receive method on the underlying socket is called with receive timeout set * to zero. Subsequent receive requests may block with non-zero timeout values when e.g. waiting * for retransmissions or subsequent BLOCK chunks - this is necessary to hide this complexity * from the user callbacks in streaming mode. * *

This function may handle more than one request at once. Upon successful return, it is * guaranteed that there is no more data to be received on the socket at the moment. * * @param channel A channel to read the message from. * @throws Exception In case of failure. */ public void serve(SelectableChannel channel) throws Exception { this.anjay.serve(channel); } /** * Determines time of next scheduled task. * *

May be used to determine how long the device may wait before calling {@link #schedRun()}. * * @return Relative time from now of next scheduled task, or an empty Optional, if no tasks are * scheduled. * @throws IllegalStateException If {@link #close()} has already been called on this object. */ public Optional timeToNext() { return this.anjay.timeToNext(); } /** * Schedules sending an Update message to the server identified by given Short Server ID. * *

The Update will be sent during the next {@link #schedRun()} call. * *

Note: This method will not schedule registration update if Anjay is in offline mode. * * @param ssid Short Server ID of the server to send Update to, or {@link #SSID_ANY} to send * Updates to all connected servers. NOTE: Since Updates are not useful for the Bootstrap * server, this method does not send one for {@link #SSID_BOOTSTRAP}. * @throws IllegalArgumentException If ssid is not representable as a 16-bit * unsigned integer. * @throws IllegalStateException If {@link #close()} has already been called on this object. * @throws AnjayException If the Update cannot be scheduled for any reason, which may include * being in offline state, no active server with a given SSID, or out-of-memory condition. */ public void scheduleRegistrationUpdate(int ssid) { this.anjay.scheduleRegistrationUpdate(ssid); } /** * Reconnects sockets associated with all servers and ongoing downloads over the specified * transports. Should be called if something related to the connectivity over those transports * changes. * *

The reconnection will be performed during the next {@link #schedRun()} call and will * trigger sending any messages necessary to maintain valid registration (DTLS session * resumption and/or Register or Update RPCs). * *

In case of ongoing downloads (started via {@link AnjayDownload} or the {@link * AnjayFirmwareUpdate} module), if the reconnection fails, the download will be aborted with an * error. * *

Note: This function puts all the transports in transportSet into online mode. * *

The reconnection will be performed during the next {@link #schedRun()} call and will * trigger Registration Update. Note: This method makes Anjay enter online mode. * * @param transportSet Set of transports whose sockets shall be reconnected. * @throws IllegalStateException If {@link #close()} has already been called on this object. * @throws AnjayException If the reconnection cannot be scheduled for any reason, which may * include an out-of-memory condition. */ public void scheduleReconnect(Set transportSet) { this.anjay.scheduleReconnect(transportSet); } /** * Overload, that issues reconnection for all transports. See {@link #scheduleReconnect(Set)} * for more details. */ public void scheduleReconnect() { this.scheduleReconnect(EnumSet.allOf(Transport.class)); } /** * This method shall be called when an LwM2M Server Object shall be disabled. The standard case * for this is when Execute is performed on the Disable resource (/1/x/4). * *

The server will be disabled for the period of time determined by the value of the Disable * Timeout resource (/1/x/5). The resource is read soon after the invocation of this method * (during next {@link #schedRun()}) and is not updated upon any subsequent * Writes to that resource. * * @param ssid Short Server ID of the server to put in a disabled state. NOTE: disabling a * server requires a Server Object Instance to be present for given ssid. * Because the Bootstrap Server does not have one, this method does nothing when called with * {@link #SSID_BOOTSTRAP}. * @throws IllegalArgumentException If ssid is not representable as a 16-bit * unsigned integer. * @throws IllegalStateException If {@link #close()} has already been called on this object. * @throws AnjayException If the disable job cannot be scheduled for any reason, which may * include an out-of-memory condition. */ public void disableServer(int ssid) { this.anjay.disableServer(ssid); } /** * Schedules a job for re-enabling a previously disabled (with a call to {@link * #disableServerWithTimeout}) server. The server will be enabled during next {@link * #schedRun()} call. * * @param ssid Short Server ID of the server to enable. * @throws IllegalStateException If {@link #close()} has already been called on this object. * @throws AnjayException If the disable job cannot be scheduled for any reason, which may * include an out-of-memory condition. */ public void enableServer(int ssid) { this.anjay.enableServer(ssid); } /** * This function shall be called when an LwM2M Server Object shall be disabled. The standard * case for this is when Execute is performed on the Disable resource (/1/x/4). It may also be * used to prevent reconnections if the server becomes unreachable. * *

The server will become disabled during next {@link #schedRun()} call. * *

NOTE: disabling a server with dual binding (e.g. UDP+SMS trigger) closes both * communication channels. Shutting down only one of them requires changing the Binding Resource * in Server object. * * @param ssid Short Server ID of the server to put in a disabled state. * @param timeout Disable timeout. If set to {@link Optional#empty()}, the server will remain * disabled until explicit call to {@link #enableServer}. Otherwise, the server will get * enabled automatically after timeout. * @throws IllegalStateException If {@link #close()} has already been called on this object. */ public void disableServerWithTimeout(int ssid, Optional timeout) { this.anjay.disableServerWithTimeout(ssid, timeout); } /** * Checks whether all the specified transports are in offline mode. * * @param transportSet Set of transports to check. * @return true if all of the transports specified by transportSet are in offline * mode, false otherwise. * @throws IllegalStateException If {@link #close()} has already been called on this object. */ public boolean isOffline(Set transportSet) { return this.anjay.isOffline(transportSet); } /** * Checks whether all transports are in offline mode. Overload of {@link #isOffline(Set)}, see * its documentation for more details. * * @return true if all transports are in offline mode. * @throws IllegalStateException If {@link #close()} has already been called on this object. */ public boolean isOffline() { return this.isOffline(EnumSet.allOf(Transport.class)); } /** * Puts all the transports specified by transportSet into offline mode. This should * be done when the connectivity for these transports is deemed unavailable or lost. * *

During subsequent calls to {@link #schedRun()}, Anjay will close all of the sockets * corresponding to the specified transport and stop attempting to make any contact with remote * hosts over it, until a call to {@link #exitOffline()} for any of the corresponding * transports. * *

Note that offline mode also affects downloads. E.g., putting the TCP transport into * offline mode will pause all ongoing downloads over TCP and prevent new such download requests * from being performed. * *

User code shall still interface normally with the library, even if all the transports are * in the offline state. This include regular calls to {@link #schedRun()}. Notifications (as * reported using {@link #notifyChanged notifyChanged()} and {@link #notifyInstancesChanged * notifyInstancesChanged()}) continue to be tracked, and may be sent after reconnecting, * depending on values of the "Notification Storing When Disabled or Offline" resource. * * @param transportSet Set of transports to put into offline mode. * @throws IllegalStateException If {@link #close()} has already been called on this object. */ public void enterOffline(Set transportSet) { this.anjay.enterOffline(transportSet); } /** * Puts all transports into offline mode. Overload of {@link #enterOffline(Set)}, see its * documentation for more details. */ public void enterOffline() { this.enterOffline(EnumSet.allOf(Transport.class)); } /** * Puts all the transports specified by transportSet back into online mode, if any * of them were previously put into offline mode using {@link #enterOffline()}. * *

Transports that are unavailable due to compile-time or runtime configuration are ignored. * *

During subsequent calls to {@link #schedRun()}, new connections to all LwM2M servers * disconnected due to offline mode will be attempted, and Register or Registration Update * messages will be sent as appropriate. Downloads paused due to offline mode will be resumed as * well. * * @param transportSet Set of transports to put into offline mode. * @throws IllegalStateException If {@link #close()} has already been called on this object. * @throws AnjayException If the job cannot be scheduled for any reason, which may include an * out-of-memory condition. */ public void exitOffline(Set transportSet) { this.anjay.exitOffline(transportSet); } /** * Puts all transports back into online mode. Overload of {@link #exitOffline(Set)}, see its * documentation for more details. */ public void exitOffline() { this.exitOffline(EnumSet.allOf(Transport.class)); } /** * Notifies the library that the value of given Resource changed. It may trigger an LwM2M Notify * message, update server connections and perform other tasks, as required for the specified * Resource. * *

Needs to be called for any Resource after its value is changed by means other than LwM2M. * *

Note that it should not be called after a Write performed by the LwM2M server. * * @param oid Object ID of the changed Resource. * @param iid Object Instance ID of the changed Resource. * @param rid Resource ID of the changed Resource. * @throws IllegalArgumentException If any of oid, iid or rid * is not representable as a 16-bit unsigned integer. * @throws IllegalStateException If {@link #close()} has already been called on this object. * @throws AnjayException If the notification cannot be scheduled for any reason, which may * include an out-of-memory condition. */ public void notifyChanged(int oid, int iid, int rid) { this.anjay.notifyChanged(oid, iid, rid); } /** * Notifies the library that the set of Instances existing in a given Object changed. It may * trigger an LwM2M Notify message, update server connections and perform other tasks, as * required for the specified Object ID. * *

Needs to be called for each Object, after an Instance is created or removed by means other * than LwM2M. * *

Note that it should not be called after a Create or Delete performed by the LwM2M server. * * @param oid Object ID of the changed Object. * @throws IllegalArgumentException If oid is not representable as a 16-bit * unsigned integer. * @throws IllegalStateException If {@link #close()} has already been called on this object. * @throws AnjayException If the notification cannot be scheduled for any reason, which may * include an out-of-memory condition. */ public void notifyInstancesChanged(int oid) { this.anjay.notifyInstancesChanged(oid); } /** * Registers the Object in the data model, making it available for RPC calls. * * @param object Previously created Object instance. */ public void registerObject(AnjayObject object) { this.anjay.registerObject(object); } /** * Queries security configuration appropriate for a specified URI. * *

Given a URI, the Security object is scanned for instances with Server URI resource * matching it in the following way: * *

    *
  • if there is at least one instance with matching hostname, protocol and port number, and * valid secure connection configuration, the first such instance (in the order as * returned via Security Object's instance list handler) is used, *
  • otherwise, if there is at least one instance with matching hostname and valid secure * connection configuration, the first such instance (in the order as returned via * Security Object's instance list handler) is used. *
* *

The returned security information is exactly the same configuration that is used for LwM2M * connection with the server chosen with the rules described above. * *

IMPORTANT: The returned (if any) security configuration is valid only as long as no calls * to {@link #schedRun} or {@link #serve} (or equivalent) are made, and as long as the * underlying data model from which the security configuration is obtained does not change. * Otherwise it MAY be invalidated and {@link java.util.ConcurrentModificationException} may be * thrown in contexts where the returned instance is used. * * @param uri URI for which to find security configuration. * @return {@link AnjaySecurityConfigFromDm} instance or empty Optional if no security * information for the specified url could be found. */ public Optional securityConfigFromDm(String uri) { if (this.anjay.hasSecurityConfigForUri(uri)) { return Optional.of(new AnjaySecurityConfigFromDm(uri)); } return Optional.empty(); } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy