diff --git a/IoTORDSAccess/.classpath b/IoTORDSAccess/.classpath new file mode 100644 index 0000000..96c6daa --- /dev/null +++ b/IoTORDSAccess/.classpath @@ -0,0 +1,51 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/IoTORDSAccess/.factorypath b/IoTORDSAccess/.factorypath new file mode 100644 index 0000000..1f07f61 --- /dev/null +++ b/IoTORDSAccess/.factorypath @@ -0,0 +1,44 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/IoTORDSAccess/.gitignore b/IoTORDSAccess/.gitignore new file mode 100644 index 0000000..7c0682a --- /dev/null +++ b/IoTORDSAccess/.gitignore @@ -0,0 +1,4 @@ +/.settings/ +/target/ +/config/ +/config-secure/ diff --git a/IoTORDSAccess/.project b/IoTORDSAccess/.project new file mode 100644 index 0000000..2f77ccd --- /dev/null +++ b/IoTORDSAccess/.project @@ -0,0 +1,23 @@ + + + IoTORDSAccess + + + + + + org.eclipse.jdt.core.javabuilder + + + + + org.eclipse.m2e.core.maven2Builder + + + + + + org.eclipse.jdt.core.javanature + org.eclipse.m2e.core.maven2Nature + + diff --git a/IoTORDSAccess/README.md b/IoTORDSAccess/README.md new file mode 100644 index 0000000..1165a24 --- /dev/null +++ b/IoTORDSAccess/README.md @@ -0,0 +1,29 @@ +## Micronaut 4.10.3 Documentation + +- [User Guide](https://docs.micronaut.io/4.10.3/guide/index.html) +- [API Reference](https://docs.micronaut.io/4.10.3/api/index.html) +- [Configuration Reference](https://docs.micronaut.io/4.10.3/guide/configurationreference.html) +- [Micronaut Guides](https://guides.micronaut.io/index.html) +--- + +- [Micronaut Maven Plugin documentation](https://micronaut-projects.github.io/micronaut-maven-plugin/latest/) +## Feature micronaut-aot documentation + +- [Micronaut AOT documentation](https://micronaut-projects.github.io/micronaut-aot/latest/guide/) + + +## Feature maven-enforcer-plugin documentation + +- [https://maven.apache.org/enforcer/maven-enforcer-plugin/](https://maven.apache.org/enforcer/maven-enforcer-plugin/) + + +## Feature serialization-jackson documentation + +- [Micronaut Serialization Jackson Core documentation](https://micronaut-projects.github.io/micronaut-serialization/latest/guide/) + + +## Feature http-client documentation + +- [Micronaut HTTP Client documentation](https://docs.micronaut.io/latest/guide/index.html#nettyHttpClient) + + diff --git a/IoTORDSAccess/aot-jar.properties b/IoTORDSAccess/aot-jar.properties new file mode 100644 index 0000000..f19e464 --- /dev/null +++ b/IoTORDSAccess/aot-jar.properties @@ -0,0 +1,37 @@ +# AOT configuration properties for jar packaging +# Please review carefully the optimizations enabled below +# Check https://micronaut-projects.github.io/micronaut-aot/latest/guide/ for more details + +# Caches environment property values: environment properties will be deemed immutable after application startup. +cached.environment.enabled=true + +# Precomputes Micronaut configuration property keys from the current environment variables +precompute.environment.properties.enabled=true + +# Replaces logback.xml with a pure Java configuration +logback.xml.to.java.enabled=true + +# Converts configuration files from YAML and properties to Java configuration +property-source-loader.generate.enabled=true + +# Scans for service types ahead-of-time, avoiding classpath scanning at startup +serviceloading.jit.enabled=true + +# Scans reactive types at build time instead of runtime +scan.reactive.types.enabled=true + +# Deduces the environment at build time instead of runtime +deduce.environment.enabled=true + +# Checks for the existence of some types at build time instead of runtime +known.missing.types.enabled=true + +# Precomputes property sources at build time +sealed.property.source.enabled=true + +# The list of service types to be scanned (comma separated) +service.types=io.micronaut.context.env.PropertySourceLoader,io.micronaut.inject.BeanConfiguration,io.micronaut.inject.BeanDefinitionReference,io.micronaut.http.HttpRequestFactory,io.micronaut.http.HttpResponseFactory,io.micronaut.core.beans.BeanIntrospectionReference,io.micronaut.core.convert.TypeConverterRegistrar,io.micronaut.context.env.PropertyExpressionResolver + +# A list of types that the AOT analyzer needs to check for existence (comma separated) +known.missing.types.list=io.reactivex.Observable,reactor.core.publisher.Flux,kotlinx.coroutines.flow.Flow,io.reactivex.rxjava3.core.Flowable,io.reactivex.rxjava3.core.Observable,io.reactivex.Single,reactor.core.publisher.Mono,io.reactivex.Maybe,io.reactivex.rxjava3.core.Single,io.reactivex.rxjava3.core.Maybe,io.reactivex.Completable,io.reactivex.rxjava3.core.Completable,io.methvin.watchservice.MacOSXListeningWatchService,io.micronaut.core.async.publisher.CompletableFuturePublisher,io.micronaut.core.async.publisher.Publishers.JustPublisher,io.micronaut.core.async.subscriber.Completable + diff --git a/IoTORDSAccess/micronaut-cli.yml b/IoTORDSAccess/micronaut-cli.yml new file mode 100644 index 0000000..464f616 --- /dev/null +++ b/IoTORDSAccess/micronaut-cli.yml @@ -0,0 +1,6 @@ +applicationType: default +defaultPackage: com.oracle.demo.timg.iot +testFramework: junit +sourceLanguage: java +buildTool: maven +features: [app-name, http-client, java, java-application, junit, logback, maven, maven-enforcer-plugin, micronaut-aot, micronaut-http-validation, micronaut-processing-compiler-args, netty-server, properties, readme, serialization-jackson, shade, static-resources] diff --git a/IoTORDSAccess/mvnw b/IoTORDSAccess/mvnw new file mode 100644 index 0000000..8822887 --- /dev/null +++ b/IoTORDSAccess/mvnw @@ -0,0 +1,287 @@ +#!/bin/sh +# ---------------------------------------------------------------------------- +# 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 +# +# https://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. +# ---------------------------------------------------------------------------- + +# ---------------------------------------------------------------------------- +# Apache Maven Wrapper startup batch script, version 3.1.1 +# +# Required ENV vars: +# ------------------ +# JAVA_HOME - location of a JDK home dir +# +# Optional ENV vars +# ----------------- +# MAVEN_OPTS - parameters passed to the Java VM when running Maven +# e.g. to debug Maven itself, use +# set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +# MAVEN_SKIP_RC - flag to disable loading of mavenrc files +# ---------------------------------------------------------------------------- + +if [ -z "$MAVEN_SKIP_RC" ] ; then + + if [ -f /usr/local/etc/mavenrc ] ; then + . /usr/local/etc/mavenrc + fi + + if [ -f /etc/mavenrc ] ; then + . /etc/mavenrc + fi + + if [ -f "$HOME/.mavenrc" ] ; then + . "$HOME/.mavenrc" + fi + +fi + +# OS specific support. $var _must_ be set to either true or false. +cygwin=false; +darwin=false; +mingw=false +case "`uname`" in + CYGWIN*) cygwin=true ;; + MINGW*) mingw=true;; + Darwin*) darwin=true + # Use /usr/libexec/java_home if available, otherwise fall back to /Library/Java/Home + # See https://developer.apple.com/library/mac/qa/qa1170/_index.html + if [ -z "$JAVA_HOME" ]; then + if [ -x "/usr/libexec/java_home" ]; then + JAVA_HOME="`/usr/libexec/java_home`"; export JAVA_HOME + else + JAVA_HOME="/Library/Java/Home"; export JAVA_HOME + fi + fi + ;; +esac + +if [ -z "$JAVA_HOME" ] ; then + if [ -r /etc/gentoo-release ] ; then + JAVA_HOME=`java-config --jre-home` + fi +fi + +# For Cygwin, ensure paths are in UNIX format before anything is touched +if $cygwin ; then + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --unix "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --unix "$CLASSPATH"` +fi + +# For Mingw, ensure paths are in UNIX format before anything is touched +if $mingw ; then + [ -n "$JAVA_HOME" ] && + JAVA_HOME="`(cd "$JAVA_HOME"; pwd)`" +fi + +if [ -z "$JAVA_HOME" ]; then + javaExecutable="`which javac`" + if [ -n "$javaExecutable" ] && ! [ "`expr \"$javaExecutable\" : '\([^ ]*\)'`" = "no" ]; then + # readlink(1) is not available as standard on Solaris 10. + readLink=`which readlink` + if [ ! `expr "$readLink" : '\([^ ]*\)'` = "no" ]; then + if $darwin ; then + javaHome="`dirname \"$javaExecutable\"`" + javaExecutable="`cd \"$javaHome\" && pwd -P`/javac" + else + javaExecutable="`readlink -f \"$javaExecutable\"`" + fi + javaHome="`dirname \"$javaExecutable\"`" + javaHome=`expr "$javaHome" : '\(.*\)/bin'` + JAVA_HOME="$javaHome" + export JAVA_HOME + fi + fi +fi + +if [ -z "$JAVACMD" ] ; then + if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD="$JAVA_HOME/jre/sh/java" + else + JAVACMD="$JAVA_HOME/bin/java" + fi + else + JAVACMD="`\\unset -f command; \\command -v java`" + fi +fi + +if [ ! -x "$JAVACMD" ] ; then + echo "Error: JAVA_HOME is not defined correctly." >&2 + echo " We cannot execute $JAVACMD" >&2 + exit 1 +fi + +if [ -z "$JAVA_HOME" ] ; then + echo "Warning: JAVA_HOME environment variable is not set." +fi + +# traverses directory structure from process work directory to filesystem root +# first directory with .mvn subdirectory is considered project base directory +find_maven_basedir() { + if [ -z "$1" ] + then + echo "Path not specified to find_maven_basedir" + return 1 + fi + + basedir="$1" + wdir="$1" + while [ "$wdir" != '/' ] ; do + if [ -d "$wdir"/.mvn ] ; then + basedir=$wdir + break + fi + # workaround for JBEAP-8937 (on Solaris 10/Sparc) + if [ -d "${wdir}" ]; then + wdir=`cd "$wdir/.."; pwd` + fi + # end of workaround + done + printf '%s' "$(cd "$basedir"; pwd)" +} + +# concatenates all lines of a file +concat_lines() { + if [ -f "$1" ]; then + echo "$(tr -s '\n' ' ' < "$1")" + fi +} + +BASE_DIR=$(find_maven_basedir "$(dirname $0)") +if [ -z "$BASE_DIR" ]; then + exit 1; +fi + +MAVEN_PROJECTBASEDIR=${MAVEN_BASEDIR:-"$BASE_DIR"}; export MAVEN_PROJECTBASEDIR +if [ "$MVNW_VERBOSE" = true ]; then + echo $MAVEN_PROJECTBASEDIR +fi + +########################################################################################## +# Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +# This allows using the maven wrapper in projects that prohibit checking in binary data. +########################################################################################## +if [ -r "$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found .mvn/wrapper/maven-wrapper.jar" + fi +else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Couldn't find .mvn/wrapper/maven-wrapper.jar, downloading it ..." + fi + if [ -n "$MVNW_REPOURL" ]; then + wrapperUrl="$MVNW_REPOURL/org/apache/maven/wrapper/maven-wrapper/3.1.1/maven-wrapper-3.1.1.jar" + else + wrapperUrl="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.1/maven-wrapper-3.1.1.jar" + fi + while IFS="=" read key value; do + case "$key" in (wrapperUrl) wrapperUrl="$value"; break ;; + esac + done < "$BASE_DIR/.mvn/wrapper/maven-wrapper.properties" + if [ "$MVNW_VERBOSE" = true ]; then + echo "Downloading from: $wrapperUrl" + fi + wrapperJarPath="$BASE_DIR/.mvn/wrapper/maven-wrapper.jar" + if $cygwin; then + wrapperJarPath=`cygpath --path --windows "$wrapperJarPath"` + fi + + if command -v wget > /dev/null; then + QUIET="--quiet" + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found wget ... using wget" + QUIET="" + fi + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + wget $QUIET "$wrapperUrl" -O "$wrapperJarPath" + else + wget $QUIET --http-user="$MVNW_USERNAME" --http-password="$MVNW_PASSWORD" "$wrapperUrl" -O "$wrapperJarPath" + fi + [ $? -eq 0 ] || rm -f "$wrapperJarPath" + elif command -v curl > /dev/null; then + QUIET="--silent" + if [ "$MVNW_VERBOSE" = true ]; then + echo "Found curl ... using curl" + QUIET="" + fi + if [ -z "$MVNW_USERNAME" ] || [ -z "$MVNW_PASSWORD" ]; then + curl $QUIET -o "$wrapperJarPath" "$wrapperUrl" -f -L + else + curl $QUIET --user "$MVNW_USERNAME:$MVNW_PASSWORD" -o "$wrapperJarPath" "$wrapperUrl" -f -L + fi + [ $? -eq 0 ] || rm -f "$wrapperJarPath" + else + if [ "$MVNW_VERBOSE" = true ]; then + echo "Falling back to using Java to download" + fi + javaSource="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.java" + javaClass="$BASE_DIR/.mvn/wrapper/MavenWrapperDownloader.class" + # For Cygwin, switch paths to Windows format before running javac + if $cygwin; then + javaSource=`cygpath --path --windows "$javaSource"` + javaClass=`cygpath --path --windows "$javaClass"` + fi + if [ -e "$javaSource" ]; then + if [ ! -e "$javaClass" ]; then + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Compiling MavenWrapperDownloader.java ..." + fi + # Compiling the Java class + ("$JAVA_HOME/bin/javac" "$javaSource") + fi + if [ -e "$javaClass" ]; then + # Running the downloader + if [ "$MVNW_VERBOSE" = true ]; then + echo " - Running MavenWrapperDownloader.java ..." + fi + ("$JAVA_HOME/bin/java" -cp .mvn/wrapper MavenWrapperDownloader "$MAVEN_PROJECTBASEDIR") + fi + fi + fi +fi +########################################################################################## +# End of extension +########################################################################################## + +MAVEN_OPTS="$(concat_lines "$MAVEN_PROJECTBASEDIR/.mvn/jvm.config") $MAVEN_OPTS" + +# For Cygwin, switch paths to Windows format before running java +if $cygwin; then + [ -n "$JAVA_HOME" ] && + JAVA_HOME=`cygpath --path --windows "$JAVA_HOME"` + [ -n "$CLASSPATH" ] && + CLASSPATH=`cygpath --path --windows "$CLASSPATH"` + [ -n "$MAVEN_PROJECTBASEDIR" ] && + MAVEN_PROJECTBASEDIR=`cygpath --path --windows "$MAVEN_PROJECTBASEDIR"` +fi + +# Provide a "standardized" way to retrieve the CLI args that will +# work with both Windows and non-Windows executions. +MAVEN_CMD_LINE_ARGS="$MAVEN_CONFIG $@" +export MAVEN_CMD_LINE_ARGS + +WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +exec "$JAVACMD" \ + $MAVEN_OPTS \ + $MAVEN_DEBUG_OPTS \ + -classpath "$MAVEN_PROJECTBASEDIR/.mvn/wrapper/maven-wrapper.jar" \ + "-Dmaven.multiModuleProjectDirectory=${MAVEN_PROJECTBASEDIR}" \ + ${WRAPPER_LAUNCHER} $MAVEN_CONFIG "$@" diff --git a/IoTORDSAccess/mvnw.bat b/IoTORDSAccess/mvnw.bat new file mode 100644 index 0000000..1d7c59b --- /dev/null +++ b/IoTORDSAccess/mvnw.bat @@ -0,0 +1,187 @@ +@REM ---------------------------------------------------------------------------- +@REM Licensed to the Apache Software Foundation (ASF) under one +@REM or more contributor license agreements. See the NOTICE file +@REM distributed with this work for additional information +@REM regarding copyright ownership. The ASF licenses this file +@REM to you under the Apache License, Version 2.0 (the +@REM "License"); you may not use this file except in compliance +@REM with the License. You may obtain a copy of the License at +@REM +@REM https://www.apache.org/licenses/LICENSE-2.0 +@REM +@REM Unless required by applicable law or agreed to in writing, +@REM software distributed under the License is distributed on an +@REM "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY +@REM KIND, either express or implied. See the License for the +@REM specific language governing permissions and limitations +@REM under the License. +@REM ---------------------------------------------------------------------------- + +@REM ---------------------------------------------------------------------------- +@REM Apache Maven Wrapper startup batch script, version 3.1.1 +@REM +@REM Required ENV vars: +@REM JAVA_HOME - location of a JDK home dir +@REM +@REM Optional ENV vars +@REM MAVEN_BATCH_ECHO - set to 'on' to enable the echoing of the batch commands +@REM MAVEN_BATCH_PAUSE - set to 'on' to wait for a keystroke before ending +@REM MAVEN_OPTS - parameters passed to the Java VM when running Maven +@REM e.g. to debug Maven itself, use +@REM set MAVEN_OPTS=-Xdebug -Xrunjdwp:transport=dt_socket,server=y,suspend=y,address=8000 +@REM MAVEN_SKIP_RC - flag to disable loading of mavenrc files +@REM ---------------------------------------------------------------------------- + +@REM Begin all REM lines with '@' in case MAVEN_BATCH_ECHO is 'on' +@echo off +@REM set title of command window +title %0 +@REM enable echoing by setting MAVEN_BATCH_ECHO to 'on' +@if "%MAVEN_BATCH_ECHO%" == "on" echo %MAVEN_BATCH_ECHO% + +@REM set %HOME% to equivalent of $HOME +if "%HOME%" == "" (set "HOME=%HOMEDRIVE%%HOMEPATH%") + +@REM Execute a user defined script before this one +if not "%MAVEN_SKIP_RC%" == "" goto skipRcPre +@REM check for pre script, once with legacy .bat ending and once with .cmd ending +if exist "%USERPROFILE%\mavenrc_pre.bat" call "%USERPROFILE%\mavenrc_pre.bat" %* +if exist "%USERPROFILE%\mavenrc_pre.cmd" call "%USERPROFILE%\mavenrc_pre.cmd" %* +:skipRcPre + +@setlocal + +set ERROR_CODE=0 + +@REM To isolate internal variables from possible post scripts, we use another setlocal +@setlocal + +@REM ==== START VALIDATION ==== +if not "%JAVA_HOME%" == "" goto OkJHome + +echo. +echo Error: JAVA_HOME not found in your environment. >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +:OkJHome +if exist "%JAVA_HOME%\bin\java.exe" goto init + +echo. +echo Error: JAVA_HOME is set to an invalid directory. >&2 +echo JAVA_HOME = "%JAVA_HOME%" >&2 +echo Please set the JAVA_HOME variable in your environment to match the >&2 +echo location of your Java installation. >&2 +echo. +goto error + +@REM ==== END VALIDATION ==== + +:init + +@REM Find the project base dir, i.e. the directory that contains the folder ".mvn". +@REM Fallback to current working directory if not found. + +set MAVEN_PROJECTBASEDIR=%MAVEN_BASEDIR% +IF NOT "%MAVEN_PROJECTBASEDIR%"=="" goto endDetectBaseDir + +set EXEC_DIR=%CD% +set WDIR=%EXEC_DIR% +:findBaseDir +IF EXIST "%WDIR%"\.mvn goto baseDirFound +cd .. +IF "%WDIR%"=="%CD%" goto baseDirNotFound +set WDIR=%CD% +goto findBaseDir + +:baseDirFound +set MAVEN_PROJECTBASEDIR=%WDIR% +cd "%EXEC_DIR%" +goto endDetectBaseDir + +:baseDirNotFound +set MAVEN_PROJECTBASEDIR=%EXEC_DIR% +cd "%EXEC_DIR%" + +:endDetectBaseDir + +IF NOT EXIST "%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config" goto endReadAdditionalConfig + +@setlocal EnableExtensions EnableDelayedExpansion +for /F "usebackq delims=" %%a in ("%MAVEN_PROJECTBASEDIR%\.mvn\jvm.config") do set JVM_CONFIG_MAVEN_PROPS=!JVM_CONFIG_MAVEN_PROPS! %%a +@endlocal & set JVM_CONFIG_MAVEN_PROPS=%JVM_CONFIG_MAVEN_PROPS% + +:endReadAdditionalConfig + +SET MAVEN_JAVA_EXE="%JAVA_HOME%\bin\java.exe" +set WRAPPER_JAR="%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.jar" +set WRAPPER_LAUNCHER=org.apache.maven.wrapper.MavenWrapperMain + +set WRAPPER_URL="https://repo.maven.apache.org/maven2/org/apache/maven/wrapper/maven-wrapper/3.1.1/maven-wrapper-3.1.1.jar" + +FOR /F "usebackq tokens=1,2 delims==" %%A IN ("%MAVEN_PROJECTBASEDIR%\.mvn\wrapper\maven-wrapper.properties") DO ( + IF "%%A"=="wrapperUrl" SET WRAPPER_URL=%%B +) + +@REM Extension to allow automatically downloading the maven-wrapper.jar from Maven-central +@REM This allows using the maven wrapper in projects that prohibit checking in binary data. +if exist %WRAPPER_JAR% ( + if "%MVNW_VERBOSE%" == "true" ( + echo Found %WRAPPER_JAR% + ) +) else ( + if not "%MVNW_REPOURL%" == "" ( + SET WRAPPER_URL="%MVNW_REPOURL%/org/apache/maven/wrapper/maven-wrapper/3.1.1/maven-wrapper-3.1.1.jar" + ) + if "%MVNW_VERBOSE%" == "true" ( + echo Couldn't find %WRAPPER_JAR%, downloading it ... + echo Downloading from: %WRAPPER_URL% + ) + + powershell -Command "&{"^ + "$webclient = new-object System.Net.WebClient;"^ + "if (-not ([string]::IsNullOrEmpty('%MVNW_USERNAME%') -and [string]::IsNullOrEmpty('%MVNW_PASSWORD%'))) {"^ + "$webclient.Credentials = new-object System.Net.NetworkCredential('%MVNW_USERNAME%', '%MVNW_PASSWORD%');"^ + "}"^ + "[Net.ServicePointManager]::SecurityProtocol = [Net.SecurityProtocolType]::Tls12; $webclient.DownloadFile('%WRAPPER_URL%', '%WRAPPER_JAR%')"^ + "}" + if "%MVNW_VERBOSE%" == "true" ( + echo Finished downloading %WRAPPER_JAR% + ) +) +@REM End of extension + +@REM Provide a "standardized" way to retrieve the CLI args that will +@REM work with both Windows and non-Windows executions. +set MAVEN_CMD_LINE_ARGS=%* + +%MAVEN_JAVA_EXE% ^ + %JVM_CONFIG_MAVEN_PROPS% ^ + %MAVEN_OPTS% ^ + %MAVEN_DEBUG_OPTS% ^ + -classpath %WRAPPER_JAR% ^ + "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" ^ + %WRAPPER_LAUNCHER% %MAVEN_CONFIG% %* +if ERRORLEVEL 1 goto error +goto end + +:error +set ERROR_CODE=1 + +:end +@endlocal & set ERROR_CODE=%ERROR_CODE% + +if not "%MAVEN_SKIP_RC%"=="" goto skipRcPost +@REM check for post script, once with legacy .bat ending and once with .cmd ending +if exist "%USERPROFILE%\mavenrc_post.bat" call "%USERPROFILE%\mavenrc_post.bat" +if exist "%USERPROFILE%\mavenrc_post.cmd" call "%USERPROFILE%\mavenrc_post.cmd" +:skipRcPost + +@REM pause the script if MAVEN_BATCH_PAUSE is set to 'on' +if "%MAVEN_BATCH_PAUSE%"=="on" pause + +if "%MAVEN_TERMINATE_CMD%"=="on" exit %ERROR_CODE% + +cmd /C exit /B %ERROR_CODE% diff --git a/IoTORDSAccess/pom.xml b/IoTORDSAccess/pom.xml new file mode 100644 index 0000000..79a459c --- /dev/null +++ b/IoTORDSAccess/pom.xml @@ -0,0 +1,191 @@ + + + + 4.0.0 + com.oracle.demo.timg.iot + iotordsaccess + 0.1 + ${packaging} + + + io.micronaut.platform + micronaut-parent + 4.10.4 + + + jar + 21 + 21 + 4.10.3 + false + com.oracle.demo.timg.iot.aot.generated + netty + com.oracle.demo.timg.iot.iotordsaccess.Application + + + + + central + https://repo.maven.apache.org/maven2 + + + + + + io.micronaut + micronaut-http-client + compile + + + + io.micronaut.jsonschema + micronaut-json-schema-annotations + compile + + + io.micronaut.serde + micronaut-serde-jackson + compile + + + ch.qos.logback + logback-classic + runtime + + + org.projectlombok + lombok + provided + + + io.micronaut.jsonschema + micronaut-json-schema-validation + test + + + org.yaml + snakeyaml + runtime + + + io.micronaut.test + micronaut-test-junit5 + test + + + org.junit.jupiter + junit-jupiter-api + test + + + org.junit.jupiter + junit-jupiter-engine + test + + + + + + io.micronaut.maven + micronaut-maven-plugin + + aot-${packaging}.properties + + + + org.apache.maven.plugins + maven-enforcer-plugin + + + org.apache.maven.plugins + maven-compiler-plugin + + + + + + + org.projectlombok + lombok + ${lombok.version} + + + io.micronaut + micronaut-inject-java + ${micronaut.core.version} + + + io.micronaut + micronaut-graal + ${micronaut.core.version} + + + io.micronaut + micronaut-http-validation + ${micronaut.core.version} + + + io.micronaut.jsonschema + micronaut-json-schema-processor + + + io.micronaut.serde + micronaut-serde-processor + ${micronaut.serialization.version} + + + io.micronaut + micronaut-inject + + + + + + -Amicronaut.processing.group=com.oracle.demo.timg.iot + -Amicronaut.processing.module=iotordsaccess + + + + + + + diff --git a/IoTORDSAccess/sample-config-secure/idcs-oauth.yml b/IoTORDSAccess/sample-config-secure/idcs-oauth.yml new file mode 100644 index 0000000..2f96a99 --- /dev/null +++ b/IoTORDSAccess/sample-config-secure/idcs-oauth.yml @@ -0,0 +1,16 @@ +ords: + idcs: + idcshostname: + username: + password: + oauth: + appid: + appsecret: +iot: + region: "uk-london-1" + domaingroup: + id: + domain: + id: + ordsapi: + version: "20250531" \ No newline at end of file diff --git a/IoTORDSAccess/sample-config/services.yml b/IoTORDSAccess/sample-config/services.yml new file mode 100644 index 0000000..dcf566e --- /dev/null +++ b/IoTORDSAccess/sample-config/services.yml @@ -0,0 +1,7 @@ +micronaut: + http: + services: + idcsoauthtoken: + url: "https://${ords.idcs.hostname}.identity.oraclecloud.com:443" + ordsapi: + url: "https://${iot.domaingroup.id}.data.iot.${iot.region}.oci.oraclecloud.com:443" diff --git a/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/Application.java b/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/Application.java new file mode 100644 index 0000000..54773be --- /dev/null +++ b/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/Application.java @@ -0,0 +1,46 @@ +/*Copyright (c) 2025 Oracle and/or its affiliates. + +The Universal Permissive License (UPL), Version 1.0 + +Subject to the condition set forth below, permission is hereby granted to any +person obtaining a copy of this software, associated documentation and/or data +(collectively the "Software"), free of charge and under any and all copyright +rights in the Software, and any and all patent rights owned or freely +licensable by each licensor hereunder covering either (i) the unmodified +Software as contributed to or provided by such licensor, or (ii) the Larger +Works (as defined below), to deal in both + +(a) the Software, and +(b) any piece of software and/or hardware listed in the lrgrwrks.txt file if +one is included with the Software (each a "Larger Work" to which the Software +is contributed by such licensors), + +without restriction, including without limitation the rights to copy, create +derivative works of, display, perform, and distribute the Software and make, +use, sell, offer for sale, import, export, have made, and have sold the +Software and the Larger Work(s), and to sublicense the foregoing rights on +either these or other terms. + +This license is subject to the following condition: +The above copyright notice and either this complete permission notice or at +a minimum a reference to the UPL must be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + */ +package com.oracle.demo.timg.iot.iotordsaccess; + +import io.micronaut.runtime.Micronaut; + +public class Application { + + public static void main(String[] args) { + Micronaut.run(Application.class, args); + } +} diff --git a/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/data/HistorizedDataEntryString.java b/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/data/HistorizedDataEntryString.java new file mode 100644 index 0000000..e4c85c3 --- /dev/null +++ b/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/data/HistorizedDataEntryString.java @@ -0,0 +1,52 @@ +/*Copyright (c) 2025 Oracle and/or its affiliates. + +The Universal Permissive License (UPL), Version 1.0 + +Subject to the condition set forth below, permission is hereby granted to any +person obtaining a copy of this software, associated documentation and/or data +(collectively the "Software"), free of charge and under any and all copyright +rights in the Software, and any and all patent rights owned or freely +licensable by each licensor hereunder covering either (i) the unmodified +Software as contributed to or provided by such licensor, or (ii) the Larger +Works (as defined below), to deal in both + +(a) the Software, and +(b) any piece of software and/or hardware listed in the lrgrwrks.txt file if +one is included with the Software (each a "Larger Work" to which the Software +is contributed by such licensors), + +without restriction, including without limitation the rights to copy, create +derivative works of, display, perform, and distribute the Software and make, +use, sell, offer for sale, import, export, have made, and have sold the +Software and the Larger Work(s), and to sublicense the foregoing rights on +either these or other terms. + +This license is subject to the following condition: +The above copyright notice and either this complete permission notice or at +a minimum a reference to the UPL must be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + */ +package com.oracle.demo.timg.iot.iotordsaccess.data; + +import java.time.ZonedDateTime; + +import io.micronaut.serde.annotation.Serdeable; +import lombok.Data; + +@Data +@Serdeable +public class HistorizedDataEntryString { + private long id; + private String digital_twin_instance_id; + private String content_path; + private String value; + private ZonedDateTime time_observed; +} diff --git a/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/data/HistorizedDataResponseString.java b/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/data/HistorizedDataResponseString.java new file mode 100644 index 0000000..cc98d49 --- /dev/null +++ b/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/data/HistorizedDataResponseString.java @@ -0,0 +1,54 @@ +/*Copyright (c) 2025 Oracle and/or its affiliates. + +The Universal Permissive License (UPL), Version 1.0 + +Subject to the condition set forth below, permission is hereby granted to any +person obtaining a copy of this software, associated documentation and/or data +(collectively the "Software"), free of charge and under any and all copyright +rights in the Software, and any and all patent rights owned or freely +licensable by each licensor hereunder covering either (i) the unmodified +Software as contributed to or provided by such licensor, or (ii) the Larger +Works (as defined below), to deal in both + +(a) the Software, and +(b) any piece of software and/or hardware listed in the lrgrwrks.txt file if +one is included with the Software (each a "Larger Work" to which the Software +is contributed by such licensors), + +without restriction, including without limitation the rights to copy, create +derivative works of, display, perform, and distribute the Software and make, +use, sell, offer for sale, import, export, have made, and have sold the +Software and the Larger Work(s), and to sublicense the foregoing rights on +either these or other terms. + +This license is subject to the following condition: +The above copyright notice and either this complete permission notice or at +a minimum a reference to the UPL must be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + */ +package com.oracle.demo.timg.iot.iotordsaccess.data; + +import java.util.List; + +import io.micronaut.serde.annotation.Serdeable; +import lombok.Data; + +@Data +@Serdeable +public class HistorizedDataResponseString { + private List items; + private boolean hasMore; + private int limit; + private int offset; + private int count; + private List links; + +} diff --git a/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/data/RawDataEntry.java b/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/data/RawDataEntry.java new file mode 100644 index 0000000..ccede6a --- /dev/null +++ b/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/data/RawDataEntry.java @@ -0,0 +1,53 @@ +/*Copyright (c) 2025 Oracle and/or its affiliates. + +The Universal Permissive License (UPL), Version 1.0 + +Subject to the condition set forth below, permission is hereby granted to any +person obtaining a copy of this software, associated documentation and/or data +(collectively the "Software"), free of charge and under any and all copyright +rights in the Software, and any and all patent rights owned or freely +licensable by each licensor hereunder covering either (i) the unmodified +Software as contributed to or provided by such licensor, or (ii) the Larger +Works (as defined below), to deal in both + +(a) the Software, and +(b) any piece of software and/or hardware listed in the lrgrwrks.txt file if +one is included with the Software (each a "Larger Work" to which the Software +is contributed by such licensors), + +without restriction, including without limitation the rights to copy, create +derivative works of, display, perform, and distribute the Software and make, +use, sell, offer for sale, import, export, have made, and have sold the +Software and the Larger Work(s), and to sublicense the foregoing rights on +either these or other terms. + +This license is subject to the following condition: +The above copyright notice and either this complete permission notice or at +a minimum a reference to the UPL must be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + */ +package com.oracle.demo.timg.iot.iotordsaccess.data; + +import java.time.ZonedDateTime; + +import io.micronaut.serde.annotation.Serdeable; +import lombok.Data; + +@Data +@Serdeable +public class RawDataEntry { + + private long id; + private String digital_twin_instance_id; + private ZonedDateTime time_received; + private String endpoint; + private String content_type; +} diff --git a/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/data/RawDataResponse.java b/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/data/RawDataResponse.java new file mode 100644 index 0000000..f271959 --- /dev/null +++ b/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/data/RawDataResponse.java @@ -0,0 +1,55 @@ +/*Copyright (c) 2025 Oracle and/or its affiliates. + +The Universal Permissive License (UPL), Version 1.0 + +Subject to the condition set forth below, permission is hereby granted to any +person obtaining a copy of this software, associated documentation and/or data +(collectively the "Software"), free of charge and under any and all copyright +rights in the Software, and any and all patent rights owned or freely +licensable by each licensor hereunder covering either (i) the unmodified +Software as contributed to or provided by such licensor, or (ii) the Larger +Works (as defined below), to deal in both + +(a) the Software, and +(b) any piece of software and/or hardware listed in the lrgrwrks.txt file if +one is included with the Software (each a "Larger Work" to which the Software +is contributed by such licensors), + +without restriction, including without limitation the rights to copy, create +derivative works of, display, perform, and distribute the Software and make, +use, sell, offer for sale, import, export, have made, and have sold the +Software and the Larger Work(s), and to sublicense the foregoing rights on +either these or other terms. + +This license is subject to the following condition: +The above copyright notice and either this complete permission notice or at +a minimum a reference to the UPL must be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + */ +package com.oracle.demo.timg.iot.iotordsaccess.data; + +import java.util.List; + +import io.micronaut.serde.annotation.Serdeable; +import lombok.Data; + +@Data +@Serdeable + +public class RawDataResponse { + private List items; + private boolean hasMore; + private int limit; + private int offset; + private int count; + private List links; + +} diff --git a/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/data/ResponseLink.java b/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/data/ResponseLink.java new file mode 100644 index 0000000..ee4048a --- /dev/null +++ b/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/data/ResponseLink.java @@ -0,0 +1,47 @@ +/*Copyright (c) 2025 Oracle and/or its affiliates. + +The Universal Permissive License (UPL), Version 1.0 + +Subject to the condition set forth below, permission is hereby granted to any +person obtaining a copy of this software, associated documentation and/or data +(collectively the "Software"), free of charge and under any and all copyright +rights in the Software, and any and all patent rights owned or freely +licensable by each licensor hereunder covering either (i) the unmodified +Software as contributed to or provided by such licensor, or (ii) the Larger +Works (as defined below), to deal in both + +(a) the Software, and +(b) any piece of software and/or hardware listed in the lrgrwrks.txt file if +one is included with the Software (each a "Larger Work" to which the Software +is contributed by such licensors), + +without restriction, including without limitation the rights to copy, create +derivative works of, display, perform, and distribute the Software and make, +use, sell, offer for sale, import, export, have made, and have sold the +Software and the Larger Work(s), and to sublicense the foregoing rights on +either these or other terms. + +This license is subject to the following condition: +The above copyright notice and either this complete permission notice or at +a minimum a reference to the UPL must be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + */ +package com.oracle.demo.timg.iot.iotordsaccess.data; + +import io.micronaut.serde.annotation.Serdeable; +import lombok.Data; + +@Data +@Serdeable +public class ResponseLink { + private String rel; + private String href; +} diff --git a/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/data/SnapshotDataEntryString.java b/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/data/SnapshotDataEntryString.java new file mode 100644 index 0000000..0740714 --- /dev/null +++ b/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/data/SnapshotDataEntryString.java @@ -0,0 +1,51 @@ +/*Copyright (c) 2025 Oracle and/or its affiliates. + +The Universal Permissive License (UPL), Version 1.0 + +Subject to the condition set forth below, permission is hereby granted to any +person obtaining a copy of this software, associated documentation and/or data +(collectively the "Software"), free of charge and under any and all copyright +rights in the Software, and any and all patent rights owned or freely +licensable by each licensor hereunder covering either (i) the unmodified +Software as contributed to or provided by such licensor, or (ii) the Larger +Works (as defined below), to deal in both + +(a) the Software, and +(b) any piece of software and/or hardware listed in the lrgrwrks.txt file if +one is included with the Software (each a "Larger Work" to which the Software +is contributed by such licensors), + +without restriction, including without limitation the rights to copy, create +derivative works of, display, perform, and distribute the Software and make, +use, sell, offer for sale, import, export, have made, and have sold the +Software and the Larger Work(s), and to sublicense the foregoing rights on +either these or other terms. + +This license is subject to the following condition: +The above copyright notice and either this complete permission notice or at +a minimum a reference to the UPL must be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + */ +package com.oracle.demo.timg.iot.iotordsaccess.data; + +import java.time.ZonedDateTime; + +import io.micronaut.serde.annotation.Serdeable; +import lombok.Data; + +@Data +@Serdeable +public class SnapshotDataEntryString { + private String digital_twin_instance_id; + private String content_path; + private String value; + private ZonedDateTime time_observed; +} diff --git a/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/data/SnapshotDataResponseString.java b/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/data/SnapshotDataResponseString.java new file mode 100644 index 0000000..807ab0d --- /dev/null +++ b/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/data/SnapshotDataResponseString.java @@ -0,0 +1,55 @@ +/*Copyright (c) 2025 Oracle and/or its affiliates. + +The Universal Permissive License (UPL), Version 1.0 + +Subject to the condition set forth below, permission is hereby granted to any +person obtaining a copy of this software, associated documentation and/or data +(collectively the "Software"), free of charge and under any and all copyright +rights in the Software, and any and all patent rights owned or freely +licensable by each licensor hereunder covering either (i) the unmodified +Software as contributed to or provided by such licensor, or (ii) the Larger +Works (as defined below), to deal in both + +(a) the Software, and +(b) any piece of software and/or hardware listed in the lrgrwrks.txt file if +one is included with the Software (each a "Larger Work" to which the Software +is contributed by such licensors), + +without restriction, including without limitation the rights to copy, create +derivative works of, display, perform, and distribute the Software and make, +use, sell, offer for sale, import, export, have made, and have sold the +Software and the Larger Work(s), and to sublicense the foregoing rights on +either these or other terms. + +This license is subject to the following condition: +The above copyright notice and either this complete permission notice or at +a minimum a reference to the UPL must be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + */ +package com.oracle.demo.timg.iot.iotordsaccess.data; + +import java.util.List; + +import io.micronaut.serde.annotation.Serdeable; +import lombok.Data; + +@Data +@Serdeable +public class SnapshotDataResponseString { + + private List items; + private boolean hasMore; + private int limit; + private int offset; + private int count; + private List links; + +} diff --git a/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/idcs/AuthTokenResponse.java b/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/idcs/AuthTokenResponse.java new file mode 100644 index 0000000..0951ca0 --- /dev/null +++ b/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/idcs/AuthTokenResponse.java @@ -0,0 +1,53 @@ +/*Copyright (c) 2025 Oracle and/or its affiliates. + +The Universal Permissive License (UPL), Version 1.0 + +Subject to the condition set forth below, permission is hereby granted to any +person obtaining a copy of this software, associated documentation and/or data +(collectively the "Software"), free of charge and under any and all copyright +rights in the Software, and any and all patent rights owned or freely +licensable by each licensor hereunder covering either (i) the unmodified +Software as contributed to or provided by such licensor, or (ii) the Larger +Works (as defined below), to deal in both + +(a) the Software, and +(b) any piece of software and/or hardware listed in the lrgrwrks.txt file if +one is included with the Software (each a "Larger Work" to which the Software +is contributed by such licensors), + +without restriction, including without limitation the rights to copy, create +derivative works of, display, perform, and distribute the Software and make, +use, sell, offer for sale, import, export, have made, and have sold the +Software and the Larger Work(s), and to sublicense the foregoing rights on +either these or other terms. + +This license is subject to the following condition: +The above copyright notice and either this complete permission notice or at +a minimum a reference to the UPL must be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + */ +package com.oracle.demo.timg.iot.iotordsaccess.idcs; + +import com.fasterxml.jackson.annotation.JsonProperty; + +import io.micronaut.serde.annotation.Serdeable; +import lombok.Data; + +@Serdeable +@Data +public class AuthTokenResponse { + @JsonProperty(value = "access_token") + private String accessToken; + @JsonProperty(value = "expires_in") + private int expiresIn; + @JsonProperty(value = "token_type") + private String tokenType; +} diff --git a/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/idcs/IDCSApplicationCredentials.java b/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/idcs/IDCSApplicationCredentials.java new file mode 100644 index 0000000..5314db6 --- /dev/null +++ b/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/idcs/IDCSApplicationCredentials.java @@ -0,0 +1,51 @@ +/*Copyright (c) 2025 Oracle and/or its affiliates. + +The Universal Permissive License (UPL), Version 1.0 + +Subject to the condition set forth below, permission is hereby granted to any +person obtaining a copy of this software, associated documentation and/or data +(collectively the "Software"), free of charge and under any and all copyright +rights in the Software, and any and all patent rights owned or freely +licensable by each licensor hereunder covering either (i) the unmodified +Software as contributed to or provided by such licensor, or (ii) the Larger +Works (as defined below), to deal in both + +(a) the Software, and +(b) any piece of software and/or hardware listed in the lrgrwrks.txt file if +one is included with the Software (each a "Larger Work" to which the Software +is contributed by such licensors), + +without restriction, including without limitation the rights to copy, create +derivative works of, display, perform, and distribute the Software and make, +use, sell, offer for sale, import, export, have made, and have sold the +Software and the Larger Work(s), and to sublicense the foregoing rights on +either these or other terms. + +This license is subject to the following condition: +The above copyright notice and either this complete permission notice or at +a minimum a reference to the UPL must be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + */ +package com.oracle.demo.timg.iot.iotordsaccess.idcs; + +import io.micronaut.context.annotation.ConfigurationProperties; +import io.micronaut.context.annotation.Requires; +import lombok.Data; + +@ConfigurationProperties(IDCSApplicationCredentials.PREFIX) +@Requires(property = IDCSApplicationCredentials.PREFIX + ".appid") +@Requires(property = IDCSApplicationCredentials.PREFIX + ".appsecret") +@Data +public class IDCSApplicationCredentials { + public static final String PREFIX = "ords.oauth"; + private String appid; + private String appsecret; +} \ No newline at end of file diff --git a/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/idcs/IDCSException.java b/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/idcs/IDCSException.java new file mode 100644 index 0000000..bebece8 --- /dev/null +++ b/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/idcs/IDCSException.java @@ -0,0 +1,62 @@ +/*Copyright (c) 2025 Oracle and/or its affiliates. + +The Universal Permissive License (UPL), Version 1.0 + +Subject to the condition set forth below, permission is hereby granted to any +person obtaining a copy of this software, associated documentation and/or data +(collectively the "Software"), free of charge and under any and all copyright +rights in the Software, and any and all patent rights owned or freely +licensable by each licensor hereunder covering either (i) the unmodified +Software as contributed to or provided by such licensor, or (ii) the Larger +Works (as defined below), to deal in both + +(a) the Software, and +(b) any piece of software and/or hardware listed in the lrgrwrks.txt file if +one is included with the Software (each a "Larger Work" to which the Software +is contributed by such licensors), + +without restriction, including without limitation the rights to copy, create +derivative works of, display, perform, and distribute the Software and make, +use, sell, offer for sale, import, export, have made, and have sold the +Software and the Larger Work(s), and to sublicense the foregoing rights on +either these or other terms. + +This license is subject to the following condition: +The above copyright notice and either this complete permission notice or at +a minimum a reference to the UPL must be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + */ +package com.oracle.demo.timg.iot.iotordsaccess.idcs; + +public class IDCSException extends Exception { + + private static final long serialVersionUID = -1050267580395460202L; + + public IDCSException() { + } + + public IDCSException(String message) { + super(message); + } + + public IDCSException(Throwable cause) { + super(cause); + } + + public IDCSException(String message, Throwable cause) { + super(message, cause); + } + + public IDCSException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } + +} diff --git a/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/idcs/IDCSOAuthApplicationTokenRetriever.java b/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/idcs/IDCSOAuthApplicationTokenRetriever.java new file mode 100644 index 0000000..8fb6039 --- /dev/null +++ b/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/idcs/IDCSOAuthApplicationTokenRetriever.java @@ -0,0 +1,127 @@ +/*Copyright (c) 2025 Oracle and/or its affiliates. + +The Universal Permissive License (UPL), Version 1.0 + +Subject to the condition set forth below, permission is hereby granted to any +person obtaining a copy of this software, associated documentation and/or data +(collectively the "Software"), free of charge and under any and all copyright +rights in the Software, and any and all patent rights owned or freely +licensable by each licensor hereunder covering either (i) the unmodified +Software as contributed to or provided by such licensor, or (ii) the Larger +Works (as defined below), to deal in both + +(a) the Software, and +(b) any piece of software and/or hardware listed in the lrgrwrks.txt file if +one is included with the Software (each a "Larger Work" to which the Software +is contributed by such licensors), + +without restriction, including without limitation the rights to copy, create +derivative works of, display, perform, and distribute the Software and make, +use, sell, offer for sale, import, export, have made, and have sold the +Software and the Larger Work(s), and to sublicense the foregoing rights on +either these or other terms. + +This license is subject to the following condition: +The above copyright notice and either this complete permission notice or at +a minimum a reference to the UPL must be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + */ +package com.oracle.demo.timg.iot.iotordsaccess.idcs; + +import java.time.Duration; +import java.time.LocalDateTime; + +import io.micronaut.context.annotation.Requires; +import io.micronaut.context.event.StartupEvent; +import io.micronaut.http.client.exceptions.HttpClientException; +import io.micronaut.runtime.event.annotation.EventListener; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; +import lombok.Getter; +import lombok.extern.java.Log; + +@Singleton +@Requires(property = IDCSUserCredentials.PREFIX + ".username") +@Requires(property = IDCSUserCredentials.PREFIX + ".password") +@Requires(property = IDCSApplicationCredentials.PREFIX + ".appid") +@Requires(property = IDCSApplicationCredentials.PREFIX + ".appsecret") +@Requires(property = IOTDomainDetails.PREFIX + ".id") +@Requires(property = IOTDomainGroupDetails.PREFIX + ".id") +@Log +public class IDCSOAuthApplicationTokenRetriever { + private final static String GRANT_TYPE = "password"; + @Inject + private IDCSUserCredentials idcsUserCredentials; + @Inject + private IOTDomainDetails domainSettings; + @Inject + private IOTDomainGroupDetails domainGroupSettings; + + private String scope; + + @Getter + private LocalDateTime currentTokenRenewTime = null; + + private String currentToken = null; + @Getter + private String tokenType; + + @Inject + private IDCSOAuthClient authClient; + + /** + * for testing only + * + */ + public void deleteTokenDetails() { + this.currentToken = null; + this.currentTokenRenewTime = null; + this.tokenType = null; + } + + /** + * for testing only + * + */ + public void forceTokenRetrievalAfter(Duration expiryOffset) { + currentTokenRenewTime = LocalDateTime.now().plus(expiryOffset); + } + + public String getToken() throws IDCSOAuthTokenRetrievalException { + if ((currentToken == null) || (currentTokenRenewTime == null) + || LocalDateTime.now().isAfter(currentTokenRenewTime)) { + AuthTokenResponse atr; + try { + atr = authClient.getOAuthToken(scope, GRANT_TYPE, idcsUserCredentials.getUsername(), + idcsUserCredentials.getPassword()); + } catch (HttpClientException e) { + throw new IDCSOAuthTokenRetrievalException("Problem getting the OAuth token " + e.getLocalizedMessage(), + e); + } + this.currentToken = atr.getAccessToken(); + this.tokenType = atr.getTokenType(); + // get a new renewal time, allow 60 seconds for processing the renewal if we + // need to, yes we should probably allow for better control or retrieval times + // but this is a demo, and not supposed to be production. + this.currentTokenRenewTime = LocalDateTime.now().plusSeconds(atr.getExpiresIn() - 60); + } + // we have a current token and it is still valid + return currentToken; + } + + @EventListener + public void onStartup(StartupEvent event) { + this.scope = "/" + this.domainGroupSettings.getId() + "/iot/" + this.domainSettings.getId(); + log.info("Startup event received for IDCSOAuthApplicationTokenRetriever idcsUserCredentials=" + + idcsUserCredentials + ", domainGroupSettings=" + domainGroupSettings + ", domainSettings=" + + domainSettings + ", scope=" + scope); + } +} \ No newline at end of file diff --git a/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/idcs/IDCSOAuthClient.java b/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/idcs/IDCSOAuthClient.java new file mode 100644 index 0000000..d725d50 --- /dev/null +++ b/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/idcs/IDCSOAuthClient.java @@ -0,0 +1,58 @@ +/*Copyright (c) 2025 Oracle and/or its affiliates. + +The Universal Permissive License (UPL), Version 1.0 + +Subject to the condition set forth below, permission is hereby granted to any +person obtaining a copy of this software, associated documentation and/or data +(collectively the "Software"), free of charge and under any and all copyright +rights in the Software, and any and all patent rights owned or freely +licensable by each licensor hereunder covering either (i) the unmodified +Software as contributed to or provided by such licensor, or (ii) the Larger +Works (as defined below), to deal in both + +(a) the Software, and +(b) any piece of software and/or hardware listed in the lrgrwrks.txt file if +one is included with the Software (each a "Larger Work" to which the Software +is contributed by such licensors), + +without restriction, including without limitation the rights to copy, create +derivative works of, display, perform, and distribute the Software and make, +use, sell, offer for sale, import, export, have made, and have sold the +Software and the Larger Work(s), and to sublicense the foregoing rights on +either these or other terms. + +This license is subject to the following condition: +The above copyright notice and either this complete permission notice or at +a minimum a reference to the UPL must be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + */ +package com.oracle.demo.timg.iot.iotordsaccess.idcs; + +import static io.micronaut.http.HttpHeaders.USER_AGENT; + +import io.micronaut.http.MediaType; +import io.micronaut.http.annotation.Consumes; +import io.micronaut.http.annotation.Header; +import io.micronaut.http.annotation.Post; +import io.micronaut.http.annotation.Produces; +import io.micronaut.http.client.annotation.Client; +import io.micronaut.http.client.exceptions.HttpClientException; + +@Client(id = "idcsoauthtoken") +@Header(name = USER_AGENT, value = "Micronaut HTTP Client") +public interface IDCSOAuthClient { + @Consumes(MediaType.APPLICATION_JSON) + @Produces(MediaType.APPLICATION_FORM_URLENCODED) + @Post(value = "/oauth2/v1/token") + public AuthTokenResponse getOAuthToken(String scope, String grant_type, String username, String password) + throws HttpClientException; + +} diff --git a/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/idcs/IDCSOAuthTokenRequestFilter.java b/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/idcs/IDCSOAuthTokenRequestFilter.java new file mode 100644 index 0000000..e665dd0 --- /dev/null +++ b/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/idcs/IDCSOAuthTokenRequestFilter.java @@ -0,0 +1,71 @@ +/*Copyright (c) 2025 Oracle and/or its affiliates. + +The Universal Permissive License (UPL), Version 1.0 + +Subject to the condition set forth below, permission is hereby granted to any +person obtaining a copy of this software, associated documentation and/or data +(collectively the "Software"), free of charge and under any and all copyright +rights in the Software, and any and all patent rights owned or freely +licensable by each licensor hereunder covering either (i) the unmodified +Software as contributed to or provided by such licensor, or (ii) the Larger +Works (as defined below), to deal in both + +(a) the Software, and +(b) any piece of software and/or hardware listed in the lrgrwrks.txt file if +one is included with the Software (each a "Larger Work" to which the Software +is contributed by such licensors), + +without restriction, including without limitation the rights to copy, create +derivative works of, display, perform, and distribute the Software and make, +use, sell, offer for sale, import, export, have made, and have sold the +Software and the Larger Work(s), and to sublicense the foregoing rights on +either these or other terms. + +This license is subject to the following condition: +The above copyright notice and either this complete permission notice or at +a minimum a reference to the UPL must be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + */ +package com.oracle.demo.timg.iot.iotordsaccess.idcs; + +import io.micronaut.context.annotation.Requires; +import io.micronaut.context.event.StartupEvent; +import io.micronaut.http.MutableHttpRequest; +import io.micronaut.http.annotation.ClientFilter; +import io.micronaut.http.annotation.RequestFilter; +import io.micronaut.runtime.event.annotation.EventListener; +import jakarta.inject.Inject; +import lombok.extern.java.Log; + +@ClientFilter(patterns = { "/oauth2/v1/token" }) +@Requires(property = IDCSApplicationCredentials.PREFIX + ".appid") +@Requires(property = IDCSApplicationCredentials.PREFIX + ".appsecret") +@Log +public class IDCSOAuthTokenRequestFilter { + private final String appid; + private final String appsecret; + + @Inject + public IDCSOAuthTokenRequestFilter(IDCSApplicationCredentials applicationCredentials) { + this.appid = applicationCredentials.getAppid(); + this.appsecret = applicationCredentials.getAppsecret(); + } + + @RequestFilter + public void doFilter(MutableHttpRequest request) { + request.basicAuth(this.appid, this.appsecret); + } + + @EventListener + public void onStartup(StartupEvent event) { + log.info("Startup event received for IDCSOAuthTokenRequestFilter appid=" + this.appid); + } +} \ No newline at end of file diff --git a/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/idcs/IDCSOAuthTokenRetrievalException.java b/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/idcs/IDCSOAuthTokenRetrievalException.java new file mode 100644 index 0000000..04477c2 --- /dev/null +++ b/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/idcs/IDCSOAuthTokenRetrievalException.java @@ -0,0 +1,63 @@ +/*Copyright (c) 2025 Oracle and/or its affiliates. + +The Universal Permissive License (UPL), Version 1.0 + +Subject to the condition set forth below, permission is hereby granted to any +person obtaining a copy of this software, associated documentation and/or data +(collectively the "Software"), free of charge and under any and all copyright +rights in the Software, and any and all patent rights owned or freely +licensable by each licensor hereunder covering either (i) the unmodified +Software as contributed to or provided by such licensor, or (ii) the Larger +Works (as defined below), to deal in both + +(a) the Software, and +(b) any piece of software and/or hardware listed in the lrgrwrks.txt file if +one is included with the Software (each a "Larger Work" to which the Software +is contributed by such licensors), + +without restriction, including without limitation the rights to copy, create +derivative works of, display, perform, and distribute the Software and make, +use, sell, offer for sale, import, export, have made, and have sold the +Software and the Larger Work(s), and to sublicense the foregoing rights on +either these or other terms. + +This license is subject to the following condition: +The above copyright notice and either this complete permission notice or at +a minimum a reference to the UPL must be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + */ +package com.oracle.demo.timg.iot.iotordsaccess.idcs; + +public class IDCSOAuthTokenRetrievalException extends IDCSException { + + private static final long serialVersionUID = 8469421315662618744L; + + public IDCSOAuthTokenRetrievalException() { + } + + public IDCSOAuthTokenRetrievalException(String message) { + super(message); + } + + public IDCSOAuthTokenRetrievalException(Throwable cause) { + super(cause); + } + + public IDCSOAuthTokenRetrievalException(String message, Throwable cause) { + super(message, cause); + } + + public IDCSOAuthTokenRetrievalException(String message, Throwable cause, boolean enableSuppression, + boolean writableStackTrace) { + super(message, cause, enableSuppression, writableStackTrace); + } + +} diff --git a/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/idcs/IDCSUserCredentials.java b/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/idcs/IDCSUserCredentials.java new file mode 100644 index 0000000..58c567a --- /dev/null +++ b/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/idcs/IDCSUserCredentials.java @@ -0,0 +1,51 @@ +/*Copyright (c) 2025 Oracle and/or its affiliates. + +The Universal Permissive License (UPL), Version 1.0 + +Subject to the condition set forth below, permission is hereby granted to any +person obtaining a copy of this software, associated documentation and/or data +(collectively the "Software"), free of charge and under any and all copyright +rights in the Software, and any and all patent rights owned or freely +licensable by each licensor hereunder covering either (i) the unmodified +Software as contributed to or provided by such licensor, or (ii) the Larger +Works (as defined below), to deal in both + +(a) the Software, and +(b) any piece of software and/or hardware listed in the lrgrwrks.txt file if +one is included with the Software (each a "Larger Work" to which the Software +is contributed by such licensors), + +without restriction, including without limitation the rights to copy, create +derivative works of, display, perform, and distribute the Software and make, +use, sell, offer for sale, import, export, have made, and have sold the +Software and the Larger Work(s), and to sublicense the foregoing rights on +either these or other terms. + +This license is subject to the following condition: +The above copyright notice and either this complete permission notice or at +a minimum a reference to the UPL must be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + */ +package com.oracle.demo.timg.iot.iotordsaccess.idcs; + +import io.micronaut.context.annotation.ConfigurationProperties; +import io.micronaut.context.annotation.Requires; +import lombok.Data; + +@ConfigurationProperties(IDCSUserCredentials.PREFIX) +@Requires(property = IDCSUserCredentials.PREFIX + ".username") +@Requires(property = IDCSUserCredentials.PREFIX + ".password") +@Data +public class IDCSUserCredentials { + public static final String PREFIX = "ords.idcs"; + private String username; + private String password; +} \ No newline at end of file diff --git a/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/idcs/IOTDomainDetails.java b/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/idcs/IOTDomainDetails.java new file mode 100644 index 0000000..49029cb --- /dev/null +++ b/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/idcs/IOTDomainDetails.java @@ -0,0 +1,49 @@ +/*Copyright (c) 2025 Oracle and/or its affiliates. + +The Universal Permissive License (UPL), Version 1.0 + +Subject to the condition set forth below, permission is hereby granted to any +person obtaining a copy of this software, associated documentation and/or data +(collectively the "Software"), free of charge and under any and all copyright +rights in the Software, and any and all patent rights owned or freely +licensable by each licensor hereunder covering either (i) the unmodified +Software as contributed to or provided by such licensor, or (ii) the Larger +Works (as defined below), to deal in both + +(a) the Software, and +(b) any piece of software and/or hardware listed in the lrgrwrks.txt file if +one is included with the Software (each a "Larger Work" to which the Software +is contributed by such licensors), + +without restriction, including without limitation the rights to copy, create +derivative works of, display, perform, and distribute the Software and make, +use, sell, offer for sale, import, export, have made, and have sold the +Software and the Larger Work(s), and to sublicense the foregoing rights on +either these or other terms. + +This license is subject to the following condition: +The above copyright notice and either this complete permission notice or at +a minimum a reference to the UPL must be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + */ +package com.oracle.demo.timg.iot.iotordsaccess.idcs; + +import io.micronaut.context.annotation.ConfigurationProperties; +import io.micronaut.context.annotation.Requires; +import lombok.Data; + +@ConfigurationProperties(IOTDomainDetails.PREFIX) +@Requires(property = IOTDomainDetails.PREFIX + ".id") +@Data +public class IOTDomainDetails { + public static final String PREFIX = "iot.domain"; + private String id; +} \ No newline at end of file diff --git a/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/idcs/IOTDomainGroupDetails.java b/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/idcs/IOTDomainGroupDetails.java new file mode 100644 index 0000000..93283cb --- /dev/null +++ b/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/idcs/IOTDomainGroupDetails.java @@ -0,0 +1,49 @@ +/*Copyright (c) 2025 Oracle and/or its affiliates. + +The Universal Permissive License (UPL), Version 1.0 + +Subject to the condition set forth below, permission is hereby granted to any +person obtaining a copy of this software, associated documentation and/or data +(collectively the "Software"), free of charge and under any and all copyright +rights in the Software, and any and all patent rights owned or freely +licensable by each licensor hereunder covering either (i) the unmodified +Software as contributed to or provided by such licensor, or (ii) the Larger +Works (as defined below), to deal in both + +(a) the Software, and +(b) any piece of software and/or hardware listed in the lrgrwrks.txt file if +one is included with the Software (each a "Larger Work" to which the Software +is contributed by such licensors), + +without restriction, including without limitation the rights to copy, create +derivative works of, display, perform, and distribute the Software and make, +use, sell, offer for sale, import, export, have made, and have sold the +Software and the Larger Work(s), and to sublicense the foregoing rights on +either these or other terms. + +This license is subject to the following condition: +The above copyright notice and either this complete permission notice or at +a minimum a reference to the UPL must be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + */ +package com.oracle.demo.timg.iot.iotordsaccess.idcs; + +import io.micronaut.context.annotation.ConfigurationProperties; +import io.micronaut.context.annotation.Requires; +import lombok.Data; + +@ConfigurationProperties(IOTDomainGroupDetails.PREFIX) +@Requires(property = IOTDomainGroupDetails.PREFIX + ".id") +@Data +public class IOTDomainGroupDetails { + public static final String PREFIX = "iot.domaingroup"; + private String id; +} \ No newline at end of file diff --git a/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/iotaccess/IoTDataAccessor.java b/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/iotaccess/IoTDataAccessor.java new file mode 100644 index 0000000..a7463f6 --- /dev/null +++ b/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/iotaccess/IoTDataAccessor.java @@ -0,0 +1,198 @@ +/*Copyright (c) 2025 Oracle and/or its affiliates. + +The Universal Permissive License (UPL), Version 1.0 + +Subject to the condition set forth below, permission is hereby granted to any +person obtaining a copy of this software, associated documentation and/or data +(collectively the "Software"), free of charge and under any and all copyright +rights in the Software, and any and all patent rights owned or freely +licensable by each licensor hereunder covering either (i) the unmodified +Software as contributed to or provided by such licensor, or (ii) the Larger +Works (as defined below), to deal in both + +(a) the Software, and +(b) any piece of software and/or hardware listed in the lrgrwrks.txt file if +one is included with the Software (each a "Larger Work" to which the Software +is contributed by such licensors), + +without restriction, including without limitation the rights to copy, create +derivative works of, display, perform, and distribute the Software and make, +use, sell, offer for sale, import, export, have made, and have sold the +Software and the Larger Work(s), and to sublicense the foregoing rights on +either these or other terms. + +This license is subject to the following condition: +The above copyright notice and either this complete permission notice or at +a minimum a reference to the UPL must be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + */ +package com.oracle.demo.timg.iot.iotordsaccess.iotaccess; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +import com.oracle.demo.timg.iot.iotordsaccess.data.HistorizedDataResponseString; +import com.oracle.demo.timg.iot.iotordsaccess.data.SnapshotDataEntryString; +import com.oracle.demo.timg.iot.iotordsaccess.data.SnapshotDataResponseString; +import com.oracle.demo.timg.iot.iotordsaccess.idcs.IDCSOAuthApplicationTokenRetriever; +import com.oracle.demo.timg.iot.iotordsaccess.ords.ORDSApiClient; +import com.oracle.demo.timg.iot.iotordsaccess.ords.ORDSDataRequestFilter; + +import io.micronaut.context.event.StartupEvent; +import io.micronaut.runtime.event.annotation.EventListener; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; +import lombok.extern.java.Log; + +@Log +@Singleton +public class IoTDataAccessor { + + @Inject + private ORDSApiClient ordsApiClient; + + // This should not be here, but for some reason at the moment it's the only way + // Micronaut can handle the request filter needing to inject the token + // retriever. + // As it fails to retrieve the token retriever properties, I suspect a + // dependencies + // issue where all of the dependencies are not resolved when going client -> + // filter -> token retriever. + @Inject + private ORDSDataRequestFilter ordsDataRequestFilter; + @Inject + private IDCSOAuthApplicationTokenRetriever idcsoAuthApplicationTokenRequest; + + public SnapshotDataResponseString getDigitalTwinInstanceSnapshotAsString(String digitalTwinInstanceId) { + String query = IotQueryBuilder.buildSnapshotData(digitalTwinInstanceId); + log.fine("Query :" + query); + return ordsApiClient.getSnapshotDataString(query); + + } + + public SnapshotDataResponseString getDigitalTwinInstanceSnapshotAsString(String digitalTwinInstanceId, + String contentPath) { + String query = IotQueryBuilder.buildSnapshotData(digitalTwinInstanceId, contentPath); + log.fine("Query :" + query); + return ordsApiClient.getSnapshotDataString(query); + + } + + public TimestampStringValue getDigitalTwinInstanceSnapshotAsTimestampString(String digitalTwinInstanceId, + String contentPath) { + SnapshotDataResponseString resp = getDigitalTwinInstanceSnapshotAsString(digitalTwinInstanceId, contentPath); + List items = resp.getItems(); + if (items.size() == 0) { + return null; + } + SnapshotDataEntryString item = items.getFirst(); + return new TimestampStringValue(item.getTime_observed(), item.getValue()); + } + + public TimestampBooleanValue getDigitalTwinInstanceSnapshotAsTimestampBoolean(String digitalTwinInstanceId, + String contentPath) { + SnapshotDataResponseString resp = getDigitalTwinInstanceSnapshotAsString(digitalTwinInstanceId, contentPath); + List items = resp.getItems(); + if (items.size() == 0) { + return null; + } + SnapshotDataEntryString item = items.getFirst(); + return new TimestampBooleanValue(item.getTime_observed(), Boolean.valueOf(item.getValue())); + } + + public TimestampDoubleValue getDigitalTwinInstanceSnapshotAsTimestampDouble(String digitalTwinInstanceId, + String contentPath) throws NumberFormatException { + SnapshotDataResponseString resp = getDigitalTwinInstanceSnapshotAsString(digitalTwinInstanceId, contentPath); + List items = resp.getItems(); + if (items.size() == 0) { + return null; + } + SnapshotDataEntryString item = items.getFirst(); + return new TimestampDoubleValue(item.getTime_observed(), Double.valueOf(item.getValue())); + } + + public TimestampLongValue getDigitalTwinInstanceSnapshotAsTimestampLong(String digitalTwinInstanceId, + String contentPath) throws NumberFormatException { + SnapshotDataResponseString resp = getDigitalTwinInstanceSnapshotAsString(digitalTwinInstanceId, contentPath); + List items = resp.getItems(); + if (items.size() == 0) { + return null; + } + SnapshotDataEntryString item = items.getFirst(); + return new TimestampLongValue(item.getTime_observed(), Long.valueOf(item.getValue())); + } + + public HistorizedDataResponseString getDigitalTwinInstanceHistoryAsString(String digitalTwinInstanceId, + String content_path, int count) { + String query = IotQueryBuilder.buildHistoryMostRecent(digitalTwinInstanceId, content_path); + log.fine("Query :" + query); + return ordsApiClient.getHistorizedData(query, 0, count); + } + + public List getDigitalTwinInstanceHistoryAsTimestampString(String digitalTwinInstanceId, + String contentPath, int count) { + HistorizedDataResponseString resp = getDigitalTwinInstanceHistoryAsString(digitalTwinInstanceId, contentPath, + count); + return resp.getItems().stream().map(item -> new TimestampStringValue(item.getTime_observed(), item.getValue())) + .toList(); + } + + public List getDigitalTwinInstanceHistoryAsTimestampBoolean(String digitalTwinInstanceId, + String contentPath, int count) { + HistorizedDataResponseString resp = getDigitalTwinInstanceHistoryAsString(digitalTwinInstanceId, contentPath, + count); + return resp.getItems().stream() + .map(item -> new TimestampBooleanValue(item.getTime_observed(), Boolean.valueOf(item.getValue()))) + .toList(); + } + + public List getDigitalTwinInstanceHistoryAsTimestampLong(String digitalTwinInstanceId, + String contentPath, int count) { + HistorizedDataResponseString resp = getDigitalTwinInstanceHistoryAsString(digitalTwinInstanceId, contentPath, + count); + return resp.getItems().stream().map((item) -> { + try { + return new TimestampLongValue(item.getTime_observed(), Long.valueOf(item.getValue())); + } catch (NumberFormatException e) { + return null; + } + }).filter(tlv -> tlv != null).toList(); + } + + public List getDigitalTwinInstanceHistoryAsTimestampDouble(String digitalTwinInstanceId, + String contentPath, int count) { + HistorizedDataResponseString resp = getDigitalTwinInstanceHistoryAsString(digitalTwinInstanceId, contentPath, + count); + return resp.getItems().stream().map((item) -> { + try { + return new TimestampDoubleValue(item.getTime_observed(), Double.valueOf(item.getValue())); + } catch (NumberFormatException e) { + return null; + } + }).filter(tdv -> tdv != null).toList(); + } + + public List getDigitalTwinInstanceContentPaths(String digitalTwinInstanceId) { + SnapshotDataResponseString snapshotData = getDigitalTwinInstanceSnapshotAsString(digitalTwinInstanceId); + Set contentPaths = snapshotData.getItems().stream().map(item -> item.getContent_path()) + .collect(Collectors.toSet()); + return new ArrayList<>(contentPaths); + } + + @EventListener + public void onStartup(StartupEvent event) { + log.info("Startup event received for IoTDataAccessor"); + ordsDataRequestFilter.setIdcsoAuthApplicationTokenRequest(idcsoAuthApplicationTokenRequest); + log.info("configured request filter"); + } +} diff --git a/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/iotaccess/IotQueryBuilder.java b/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/iotaccess/IotQueryBuilder.java new file mode 100644 index 0000000..34a1663 --- /dev/null +++ b/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/iotaccess/IotQueryBuilder.java @@ -0,0 +1,71 @@ +/*Copyright (c) 2025 Oracle and/or its affiliates. + +The Universal Permissive License (UPL), Version 1.0 + +Subject to the condition set forth below, permission is hereby granted to any +person obtaining a copy of this software, associated documentation and/or data +(collectively the "Software"), free of charge and under any and all copyright +rights in the Software, and any and all patent rights owned or freely +licensable by each licensor hereunder covering either (i) the unmodified +Software as contributed to or provided by such licensor, or (ii) the Larger +Works (as defined below), to deal in both + +(a) the Software, and +(b) any piece of software and/or hardware listed in the lrgrwrks.txt file if +one is included with the Software (each a "Larger Work" to which the Software +is contributed by such licensors), + +without restriction, including without limitation the rights to copy, create +derivative works of, display, perform, and distribute the Software and make, +use, sell, offer for sale, import, export, have made, and have sold the +Software and the Larger Work(s), and to sublicense the foregoing rights on +either these or other terms. + +This license is subject to the following condition: +The above copyright notice and either this complete permission notice or at +a minimum a reference to the UPL must be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + */ +package com.oracle.demo.timg.iot.iotordsaccess.iotaccess; + +import com.oracle.demo.timg.iot.iotordsaccess.ords.query.BooleanAnd; +import com.oracle.demo.timg.iot.iotordsaccess.ords.query.OrderBy; +import com.oracle.demo.timg.iot.iotordsaccess.ords.query.OrderByDirection; +import com.oracle.demo.timg.iot.iotordsaccess.ords.query.Query; +import com.oracle.demo.timg.iot.iotordsaccess.ords.query.ValueEqualsString; + +public class IotQueryBuilder { + public final static String DT_INSTANCE_ID = "digital_twin_instance_id"; + public final static String CONTENT_PATH = "content_path"; + public final static String TIME_OBSERVED = "time_observed"; + + public static String buildHistoryMostRecent(String digitalTwinInstanceId, String contentPath) { + BooleanAnd band = new BooleanAnd(); + band.addValueTest(ValueEqualsString.builder().name(DT_INSTANCE_ID).value(digitalTwinInstanceId).build()); + band.addValueTest(ValueEqualsString.builder().name(CONTENT_PATH).value(contentPath).build()); + OrderBy orderBy = OrderBy.builder().name(TIME_OBSERVED).direction(OrderByDirection.DESC).build(); + return Query.builder().booleanTest(band).orderBy(orderBy).build().toQueryString(); + } + + public static String buildSnapshotData(String digitalTwinInstanceId) { + BooleanAnd band = new BooleanAnd(); + band.addValueTest(ValueEqualsString.builder().name(DT_INSTANCE_ID).value(digitalTwinInstanceId).build()); + OrderBy orderBy = OrderBy.builder().name(CONTENT_PATH).direction(OrderByDirection.ASC).build(); + return Query.builder().booleanTest(band).orderBy(orderBy).build().toQueryString(); + } + + public static String buildSnapshotData(String digitalTwinInstanceId, String contentPath) { + BooleanAnd band = new BooleanAnd(); + band.addValueTest(ValueEqualsString.builder().name(DT_INSTANCE_ID).value(digitalTwinInstanceId).build()); + band.addValueTest(ValueEqualsString.builder().name(CONTENT_PATH).value(contentPath).build()); + return Query.builder().booleanTest(band).build().toQueryString(); + } +} diff --git a/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/iotaccess/TimestampBooleanValue.java b/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/iotaccess/TimestampBooleanValue.java new file mode 100644 index 0000000..52e5144 --- /dev/null +++ b/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/iotaccess/TimestampBooleanValue.java @@ -0,0 +1,49 @@ +/*Copyright (c) 2025 Oracle and/or its affiliates. + +The Universal Permissive License (UPL), Version 1.0 + +Subject to the condition set forth below, permission is hereby granted to any +person obtaining a copy of this software, associated documentation and/or data +(collectively the "Software"), free of charge and under any and all copyright +rights in the Software, and any and all patent rights owned or freely +licensable by each licensor hereunder covering either (i) the unmodified +Software as contributed to or provided by such licensor, or (ii) the Larger +Works (as defined below), to deal in both + +(a) the Software, and +(b) any piece of software and/or hardware listed in the lrgrwrks.txt file if +one is included with the Software (each a "Larger Work" to which the Software +is contributed by such licensors), + +without restriction, including without limitation the rights to copy, create +derivative works of, display, perform, and distribute the Software and make, +use, sell, offer for sale, import, export, have made, and have sold the +Software and the Larger Work(s), and to sublicense the foregoing rights on +either these or other terms. + +This license is subject to the following condition: +The above copyright notice and either this complete permission notice or at +a minimum a reference to the UPL must be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + */ +package com.oracle.demo.timg.iot.iotordsaccess.iotaccess; + +import java.time.ZonedDateTime; + +import lombok.Builder; +import lombok.Data; + +@Data +@Builder +public class TimestampBooleanValue { + private ZonedDateTime time_observed; + private Boolean value; +} diff --git a/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/iotaccess/TimestampDoubleValue.java b/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/iotaccess/TimestampDoubleValue.java new file mode 100644 index 0000000..19fc5c2 --- /dev/null +++ b/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/iotaccess/TimestampDoubleValue.java @@ -0,0 +1,49 @@ +/*Copyright (c) 2025 Oracle and/or its affiliates. + +The Universal Permissive License (UPL), Version 1.0 + +Subject to the condition set forth below, permission is hereby granted to any +person obtaining a copy of this software, associated documentation and/or data +(collectively the "Software"), free of charge and under any and all copyright +rights in the Software, and any and all patent rights owned or freely +licensable by each licensor hereunder covering either (i) the unmodified +Software as contributed to or provided by such licensor, or (ii) the Larger +Works (as defined below), to deal in both + +(a) the Software, and +(b) any piece of software and/or hardware listed in the lrgrwrks.txt file if +one is included with the Software (each a "Larger Work" to which the Software +is contributed by such licensors), + +without restriction, including without limitation the rights to copy, create +derivative works of, display, perform, and distribute the Software and make, +use, sell, offer for sale, import, export, have made, and have sold the +Software and the Larger Work(s), and to sublicense the foregoing rights on +either these or other terms. + +This license is subject to the following condition: +The above copyright notice and either this complete permission notice or at +a minimum a reference to the UPL must be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + */ +package com.oracle.demo.timg.iot.iotordsaccess.iotaccess; + +import java.time.ZonedDateTime; + +import lombok.Builder; +import lombok.Data; + +@Data +@Builder +public class TimestampDoubleValue { + private ZonedDateTime time_observed; + private Double value; +} diff --git a/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/iotaccess/TimestampLongValue.java b/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/iotaccess/TimestampLongValue.java new file mode 100644 index 0000000..195aacc --- /dev/null +++ b/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/iotaccess/TimestampLongValue.java @@ -0,0 +1,49 @@ +/*Copyright (c) 2025 Oracle and/or its affiliates. + +The Universal Permissive License (UPL), Version 1.0 + +Subject to the condition set forth below, permission is hereby granted to any +person obtaining a copy of this software, associated documentation and/or data +(collectively the "Software"), free of charge and under any and all copyright +rights in the Software, and any and all patent rights owned or freely +licensable by each licensor hereunder covering either (i) the unmodified +Software as contributed to or provided by such licensor, or (ii) the Larger +Works (as defined below), to deal in both + +(a) the Software, and +(b) any piece of software and/or hardware listed in the lrgrwrks.txt file if +one is included with the Software (each a "Larger Work" to which the Software +is contributed by such licensors), + +without restriction, including without limitation the rights to copy, create +derivative works of, display, perform, and distribute the Software and make, +use, sell, offer for sale, import, export, have made, and have sold the +Software and the Larger Work(s), and to sublicense the foregoing rights on +either these or other terms. + +This license is subject to the following condition: +The above copyright notice and either this complete permission notice or at +a minimum a reference to the UPL must be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + */ +package com.oracle.demo.timg.iot.iotordsaccess.iotaccess; + +import java.time.ZonedDateTime; + +import lombok.Builder; +import lombok.Data; + +@Data +@Builder +public class TimestampLongValue { + private ZonedDateTime time_observed; + private Long value; +} diff --git a/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/iotaccess/TimestampStringValue.java b/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/iotaccess/TimestampStringValue.java new file mode 100644 index 0000000..62aedad --- /dev/null +++ b/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/iotaccess/TimestampStringValue.java @@ -0,0 +1,49 @@ +/*Copyright (c) 2025 Oracle and/or its affiliates. + +The Universal Permissive License (UPL), Version 1.0 + +Subject to the condition set forth below, permission is hereby granted to any +person obtaining a copy of this software, associated documentation and/or data +(collectively the "Software"), free of charge and under any and all copyright +rights in the Software, and any and all patent rights owned or freely +licensable by each licensor hereunder covering either (i) the unmodified +Software as contributed to or provided by such licensor, or (ii) the Larger +Works (as defined below), to deal in both + +(a) the Software, and +(b) any piece of software and/or hardware listed in the lrgrwrks.txt file if +one is included with the Software (each a "Larger Work" to which the Software +is contributed by such licensors), + +without restriction, including without limitation the rights to copy, create +derivative works of, display, perform, and distribute the Software and make, +use, sell, offer for sale, import, export, have made, and have sold the +Software and the Larger Work(s), and to sublicense the foregoing rights on +either these or other terms. + +This license is subject to the following condition: +The above copyright notice and either this complete permission notice or at +a minimum a reference to the UPL must be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + */ +package com.oracle.demo.timg.iot.iotordsaccess.iotaccess; + +import java.time.ZonedDateTime; + +import lombok.Builder; +import lombok.Data; + +@Data +@Builder +public class TimestampStringValue { + private ZonedDateTime time_observed; + private String value; +} diff --git a/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/ords/ORDSApiClient.java b/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/ords/ORDSApiClient.java new file mode 100644 index 0000000..0293d79 --- /dev/null +++ b/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/ords/ORDSApiClient.java @@ -0,0 +1,97 @@ +/*Copyright (c) 2025 Oracle and/or its affiliates. + +The Universal Permissive License (UPL), Version 1.0 + +Subject to the condition set forth below, permission is hereby granted to any +person obtaining a copy of this software, associated documentation and/or data +(collectively the "Software"), free of charge and under any and all copyright +rights in the Software, and any and all patent rights owned or freely +licensable by each licensor hereunder covering either (i) the unmodified +Software as contributed to or provided by such licensor, or (ii) the Larger +Works (as defined below), to deal in both + +(a) the Software, and +(b) any piece of software and/or hardware listed in the lrgrwrks.txt file if +one is included with the Software (each a "Larger Work" to which the Software +is contributed by such licensors), + +without restriction, including without limitation the rights to copy, create +derivative works of, display, perform, and distribute the Software and make, +use, sell, offer for sale, import, export, have made, and have sold the +Software and the Larger Work(s), and to sublicense the foregoing rights on +either these or other terms. + +This license is subject to the following condition: +The above copyright notice and either this complete permission notice or at +a minimum a reference to the UPL must be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + */ +package com.oracle.demo.timg.iot.iotordsaccess.ords; + +import static io.micronaut.http.HttpHeaders.ACCEPT; +import static io.micronaut.http.HttpHeaders.USER_AGENT; + +import com.oracle.demo.timg.iot.iotordsaccess.data.HistorizedDataResponseString; +import com.oracle.demo.timg.iot.iotordsaccess.data.SnapshotDataResponseString; +import com.oracle.demo.timg.iot.iotordsaccess.data.RawDataResponse; + +import io.micronaut.context.annotation.Requires; +import io.micronaut.http.annotation.Get; +import io.micronaut.http.annotation.Header; +import io.micronaut.http.annotation.QueryValue; +import io.micronaut.http.client.annotation.Client; +import io.micronaut.http.client.exceptions.HttpClientException; + +@Client(id = "ordsapi", path = "/ords/${iot.domain.id}/${iot.ordsapi.version}") +@Header(name = USER_AGENT, value = "Micronaut HTTP Client") +@Header(name = ACCEPT, value = "application/json") +@Requires(property = "iot.domain.id") +@Requires(property = "iot.ordsapi.version") +public interface ORDSApiClient { + + @Get("/rawData") + public RawDataResponse getRawData(@QueryValue(value = "q") String query) throws HttpClientException; + + @Get("/rawData") + public String getRawData(@QueryValue(value = "q") String query, @QueryValue(value = "offset") long offset, + @QueryValue(value = "limit") long limit) throws HttpClientException; + + @Get("/rawData") + public RawDataResponse getRawData(@QueryValue(value = "offset") long offset, + @QueryValue(value = "limit") long limit) throws HttpClientException; + + @Get("/snapshotData") + public SnapshotDataResponseString getSnapshotDataString(@QueryValue(value = "q") String query) + throws HttpClientException; + + @Get("/snapshotData") + public SnapshotDataResponseString getSnapshotDataString(@QueryValue(value = "q") String query, + @QueryValue(value = "offset") long offset, @QueryValue(value = "limit") long limit) + throws HttpClientException; + + @Get("/snapshotData") + public SnapshotDataResponseString getSnapshotDataString(@QueryValue(value = "offset") long offset, + @QueryValue(value = "limit") long limit) throws HttpClientException; + + @Get("/historizedData") + public HistorizedDataResponseString getHistorizedData(@QueryValue(value = "q") String query) + throws HttpClientException; + + @Get("/historizedData") + public HistorizedDataResponseString getHistorizedData(@QueryValue(value = "q") String query, + @QueryValue(value = "offset") long offset, @QueryValue(value = "limit") long limit) + throws HttpClientException; + + @Get("/historizedData") + public HistorizedDataResponseString getHistorizedDataString(@QueryValue(value = "offset") long offset, + @QueryValue(value = "limit") long limit) throws HttpClientException; + +} diff --git a/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/ords/ORDSDataRequestFilter.java b/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/ords/ORDSDataRequestFilter.java new file mode 100644 index 0000000..8295dca --- /dev/null +++ b/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/ords/ORDSDataRequestFilter.java @@ -0,0 +1,82 @@ +/*Copyright (c) 2025 Oracle and/or its affiliates. + +The Universal Permissive License (UPL), Version 1.0 + +Subject to the condition set forth below, permission is hereby granted to any +person obtaining a copy of this software, associated documentation and/or data +(collectively the "Software"), free of charge and under any and all copyright +rights in the Software, and any and all patent rights owned or freely +licensable by each licensor hereunder covering either (i) the unmodified +Software as contributed to or provided by such licensor, or (ii) the Larger +Works (as defined below), to deal in both + +(a) the Software, and +(b) any piece of software and/or hardware listed in the lrgrwrks.txt file if +one is included with the Software (each a "Larger Work" to which the Software +is contributed by such licensors), + +without restriction, including without limitation the rights to copy, create +derivative works of, display, perform, and distribute the Software and make, +use, sell, offer for sale, import, export, have made, and have sold the +Software and the Larger Work(s), and to sublicense the foregoing rights on +either these or other terms. + +This license is subject to the following condition: +The above copyright notice and either this complete permission notice or at +a minimum a reference to the UPL must be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + */ +package com.oracle.demo.timg.iot.iotordsaccess.ords; + +import com.oracle.demo.timg.iot.iotordsaccess.idcs.IDCSOAuthApplicationTokenRetriever; +import com.oracle.demo.timg.iot.iotordsaccess.idcs.IDCSOAuthTokenRetrievalException; + +import io.micronaut.context.event.StartupEvent; +import io.micronaut.http.MutableHttpRequest; +import io.micronaut.http.annotation.ClientFilter; +import io.micronaut.http.annotation.RequestFilter; +import io.micronaut.http.client.exceptions.HttpClientException; +import io.micronaut.runtime.event.annotation.EventListener; +import jakarta.inject.Singleton; +import lombok.Setter; +import lombok.extern.java.Log; + +@ClientFilter(patterns = { "/ords/**" }) +@Log +@Singleton +public class ORDSDataRequestFilter { + // @Inject + // @Getter + @Setter + private IDCSOAuthApplicationTokenRetriever idcsoAuthApplicationTokenRequest; + +// @Inject +// public ORDSDataRequestFilter(IDCSOAuthApplicationTokenRetriever idcsoAuthApplicationTokenRequest) { +// this.idcsoAuthApplicationTokenRequest = idcsoAuthApplicationTokenRequest; +// log.info("ORDSDataFiloter - set idcsoAuthApplicationTokenRequest"); +// } + + @RequestFilter + public void doFilter(MutableHttpRequest request) { + log.info("Adding bearer auth header to path " + request.getPath()); + try { + request.bearerAuth(idcsoAuthApplicationTokenRequest.getToken()); + } catch (IDCSOAuthTokenRetrievalException e) { + log.warning("Exception getting token, request won't send"); + throw new HttpClientException("Can't get outh token", e); + } + } + + @EventListener + public void onStartup(StartupEvent event) { + log.info("Startup event received for ORDSDataRequestFilter"); + } +} \ No newline at end of file diff --git a/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/ords/query/BooleanAnd.java b/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/ords/query/BooleanAnd.java new file mode 100644 index 0000000..714a528 --- /dev/null +++ b/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/ords/query/BooleanAnd.java @@ -0,0 +1,55 @@ +/*Copyright (c) 2025 Oracle and/or its affiliates. + +The Universal Permissive License (UPL), Version 1.0 + +Subject to the condition set forth below, permission is hereby granted to any +person obtaining a copy of this software, associated documentation and/or data +(collectively the "Software"), free of charge and under any and all copyright +rights in the Software, and any and all patent rights owned or freely +licensable by each licensor hereunder covering either (i) the unmodified +Software as contributed to or provided by such licensor, or (ii) the Larger +Works (as defined below), to deal in both + +(a) the Software, and +(b) any piece of software and/or hardware listed in the lrgrwrks.txt file if +one is included with the Software (each a "Larger Work" to which the Software +is contributed by such licensors), + +without restriction, including without limitation the rights to copy, create +derivative works of, display, perform, and distribute the Software and make, +use, sell, offer for sale, import, export, have made, and have sold the +Software and the Larger Work(s), and to sublicense the foregoing rights on +either these or other terms. + +This license is subject to the following condition: +The above copyright notice and either this complete permission notice or at +a minimum a reference to the UPL must be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + */ +package com.oracle.demo.timg.iot.iotordsaccess.ords.query; + +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +@Data +@EqualsAndHashCode(callSuper = true) +@NoArgsConstructor +@Builder +public class BooleanAnd extends BooleanOperator { + public final static String AND = "\"$and\""; + + @Override + public String toQueryString() { + return toQueryString(AND); + } +} diff --git a/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/ords/query/BooleanOperator.java b/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/ords/query/BooleanOperator.java new file mode 100644 index 0000000..c0604a5 --- /dev/null +++ b/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/ords/query/BooleanOperator.java @@ -0,0 +1,55 @@ +/*Copyright (c) 2025 Oracle and/or its affiliates. + +The Universal Permissive License (UPL), Version 1.0 + +Subject to the condition set forth below, permission is hereby granted to any +person obtaining a copy of this software, associated documentation and/or data +(collectively the "Software"), free of charge and under any and all copyright +rights in the Software, and any and all patent rights owned or freely +licensable by each licensor hereunder covering either (i) the unmodified +Software as contributed to or provided by such licensor, or (ii) the Larger +Works (as defined below), to deal in both + +(a) the Software, and +(b) any piece of software and/or hardware listed in the lrgrwrks.txt file if +one is included with the Software (each a "Larger Work" to which the Software +is contributed by such licensors), + +without restriction, including without limitation the rights to copy, create +derivative works of, display, perform, and distribute the Software and make, +use, sell, offer for sale, import, export, have made, and have sold the +Software and the Larger Work(s), and to sublicense the foregoing rights on +either these or other terms. + +This license is subject to the following condition: +The above copyright notice and either this complete permission notice or at +a minimum a reference to the UPL must be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + */ +package com.oracle.demo.timg.iot.iotordsaccess.ords.query; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +public abstract class BooleanOperator implements BooleanTest { + private final List tests = new ArrayList<>(10); + + public String toQueryString(String operator) { + String valueTests = tests.stream().map(test -> test.toQueryString()).collect(Collectors.joining(",")); + return operator + ":[" + valueTests + "]"; + } + + public BooleanOperator addValueTest(ValueTest t) { + tests.add(t); + return this; + } +} diff --git a/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/ords/query/BooleanOr.java b/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/ords/query/BooleanOr.java new file mode 100644 index 0000000..a27274a --- /dev/null +++ b/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/ords/query/BooleanOr.java @@ -0,0 +1,55 @@ +/*Copyright (c) 2025 Oracle and/or its affiliates. + +The Universal Permissive License (UPL), Version 1.0 + +Subject to the condition set forth below, permission is hereby granted to any +person obtaining a copy of this software, associated documentation and/or data +(collectively the "Software"), free of charge and under any and all copyright +rights in the Software, and any and all patent rights owned or freely +licensable by each licensor hereunder covering either (i) the unmodified +Software as contributed to or provided by such licensor, or (ii) the Larger +Works (as defined below), to deal in both + +(a) the Software, and +(b) any piece of software and/or hardware listed in the lrgrwrks.txt file if +one is included with the Software (each a "Larger Work" to which the Software +is contributed by such licensors), + +without restriction, including without limitation the rights to copy, create +derivative works of, display, perform, and distribute the Software and make, +use, sell, offer for sale, import, export, have made, and have sold the +Software and the Larger Work(s), and to sublicense the foregoing rights on +either these or other terms. + +This license is subject to the following condition: +The above copyright notice and either this complete permission notice or at +a minimum a reference to the UPL must be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + */ +package com.oracle.demo.timg.iot.iotordsaccess.ords.query; + +import lombok.Builder; +import lombok.Data; +import lombok.EqualsAndHashCode; +import lombok.NoArgsConstructor; + +@Data +@EqualsAndHashCode(callSuper = true) +@NoArgsConstructor +@Builder +public class BooleanOr extends BooleanOperator { + public final static String OR = "\"$or\""; + + @Override + public String toQueryString() { + return toQueryString(OR); + } +} diff --git a/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/ords/query/BooleanTest.java b/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/ords/query/BooleanTest.java new file mode 100644 index 0000000..01083a1 --- /dev/null +++ b/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/ords/query/BooleanTest.java @@ -0,0 +1,41 @@ +/*Copyright (c) 2025 Oracle and/or its affiliates. + +The Universal Permissive License (UPL), Version 1.0 + +Subject to the condition set forth below, permission is hereby granted to any +person obtaining a copy of this software, associated documentation and/or data +(collectively the "Software"), free of charge and under any and all copyright +rights in the Software, and any and all patent rights owned or freely +licensable by each licensor hereunder covering either (i) the unmodified +Software as contributed to or provided by such licensor, or (ii) the Larger +Works (as defined below), to deal in both + +(a) the Software, and +(b) any piece of software and/or hardware listed in the lrgrwrks.txt file if +one is included with the Software (each a "Larger Work" to which the Software +is contributed by such licensors), + +without restriction, including without limitation the rights to copy, create +derivative works of, display, perform, and distribute the Software and make, +use, sell, offer for sale, import, export, have made, and have sold the +Software and the Larger Work(s), and to sublicense the foregoing rights on +either these or other terms. + +This license is subject to the following condition: +The above copyright notice and either this complete permission notice or at +a minimum a reference to the UPL must be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + */ +package com.oracle.demo.timg.iot.iotordsaccess.ords.query; + +public interface BooleanTest extends QueryTest { + +} diff --git a/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/ords/query/OrderBy.java b/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/ords/query/OrderBy.java new file mode 100644 index 0000000..fb9750c --- /dev/null +++ b/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/ords/query/OrderBy.java @@ -0,0 +1,53 @@ +/*Copyright (c) 2025 Oracle and/or its affiliates. + +The Universal Permissive License (UPL), Version 1.0 + +Subject to the condition set forth below, permission is hereby granted to any +person obtaining a copy of this software, associated documentation and/or data +(collectively the "Software"), free of charge and under any and all copyright +rights in the Software, and any and all patent rights owned or freely +licensable by each licensor hereunder covering either (i) the unmodified +Software as contributed to or provided by such licensor, or (ii) the Larger +Works (as defined below), to deal in both + +(a) the Software, and +(b) any piece of software and/or hardware listed in the lrgrwrks.txt file if +one is included with the Software (each a "Larger Work" to which the Software +is contributed by such licensors), + +without restriction, including without limitation the rights to copy, create +derivative works of, display, perform, and distribute the Software and make, +use, sell, offer for sale, import, export, have made, and have sold the +Software and the Larger Work(s), and to sublicense the foregoing rights on +either these or other terms. + +This license is subject to the following condition: +The above copyright notice and either this complete permission notice or at +a minimum a reference to the UPL must be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + */ +package com.oracle.demo.timg.iot.iotordsaccess.ords.query; + +import lombok.Builder; +import lombok.Data; + +@Data +@Builder +public class OrderBy { + public final static String ORDER_BY = "\"$orderby\""; + private String name; + private OrderByDirection direction; + + public String toQueryString() { + return ORDER_BY + ":{\"" + name + "\":\"" + direction + "\"}"; + // "$orderby":{"time_observed":"desc"}}" + } +} diff --git a/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/ords/query/OrderByDirection.java b/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/ords/query/OrderByDirection.java new file mode 100644 index 0000000..e20c9d2 --- /dev/null +++ b/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/ords/query/OrderByDirection.java @@ -0,0 +1,41 @@ +/*Copyright (c) 2025 Oracle and/or its affiliates. + +The Universal Permissive License (UPL), Version 1.0 + +Subject to the condition set forth below, permission is hereby granted to any +person obtaining a copy of this software, associated documentation and/or data +(collectively the "Software"), free of charge and under any and all copyright +rights in the Software, and any and all patent rights owned or freely +licensable by each licensor hereunder covering either (i) the unmodified +Software as contributed to or provided by such licensor, or (ii) the Larger +Works (as defined below), to deal in both + +(a) the Software, and +(b) any piece of software and/or hardware listed in the lrgrwrks.txt file if +one is included with the Software (each a "Larger Work" to which the Software +is contributed by such licensors), + +without restriction, including without limitation the rights to copy, create +derivative works of, display, perform, and distribute the Software and make, +use, sell, offer for sale, import, export, have made, and have sold the +Software and the Larger Work(s), and to sublicense the foregoing rights on +either these or other terms. + +This license is subject to the following condition: +The above copyright notice and either this complete permission notice or at +a minimum a reference to the UPL must be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + */ +package com.oracle.demo.timg.iot.iotordsaccess.ords.query; + +public enum OrderByDirection { + DESC, ASC +} diff --git a/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/ords/query/Query.java b/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/ords/query/Query.java new file mode 100644 index 0000000..ac5931f --- /dev/null +++ b/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/ords/query/Query.java @@ -0,0 +1,60 @@ +/*Copyright (c) 2025 Oracle and/or its affiliates. + +The Universal Permissive License (UPL), Version 1.0 + +Subject to the condition set forth below, permission is hereby granted to any +person obtaining a copy of this software, associated documentation and/or data +(collectively the "Software"), free of charge and under any and all copyright +rights in the Software, and any and all patent rights owned or freely +licensable by each licensor hereunder covering either (i) the unmodified +Software as contributed to or provided by such licensor, or (ii) the Larger +Works (as defined below), to deal in both + +(a) the Software, and +(b) any piece of software and/or hardware listed in the lrgrwrks.txt file if +one is included with the Software (each a "Larger Work" to which the Software +is contributed by such licensors), + +without restriction, including without limitation the rights to copy, create +derivative works of, display, perform, and distribute the Software and make, +use, sell, offer for sale, import, export, have made, and have sold the +Software and the Larger Work(s), and to sublicense the foregoing rights on +either these or other terms. + +This license is subject to the following condition: +The above copyright notice and either this complete permission notice or at +a minimum a reference to the UPL must be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + */ +package com.oracle.demo.timg.iot.iotordsaccess.ords.query; + +import lombok.Builder; +import lombok.Data; + +@Builder +@Data +public class Query implements QueryTest { + private BooleanTest booleanTest; + private OrderBy orderBy; + + @Override + public String toQueryString() { + String query = "{"; + if (booleanTest != null) { + query += booleanTest.toQueryString(); + } + if (orderBy != null) { + query += "," + orderBy.toQueryString(); + } + query += "}"; + return query; + } +} diff --git a/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/ords/query/QueryTest.java b/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/ords/query/QueryTest.java new file mode 100644 index 0000000..80dc371 --- /dev/null +++ b/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/ords/query/QueryTest.java @@ -0,0 +1,41 @@ +/*Copyright (c) 2025 Oracle and/or its affiliates. + +The Universal Permissive License (UPL), Version 1.0 + +Subject to the condition set forth below, permission is hereby granted to any +person obtaining a copy of this software, associated documentation and/or data +(collectively the "Software"), free of charge and under any and all copyright +rights in the Software, and any and all patent rights owned or freely +licensable by each licensor hereunder covering either (i) the unmodified +Software as contributed to or provided by such licensor, or (ii) the Larger +Works (as defined below), to deal in both + +(a) the Software, and +(b) any piece of software and/or hardware listed in the lrgrwrks.txt file if +one is included with the Software (each a "Larger Work" to which the Software +is contributed by such licensors), + +without restriction, including without limitation the rights to copy, create +derivative works of, display, perform, and distribute the Software and make, +use, sell, offer for sale, import, export, have made, and have sold the +Software and the Larger Work(s), and to sublicense the foregoing rights on +either these or other terms. + +This license is subject to the following condition: +The above copyright notice and either this complete permission notice or at +a minimum a reference to the UPL must be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + */ +package com.oracle.demo.timg.iot.iotordsaccess.ords.query; + +public interface QueryTest { + public String toQueryString(); +} diff --git a/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/ords/query/ValueEqualsString.java b/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/ords/query/ValueEqualsString.java new file mode 100644 index 0000000..0d50a94 --- /dev/null +++ b/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/ords/query/ValueEqualsString.java @@ -0,0 +1,52 @@ +/*Copyright (c) 2025 Oracle and/or its affiliates. + +The Universal Permissive License (UPL), Version 1.0 + +Subject to the condition set forth below, permission is hereby granted to any +person obtaining a copy of this software, associated documentation and/or data +(collectively the "Software"), free of charge and under any and all copyright +rights in the Software, and any and all patent rights owned or freely +licensable by each licensor hereunder covering either (i) the unmodified +Software as contributed to or provided by such licensor, or (ii) the Larger +Works (as defined below), to deal in both + +(a) the Software, and +(b) any piece of software and/or hardware listed in the lrgrwrks.txt file if +one is included with the Software (each a "Larger Work" to which the Software +is contributed by such licensors), + +without restriction, including without limitation the rights to copy, create +derivative works of, display, perform, and distribute the Software and make, +use, sell, offer for sale, import, export, have made, and have sold the +Software and the Larger Work(s), and to sublicense the foregoing rights on +either these or other terms. + +This license is subject to the following condition: +The above copyright notice and either this complete permission notice or at +a minimum a reference to the UPL must be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + */ +package com.oracle.demo.timg.iot.iotordsaccess.ords.query; + +import lombok.Builder; +import lombok.Data; + +@Data +@Builder +public class ValueEqualsString implements ValueTest { + private String name; + private String value; + + @Override + public String toQueryString() { + return "{\"" + name + "\":\"" + value + "\"}"; + } +} diff --git a/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/ords/query/ValueTest.java b/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/ords/query/ValueTest.java new file mode 100644 index 0000000..38e6dbe --- /dev/null +++ b/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/ords/query/ValueTest.java @@ -0,0 +1,40 @@ +/*Copyright (c) 2025 Oracle and/or its affiliates. + +The Universal Permissive License (UPL), Version 1.0 + +Subject to the condition set forth below, permission is hereby granted to any +person obtaining a copy of this software, associated documentation and/or data +(collectively the "Software"), free of charge and under any and all copyright +rights in the Software, and any and all patent rights owned or freely +licensable by each licensor hereunder covering either (i) the unmodified +Software as contributed to or provided by such licensor, or (ii) the Larger +Works (as defined below), to deal in both + +(a) the Software, and +(b) any piece of software and/or hardware listed in the lrgrwrks.txt file if +one is included with the Software (each a "Larger Work" to which the Software +is contributed by such licensors), + +without restriction, including without limitation the rights to copy, create +derivative works of, display, perform, and distribute the Software and make, +use, sell, offer for sale, import, export, have made, and have sold the +Software and the Larger Work(s), and to sublicense the foregoing rights on +either these or other terms. + +This license is subject to the following condition: +The above copyright notice and either this complete permission notice or at +a minimum a reference to the UPL must be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + */ +package com.oracle.demo.timg.iot.iotordsaccess.ords.query; + +public interface ValueTest extends QueryTest { +} diff --git a/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/testers/IDCSTestTokenRetrieval.java b/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/testers/IDCSTestTokenRetrieval.java new file mode 100644 index 0000000..d416c05 --- /dev/null +++ b/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/testers/IDCSTestTokenRetrieval.java @@ -0,0 +1,101 @@ +/*Copyright (c) 2025 Oracle and/or its affiliates. + +The Universal Permissive License (UPL), Version 1.0 + +Subject to the condition set forth below, permission is hereby granted to any +person obtaining a copy of this software, associated documentation and/or data +(collectively the "Software"), free of charge and under any and all copyright +rights in the Software, and any and all patent rights owned or freely +licensable by each licensor hereunder covering either (i) the unmodified +Software as contributed to or provided by such licensor, or (ii) the Larger +Works (as defined below), to deal in both + +(a) the Software, and +(b) any piece of software and/or hardware listed in the lrgrwrks.txt file if +one is included with the Software (each a "Larger Work" to which the Software +is contributed by such licensors), + +without restriction, including without limitation the rights to copy, create +derivative works of, display, perform, and distribute the Software and make, +use, sell, offer for sale, import, export, have made, and have sold the +Software and the Larger Work(s), and to sublicense the foregoing rights on +either these or other terms. + +This license is subject to the following condition: +The above copyright notice and either this complete permission notice or at +a minimum a reference to the UPL must be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + */ +package com.oracle.demo.timg.iot.iotordsaccess.testers; + +import java.time.Duration; +import java.time.LocalDateTime; +import java.time.format.DateTimeFormatter; + +import com.oracle.demo.timg.iot.iotordsaccess.idcs.IDCSOAuthApplicationTokenRetriever; +import com.oracle.demo.timg.iot.iotordsaccess.idcs.IDCSOAuthTokenRetrievalException; + +import io.micronaut.context.annotation.Requires; +import io.micronaut.context.event.StartupEvent; +import io.micronaut.runtime.event.annotation.EventListener; +import io.micronaut.scheduling.TaskExecutors; +import io.micronaut.scheduling.annotation.ExecuteOn; +import io.micronaut.scheduling.annotation.Scheduled; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; +import lombok.extern.java.Log; + +@Log +@Singleton +@Requires(property = "iot.idcs.test-token-retrieval", value = "true", defaultValue = "false") +public class IDCSTestTokenRetrieval { + @Inject + private IDCSOAuthApplicationTokenRetriever idcsoAuthApplicationTokenRequest; + + private int counter = 0; + @Inject + private IDCSOAuthApplicationTokenRetriever idcsoAuthApplicationTokenRetriever; + + @ExecuteOn(TaskExecutors.IO) + @Scheduled(fixedRate = "10s", initialDelay = "10s") + public void testGetToken() { + if (counter++ > 12) { + System.exit(0); + } + String token; + try { + token = idcsoAuthApplicationTokenRetriever.getToken(); + } catch (IDCSOAuthTokenRetrievalException e) { + log.warning("Problem getting token, " + e.getLocalizedMessage()); + return; + } + String tokenType = idcsoAuthApplicationTokenRetriever.getTokenType(); + LocalDateTime ldt = idcsoAuthApplicationTokenRetriever.getCurrentTokenRenewTime(); + log.info("Loop :" + counter + " expiry=" + ldt.format(DateTimeFormatter.ISO_DATE_TIME) + ", type=" + tokenType + + ", token=" + token); + if (counter == 3) { + log.info("Forcing complete token data reset"); + idcsoAuthApplicationTokenRetriever.deleteTokenDetails(); + } + if ((counter == 6) || (counter == 9)) { + log.info("Forcing token timout after next retrieval"); + idcsoAuthApplicationTokenRetriever.forceTokenRetrievalAfter(Duration.ofSeconds(15)); + log.info("current time is " + LocalDateTime.now().format(DateTimeFormatter.ISO_DATE_TIME) + + ", new expiry time is " + idcsoAuthApplicationTokenRetriever.getCurrentTokenRenewTime() + .format(DateTimeFormatter.ISO_DATE_TIME)); + } + } + + @EventListener + public void onStartup(StartupEvent event) { + log.info("Startup event received for IDCSTestTokenRetrieval"); + } +} diff --git a/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/testers/ORDSTestDataRetrieval.java b/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/testers/ORDSTestDataRetrieval.java new file mode 100644 index 0000000..0d11f57 --- /dev/null +++ b/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/testers/ORDSTestDataRetrieval.java @@ -0,0 +1,91 @@ +/*Copyright (c) 2025 Oracle and/or its affiliates. + +The Universal Permissive License (UPL), Version 1.0 + +Subject to the condition set forth below, permission is hereby granted to any +person obtaining a copy of this software, associated documentation and/or data +(collectively the "Software"), free of charge and under any and all copyright +rights in the Software, and any and all patent rights owned or freely +licensable by each licensor hereunder covering either (i) the unmodified +Software as contributed to or provided by such licensor, or (ii) the Larger +Works (as defined below), to deal in both + +(a) the Software, and +(b) any piece of software and/or hardware listed in the lrgrwrks.txt file if +one is included with the Software (each a "Larger Work" to which the Software +is contributed by such licensors), + +without restriction, including without limitation the rights to copy, create +derivative works of, display, perform, and distribute the Software and make, +use, sell, offer for sale, import, export, have made, and have sold the +Software and the Larger Work(s), and to sublicense the foregoing rights on +either these or other terms. + +This license is subject to the following condition: +The above copyright notice and either this complete permission notice or at +a minimum a reference to the UPL must be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + */ +package com.oracle.demo.timg.iot.iotordsaccess.testers; + +import java.util.List; + +import com.oracle.demo.timg.iot.iotordsaccess.data.HistorizedDataResponseString; +import com.oracle.demo.timg.iot.iotordsaccess.data.SnapshotDataResponseString; +import com.oracle.demo.timg.iot.iotordsaccess.iotaccess.IoTDataAccessor; + +import io.micronaut.context.annotation.Property; +import io.micronaut.context.annotation.Requires; +import io.micronaut.context.event.StartupEvent; +import io.micronaut.runtime.event.annotation.EventListener; +import io.micronaut.scheduling.TaskExecutors; +import io.micronaut.scheduling.annotation.ExecuteOn; +import io.micronaut.scheduling.annotation.Scheduled; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; +import lombok.extern.java.Log; + +@Log +@Singleton +@Requires(property = "iot.ords.test-data-retrieval", value = "true", defaultValue = "false") +public class ORDSTestDataRetrieval { + private int counter = 0; + @Inject + private IoTDataAccessor dataAccessor; + + @Property(name = "iot.dti.id") + private String dtid; + @Property(name = "iot.dti.content-path") + private String content_Path; + + @ExecuteOn(TaskExecutors.IO) + @Scheduled(fixedRate = "10s", initialDelay = "5s") + public void testGetSnapshotData() { + if (counter++ > 6) { + System.exit(0); + } + List contentPathNames = dataAccessor.getDigitalTwinInstanceContentPaths(dtid); + log.info("Content paths " + contentPathNames); + SnapshotDataResponseString allsnapshotdata = dataAccessor.getDigitalTwinInstanceSnapshotAsString(dtid); + log.info("All snapshot data retrieved " + allsnapshotdata); + SnapshotDataResponseString limitedsnapshotdata = dataAccessor.getDigitalTwinInstanceSnapshotAsString(dtid, + content_Path); + log.info("Only " + content_Path + " snapshot data retrieved " + limitedsnapshotdata); + HistorizedDataResponseString historyDataContentPath = dataAccessor.getDigitalTwinInstanceHistoryAsString(dtid, + content_Path, 10); + log.info("History data for " + content_Path + " retrieved " + historyDataContentPath); + } + + @EventListener + public void onStartup(StartupEvent event) { + log.info("Startup event received for ORDSTestDataRetrieval"); + } +} diff --git a/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/testers/ORDSTestHistorizedDataRetrieval.java b/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/testers/ORDSTestHistorizedDataRetrieval.java new file mode 100644 index 0000000..97ecb9f --- /dev/null +++ b/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/testers/ORDSTestHistorizedDataRetrieval.java @@ -0,0 +1,90 @@ +/*Copyright (c) 2025 Oracle and/or its affiliates. + +The Universal Permissive License (UPL), Version 1.0 + +Subject to the condition set forth below, permission is hereby granted to any +person obtaining a copy of this software, associated documentation and/or data +(collectively the "Software"), free of charge and under any and all copyright +rights in the Software, and any and all patent rights owned or freely +licensable by each licensor hereunder covering either (i) the unmodified +Software as contributed to or provided by such licensor, or (ii) the Larger +Works (as defined below), to deal in both + +(a) the Software, and +(b) any piece of software and/or hardware listed in the lrgrwrks.txt file if +one is included with the Software (each a "Larger Work" to which the Software +is contributed by such licensors), + +without restriction, including without limitation the rights to copy, create +derivative works of, display, perform, and distribute the Software and make, +use, sell, offer for sale, import, export, have made, and have sold the +Software and the Larger Work(s), and to sublicense the foregoing rights on +either these or other terms. + +This license is subject to the following condition: +The above copyright notice and either this complete permission notice or at +a minimum a reference to the UPL must be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + */ +package com.oracle.demo.timg.iot.iotordsaccess.testers; + +import com.oracle.demo.timg.iot.iotordsaccess.data.HistorizedDataResponseString; +import com.oracle.demo.timg.iot.iotordsaccess.idcs.IDCSOAuthApplicationTokenRetriever; +import com.oracle.demo.timg.iot.iotordsaccess.ords.ORDSApiClient; +import com.oracle.demo.timg.iot.iotordsaccess.ords.ORDSDataRequestFilter; + +import io.micronaut.context.annotation.Requires; +import io.micronaut.context.event.StartupEvent; +import io.micronaut.runtime.event.annotation.EventListener; +import io.micronaut.scheduling.TaskExecutors; +import io.micronaut.scheduling.annotation.ExecuteOn; +import io.micronaut.scheduling.annotation.Scheduled; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; +import lombok.extern.java.Log; + +@Log +@Singleton +@Requires(property = "iot.ords.test-historizeddata-retrieval", value = "true", defaultValue = "false") +public class ORDSTestHistorizedDataRetrieval { + private int counter = 0; + @Inject + private ORDSApiClient ordsApiClient; + + // This should not be here, but for some reason at the moment it's the only way + // Micronaut can handle the request filter needing to inject the token + // retriever. + // As it fails to retrieve the token retriever properties, I suspect a + // dependencies + // issue where all of the dependencies are not resolved when going client -> + // filter -> token retriever. + @Inject + private ORDSDataRequestFilter ordsDataRequestFilter; + @Inject + private IDCSOAuthApplicationTokenRetriever idcsoAuthApplicationTokenRequest; + + @ExecuteOn(TaskExecutors.IO) + @Scheduled(fixedRate = "10s", initialDelay = "5s") + public void testGetHistorizedData() { + if (counter++ > 6) { + System.exit(0); + } + HistorizedDataResponseString data = ordsApiClient.getHistorizedDataString(0, 2); + log.info("Count " + counter + " retrieved " + data); + } + + @EventListener + public void onStartup(StartupEvent event) { + log.info("Startup event received for ORDSApiClient"); + ordsDataRequestFilter.setIdcsoAuthApplicationTokenRequest(idcsoAuthApplicationTokenRequest); + log.info("configured request filter"); + } +} diff --git a/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/testers/ORDSTestRawDataRetrieval.java b/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/testers/ORDSTestRawDataRetrieval.java new file mode 100644 index 0000000..68deb7c --- /dev/null +++ b/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/testers/ORDSTestRawDataRetrieval.java @@ -0,0 +1,91 @@ +/*Copyright (c) 2025 Oracle and/or its affiliates. + +The Universal Permissive License (UPL), Version 1.0 + +Subject to the condition set forth below, permission is hereby granted to any +person obtaining a copy of this software, associated documentation and/or data +(collectively the "Software"), free of charge and under any and all copyright +rights in the Software, and any and all patent rights owned or freely +licensable by each licensor hereunder covering either (i) the unmodified +Software as contributed to or provided by such licensor, or (ii) the Larger +Works (as defined below), to deal in both + +(a) the Software, and +(b) any piece of software and/or hardware listed in the lrgrwrks.txt file if +one is included with the Software (each a "Larger Work" to which the Software +is contributed by such licensors), + +without restriction, including without limitation the rights to copy, create +derivative works of, display, perform, and distribute the Software and make, +use, sell, offer for sale, import, export, have made, and have sold the +Software and the Larger Work(s), and to sublicense the foregoing rights on +either these or other terms. + +This license is subject to the following condition: +The above copyright notice and either this complete permission notice or at +a minimum a reference to the UPL must be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + */ +package com.oracle.demo.timg.iot.iotordsaccess.testers; + +import com.oracle.demo.timg.iot.iotordsaccess.data.RawDataResponse; +import com.oracle.demo.timg.iot.iotordsaccess.idcs.IDCSOAuthApplicationTokenRetriever; +import com.oracle.demo.timg.iot.iotordsaccess.ords.ORDSApiClient; +import com.oracle.demo.timg.iot.iotordsaccess.ords.ORDSDataRequestFilter; + +import io.micronaut.context.annotation.Requires; +import io.micronaut.context.event.StartupEvent; +import io.micronaut.runtime.event.annotation.EventListener; +import io.micronaut.scheduling.TaskExecutors; +import io.micronaut.scheduling.annotation.ExecuteOn; +import io.micronaut.scheduling.annotation.Scheduled; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; +import lombok.extern.java.Log; + +@Log +@Singleton +@Requires(property = "iot.ords.test-rawdata-retrieval", value = "true", defaultValue = "false") +public class ORDSTestRawDataRetrieval { + private int counter = 0; + @Inject + private ORDSApiClient ordsApiClient; + + // This should not be here, but for some reason at the moment it's the only way + // Micronaut can handle the request filter needing to inject the token + // retriever. + // As it fails to retrieve the token retriever properties, I suspect a + // dependencies + // issue where all of the dependencies are not resolved when going client -> + // filter -> token retriever. + @Inject + private ORDSDataRequestFilter ordsDataRequestFilter; + @Inject + private IDCSOAuthApplicationTokenRetriever idcsoAuthApplicationTokenRequest; + + @ExecuteOn(TaskExecutors.IO) + @Scheduled(fixedRate = "10s", initialDelay = "5s") + public void testGetRawData() { + if (counter++ > 6) { + System.exit(0); + } + RawDataResponse data = ordsApiClient.getRawData(0, 2); + + log.info("Count " + counter + " retrieved " + data); + } + + @EventListener + public void onStartup(StartupEvent event) { + log.info("Startup event received for ORDSApiClient"); + ordsDataRequestFilter.setIdcsoAuthApplicationTokenRequest(idcsoAuthApplicationTokenRequest); + log.info("configured request filter"); + } +} diff --git a/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/testers/ORDSTestSnapshotDataRetrieval.java b/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/testers/ORDSTestSnapshotDataRetrieval.java new file mode 100644 index 0000000..e1f802d --- /dev/null +++ b/IoTORDSAccess/src/main/java/com/oracle/demo/timg/iot/iotordsaccess/testers/ORDSTestSnapshotDataRetrieval.java @@ -0,0 +1,90 @@ +/*Copyright (c) 2025 Oracle and/or its affiliates. + +The Universal Permissive License (UPL), Version 1.0 + +Subject to the condition set forth below, permission is hereby granted to any +person obtaining a copy of this software, associated documentation and/or data +(collectively the "Software"), free of charge and under any and all copyright +rights in the Software, and any and all patent rights owned or freely +licensable by each licensor hereunder covering either (i) the unmodified +Software as contributed to or provided by such licensor, or (ii) the Larger +Works (as defined below), to deal in both + +(a) the Software, and +(b) any piece of software and/or hardware listed in the lrgrwrks.txt file if +one is included with the Software (each a "Larger Work" to which the Software +is contributed by such licensors), + +without restriction, including without limitation the rights to copy, create +derivative works of, display, perform, and distribute the Software and make, +use, sell, offer for sale, import, export, have made, and have sold the +Software and the Larger Work(s), and to sublicense the foregoing rights on +either these or other terms. + +This license is subject to the following condition: +The above copyright notice and either this complete permission notice or at +a minimum a reference to the UPL must be included in all copies or +substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. + */ +package com.oracle.demo.timg.iot.iotordsaccess.testers; + +import com.oracle.demo.timg.iot.iotordsaccess.data.SnapshotDataResponseString; +import com.oracle.demo.timg.iot.iotordsaccess.idcs.IDCSOAuthApplicationTokenRetriever; +import com.oracle.demo.timg.iot.iotordsaccess.ords.ORDSApiClient; +import com.oracle.demo.timg.iot.iotordsaccess.ords.ORDSDataRequestFilter; + +import io.micronaut.context.annotation.Requires; +import io.micronaut.context.event.StartupEvent; +import io.micronaut.runtime.event.annotation.EventListener; +import io.micronaut.scheduling.TaskExecutors; +import io.micronaut.scheduling.annotation.ExecuteOn; +import io.micronaut.scheduling.annotation.Scheduled; +import jakarta.inject.Inject; +import jakarta.inject.Singleton; +import lombok.extern.java.Log; + +@Log +@Singleton +@Requires(property = "iot.ords.test-snapshotdata-retrieval", value = "true", defaultValue = "false") +public class ORDSTestSnapshotDataRetrieval { + private int counter = 0; + @Inject + private ORDSApiClient ordsApiClient; + + // This should not be here, but for some reason at the moment it's the only way + // Micronaut can handle the request filter needing to inject the token + // retriever. + // As it fails to retrieve the token retriever properties, I suspect a + // dependencies + // issue where all of the dependencies are not resolved when going client -> + // filter -> token retriever. + @Inject + private ORDSDataRequestFilter ordsDataRequestFilter; + @Inject + private IDCSOAuthApplicationTokenRetriever idcsoAuthApplicationTokenRequest; + + @ExecuteOn(TaskExecutors.IO) + @Scheduled(fixedRate = "10s", initialDelay = "5s") + public void testGetSnapshotData() { + if (counter++ > 6) { + System.exit(0); + } + SnapshotDataResponseString data = ordsApiClient.getSnapshotDataString(0, 2); + log.info("Count " + counter + " retrieved " + data); + } + + @EventListener + public void onStartup(StartupEvent event) { + log.info("Startup event received for ORDSApiClient"); + ordsDataRequestFilter.setIdcsoAuthApplicationTokenRequest(idcsoAuthApplicationTokenRequest); + log.info("configured request filter"); + } +} diff --git a/IoTORDSAccess/src/main/resources/application.properties b/IoTORDSAccess/src/main/resources/application.properties new file mode 100644 index 0000000..2713a12 --- /dev/null +++ b/IoTORDSAccess/src/main/resources/application.properties @@ -0,0 +1,2 @@ +#Fri Dec 05 11:37:07 UTC 2025 +micronaut.application.name=iotordsaccess diff --git a/IoTORDSAccess/src/main/resources/logback.xml b/IoTORDSAccess/src/main/resources/logback.xml new file mode 100644 index 0000000..2d77bda --- /dev/null +++ b/IoTORDSAccess/src/main/resources/logback.xml @@ -0,0 +1,14 @@ + + + + + + %cyan(%d{HH:mm:ss.SSS}) %gray([%thread]) %highlight(%-5level) %magenta(%logger{36}) - %msg%n + + + + + + + diff --git a/IoTSonnenUploader/DigitalTwin/AnalyticsDBAccess.txt b/IoTSonnenUploader/DigitalTwin/AnalyticsDBAccess.txt new file mode 100644 index 0000000..5dc5a72 --- /dev/null +++ b/IoTSonnenUploader/DigitalTwin/AnalyticsDBAccess.txt @@ -0,0 +1,41 @@ +you must have setup the IoT instance +You must have completed the instructions for Srep 1 (setting upt he VCN) at https://docs.oracle.com/en-us/iaas/Content/internet-of-things/connect-analytics-cloud.htm +The first part of these steps is the same for Analytics AND Direct DB access from a compute instance + +export IOT_DB_ACCESS_VCN_OCID= + +# $IOT_DOMAIN_GROUP_OCID is set when you follow the process in instructions.txt +# connect the domain group to the vcn, wait for it to complete +oci iot domain-group configure-data-access --db-allow-listed-vcn-ids "[\"$IOT_DB_ACCESS_VCN_OCID\"]" --iot-domain-group-id $IOT_DOMAIN_GROUP_OCID --wait-for-state SUCCEEDED --wait-for-state FAILED + +## The following are the the compute oinstance instructions +Basically go on from step 3 at https://docs.oracle.com/en-us/iaas/Content/internet-of-things/connect-database.htm + + + +## The following are the anlytics instructions + +export IOT_DOMAIN_GROUP_INFO=`oci iot domain-group get --iot-domain-group-id $IOT_DOMAIN_GROUP_OCID` +export IOT_DB_CONNECTION_STRING=`echo $IOT_DOMAIN_GROUP_INFO | jq -r '.data."db-connection-string"'` +export IOT_DB_TOKEN_SCOPE=`echo $IOT_DOMAIN_GROUP_INFO | jq -r '.data."db-token-scope"'` + +# get the tenancy OCID +# set the idcs name and the idcs group name you're using, use Default if you're using the system wide idcs +export IDCS_DOMAIN_NAME= +export IDCS_IOT_GROUP_NAME= +export OCI_TENANCY_OCID=`oci iam compartment list --query 'data[?contains("compartment-id", \`.tenancy\`)]."compartment-id" | [0]' --raw-output` + +export OCI_TENANCY_OCID=`oci iam compartment list --query 'data[?contains("compartment-id", \`.tenancy\`)]."compartment-id" | [0]' --raw-output` + + +oci iot domain configure-direct-data-access --iot-domain-id $IOT_DOMAIN_OCID --db-allow-listed-identity-group-names '["'$OCI_TENANCY_OCID':'$IDCS_DOMAIN_NAME'/'$IDCS_IOT_GROUP_NAME'", "'$OCI_TENANCY_OCID':OracleIdentityCloudService/Domain_Specialists"]' --wait-for-state SUCCEEDED --wait-for-state FAILED + + +# make sure it worked, look in the domain details +oci iot domain get --iot-domain-id $IOT_DOMAIN_OCID | jq -r '.data."db-allow-listed-identity-group-names"' + +you shouold see some contents in the resulting array + +follow the instructions in step 6 at https://docs.oracle.com/en-us/iaas/Content/internet-of-things/connect-analytics-cloud.htm to create and setup the Analytics instance and connect it + +## The following are the \ No newline at end of file diff --git a/IoTSonnenUploader/DigitalTwin/DeleteInstanceAdapterModel.txt b/IoTSonnenUploader/DigitalTwin/DeleteInstanceAdapterModel.txt new file mode 100644 index 0000000..cff2465 --- /dev/null +++ b/IoTSonnenUploader/DigitalTwin/DeleteInstanceAdapterModel.txt @@ -0,0 +1,10 @@ +# this will delete the twin instance, model and adaptor + +oci iot digital-twin-instance delete --digital-twin-instance-id $DIGITAL_TWIN_INSTANCE_OCID --force --wait-for-state DELETED +oci iot digital-twin-adapter delete --digital-twin-adapter-id $DIGITAL_TWIN_ADAPTER_OCID --force --wait-for-state DELETED +oci iot digital-twin-model delete --digital-twin-model-id $DIGTAL_TWIN_MODEL_ID --force --wait-for-state DELETED + +unset DIGTAL_TWIN_MODEL_ID +unset DIGITAL_TWIN_ADAPTER_OCID +unset DIGITAL_TWIN_INSTANCE_OCID +unset DEVICE_EXTERNAL_KEY \ No newline at end of file diff --git a/IoTSonnenUploader/DigitalTwin/HomeBatteryDTMI.json b/IoTSonnenUploader/DigitalTwin/HomeBatteryDTMI.json index 105912d..42b5b2f 100644 --- a/IoTSonnenUploader/DigitalTwin/HomeBatteryDTMI.json +++ b/IoTSonnenUploader/DigitalTwin/HomeBatteryDTMI.json @@ -123,6 +123,17 @@ "schema": "integer", "unit": "watt" }, + { + "@type": [ + "Telemetry", + "Historized", + "EnergyRate" + ], + "displayName": "Inverter power intake", + "name": "InverterPowerWattsPointInTime", + "schema": "integer", + "unit": "watt" + }, { "@type": [ "Telemetry", diff --git a/IoTSonnenUploader/DigitalTwin/Instructions.txt b/IoTSonnenUploader/DigitalTwin/Instructions.txt index c6afe38..c577c76 100644 --- a/IoTSonnenUploader/DigitalTwin/Instructions.txt +++ b/IoTSonnenUploader/DigitalTwin/Instructions.txt @@ -1,5 +1,5 @@ All examples below use the default oci config entry -Make sure you have the latest OCI command line client 370.1 works as may earlier versions, buyt 3.45 does not. On Macos you can use homebrew - https://docs.oracle.com/en-us/iaas/Content/API/SDKDocs/cliinstall.htm#InstallingCLI__macos_homebrew other instrucitons are at - see https://docs.oracle.com/en-us/iaas/Content/API/SDKDocs/climanualinst.htm +Make sure you have the latest OCI command line client 3.70.1 works as may earlier versions, but 3.45 does not. On Macos you can use homebrew - https://docs.oracle.com/en-us/iaas/Content/API/SDKDocs/cliinstall.htm#InstallingCLI__macos_homebrew other instrucitons are at - see https://docs.oracle.com/en-us/iaas/Content/API/SDKDocs/climanualinst.htm Make sure you havce setup a group and policies as per https://docs.oracle.com/en-us/iaas/Content/internet-of-things/overview.htm#prerequisites @@ -11,20 +11,21 @@ export IOT_DOMAIN_NAME=iot-domain-timg # Create the IoT Domain Group imstructions at https://docs.oracle.com/en-us/iaas/Content/internet-of-things/create-domain-group.htm # to make sure it's in a ready state -oci iot domain-group create --compartment-id $IOT_COMPARTMENT_OCID --display_name $IOT_DOMAIN_GROUP_NAME --wait-for-state SUCCEEDED --wait-for-state FAILED +oci iot domain-group create --compartment-id $IOT_COMPARTMENT_OCID --display-name $IOT_DOMAIN_GROUP_NAME --wait-for-state SUCCEEDED --wait-for-state FAILED # this will return on success or fail, also this may start a work request, which runs in the background, use this command to see if it's created oci iot domain-group list --display-name $IOT_DOMAIN_GROUP_NAME --compartment-id $IOT_COMPARTMENT_OCID # get the domain group ocid (only run this once' it's created) -export IOT_DOMAIN_GROUP_OCID=`oci iot domain-group list --display-name $IOT_DOMAIN_GROUP_NAME --compartment-id $IOT_COMPARTMENT_OCID | jq -r '.data.items[0].id'` +export IOT_DOMAIN_GROUP_OCID=`oci iot domain-group list --display-name $IOT_DOMAIN_GROUP_NAME --compartment-id $IOT_COMPARTMENT_OCID | jq -r '.data.items[]| select (."lifecycle-state" == "ACTIVE") | ."id"'` # get the data host -export IOD_DOMAIN_GROUP_DATA_HOST=`oci iot domain-group get --iot-domain-group-id $IOT_DOMAIN_GROUP_OCID | jq -r '.data."data-host"'` +export IOT_DOMAIN_GROUP_DATA_HOST=`oci iot domain-group get --iot-domain-group-id $IOT_DOMAIN_GROUP_OCID | jq -r '.data."data-host"'` +export IOT_DOMAIN_GROUP_SHORT_ID=`echo $IOT_DOMAIN_GROUP_DATA_HOST| tr '.' ' ' | awk '{print $1}'` #Create the IoT domain within the group -oci iot domaincreate --compartment-id $IOT_COMPARTMENT_OCID --display_name $IOT_DOMAIN_NAME --iot-domain-group-id $IOT_DOMAIN_GROUP_OCID --wait-for-state SUCCEEDED --wait-for-state FAILED +oci iot domain create --compartment-id $IOT_COMPARTMENT_OCID --display-name $IOT_DOMAIN_NAME --iot-domain-group-id $IOT_DOMAIN_GROUP_OCID --wait-for-state SUCCEEDED --wait-for-state FAILED # this will return on success or fail, also this may start a work request, which runs in the background, use this command to see if it's created oci iot domain list --display-name $IOT_DOMAIN_NAME --compartment-id $IOT_COMPARTMENT_OCID --iot-domain-group-id $IOT_DOMAIN_GROUP_OCID #Get the OCID we will need -export IOT_DOMAIN_OCID=`oci iot domain list --display-name $IOT_DOMAIN_NAME --compartment-id $IOT_COMPARTMENT_OCID --iot-domain-group-id $IOTDOMAIN_GROUP_OCID | jq -r '.data.items[0].id'` +export IOT_DOMAIN_OCID=`oci iot domain list --display-name $IOT_DOMAIN_NAME --compartment-id $IOT_COMPARTMENT_OCID --iot-domain-group-id $IOT_DOMAIN_GROUP_OCID | jq -r '.data.items[]| select (."lifecycle-state" == "ACTIVE") | ."id"'` export IOT_DOMAIN_HOST=`oci iot domain get --iot-domain-id $IOT_DOMAIN_OCID | jq -r '.data."device-host"'` export IOT_DOMAIN_SHORT_ID=`echo $IOT_DOMAIN_HOST| tr '.' ' ' | awk '{print $1}'` @@ -36,15 +37,15 @@ The IoT core is now in place, the underlyign DB and Kubernrtes runtime has been export DEVICE_VAULT_SECRET_OCID= set the id that will be used to identify the device - export DEVICE_ID=tims + export DEVICE_ID=timssonnen now create the digital twin to be linked to the device - this is for unstructured data only oci iot digital-twin-instance create --iot-domain-id $IOT_DOMAIN_OCID --auth-id $DEVICE_VAULT_SECRET_OCID --display-name $DEVICE_ID # get the OCID of the digital twin - export DIGITAL_TWIN_INSTANCE_OCID=`oci iot digital-twin-instance list --iot-domain-id $IOT_DOMAIN_OCID --display-name $DEVICE_ID | jq -r '.data.items[0].id'` +export DIGITAL_TWIN_INSTANCE_OCID=`oci iot digital-twin-instance list --iot-domain-id $IOT_DOMAIN_OCID --display-name $DEVICE_ID | jq -r '.data.items[]| select (."lifecycle-state" == "ACTIVE") | ."id"'` get it's external key - export DEVICE_EXTERNAL_KEY=`oci iot digital-twin-instance list --iot-domain-id $IOT_DOMAIN_OCID --display-name $DEVICE_ID | jq -r '.data.items[0]."external-key"'` +export DEVICE_EXTERNAL_KEY=`oci iot digital-twin-instance get --digital-twin-instance-id $DIGITAL_TWIN_INSTANCE_OCID | jq -r '.data."external-key"'` we can test sending some external unstructured data now export DEVICE_SECRET_BASE64=`oci secrets secret-bundle get --secret-id $DEVICE_VAULT_SECRET_OCID --stage CURRENT | jq -r '.data."secret-bundle-content".content'` @@ -54,10 +55,10 @@ curl -u "$DEVICE_EXTERNAL_KEY:$DEVICE_SECRET" https://$IOT_DOMAIN_HOST/sampletop Go into the and setup APEX using the data access options export IOT_APEX_INITIAL_PASSWORD= -oci iot domain configure-apex-data-access --iot-domain-id $IOT_DOMAIN_OCID --db-workspace-admin-initial-password $IOT_APEX_INITIAL_PASSWORD +oci iot domain configure-apex-data-access --iot-domain-id $IOT_DOMAIN_OCID --db-workspace-admin-initial-password $IOT_APEX_INITIAL_PASSWORD --wait-for-state SUCCEEDED --wait-for-state FAILED #Get the apex URL -echo APEX_URL "https://$IOD_DOMAIN_GROUP_DATA_HOST/ords/apex/" +echo APEX_URL "https://$IOT_DOMAIN_GROUP_DATA_HOST/ords/apex/" #get the user id and workspace echo APEX_Workspace "$IOT_DOMAIN_SHORT_ID"__WKSP echo APEX_User "$IOT_DOMAIN_SHORT_ID"__WKSP @@ -68,25 +69,26 @@ switch to the IOT Scheme (upper right) select the raw data content orded by the most recent to oldest select * from RAW_DATA order by TIME_RECEIVED DESC -have the Client code send some data, you will need to make changes to the configuration file -device.id to $DEVICE_ID -iotserverhttps.username to $DEVICE_EXTERNAL_KEY -iotserverhttps.password to $DEVICE_SECRET_BASE64 -micronaut.http.services.iotservicehttps.url https://$IOT_DOMAIN_HOST +# have the Client application send some data, you will need to make changes to the configuration file as follows +# this shows the JSON path, it's actually a indented yaml hierarchy" +echo "\"device.id\": \"$DEVICE_ID\"" +echo "\"iotserverhttps.username\": \"$DEVICE_EXTERNAL_KEY\"" +echo iotserverhttps.password to $DEVICE_SECRET_BASE64 +echo micronaut.http.services.iotservicehttps.url https://$IOT_DOMAIN_HOST -make sure that this is set to true -iotservicehttps.statusupload.enabled +#make sure that this is set to true +echo '"iotservicehttps.statusupload.enabled: true"' make sure that these are set to PLAIN -iotservicehttps.statusupload.sendtype +echo '"iotservicehttps.statusupload.sendtype": PLAIN make sure that these is set to false -iotservicehttps.configurationupload.enabled -mqtt.statusupload.enabled -mqtt.configurationupload.enabled -mqtt.monitorreference.enabled -mqtt.monitoruploads.enabled +echo '"iotservicehttps.configurationupload.enabled": false' +echo '"mqtt.statusupload.enabled": false' +echo '"mqtt.configurationupload.enabled": false' +echo '"mqtt.monitorreference.enabled": false' +echo '"mqtt.monitoruploads.enabled": false' Run the simulation, it should happily upload the data if the above is set (and of course you have access to a sonnen and have set the approipriate settings in the battery.properties file) @@ -101,34 +103,29 @@ delete the basic digital twin oci iot digital-twin-instance delete --digital-twin-instance-id $DIGITAL_TWIN_INSTANCE_OCID --force --wait-for-state DELETED -now let's setup a digital twin model - this uses the exact field names in the data being uploaded +now let's setup a digital twin model - this uses the exact field names in the data being uploaded, the model definition lanhguats is JSON, see the documents at https://github.com/Azure/opendigitaltwins-dtdl/blob/master/DTDL/v3/DTDL.v3.md export DIGITAL_TWIN_MODEL_NAME=sonnenbattery export DIGITAL_TWIN_MODEL_FILE_NAME=SonnenSpecificDTMI.json export DIGITAL_TWIN_MODEL_FILE=file://$DIGITAL_TWIN_MODEL_FILE_NAME # Create the digntal twin model, note this is the simple version, run from within the DigitalTwin folder oci iot digital-twin-model create --iot-domain-id $IOT_DOMAIN_OCID --display-name $DIGITAL_TWIN_MODEL_NAME --spec $DIGITAL_TWIN_MODEL_FILE --wait-for-state ACTIVE - # get the id of the model you just created -export DIGTAL_TWIN_MODEL_ID=`oci iot digital-twin-model list --iot-domain-id $IOT_DOMAIN_OCID --display-name $DIGITAL_TWIN_MODEL_NAME | jq -r '.data.items[0].id'` - -# to replace the model with a new one you have to delete the old one then create a new one -oci iot digital-twin-model delete --digital-twin-model-id $DIGTAL_TWIN_MODEL_ID --force --wait-for-state DELETED -export DIGTAL_TWIN_MODEL_ID=`oci iot digital-twin-model create --iot-domain-id $IOT_DOMAIN_OCID --display-name $DIGITAL_TWIN_MODEL_NAME --query data.id --raw-output --spec $DIGITAL_TWIN_MODEL_FILE` +export DIGITAL_TWIN_MODEL_ID=`oci iot digital-twin-model list --iot-domain-id $IOT_DOMAIN_OCID --display-name $DIGITAL_TWIN_MODEL_NAME | jq -r '.data.items[]| select (."lifecycle-state" == "ACTIVE") | ."id"'` # to get the current spec to edit it -oci iot digital-twin-model get-spec --digital-twin-model-id $DIGTAL_TWIN_MODEL_ID +oci iot digital-twin-model get-spec --digital-twin-model-id $DIGITAL_TWIN_MODEL_ID get the model identifier export DIGITAL_TWIN_MODEL_IDENTIFIER=`cat $DIGITAL_TWIN_MODEL_FILE_NAME | jq -r '.["@id"]'` -export DIGITAL_TWIN_ADAPTER_NAME="$DIGITAL_TWIN_MODEL_NAME"_adapter +export DIGITAL_TWIN_ADAPTER_NAME=sonnen-direct-mapping now create the adapter. For the sonnenbattery model as we use exactly the same field names we don't need to worry about setting up any mappings, -oci iot digital-twin-adapter create --iot-domain-id $IOT_DOMAIN_OCID --digital-twin-model-id $DIGTAL_TWIN_MODEL_ID --display-name $DIGITAL_TWIN_ADAPTER_NAME --wait-for-state ACTIVE +oci iot digital-twin-adapter create --iot-domain-id $IOT_DOMAIN_OCID --digital-twin-model-id $DIGITAL_TWIN_MODEL_ID --display-name $DIGITAL_TWIN_ADAPTER_NAME --wait-for-state ACTIVE -export DIGITAL_TWIN_ADAPTER_OCID=`oci iot digital-twin-adapter list --iot-domain-id $IOT_DOMAIN_OCID --display-name $DIGITAL_TWIN_ADAPTER_NAME | jq -r '.data.items[0].id'` +export DIGITAL_TWIN_ADAPTER_OCID=`oci iot digital-twin-adapter list --iot-domain-id $IOT_DOMAIN_OCID --display-name $DIGITAL_TWIN_ADAPTER_NAME | jq -r '.data.items[]| select (."lifecycle-state" == "ACTIVE") | ."id"'` to see the adaptor contents oci iot digital-twin-adapter get --digital-twin-adapter-id $DIGITAL_TWIN_ADAPTER_OCID @@ -140,10 +137,10 @@ now let's re-create our device using the adaptor to process structured data oci iot digital-twin-instance create --iot-domain-id $IOT_DOMAIN_OCID --auth-id $DEVICE_VAULT_SECRET_OCID --display-name $DEVICE_ID --digital-twin-adapter-id $DIGITAL_TWIN_ADAPTER_OCID --wait-for-state ACTIVE # get the OCID of the digital twin - export DIGITAL_TWIN_INSTANCE_OCID=`oci iot digital-twin-instance list --iot-domain-id $IOT_DOMAIN_OCID --display-name $DEVICE_ID | jq -r '.data.items[0].id'` +export DIGITAL_TWIN_INSTANCE_OCID=`oci iot digital-twin-instance list --iot-domain-id $IOT_DOMAIN_OCID --display-name $DEVICE_ID | jq -r '.data.items[]| select (."lifecycle-state" == "ACTIVE") | ."id"'` # get it's external key - export DEVICE_EXTERNAL_KEY=`oci iot digital-twin-instance list --iot-domain-id $IOT_DOMAIN_OCID --display-name $DEVICE_ID | jq -r '.data.items[0]."external-key"'` +export DEVICE_EXTERNAL_KEY=`oci iot digital-twin-instance get --digital-twin-instance-id $DIGITAL_TWIN_INSTANCE_OCID | jq -r '.data."external-key"'` let's send some sample JSON data, the iot has set this up to accept data on any inbound path, so let's use the one we will use for the structured data curl -i -X POST -u "$DEVICE_EXTERNAL_KEY:$DEVICE_SECRET" https://$IOT_DOMAIN_HOST/home/sonnenstatus/$DEVICE_ID -H "Content-Type:application/json" -d '{"consumptionAvgWattsLastMinute":566,"consumptionWattsPointInTime":141,"currentBatteryCapacityPercentage":97,"currentBatteryCapacitySystemPercentage":97,"gridConsumptionWattsPointInTime":63,"operatingMode":2,"remainingBatteryCapacityWattHours":0,"reservedBatteryCapacityPercentage":5,"solarProductionWattsPointInTime":0,"timestamp":"2025-11-18T16:22:58.348041Z","batteryCharging":false,"batteryDischarging":true}' @@ -180,7 +177,7 @@ can now delete the items we have just created (not strictly needed, but helps to oci iot digital-twin-instance delete --digital-twin-instance-id $DIGITAL_TWIN_INSTANCE_OCID --force --wait-for-state DELETED oci iot digital-twin-adapter delete --digital-twin-adapter-id $DIGITAL_TWIN_ADAPTER_OCID --force --wait-for-state DELETED -oci iot digital-twin-model delete --digital-twin-model-id $DIGTAL_TWIN_MODEL_ID --force --wait-for-state DELETED +oci iot digital-twin-model delete --digital-twin-model-id $DIGITAL_TWIN_MODEL_ID --force --wait-for-state DELETED This however is assuming that the digital twin model is an exact match for the data comming from the device, this is an ideal use case, but what if you wanted to model a generic home battery but with different homke betteries, you will need to map the data to the model @@ -189,12 +186,12 @@ Let's create a new model that had generic names for the attributes. export DIGITAL_TWIN_MODEL_NAME=homebattery export DIGITAL_TWIN_MODEL_FILE_NAME=HomeBatteryDTMI.json export DIGITAL_TWIN_MODEL_FILE=file://$DIGITAL_TWIN_MODEL_FILE_NAME -# Create the digtal twin model, note this is the simple version, run from within the DigitalTwin folder +# Create the digtal twin model for the generic home battery, run from within the DigitalTwin folder oci iot digital-twin-model create --iot-domain-id $IOT_DOMAIN_OCID --display-name $DIGITAL_TWIN_MODEL_NAME --spec $DIGITAL_TWIN_MODEL_FILE --wait-for-state ACTIVE # get the id of the model you just created -export DIGTAL_TWIN_MODEL_ID=`oci iot digital-twin-model list --iot-domain-id $IOT_DOMAIN_OCID --display-name $DIGITAL_TWIN_MODEL_NAME | jq -r '.data.items[0].id'` +export DIGITAL_TWIN_MODEL_ID=`oci iot digital-twin-model list --iot-domain-id $IOT_DOMAIN_OCID --display-name $DIGITAL_TWIN_MODEL_NAME | jq -r '.data.items[]| select (."lifecycle-state" == "ACTIVE") | ."id"'` # and the models name export DIGITAL_TWIN_MODEL_IDENTIFIER=`cat $DIGITAL_TWIN_MODEL_FILE_NAME | jq -r '.["@id"]'` @@ -207,19 +204,19 @@ export DIGITAL_TWIN_ADAPTER_NAME=sonnen-single-route # create the adaptor using the route file, even though our envelope mapping is the default we actually still have to specify it sadly. # note that as the file contents is inlined into the JSON request then the stricture of the JSON files MUST be OK (if not you'll get missing param errors, even though you have specifried all fo the actual flags correctly -oci iot digital-twin-adapter create --iot-domain-id $IOT_DOMAIN_OCID --digital-twin-model-id $DIGTAL_TWIN_MODEL_ID --inbound-routes $DIGITAL_TWIN_ADAPTOR_ROUTE_MAPPINGS_FILE --display-name $DIGITAL_TWIN_ADAPTER_NAME --inbound-envelope $DIGITAL_TWIN_ADAPTOR_ENVELOPE_MAPPINGS_FILE --wait-for-state ACTIVE +oci iot digital-twin-adapter create --iot-domain-id $IOT_DOMAIN_OCID --digital-twin-model-id $DIGITAL_TWIN_MODEL_ID --inbound-routes $DIGITAL_TWIN_ADAPTOR_ROUTE_MAPPINGS_FILE --display-name $DIGITAL_TWIN_ADAPTER_NAME --inbound-envelope $DIGITAL_TWIN_ADAPTOR_ENVELOPE_MAPPINGS_FILE --wait-for-state ACTIVE # get the OCID of the new adaptor -export DIGITAL_TWIN_ADAPTER_OCID=`oci iot digital-twin-adapter list --iot-domain-id $IOT_DOMAIN_OCID --display-name $DIGITAL_TWIN_ADAPTER_NAME | jq -r '.data.items[0].id'` +export DIGITAL_TWIN_ADAPTER_OCID=`oci iot digital-twin-adapter list --iot-domain-id $IOT_DOMAIN_OCID --display-name $DIGITAL_TWIN_ADAPTER_NAME | jq -r '.data.items[]| select (."lifecycle-state" == "ACTIVE") | ."id"'` Finally we create a digital twin instance using the mapping based adaptor oci iot digital-twin-instance create --iot-domain-id $IOT_DOMAIN_OCID --auth-id $DEVICE_VAULT_SECRET_OCID --display-name $DEVICE_ID --digital-twin-adapter-id $DIGITAL_TWIN_ADAPTER_OCID --wait-for-state ACTIVE # get the OCID of the digital twin - export DIGITAL_TWIN_INSTANCE_OCID=`oci iot digital-twin-instance list --iot-domain-id $IOT_DOMAIN_OCID --display-name $DEVICE_ID | jq -r '.data.items[0].id'` +export DIGITAL_TWIN_INSTANCE_OCID=`oci iot digital-twin-instance list --iot-domain-id $IOT_DOMAIN_OCID --display-name $DEVICE_ID | jq -r '.data.items[]| select (."lifecycle-state" == "ACTIVE") | ."id"'` # get it's external key - export DEVICE_EXTERNAL_KEY=`oci iot digital-twin-instance list --iot-domain-id $IOT_DOMAIN_OCID --display-name $DEVICE_ID | jq -r '.data.items[0]."external-key"'` +export DEVICE_EXTERNAL_KEY=`oci iot digital-twin-instance get --digital-twin-instance-id $DIGITAL_TWIN_INSTANCE_OCID | jq -r '.data."external-key"'` curl -i -X POST -u "$DEVICE_EXTERNAL_KEY:$DEVICE_SECRET" https://$IOT_DOMAIN_HOST/home/sonnenstatus/$DEVICE_ID -H "Content-Type:application/json" -d '{"consumptionAvgWattsLastMinute":339,"consumptionWattsPointInTime":333,"currentBatteryCapacityPercentage":59,"currentBatteryCapacitySystemPercentage":62,"gridConsumptionWattsPointInTime":41,"operatingMode":2,"remainingBatteryCapacityWattHours":9102,"reservedBatteryCapacityPercentage":5,"solarProductionWattsPointInTime":131,"time":1763981430279,"timestamp":"2025-11-24T10:50:30.279369Z[Europe/London]","batteryCharging":false,"batteryDischarging":true}' @@ -243,21 +240,19 @@ export DIGITAL_TWIN_ADAPTER_NAME=sonnen-multiple-routes # create the adaptor using the multiple routes file. # note that as the file contents is inlined into the JSON request then the stricture of the JSON files MUST be OK (if not you'll get missing param errors, even though you have specifried all fo the actual flags correctly -oci iot digital-twin-adapter create --iot-domain-id $IOT_DOMAIN_OCID --digital-twin-model-id $DIGTAL_TWIN_MODEL_ID --inbound-routes $DIGITAL_TWIN_ADAPTOR_ROUTE_MAPPINGS_FILE --display-name $DIGITAL_TWIN_ADAPTER_NAME --inbound-envelope $DIGITAL_TWIN_ADAPTOR_ENVELOPE_MAPPINGS_FILE --wait-for-state ACTIVE +oci iot digital-twin-adapter create --iot-domain-id $IOT_DOMAIN_OCID --digital-twin-model-id $DIGITAL_TWIN_MODEL_ID --inbound-routes $DIGITAL_TWIN_ADAPTOR_ROUTE_MAPPINGS_FILE --display-name $DIGITAL_TWIN_ADAPTER_NAME --inbound-envelope $DIGITAL_TWIN_ADAPTOR_ENVELOPE_MAPPINGS_FILE --wait-for-state ACTIVE # get the OCID of the new adaptor - -export DIGITAL_TWIN_ADAPTER_OCID=`oci iot digital-twin-adapter list --iot-domain-id $IOT_DOMAIN_OCID --display-name $DIGITAL_TWIN_ADAPTER_NAME | jq -r '.data.items[0].id'` - +export DIGITAL_TWIN_ADAPTER_OCID=`oci iot digital-twin-adapter list --iot-domain-id $IOT_DOMAIN_OCID --display-name $DIGITAL_TWIN_ADAPTER_NAME | jq -r '.data.items[]| select (."lifecycle-state" == "ACTIVE") | ."id"'` Finally we create a digital twin instance using the mapping based adaptor oci iot digital-twin-instance create --iot-domain-id $IOT_DOMAIN_OCID --auth-id $DEVICE_VAULT_SECRET_OCID --display-name $DEVICE_ID --digital-twin-adapter-id $DIGITAL_TWIN_ADAPTER_OCID --wait-for-state ACTIVE - # get the OCID of the digital twin - export DIGITAL_TWIN_INSTANCE_OCID=`oci iot digital-twin-instance list --iot-domain-id $IOT_DOMAIN_OCID --display-name $DEVICE_ID | jq -r '.data.items[0].id'` - - # get it's external key - export DEVICE_EXTERNAL_KEY=`oci iot digital-twin-instance list --iot-domain-id $IOT_DOMAIN_OCID --display-name $DEVICE_ID | jq -r '.data.items[0]."external-key"'` +# get the OCID of the digital twin +export DIGITAL_TWIN_INSTANCE_OCID=`oci iot digital-twin-instance list --iot-domain-id $IOT_DOMAIN_OCID --display-name $DEVICE_ID | jq -r '.data.items[]| select (."lifecycle-state" == "ACTIVE") | ."id"'` +# get it's external key +export DEVICE_EXTERNAL_KEY=`oci iot digital-twin-instance get --digital-twin-instance-id $DIGITAL_TWIN_INSTANCE_OCID | jq -r '.data."external-key"'` +echo $DEVICE_EXTERNAL_KEY # make sure we can post the status data curl -i -X POST -u "$DEVICE_EXTERNAL_KEY:$DEVICE_SECRET" https://$IOT_DOMAIN_HOST/home/sonnenstatus/$DEVICE_ID -H "Content-Type:application/json" -d '{"consumptionAvgWattsLastMinute":488,"consumptionWattsPointInTime":517,"currentBatteryCapacityPercentage":25,"currentBatteryCapacitySystemPercentage":30,"gridConsumptionWattsPointInTime":44,"operatingMode":10,"remainingBatteryCapacityWattHours":4775,"reservedBatteryCapacityPercentage":5,"solarProductionWattsPointInTime":0,"time":1764004104225,"timestamp":"2025-11-24T17:08:24.225022Z[Europe/London]","batteryCharging":false,"batteryDischarging":true}' diff --git a/IoTSonnenUploader/DigitalTwin/ORDSDataAccess.txt b/IoTSonnenUploader/DigitalTwin/ORDSDataAccess.txt new file mode 100644 index 0000000..190c3d7 --- /dev/null +++ b/IoTSonnenUploader/DigitalTwin/ORDSDataAccess.txt @@ -0,0 +1,45 @@ +setup ORDS data access as described in the documentation at https://docs.oracle.com/en-us/iaas/Content/internet-of-things/connect-iot-ords.htm + +# get the various system values from the setup and use them here +# sub steps are from "Step 1: Create a Confidential Application for your Identity Domain" +# in the URL above. +# note that for the IOT_ORDS_IDSC_PASSWORD you may need to create a non admin user and set a password for them as well as assigning them to your group if creating your own domain as an admin (rather than using a user in an existing one) +# If using the administrator user you created for tyhe domain then under the domain users tab select tt user then in the actions dropdown for users chose reset password and a password email will be sent +# unclear if the user name and password relate to the new identify domain or the main once for the tenancy + +export IOT_ORDS_IDCS_USERNAME= +export IOT_ORDS_IDCS_PASSWORD= +export IOT_ORDS_OAUTH_ID= +export IOT_ORDS_OAUTH_SECRET= +export IOT_IDENTITY_DOMAIN_HOST= + +# this uses the above to get the token and so on +export IOT_IDENTITY_DOMAIN_HOST_SHORT=`echo $IOT_IDENTITY_DOMAIN_HOST | tr '.' ' ' | awk '{print $1}'` +export IOT_IDENTITY_DOMAIN_URL=https://$IOT_IDENTITY_DOMAIN_HOST:443/oauth2/v1/token +# the IOT_DOMAIN_GROUP_SHORT_ID and IOT_DOMAIN_SHORT_ID were set in the Instructions.txt +export IOT_ORDS_AUTH_DETAILS=`curl -s --request POST --url "${IOT_IDENTITY_DOMAIN_URL}" --header 'Content-Type: application/x-www-form-urlencoded' --user "${IOT_ORDS_OAUTH_ID}:${IOT_ORDS_OAUTH_SECRET}" --data "scope=/${IOT_DOMAIN_GROUP_SHORT_ID}/iot/${IOT_DOMAIN_SHORT_ID}" --data "grant_type=password" --data "username=${IOT_ORDS_IDCS_USERNAME}" --data "password=${IOT_ORDS_IDCS_PASSWORD}"` +export IOT_ORDS_AUTH_ACCESS_TOKEN=`echo $IOT_ORDS_AUTH_DETAILS | jq -r '.access_token'` +export IOT_ORDS_AUTH_TOKEN_DURATION=`echo $IOT_ORDS_AUTH_DETAILS | jq -r '.expires_in'` +export IOT_ORDS_AUTH_TOKEN_TYPE=`echo $IOT_ORDS_AUTH_DETAILS | jq -r '.token_type'` + +# lets get a couple of data objects +# this will get a couple of the raw data irtems (limiting it to 2) +curl -k -s --get --location "https://${IOT_DOMAIN_GROUP_DATA_HOST}/ords/$IOT_DOMAIN_SHORT_ID/20250531/rawData" --header "Authorization: Bearer ${IOT_ORDS_AUTH_ACCESS_TOKEN}" --header "Content-Type: application/json" --data-urlencode offset=0 --data-urlencode limit=2 | jq '.items' +# we can put a query in place - let's limit it to raw data for the specific digital twin +curl -k -s --get --location "https://${IOT_DOMAIN_GROUP_DATA_HOST}/ords/$IOT_DOMAIN_SHORT_ID/20250531/rawData" --header "Authorization: Bearer ${IOT_ORDS_AUTH_ACCESS_TOKEN}" --header "Content-Type: application/json" --data-urlencode offset=0 --data-urlencode limit=2 --data-urlencode 'q={"$and":[{"digital_twin_instance_id":"'$DIGITAL_TWIN_INSTANCE_OCID'"}]}"' | jq '.items' + + +# we can of course access the other data tables, this is the snapshot data, we'll retrieve the most recent 20 as each data item in the upload is in its own row +curl -k -s --get --location "https://${IOT_DOMAIN_GROUP_DATA_HOST}/ords/$IOT_DOMAIN_SHORT_ID/20250531/snapshotData" --header "Authorization: Bearer ${IOT_ORDS_AUTH_ACCESS_TOKEN}" --header "Content-Type: application/json" --data-urlencode offset=0 --data-urlencode limit=20 --data-urlencode 'q={"$and":[{"digital_twin_instance_id":"'$DIGITAL_TWIN_INSTANCE_OCID'"}]}"' | jq '.items' + +# The historized data isn't so helpfull, were just getting one content path +curl -k -s --get --location "https://${IOT_DOMAIN_GROUP_DATA_HOST}/ords/$IOT_DOMAIN_SHORT_ID/20250531/historizedData" --header "Authorization: Bearer ${IOT_ORDS_AUTH_ACCESS_TOKEN}" --header "Content-Type: application/json" --data-urlencode offset=0 --data-urlencode limit=20 --data-urlencode 'q={"$and":[{"digital_twin_instance_id":"'$DIGITAL_TWIN_INSTANCE_OCID'"}]}"' | jq '.items' + +# let's add an additional quesy item to the quest to also focus on SolarGeneration +curl -k -s --get --location "https://${IOT_DOMAIN_GROUP_DATA_HOST}/ords/$IOT_DOMAIN_SHORT_ID/20250531/historizedData" --header "Authorization: Bearer ${IOT_ORDS_AUTH_ACCESS_TOKEN}" --header "Content-Type: application/json" --data-urlencode offset=0 --data-urlencode limit=20 --data-urlencode 'q={"$and":[{"digital_twin_instance_id":"'$DIGITAL_TWIN_INSTANCE_OCID'"}, {"content_path":"SolarGeneration"}]}"' | jq '.items' + +# that was the data we wanted, but not very useful as it was some pretty random items, let's try and order it, we'll include some poer draw numbers as well +curl -k -s --get --location "https://${IOT_DOMAIN_GROUP_DATA_HOST}/ords/$IOT_DOMAIN_SHORT_ID/20250531/historizedData" --header "Authorization: Bearer ${IOT_ORDS_AUTH_ACCESS_TOKEN}" --header "Content-Type: application/json" --data-urlencode offset=0 --data-urlencode limit=20 --data-urlencode 'q={"$and":[{"digital_twin_instance_id":"'$DIGITAL_TWIN_INSTANCE_OCID'"}, {"content_path":"SolarGeneration"}],"$orderby":{"time_observed":"desc"}}"' | jq '.items' + +# of course we may want multiple data items, so let's get both thye SolarGeneration and the DischargePower - it's up to thge called to look at the returned data and decide which what resulting rows relate to which data item of course +curl -k -s --get --location "https://${IOT_DOMAIN_GROUP_DATA_HOST}/ords/$IOT_DOMAIN_SHORT_ID/20250531/historizedData" --header "Authorization: Bearer ${IOT_ORDS_AUTH_ACCESS_TOKEN}" --header "Content-Type: application/json" --data-urlencode offset=0 --data-urlencode limit=20 --data-urlencode 'q={"$and":[{"digital_twin_instance_id":"'$DIGITAL_TWIN_INSTANCE_OCID'"}, {"content_path": {"$in": ["SolarGeneration", "DischargePower"]}}],"$orderby":{"time_observed":"desc"}}"' | jq '.items' diff --git a/IoTSonnenUploader/DigitalTwin/RetrieveEnvVars.txt b/IoTSonnenUploader/DigitalTwin/RetrieveEnvVars.txt new file mode 100644 index 0000000..2237800 --- /dev/null +++ b/IoTSonnenUploader/DigitalTwin/RetrieveEnvVars.txt @@ -0,0 +1,64 @@ +# this follows the steps to get the various OCID's and so on. +# it is basically all of the steps in the instructions.txt but +# with none of the create or modify steps +# Each step should work if the one before it suceeds PROVIDED +# that the object at that step exists. I.e. if the adaptor has +# not been created (or has been destriyed) then you probaly don't +# have an instance so can't retrieve the instance OCID +# note that in some cases you may need to set some environment +# variables as they use things like names to work. +# +# Things you may need to change are here +# +export IOT_COMPARTMENT_OCID= +export DEVICE_VAULT_SECRET_OCID= + +# change these names as required +export IOT_DOMAIN_GROUP_NAME=iot-domain-group-timg +export IOT_DOMAIN_NAME=iot-domain-timg +export DEVICE_ID=timssonnen +# note that this is set for homebattery (the generic model), but it might well be sonnenbattery for the sonnen specific model +export DIGITAL_TWIN_MODEL_NAME=homebattery +# DIGITAL_TWIN_MODEL_FILE_NAME should be the name of the file containing the model for example HomeBatteryDTMI.json for the generic home battery, SonnenSpecificDTMI.json for the sonnen specific version +export DIGITAL_TWIN_MODEL_FILE_NAME=HomeBatteryDTMI.json +# this will be one of sonnen-direct-mapping, sonnen-single-route or sonnen-multiple-routes +export DIGITAL_TWIN_ADAPTER_NAME=sonnen-multiple-routes +# get the domain group info +# get the domain group ocid (only run this once it has been created) +export IOT_DOMAIN_GROUP_OCID=`oci iot domain-group list --display-name $IOT_DOMAIN_GROUP_NAME --compartment-id $IOT_COMPARTMENT_OCID | jq -r '.data.items[]| select (."lifecycle-state" == "ACTIVE") | ."id"'` + +# get the data host +export IOT_DOMAIN_GROUP_DATA_HOST=`oci iot domain-group get --iot-domain-group-id $IOT_DOMAIN_GROUP_OCID | jq -r '.data."data-host"'` +export IOT_DOMAIN_GROUP_SHORT_ID=`echo $IOT_DOMAIN_GROUP_DATA_HOST| tr '.' ' ' | awk '{print $1}'` +# Now get the domain stuff +export IOT_DOMAIN_OCID=`oci iot domain list --display-name $IOT_DOMAIN_NAME --compartment-id $IOT_COMPARTMENT_OCID --iot-domain-group-id $IOT_DOMAIN_GROUP_OCID | jq -r '.data.items[]| select (."lifecycle-state" == "ACTIVE") | ."id"'` +export IOT_DOMAIN_HOST=`oci iot domain get --iot-domain-id $IOT_DOMAIN_OCID | jq -r '.data."device-host"'` +export IOT_DOMAIN_SHORT_ID=`echo $IOT_DOMAIN_HOST| tr '.' ' ' | awk '{print $1}'` + +# these are only relevant if you have setup the digital twin model +# the DIGITAL_TWIN_MODEL_NAME should relate to the model you are creating, e.g. homebattery for the generic model, sonnenbattery for the sonnen specific one +export DIGITAL_TWIN_MODEL_ID=`oci iot digital-twin-model list --iot-domain-id $IOT_DOMAIN_OCID --display-name $DIGITAL_TWIN_MODEL_NAME | jq -r '.data.items[]| select (."lifecycle-state" == "ACTIVE") | ."id"'` + +# these are only relevant if you have setup a digital twin adaptor +# DIGITAL_TWIN_MODEL_FILE_NAME should be the name of the file containing the model for example HomeBatteryDTMI.json for the generic home battery, SonnenSpecificDTMI.json for the sonnen specific version +export DIGITAL_TWIN_MODEL_IDENTIFIER=`cat $DIGITAL_TWIN_MODEL_FILE_NAME | jq -r '.["@id"]'` +export DIGITAL_TWIN_ADAPTER_OCID=`oci iot digital-twin-adapter list --iot-domain-id $IOT_DOMAIN_OCID --display-name $DIGITAL_TWIN_ADAPTER_NAME | jq -r '.data.items[]| select (."lifecycle-state" == "ACTIVE") | ."id"'` + +# the digital twin instance itself +# this can work if there is not a model or adaptor configured +# get the OCID of the digital twin +export DIGITAL_TWIN_INSTANCE_OCID=`oci iot digital-twin-instance list --iot-domain-id $IOT_DOMAIN_OCID --display-name $DEVICE_ID | jq -r '.data.items[]| select (."lifecycle-state" == "ACTIVE") | ."id"'` +# and the external key +export DEVICE_EXTERNAL_KEY=`oci iot digital-twin-instance get --digital-twin-instance-id $DIGITAL_TWIN_INSTANCE_OCID | jq -r '.data."external-key"'` +echo Device external key $DEVICE_EXTERNAL_KEY +# needed to setup the client code +export DEVICE_SECRET_BASE64=`oci secrets secret-bundle get --secret-id $DEVICE_VAULT_SECRET_OCID --stage CURRENT | jq -r '.data."secret-bundle-content".content'` +export DEVICE_SECRET=`echo $DEVICE_SECRET_BASE64 | base64 --decode` + +# this is for APEX, only relevant if APEX has been setup +#Get the apex URL +echo APEX_URL "https://$IOT_DOMAIN_GROUP_DATA_HOST/ords/apex/" +#get the user id and workspace +echo APEX_Workspace "$IOT_DOMAIN_SHORT_ID"__WKSP +echo APEX_User "$IOT_DOMAIN_SHORT_ID"__WKSP +echo APEX_Schema "$IOT_DOMAIN_SHORT_ID"__IOT diff --git a/IoTSonnenUploader/DigitalTwin/SonnenSpecificDTMI.json b/IoTSonnenUploader/DigitalTwin/SonnenSpecificDTMI.json index 25fd5df..c1ed649 100644 --- a/IoTSonnenUploader/DigitalTwin/SonnenSpecificDTMI.json +++ b/IoTSonnenUploader/DigitalTwin/SonnenSpecificDTMI.json @@ -123,6 +123,17 @@ "schema": "integer", "unit": "watt" }, + { + "@type": [ + "Telemetry", + "Historized", + "EnergyRate" + ], + "displayName": "Inverter power intake", + "name": "inverterPowerWattsPointInTime", + "schema": "integer", + "unit": "watt" + }, { "@type": [ "Telemetry" diff --git a/IoTSonnenUploader/DigitalTwin/sonnen-to-generic-mapping-envelope.json b/IoTSonnenUploader/DigitalTwin/sonnen-to-generic-mapping-envelope.json index ad378ab..4e54bd6 100644 --- a/IoTSonnenUploader/DigitalTwin/sonnen-to-generic-mapping-envelope.json +++ b/IoTSonnenUploader/DigitalTwin/sonnen-to-generic-mapping-envelope.json @@ -13,6 +13,7 @@ "reservedBatteryCapacityPercentage": 0, "solarProductionWattsPointInTime": 0, "time": 123456, + "inverterPowerWattsPointInTime": 42, "timestamp": "2025-11-18T16:23:52.081763412Z" }, "data-format": "JSON" diff --git a/IoTSonnenUploader/DigitalTwin/sonnen-to-generic-mapping-multiple-routes.json b/IoTSonnenUploader/DigitalTwin/sonnen-to-generic-mapping-multiple-routes.json index 2bef958..25b3597 100644 --- a/IoTSonnenUploader/DigitalTwin/sonnen-to-generic-mapping-multiple-routes.json +++ b/IoTSonnenUploader/DigitalTwin/sonnen-to-generic-mapping-multiple-routes.json @@ -17,7 +17,8 @@ "time": 1763981430279, "timestamp": "2025-11-24T10:50:30.279369Z[Europe/London]", "batteryCharging": false, - "batteryDischarging": true + "batteryDischarging": true, + "inverterPowerWattsPointInTime": 42 } }, "payload-mapping": { @@ -31,7 +32,8 @@ "$.CapacityRemaining": "$.remainingBatteryCapacityWattHours", "$.ReservedChargePercentage": "$.reservedBatteryCapacityPercentage", "$.SolarGeneration": "$.solarProductionWattsPointInTime", - "$.StatusTimestamp": "$.timestamp" + "$.StatusTimestamp": "$.timestamp", + "$.InverterPowerWattsPointInTime": "$.inverterPowerWattsPointInTime" } }, { diff --git a/IoTSonnenUploader/DigitalTwin/sonnen-to-generic-mapping-single-route.json b/IoTSonnenUploader/DigitalTwin/sonnen-to-generic-mapping-single-route.json index f1ff67a..ed1616a 100644 --- a/IoTSonnenUploader/DigitalTwin/sonnen-to-generic-mapping-single-route.json +++ b/IoTSonnenUploader/DigitalTwin/sonnen-to-generic-mapping-single-route.json @@ -13,6 +13,7 @@ "$.CapacityRemaining": "$.remainingBatteryCapacityWattHours", "$.ReservedChargePercentage": "$.reservedBatteryCapacityPercentage", "$.SolarGeneration": "$.solarProductionWattsPointInTime", + "$.InverterPowerWattsPointInTime": "$.inverterPowerWattsPointInTime", "$.StatusTimestamp": "$.timestamp" }, "reference-payload": { @@ -30,7 +31,8 @@ "time": 1763981430279, "timestamp": "2025-11-24T10:50:30.279369Z[Europe/London]", "batteryCharging": false, - "batteryDischarging": true + "batteryDischarging": true, + "inverterPowerWattsPointInTime": 42 } } } diff --git a/IoTSonnenUploader/pom.xml b/IoTSonnenUploader/pom.xml index 34dcea0..12d0ba5 100644 --- a/IoTSonnenUploader/pom.xml +++ b/IoTSonnenUploader/pom.xml @@ -53,7 +53,7 @@ SOFTWARE. --> 21 4.10.1 false - com.oracle.demo.timg.iot.aot.generated + com.oracle.demo.timg.iot.iotsonnenuploader.aot.generated true netty com.oracle.demo.timg.iot.iotsonnenuploader.Application diff --git a/IoTSonnenUploader/src/main/java/com/oracle/demo/timg/iot/iotsonnenuploader/incommingdata/SonnenStatus.java b/IoTSonnenUploader/src/main/java/com/oracle/demo/timg/iot/iotsonnenuploader/incommingdata/SonnenStatus.java index dcff53d..581465b 100644 --- a/IoTSonnenUploader/src/main/java/com/oracle/demo/timg/iot/iotsonnenuploader/incommingdata/SonnenStatus.java +++ b/IoTSonnenUploader/src/main/java/com/oracle/demo/timg/iot/iotsonnenuploader/incommingdata/SonnenStatus.java @@ -141,4 +141,11 @@ public void setProductionWattsPointInTimeFromSonnen(int solarProductionWatts) { private int solarProductionWattsPointInTime; + @JsonProperty("Pac_total_W") + public void setInverterPowerWattsPointInTimeFromSonnen(int inverterPowerWattsPointInTime) { + this.inverterPowerWattsPointInTime = inverterPowerWattsPointInTime; + } + + private int inverterPowerWattsPointInTime; + } diff --git a/IoTSonnenUploader/src/main/java/com/oracle/demo/timg/iot/iotsonnenuploader/uploadermqtt/ConfigurationUploaderMqtt.java b/IoTSonnenUploader/src/main/java/com/oracle/demo/timg/iot/iotsonnenuploader/uploadermqtt/ConfigurationUploaderMqtt.java index 0b88ab3..291c79e 100644 --- a/IoTSonnenUploader/src/main/java/com/oracle/demo/timg/iot/iotsonnenuploader/uploadermqtt/ConfigurationUploaderMqtt.java +++ b/IoTSonnenUploader/src/main/java/com/oracle/demo/timg/iot/iotsonnenuploader/uploadermqtt/ConfigurationUploaderMqtt.java @@ -74,8 +74,12 @@ public SonnenConfiguration processConfiguration() { return null; } log.info("Retrieved configuration from battery : " + conf); - CompletableFuture publishResp = mqttSonnenBatteryPublisher.publishSonnenConfiguration(conf); - publishResp.thenRun(() -> log.info("Published configuration to mqtt")); + try { + CompletableFuture publishResp = mqttSonnenBatteryPublisher.publishSonnenConfiguration(conf); + publishResp.thenRun(() -> log.info("Published configuration to mqtt")); + } catch (Exception e) { + log.warning("Problem publishing configuration to mqtt, " + e.getLocalizedMessage()); + } return conf; } diff --git a/IoTSonnenUploader/src/main/java/com/oracle/demo/timg/iot/iotsonnenuploader/uploadermqtt/StatusUploaderMqtt.java b/IoTSonnenUploader/src/main/java/com/oracle/demo/timg/iot/iotsonnenuploader/uploadermqtt/StatusUploaderMqtt.java index a26bca1..f8edbb4 100644 --- a/IoTSonnenUploader/src/main/java/com/oracle/demo/timg/iot/iotsonnenuploader/uploadermqtt/StatusUploaderMqtt.java +++ b/IoTSonnenUploader/src/main/java/com/oracle/demo/timg/iot/iotsonnenuploader/uploadermqtt/StatusUploaderMqtt.java @@ -74,8 +74,12 @@ public SonnenStatus processStatus() { return null; } log.info("Retrieved status from battery : " + status); - CompletableFuture publishResp = mqttSonnenBatteryPublisher.publishSonnenStatus(status); - publishResp.thenRun(() -> log.info("Published status to mqtt")); + try { + CompletableFuture publishResp = mqttSonnenBatteryPublisher.publishSonnenStatus(status); + publishResp.thenRun(() -> log.info("Published status to mqtt")); + } catch (Exception e) { + log.warning("Problem publishing status to mqtt, " + e.getLocalizedMessage()); + } return status; }