blob: 7786ea49ee67c7abc941134e730f927cfef0825c [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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 org.apache.nlpcraft.model.tools.embedded;
import org.apache.nlpcraft.common.*;
import org.apache.nlpcraft.model.tools.test.*;
import org.apache.nlpcraft.probe.*;
import org.apache.nlpcraft.probe.mgrs.nlp.*;
import java.util.concurrent.*;
import java.util.function.*;
/**
* Embedded probe controller. Typically, data probes are launched in their own independent JVMs. However,
* in some cases it is more convenient for model implementation or preferable for performance reasons to host
* a data model (and hence the data probe) in the same "client" JVM.
* <p>
* The standard processing flow with the data probe running in a separate JVM looks like this:
* <br>
* <code>
* App ⇒ <b>JVM</b><sub>1</sub>(REST Server) ⇒ <b>JVM</b><sub>2</sub>(Probe) ⇒ <b>JVM</b><sub>1</sub>(REST Server) ⇒ App
* </code>
* <br>
* There are at least 4 networks hops between client application request and response.
* <p>
* However, when using native Java Client or {@link NCTestClient Java Test Client} in embedded probe mode
* the processing flow is shortened:
* <br>
* <code>
* <b>JVM</b><sub>1</sub>(App) ⇒ <b>JVM</b><sub>2</sub>(REST Server) ⇒ <b>JVM</b><sub>1</sub>(Probe ⇒ App)
* </code>
* <br>
* In this case there are only 2 hops as both client application and the data probe (and the model) are hosted
* in the same JVM.
* <p>
* Notes:
* <ul>
* <li>
* Embedded probe is only available for JVM processes (and can be used with any JVM languages).
* </li>
* <li>
* There can be only one embedded probe per JVM.
* </li>
* <li>
* Once data probe is stopped and cannot be started again in the same JVM.
* </li>
* <li>
* Even though the caller can register local-JVM listener for the query results, these results
* will still be asynchronously delivered to the REST server in the usual manner so that other clients
* could fetch these results to maintain internal logging, tracing and metrics. If the client
* application hosting data model and its probe <i>is the only client</i> for that model it needs to cancel the
* request on the REST server after receiving a local-JVM callback to release associated
* resources on the REST server.
* </li>
* </ul>
*/
public class NCEmbeddedProbe {
private static boolean waitForFuture(CompletableFuture<Integer> fut) {
while (!fut.isDone())
try {
return fut.get() == 0;
}
catch (InterruptedException | ExecutionException ignored) {}
return false;
}
/**
* Start the embedded probe with optional configuration file and models overrides.
*
* @param cfgFile Optional configuration file path. It should be either a full path or the file name
* that can be found in the current working directory or on the classpath as a class loader
* resource. If provided - it is equivalent to starting a probe using <code>-config=cfgFile</code>
* command line argument. If {@code null} - the probe will start with the default configuration.
* @param mdlClasses Optional data model classes to be deployed by the embedded probe. If provided -
* these will override {@code nlpcraft.probe.models} configuration property. If {@code null} - the models
* defined in the configuration (default or provided via {@code cfgFile} parameter) will be used.
* Each class should be a fully qualified class name.
* @throws NCException Thrown in case of any errors starting the data probe.
* @return Whether or not probe started ok.
*/
public static boolean start(String cfgFile, String... mdlClasses) {
CompletableFuture<Integer> fut = new CompletableFuture<>();
NCProbeBoot$.MODULE$.startEmbedded(cfgFile, mdlClasses, fut);
return waitForFuture(fut);
}
/**
* Starts the embedded probe with default configuration and specified overrides.
*
* @param probeId Probe ID override.
* @param tok Probe token override.
* @param upLink Probe up-link to the server override.
* @param dnLink Probe down-link from the server override.
* @param mdlClasses One or more data model classes overrides to be deployed by the embedded probe. At least
* model must be provided. Each class should be a fully qualified class name.
* @throws NCException Thrown in case of any errors starting the data probe.
* @return Whether or not probe started ok.
*/
public static boolean start(
String probeId,
String tok,
String upLink,
String dnLink,
String... mdlClasses) {
if (mdlClasses.length == 0)
throw new NCException("At least one model class must be provided when starting embedded probe.");
CompletableFuture<Integer> fut = new CompletableFuture<>();
NCProbeBoot$.MODULE$.startEmbedded(probeId, tok, upLink, dnLink, mdlClasses, fut);
return waitForFuture(fut);
}
/**
* Stops the embedded probe, if it was started before. Note that the probe cannot be started again
* in the same JVM process.
*
* @throws NCException Thrown in case of any errors stopping the data probe.
*/
public static void stop() {
NCProbeBoot$.MODULE$.stop();
}
/**
* Registers the callback on query processing results. Results from all models deployed on this embedded probe
* will trigger this callback.
*
* @param cb Callback to register.
* @throws NCException Thrown in case of any errors registering a callback.
*/
public static void registerCallback(Consumer<NCEmbeddedResult> cb) {
NCProbeEnrichmentManager$.MODULE$.addEmbeddedCallback(cb);
}
/**
* Unregisters previously registered callback. Ignored if given callback wasn't registered before.
*
* @param cb Callback to unregister.
* @throws NCException Thrown in case of any errors unregistering a callback.
*/
public static void unregisterCallback(Consumer<NCEmbeddedResult> cb) {
NCProbeEnrichmentManager$.MODULE$.removeEmbeddedCallback(cb);
}
}