diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 881a99088c..02cd651bc4 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -1,9 +1,6 @@ name: Build and Test on: - push: - branches: - - dev pull_request: branches: - dev diff --git a/.github/workflows/detekt-analysis.yml b/.github/workflows/detekt-analysis.yml deleted file mode 100644 index aabd2a2369..0000000000 --- a/.github/workflows/detekt-analysis.yml +++ /dev/null @@ -1,103 +0,0 @@ -# This workflow performs a static analysis of your Kotlin source code using -# Detekt. -# -# Scans are triggered: -# 1. On every push to default and protected branches -# 2. On every Pull Request targeting the default branch -# 3. On a weekly schedule -# 4. Manually, on demand, via the "workflow_dispatch" event -# -# The workflow should work with no modifications, but you might like to use a -# later version of the Detekt CLI by modifing the $DETEKT_RELEASE_TAG -# environment variable. -name: Scan with Detekt - -on: - # Triggers the workflow on push or pull request events but only for default and protected branches - push: - branches: [ dev, beta, stable ] - pull_request: - branches: [ dev ] - schedule: - - cron: '19 11 * * 4' - - # Allows you to run this workflow manually from the Actions tab - workflow_dispatch: - -env: - # Release tag associated with version of Detekt to be installed - # SARIF support (required for this workflow) was introduced in Detekt v1.15.0 - DETEKT_RELEASE_TAG: v1.15.0 - -# A workflow run is made up of one or more jobs that can run sequentially or in parallel -jobs: - # This workflow contains a single job called "scan" - scan: - name: Scan - # The type of runner that the job will run on - runs-on: ubuntu-latest - - # Steps represent a sequence of tasks that will be executed as part of the job - steps: - # Checks-out your repository under $GITHUB_WORKSPACE, so your job can access it - - uses: actions/checkout@v2 - - # Gets the download URL associated with the $DETEKT_RELEASE_TAG - - name: Get Detekt download URL - id: detekt_info - env: - GH_TOKEN: ${{ secrets.GITHUB_TOKEN }} - run: | - DETEKT_DOWNLOAD_URL=$( gh api graphql --field tagName=$DETEKT_RELEASE_TAG --raw-field query=' - query getReleaseAssetDownloadUrl($tagName: String!) { - repository(name: "detekt", owner: "detekt") { - release(tagName: $tagName) { - releaseAssets(name: "detekt", first: 1) { - nodes { - downloadUrl - } - } - } - } - } - ' | \ - jq --raw-output '.data.repository.release.releaseAssets.nodes[0].downloadUrl' ) - echo "::set-output name=download_url::$DETEKT_DOWNLOAD_URL" - - # Sets up the detekt cli - - name: Setup Detekt - run: | - dest=$( mktemp -d ) - curl --request GET \ - --url ${{ steps.detekt_info.outputs.download_url }} \ - --silent \ - --location \ - --output $dest/detekt - chmod a+x $dest/detekt - echo $dest >> $GITHUB_PATH - - # Performs static analysis using Detekt - - name: Run Detekt - continue-on-error: true - run: | - detekt --input ${{ github.workspace }} --report sarif:${{ github.workspace }}/detekt.sarif.json - - # Modifies the SARIF output produced by Detekt so that absolute URIs are relative - # This is so we can easily map results onto their source files - # This can be removed once relative URI support lands in Detekt: https://git.io/JLBbA - - name: Make artifact location URIs relative - continue-on-error: true - run: | - echo "$( - jq \ - --arg github_workspace ${{ github.workspace }} \ - '. | ( .runs[].results[].locations[].physicalLocation.artifactLocation.uri |= if test($github_workspace) then .[($github_workspace | length | . + 1):] else . end )' \ - ${{ github.workspace }}/detekt.sarif.json - )" > ${{ github.workspace }}/detekt.sarif.json - - # Uploads results to GitHub repository using the upload-sarif action - - uses: github/codeql-action/upload-sarif@v1 - with: - # Path to SARIF file relative to the root of the repository - sarif_file: ${{ github.workspace }}/detekt.sarif.json - checkout_path: ${{ github.workspace }} diff --git a/module/app/cloudconnector/src/main/java/org/openbase/bco/app/cloudconnector/CloudConnectorApp.java b/module/app/cloudconnector/src/main/java/org/openbase/bco/app/cloudconnector/CloudConnectorApp.java index 77f7bdd97b..7ae502369c 100644 --- a/module/app/cloudconnector/src/main/java/org/openbase/bco/app/cloudconnector/CloudConnectorApp.java +++ b/module/app/cloudconnector/src/main/java/org/openbase/bco/app/cloudconnector/CloudConnectorApp.java @@ -10,12 +10,12 @@ * it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public * License along with this program. If not, see * . @@ -34,7 +34,6 @@ import org.openbase.jul.communication.iface.RPCServer; import org.openbase.jul.exception.CouldNotPerformException; import org.openbase.jul.exception.InitializationException; -import org.openbase.jul.exception.InstantiationException; import org.openbase.jul.exception.NotAvailableException; import org.openbase.jul.extension.type.processing.MetaConfigPool; import org.openbase.jul.extension.type.processing.MetaConfigVariableProvider; @@ -65,14 +64,12 @@ public class CloudConnectorApp extends AbstractAppController implements CloudCon private static final Logger LOGGER = LoggerFactory.getLogger(CloudConnectorApp.class); private final CloudConnectorTokenStore tokenStore; - private final JsonParser jsonParser; private final Map userIdSocketMap; - public CloudConnectorApp() throws InstantiationException { + public CloudConnectorApp() { super(); this.userIdSocketMap = new HashMap<>(); this.tokenStore = new CloudConnectorTokenStore(); - this.jsonParser = new JsonParser(); } @Override @@ -235,7 +232,8 @@ public Future connect(final AuthenticatedValue authenticated socketWrapper.activate(); socketWrapper.getLoginFuture().get(10, TimeUnit.SECONDS); } - } catch (CouldNotPerformException | ExecutionException | InterruptedException | TimeoutException ex) { + } catch (CouldNotPerformException | ExecutionException | InterruptedException | + TimeoutException ex) { if (ex instanceof InterruptedException) { Thread.currentThread().interrupt(); } @@ -278,7 +276,7 @@ public Future register(AuthenticatedValue authenticatedValue try { // parse string as json - final JsonObject params = jsonParser.parse(jsonString).getAsJsonObject(); + final JsonObject params = JsonParser.parseString(jsonString).getAsJsonObject(); // validate that password hash is available if (!params.has(PASSWORD_HASH_KEY)) { diff --git a/module/app/influxdbconnector/src/main/java/org/openbase/bco/app/influxdbconnector/InfluxDbconnectorApp.java b/module/app/influxdbconnector/src/main/java/org/openbase/bco/app/influxdbconnector/InfluxDbconnectorApp.java deleted file mode 100644 index 343703718c..0000000000 --- a/module/app/influxdbconnector/src/main/java/org/openbase/bco/app/influxdbconnector/InfluxDbconnectorApp.java +++ /dev/null @@ -1,516 +0,0 @@ -package org.openbase.bco.app.influxdbconnector; - -/*- - * #%L - * BCO InfluxDB Connector - * %% - * Copyright (C) 2018 - 2021 openbase.org - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program. If not, see - * . - * #L% - */ - - -import com.google.protobuf.Descriptors; -import com.google.protobuf.Message; -import com.influxdb.client.InfluxDBClient; -import com.influxdb.client.InfluxDBClientFactory; -import com.influxdb.client.WriteApi; -import com.influxdb.client.WriteOptions; -import com.influxdb.client.domain.Bucket; -import com.influxdb.client.domain.WritePrecision; -import com.influxdb.client.write.Point; -import com.influxdb.client.write.events.WriteErrorEvent; -import com.influxdb.client.write.events.WriteSuccessEvent; -import org.openbase.bco.dal.control.layer.unit.app.AbstractAppController; -import org.openbase.bco.dal.lib.layer.service.ServiceStateProvider; -import org.openbase.bco.dal.lib.layer.service.Services; -import org.openbase.bco.dal.lib.layer.unit.Unit; -import org.openbase.bco.dal.lib.layer.unit.UnitRemote; -import org.openbase.bco.dal.remote.layer.unit.CustomUnitPool; -import org.openbase.bco.dal.remote.layer.unit.Units; -import org.openbase.bco.registry.remote.Registries; -import org.openbase.jul.exception.InstantiationException; -import org.openbase.jul.exception.*; -import org.openbase.jul.exception.printer.ExceptionPrinter; -import org.openbase.jul.exception.printer.LogLevel; -import org.openbase.jul.extension.type.processing.LabelProcessor; -import org.openbase.jul.extension.type.processing.TimestampProcessor; -import org.openbase.jul.pattern.Observer; -import org.openbase.jul.schedule.CloseableWriteLockWrapper; -import org.openbase.jul.schedule.GlobalCachedExecutorService; -import org.openbase.jul.schedule.GlobalScheduledExecutorService; -import org.openbase.type.domotic.action.ActionDescriptionType.ActionDescription; -import org.openbase.type.domotic.service.ServiceDescriptionType; -import org.openbase.type.domotic.service.ServiceTemplateType; -import org.openbase.type.domotic.service.ServiceTempusTypeType; -import org.openbase.type.domotic.service.ServiceTempusTypeType.ServiceTempusType.ServiceTempus; -import org.openbase.type.domotic.state.ActivationStateType.ActivationState; -import org.openbase.type.domotic.unit.UnitConfigType; -import org.openbase.type.domotic.unit.UnitConfigType.UnitConfig; -import org.openbase.type.language.LabelType; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.concurrent.TimeoutException; -import java.util.concurrent.*; - -import static org.openbase.bco.dal.control.layer.unit.InfluxDbProcessor.*; -import static org.openbase.bco.dal.lib.layer.service.Services.resolveStateValue; - -public class InfluxDbconnectorApp extends AbstractAppController { - - private Logger logger = LoggerFactory.getLogger(getClass()); - - private WriteApi writeApi; - private Integer databaseTimeout = DATABASE_TIMEOUT_DEFAULT; - private Bucket bucket; - private char[] token; - private Future task; - private Future heartbeat; - private String databaseUrl; - private String bucketName; - private InfluxDBClient influxDBClient; - private Integer batchTime; - private Integer batchLimit; - private final CustomUnitPool customUnitPool; - private final Observer, Message> unitStateObserver; - private String org; - - - public InfluxDbconnectorApp() throws InstantiationException { - this.customUnitPool = new CustomUnitPool(); - this.unitStateObserver = (source, data) -> storeServiceState((Unit) source.getServiceProvider(), source.getServiceType(), false); - } - - @Override - public UnitConfig applyConfigUpdate(UnitConfig config) throws CouldNotPerformException, InterruptedException { - try (final CloseableWriteLockWrapper ignored = getManageWriteLockInterruptible(this)) { - config = super.applyConfigUpdate(config); - - bucketName = generateVariablePool().getValue(INFLUXDB_BUCKET, INFLUXDB_BUCKET_DEFAULT); - batchTime = Integer.valueOf(generateVariablePool().getValue(INFLUXDB_BATCH_TIME, INFLUXDB_BATCH_TIME_DEFAULT)); - batchLimit = Integer.valueOf(generateVariablePool().getValue(INFLUXDB_BATCH_LIMIT, INFLUXDB_BATCH_LIMIT_DEFAULT)); - databaseUrl = generateVariablePool().getValue(INFLUXDB_URL, INFLUXDB_URL_DEFAULT); - token = generateVariablePool().getValue(INFLUXDB_TOKEN).toCharArray(); - org = generateVariablePool().getValue(INFLUXDB_ORG, INFLUXDB_ORG_DEFAULT); - - return config; - } - } - - @Override - protected ActionDescription execute(ActivationState activationState) { - - task = GlobalCachedExecutorService.submit(() -> { - - try { - logger.debug("Execute influx db connector"); - - // connect to db - connectToDatabase(); - while (!task.isCancelled()) { - try { - verifyConnection(); - break; - - } catch (CouldNotPerformException ex) { - ExceptionPrinter.printHistory("Could not reach influxdb server at " + databaseUrl + ". Try again in " + databaseTimeout / 1000 + " seconds!", ex, logger, LogLevel.WARN); - Thread.sleep(databaseTimeout); - if (databaseTimeout < MAX_TIMEOUT) databaseTimeout += ADDITIONAL_TIMEOUT; - } - } - - // lookup bucked - while (!task.isCancelled()) { - try { - // check if bucked found - getDatabaseBucket(); - break; - - } catch (NotAvailableException ex) { - logger.warn("Could not get bucket. Try again in " + databaseTimeout / 1000 + " seconds!"); - - ExceptionPrinter.printHistory(ex, logger); - Thread.sleep(databaseTimeout); - } - } - - // start observation - try { - startObservation(); - } catch (InitializationException ex) { - ExceptionPrinter.printHistory(ex, logger); - } - } catch (InterruptedException ex) { - // finish task because its canceled. - } - - if (!task.isCancelled() && isConnected()) { - try { - // write initial heartbeat - logger.debug("initial heartbeat"); - writeApi.writePoint(bucketName, org, Point.measurement(HEARTBEAT_MEASUREMENT) - .addField(HEARTBEAT_FIELD, HEARTBEAT_OFFLINE_VALUE) - .time(System.currentTimeMillis() - 1, WritePrecision.MS)); - writeApi.writePoint(bucketName, org, Point.measurement(HEARTBEAT_MEASUREMENT) - .addField(HEARTBEAT_FIELD, HEARTBEAT_ONLINE_VALUE) - .time(System.currentTimeMillis(), WritePrecision.MS)); - - heartbeat = GlobalScheduledExecutorService.scheduleAtFixedRate(() -> { - logger.debug("write heartbeat"); - writeApi.writePoint(bucketName, org, Point.measurement(HEARTBEAT_MEASUREMENT) - .addField(HEARTBEAT_FIELD, HEARTBEAT_ONLINE_VALUE) - .time(System.currentTimeMillis(), WritePrecision.MS)); - - }, HEARTBEAT_INITIAL_DELAY, HEARTBEAT_PERIOD, TimeUnit.MILLISECONDS); - } catch (NotAvailableException ex) { - ExceptionPrinter.printHistory("Could not write heartbeat!", ex, logger, LogLevel.WARN); - } - } - return null; - }); - return activationState.getResponsibleAction(); - } - - @Override - protected void stop(ActivationState activationState) throws CouldNotPerformException, InterruptedException { - - // finish task - logger.debug("finish task"); - if (task != null && !task.isDone()) { - task.cancel(true); - try { - task.get(5, TimeUnit.SECONDS); - } catch (CancellationException ex) { - // that's what we are waiting for. - } catch (Exception ex) { - ExceptionPrinter.printHistory(ex, logger); - } - } - - logger.debug("finish heartbeat"); - if (heartbeat != null && !heartbeat.isDone()) { - heartbeat.cancel(true); - try { - task.get(5, TimeUnit.SECONDS); - } catch (CancellationException ex) { - // that's what we are waiting for. - } catch (Exception ex) { - ExceptionPrinter.printHistory(ex, logger); - } - } - - if (isConnected()) { - // write final heartbeat if connection is established. - writeApi.writePoint(bucketName, org, Point.measurement(HEARTBEAT_MEASUREMENT) - .addField(HEARTBEAT_FIELD, HEARTBEAT_ONLINE_VALUE) - .time(System.currentTimeMillis() - 1, WritePrecision.MS)); - writeApi.writePoint(bucketName, org, Point.measurement(HEARTBEAT_MEASUREMENT) - .addField(HEARTBEAT_FIELD, HEARTBEAT_OFFLINE_VALUE) - .time(System.currentTimeMillis(), WritePrecision.MS)); - writeApi.flush(); - } - - // deregister - customUnitPool.removeServiceStateObserver(unitStateObserver); - customUnitPool.deactivate(); - disconnectDatabase(); - - super.stop(activationState); - } - - public void startObservation() throws InitializationException, InterruptedException { - try { - // setup pool - customUnitPool.addServiceStateObserver(unitStateObserver); - customUnitPool.activate(); - - for (UnitConfigType.UnitConfig unitConfig : Registries.getUnitRegistry(true).getUnitConfigs()) { - final UnitRemote unit; - try { - unit = Units.getFutureUnit(unitConfig, true).get(MAX_INITIAL_STORAGE_TIMEOUT, TimeUnit.MILLISECONDS); - } catch (ExecutionException | TimeoutException ex) { - ExceptionPrinter.printHistory("Could not reach Unit " + LabelProcessor.getBestMatch(unitConfig.getLabel()) + "! Skip initial service state synchronisation because unit will be synchronized anyway when it connection is established.", ex, logger, LogLevel.DEBUG); - continue; - } - try { - for (ServiceDescriptionType.ServiceDescription serviceDescription : unit.getUnitTemplate().getServiceDescriptionList()) { - - if (serviceDescription.getPattern() != ServiceTemplateType.ServiceTemplate.ServicePattern.PROVIDER) { - continue; - } - storeServiceState(unit, serviceDescription.getServiceType(), true); - } - } catch (CouldNotPerformException ex) { - ExceptionPrinter.printHistory("Could not store service state " + unit, ex, logger); - } - } - } catch (CouldNotPerformException ex) { - throw new InitializationException(this, ex); - } - } - - private void storeServiceState(Unit unit, ServiceTemplateType.ServiceTemplate.ServiceType serviceType, boolean initialSync) throws CouldNotPerformException { - - final Message currentServiceState; - Message lastServiceState = null; - try { - currentServiceState = Services.invokeProviderServiceMethod(serviceType, ServiceTempus.CURRENT, unit.getData()); - } catch (NotAvailableException ex) { - // if the current state is not available, we just try to at least store the last known service state if available. - - try { - lastServiceState = Services.invokeProviderServiceMethod(serviceType, ServiceTempusTypeType.ServiceTempusType.ServiceTempus.LAST, unit.getData()); - storeServiceState(unit, serviceType, lastServiceState); - } catch (CouldNotPerformException exx) { - // we don't care if the last service state is not available - // which can be the case for an initial sync - // or any states which got only one state update since system startup. - } - return; - } - - // store t - 1 entry - try { - lastServiceState = Services.invokeProviderServiceMethod(serviceType, ServiceTempusTypeType.ServiceTempusType.ServiceTempus.LAST, unit.getData()); - final long serviceStateTimestamp = TimestampProcessor.getTimestamp(currentServiceState, TimeUnit.MILLISECONDS) - 1l; - lastServiceState = TimestampProcessor.updateTimestamp(serviceStateTimestamp, lastServiceState, TimeUnit.MILLISECONDS); - storeServiceState(unit, serviceType, lastServiceState); - } catch (CouldNotPerformException ex) { - // we don't care if the last service state is not available - // which can be the case for an initial sync - // or any states which got only one state update since system startup. - } - - try { - storeServiceState(unit, serviceType, currentServiceState); - } catch (CouldNotPerformException ex) { - - // filter log if initial timestamps are missing - if (initialSync) { - return; - } - - ExceptionPrinter.printHistory("Could not store service state change into db! " + - "UnitType[" + unit.getUnitType() + "] " + - "ServiceType[" + serviceType + "] " + - "CurrentServiceState[" + currentServiceState + "] " + - "LastServiceState[" + lastServiceState + "]" - , ex, logger, LogLevel.DEBUG); - } - } - - private void storeServiceState(final Unit unit, final ServiceTemplateType.ServiceTemplate.ServiceType serviceType, final Message serviceState) throws InvalidStateException { - - final long timestamp = TimestampProcessor.getTimestamp(serviceState, TimeUnit.MILLISECONDS); - try { - String initiator; - try { - initiator = Services.getResponsibleAction(serviceState).getActionInitiator().getInitiatorType().name().toLowerCase(); - } catch (NotAvailableException ex) { - // in this case we use the system as initiator because responsible actions are not available for pure provider services and those are always system generated. - initiator = "system"; - } - Map stateValuesMap = resolveStateValueToMap(serviceState); - Point point = Point.measurement(serviceType.name().toLowerCase()) - .addTag("alias", unit.getConfig().getAlias(0)) - .addTag("initiator", initiator) - .addTag("unit_id", unit.getId()) - .addTag("unit_type", unit.getUnitType().name().toLowerCase()) - .addTag("location_id", unit.getParentLocationConfig().getId()) - .addTag("location_alias", unit.getParentLocationConfig().getAlias(0)) - .time(timestamp, WritePrecision.MS); - - Integer values = 0; - for (Map.Entry entry : stateValuesMap.entrySet()) { - // detect numbers with regex - if (entry.getValue().matches("-?\\d+(\\.\\d+)?")) { - values++; - point.addField(entry.getKey(), Double.valueOf(entry.getValue())); - - } else { - point.addTag(entry.getKey(), entry.getValue()); - } - } - - List entryList = unit.getConfig().getLabel().getEntryList(); - for (LabelType.Label.MapFieldEntry entry : entryList) { - // skip entries that offer a language key but do not provide any label. - if(entry.getValueList().isEmpty()) { - continue; - } - point.addTag("label_" + entry.getKey(), entry.getValue(0)); - } - - if (values > 0) { - writeApi.writePoint(bucketName, org, point); - } - } catch (CouldNotPerformException ex) { - ExceptionPrinter.printHistory("Could not store service state " + serviceType.name() + " of " + unit, ex, logger); - } - } - - - public Map resolveStateValueToMap(Message serviceState) throws CouldNotPerformException { - final Map stateValues = new HashMap<>(); - for (Descriptors.FieldDescriptor fieldDescriptor : serviceState.getDescriptorForType().getFields()) { - String stateName = fieldDescriptor.getName(); - String stateType = fieldDescriptor.getType().toString().toLowerCase(); - - // filter invalid states - if (stateName == null || stateType == null) { - logger.warn("Could not detect datatype of " + stateName); - } - - // filter general service fields - switch (stateName) { - case "aggregated_value_coverage": - case "last_value_occurrence": - case "timestamp": - case "responsible_action": - case "type": - case "rgb_color": - case "frame_id": - continue; - } - - // filter data units - if (stateName.endsWith("data_unit")) { - continue; - } - - String stateValue = serviceState.getField(fieldDescriptor).toString(); - - try { - if (fieldDescriptor.getType() == Descriptors.FieldDescriptor.Type.MESSAGE) { - if (fieldDescriptor.isRepeated()) { - List types = new ArrayList<>(); - - for (int i = 0; i < serviceState.getRepeatedFieldCount(fieldDescriptor); i++) { - final Object repeatedFieldEntry = serviceState.getRepeatedField(fieldDescriptor, i); - if (repeatedFieldEntry instanceof Message) { - types.add("[" + resolveStateValue((Message) repeatedFieldEntry).toString() + "]"); - } - types.add(repeatedFieldEntry.toString()); - } - stateType = types.toString().toLowerCase(); - } else { - stateValue = resolveStateValue((Message) serviceState.getField(fieldDescriptor)).toString(); - } - } - } catch (InvalidStateException ex) { - logger.warn("Could not process value of " + fieldDescriptor.getName()); - continue; - } - - // filter values - switch (stateValue) { - case "": - case "NaN": - continue; - default: - break; - } - if (fieldDescriptor.getJavaType() == Descriptors.FieldDescriptor.JavaType.ENUM) { - String finalStateValue = stateValue; - stateValue = String.valueOf(fieldDescriptor.getEnumType().getValues().stream().filter(val -> val.getName().equals(finalStateValue)).findFirst().get().getNumber()); - } - - stateValues.put(fieldDescriptor.getName(), stateValue.toLowerCase()); - } - return stateValues; - } - - /** - * Method checks if the connection is established. - * - * @return true if the connection to influx db is established, otherwise false. - */ - private boolean isConnected() { - try { - verifyConnection(); - } catch (VerificationFailedException ex) { - return false; - } - return true; - } - - /** - * Method verifies the connection state. - * - * @throws VerificationFailedException is thrown if the connection is not established. - */ - private void verifyConnection() throws VerificationFailedException { - - if (influxDBClient == null) { - throw new VerificationFailedException("Influx db connection has never been initiated."); - } - - if (influxDBClient.health().getStatus().getValue() != "pass") { - throw new VerificationFailedException("Could not connect to database server at " + databaseUrl + "!"); - } - - // initiate WriteApi - WriteOptions writeoptions = WriteOptions.builder().batchSize(batchLimit).flushInterval(batchTime).build(); - writeApi = influxDBClient.getWriteApi(writeoptions); - writeApi.listenEvents(WriteSuccessEvent.class, event -> { - logger.debug("Successfully wrote data into db"); - }); - writeApi.listenEvents(WriteErrorEvent.class, event -> { - Throwable exception = event.getThrowable(); - logger.warn(exception.getMessage()); - }); - logger.debug("Connected to Influxdb at " + databaseUrl); - } - - private void connectToDatabase() { - try { - if (influxDBClient != null) { - influxDBClient.close(); - } - } catch (Exception ex) { - ExceptionPrinter.printHistory("Could not shutdown database connection!", ex, logger); - } - logger.debug(" Try to connect to influxDB at " + databaseUrl); - influxDBClient = InfluxDBClientFactory.create(databaseUrl + "?readTimeout=" + READ_TIMEOUT + "&connectTimeout=" + CONNECT_TIMOUT + "&writeTimeout=" + WRITE_TIMEOUT + "&logLevel=BASIC", token); - } - - private void disconnectDatabase() { - try { - if (influxDBClient != null) { - if (writeApi != null) { - writeApi.flush(); - } - influxDBClient.close(); - writeApi = null; - } - } catch (Exception ex) { - ExceptionPrinter.printHistory("Could not shutdown database connection!", ex, logger); - } - } - - private void getDatabaseBucket() throws NotAvailableException { - logger.debug("Get bucket " + bucketName); - bucket = influxDBClient.getBucketsApi().findBucketByName(bucketName); - if (bucket == null) { - throw new NotAvailableException("bucket", bucketName); - } - } -} diff --git a/module/app/influxdbconnector/src/main/java/org/openbase/bco/app/influxdbconnector/InfluxDbconnectorApp.kt b/module/app/influxdbconnector/src/main/java/org/openbase/bco/app/influxdbconnector/InfluxDbconnectorApp.kt new file mode 100644 index 0000000000..c4e1923a1a --- /dev/null +++ b/module/app/influxdbconnector/src/main/java/org/openbase/bco/app/influxdbconnector/InfluxDbconnectorApp.kt @@ -0,0 +1,560 @@ +package org.openbase.bco.app.influxdbconnector + +import com.google.protobuf.Descriptors +import com.google.protobuf.Message +import com.influxdb.client.InfluxDBClient +import com.influxdb.client.InfluxDBClientFactory +import com.influxdb.client.WriteApi +import com.influxdb.client.WriteOptions +import com.influxdb.client.domain.Bucket +import com.influxdb.client.domain.WritePrecision +import com.influxdb.client.write.Point +import com.influxdb.client.write.events.WriteErrorEvent +import com.influxdb.client.write.events.WriteSuccessEvent +import org.openbase.bco.dal.control.layer.unit.InfluxDbProcessor +import org.openbase.bco.dal.control.layer.unit.app.AbstractAppController +import org.openbase.bco.dal.lib.layer.service.ServiceStateProvider +import org.openbase.bco.dal.lib.layer.service.Services +import org.openbase.bco.dal.lib.layer.unit.UnitRemote +import org.openbase.bco.dal.remote.layer.unit.CustomUnitPool +import org.openbase.bco.dal.remote.layer.unit.Units +import org.openbase.bco.registry.remote.Registries +import org.openbase.jul.exception.* +import org.openbase.jul.exception.printer.ExceptionPrinter +import org.openbase.jul.exception.printer.LogLevel +import org.openbase.jul.extension.type.processing.LabelProcessor.getBestMatch +import org.openbase.jul.extension.type.processing.TimestampProcessor +import org.openbase.jul.pattern.Observer +import org.openbase.jul.schedule.GlobalCachedExecutorService +import org.openbase.jul.schedule.GlobalScheduledExecutorService +import org.openbase.type.domotic.action.ActionDescriptionType +import org.openbase.type.domotic.service.ServiceTemplateType +import org.openbase.type.domotic.service.ServiceTemplateType.ServiceTemplate.ServicePattern +import org.openbase.type.domotic.service.ServiceTempusTypeType.ServiceTempusType.ServiceTempus +import org.openbase.type.domotic.state.ActivationStateType +import org.openbase.type.domotic.unit.UnitConfigType +import java.util.* +import java.util.concurrent.* +import java.util.concurrent.TimeoutException + + +class InfluxDbconnectorApp : AbstractAppController() { + private var writeApi: WriteApi? = null + private var databaseTimeout: Int = InfluxDbProcessor.DATABASE_TIMEOUT_DEFAULT + private var bucket: Bucket? = null + private var token: CharArray? = null + private var task: Future<*>? = null + private var heartbeat: Future<*>? = null + private var databaseUrl: String? = null + private var bucketName: String? = null + private var influxDBClient: InfluxDBClient? = null + private var batchTime: Int? = null + private var batchLimit: Int? = null + private val customUnitPool: CustomUnitPool<*, *> = CustomUnitPool>() + private val unitStateObserver: Observer, Message> + private var org: String? = null + + + init { + this.unitStateObserver = + Observer, Message> { source: ServiceStateProvider, data: Message -> + storeServiceState( + source.serviceProvider as org.openbase.bco.dal.lib.layer.unit.Unit<*>, + source.serviceType, + false + ) + } + } + + @Throws(CouldNotPerformException::class, InterruptedException::class) + override fun applyConfigUpdate(config: UnitConfigType.UnitConfig): UnitConfigType.UnitConfig { + var config: UnitConfigType.UnitConfig? = config + getManageWriteLockInterruptible(this).use { ignored -> + config = super.applyConfigUpdate(config!!) + bucketName = generateVariablePool().getValue( + InfluxDbProcessor.INFLUXDB_BUCKET, + InfluxDbProcessor.INFLUXDB_BUCKET_DEFAULT + ) + batchTime = generateVariablePool().getValue( + InfluxDbProcessor.INFLUXDB_BATCH_TIME, + InfluxDbProcessor.INFLUXDB_BATCH_TIME_DEFAULT + ).toInt() + batchLimit = generateVariablePool().getValue( + InfluxDbProcessor.INFLUXDB_BATCH_LIMIT, + InfluxDbProcessor.INFLUXDB_BATCH_LIMIT_DEFAULT + ).toInt() + databaseUrl = + generateVariablePool().getValue(InfluxDbProcessor.INFLUXDB_URL, InfluxDbProcessor.INFLUXDB_URL_DEFAULT) + token = generateVariablePool().getValue(InfluxDbProcessor.INFLUXDB_TOKEN).toCharArray() + org = + generateVariablePool().getValue(InfluxDbProcessor.INFLUXDB_ORG, InfluxDbProcessor.INFLUXDB_ORG_DEFAULT) + return config!! + } + } + + override fun execute(activationState: ActivationStateType.ActivationState): ActionDescriptionType.ActionDescription? { + task = GlobalCachedExecutorService.submit { + try { + logger.debug("Execute influx db connector") + + // connect to db + connectToDatabase() + while (!task!!.isCancelled) { + try { + verifyConnection() + break + } catch (ex: CouldNotPerformException) { + ExceptionPrinter.printHistory( + "Could not reach influxdb server at " + databaseUrl + ". Try again in " + databaseTimeout / 1000 + " seconds!", + ex, + logger, + LogLevel.WARN + ) + Thread.sleep(databaseTimeout.toLong()) + if (databaseTimeout < InfluxDbProcessor.MAX_TIMEOUT) databaseTimeout += InfluxDbProcessor.ADDITIONAL_TIMEOUT + } + } + + // lookup bucked + while (!task!!.isCancelled) { + try { + // check if bucked found + databaseBucket + break + } catch (ex: NotAvailableException) { + logger.warn("Could not get bucket. Try again in " + databaseTimeout / 1000 + " seconds!") + + ExceptionPrinter.printHistory(ex, logger) + Thread.sleep(databaseTimeout.toLong()) + } + } + + // start observation + try { + startObservation() + } catch (ex: InitializationException) { + ExceptionPrinter.printHistory(ex, logger) + } + } catch (ex: InterruptedException) { + // finish task because its canceled. + } + if (!task!!.isCancelled && isConnected) { + try { + // write initial heartbeat + logger.debug("initial heartbeat") + writeApi!!.writePoint( + bucketName!!, org!!, Point.measurement(InfluxDbProcessor.HEARTBEAT_MEASUREMENT) + .addField(InfluxDbProcessor.HEARTBEAT_FIELD, InfluxDbProcessor.HEARTBEAT_OFFLINE_VALUE) + .time(System.currentTimeMillis() - 1, WritePrecision.MS) + ) + writeApi!!.writePoint( + bucketName!!, org!!, Point.measurement(InfluxDbProcessor.HEARTBEAT_MEASUREMENT) + .addField(InfluxDbProcessor.HEARTBEAT_FIELD, InfluxDbProcessor.HEARTBEAT_ONLINE_VALUE) + .time(System.currentTimeMillis(), WritePrecision.MS) + ) + + heartbeat = GlobalScheduledExecutorService.scheduleAtFixedRate( + { + logger.debug("write heartbeat") + writeApi!!.writePoint( + bucketName!!, org!!, Point.measurement(InfluxDbProcessor.HEARTBEAT_MEASUREMENT) + .addField( + InfluxDbProcessor.HEARTBEAT_FIELD, + InfluxDbProcessor.HEARTBEAT_ONLINE_VALUE + ) + .time(System.currentTimeMillis(), WritePrecision.MS) + ) + }, + InfluxDbProcessor.HEARTBEAT_INITIAL_DELAY.toLong(), + InfluxDbProcessor.HEARTBEAT_PERIOD, + TimeUnit.MILLISECONDS + ) + } catch (ex: NotAvailableException) { + ExceptionPrinter.printHistory( + "Could not write heartbeat!", + ex, + logger, + LogLevel.WARN + ) + } + } + null + } + return activationState.responsibleAction + } + + @Throws(CouldNotPerformException::class, InterruptedException::class) + override fun stop(activationState: ActivationStateType.ActivationState) { + // finish task + + logger.debug("finish task") + if (task != null && !task!!.isDone) { + task!!.cancel(true) + try { + task!![5, TimeUnit.SECONDS] + } catch (ex: CancellationException) { + // that's what we are waiting for. + } catch (ex: Exception) { + ExceptionPrinter.printHistory(ex, logger) + } + } + + logger.debug("finish heartbeat") + if (heartbeat != null && !heartbeat!!.isDone) { + heartbeat!!.cancel(true) + try { + task!![5, TimeUnit.SECONDS] + } catch (ex: CancellationException) { + // that's what we are waiting for. + } catch (ex: Exception) { + ExceptionPrinter.printHistory(ex, logger) + } + } + + if (isConnected) { + // write final heartbeat if connection is established. + writeApi!!.writePoint( + bucketName!!, org!!, Point.measurement(InfluxDbProcessor.HEARTBEAT_MEASUREMENT) + .addField(InfluxDbProcessor.HEARTBEAT_FIELD, InfluxDbProcessor.HEARTBEAT_ONLINE_VALUE) + .time(System.currentTimeMillis() - 1, WritePrecision.MS) + ) + writeApi!!.writePoint( + bucketName!!, org!!, Point.measurement(InfluxDbProcessor.HEARTBEAT_MEASUREMENT) + .addField(InfluxDbProcessor.HEARTBEAT_FIELD, InfluxDbProcessor.HEARTBEAT_OFFLINE_VALUE) + .time(System.currentTimeMillis(), WritePrecision.MS) + ) + writeApi!!.flush() + } + + // deregister + customUnitPool.removeServiceStateObserver(unitStateObserver) + customUnitPool.deactivate() + disconnectDatabase() + + super.stop(activationState) + } + + @Throws(InitializationException::class, InterruptedException::class) + fun startObservation() { + try { + // setup pool + customUnitPool.addServiceStateObserver(unitStateObserver) + customUnitPool.activate() + + for (unitConfig in Registries.getUnitRegistry(true).unitConfigs) { + val unit: UnitRemote<*> + try { + unit = Units.getFutureUnit(unitConfig, true) + .get(InfluxDbProcessor.MAX_INITIAL_STORAGE_TIMEOUT, TimeUnit.MILLISECONDS) + } catch (ex: ExecutionException) { + ExceptionPrinter.printHistory( + "Could not reach Unit " + getBestMatch(unitConfig.label) + "! Skip initial service state synchronisation because unit will be synchronized anyway when it connection is established.", + ex, + logger, + LogLevel.DEBUG + ) + continue + } catch (ex: TimeoutException) { + ExceptionPrinter.printHistory( + "Could not reach Unit " + getBestMatch(unitConfig.label) + "! Skip initial service state synchronisation because unit will be synchronized anyway when it connection is established.", + ex, + logger, + LogLevel.DEBUG + ) + continue + } + try { + for (serviceDescription in unit.unitTemplate.serviceDescriptionList) { + if (serviceDescription.pattern != ServicePattern.PROVIDER) { + continue + } + storeServiceState(unit, serviceDescription.serviceType, true) + } + } catch (ex: CouldNotPerformException) { + ExceptionPrinter.printHistory("Could not store service state $unit", ex, logger) + } + } + } catch (ex: CouldNotPerformException) { + throw InitializationException(this, ex) + } + } + + @Throws(CouldNotPerformException::class) + private fun storeServiceState( + unit: org.openbase.bco.dal.lib.layer.unit.Unit<*>, + serviceType: ServiceTemplateType.ServiceTemplate.ServiceType, + initialSync: Boolean, + ) { + val currentServiceState: Message + var lastServiceState: Message? = null + try { + currentServiceState = Services.invokeProviderServiceMethod( + serviceType, + ServiceTempus.CURRENT, + unit.data + ) + } catch (ex: NotAvailableException) { + // if the current state is not available, we just try to at least store the last known service state if available. + + try { + lastServiceState = Services.invokeProviderServiceMethod( + serviceType, + ServiceTempus.LAST, + unit.data + ) + storeServiceState(unit, serviceType, lastServiceState) + } catch (exx: CouldNotPerformException) { + // we don't care if the last service state is not available + // which can be the case for an initial sync + // or any states which got only one state update since system startup. + } + return + } + + // store t - 1 entry + try { + lastServiceState = Services.invokeProviderServiceMethod( + serviceType, + ServiceTempus.LAST, + unit.data + ) + val serviceStateTimestamp = TimestampProcessor.getTimestamp(currentServiceState, TimeUnit.MILLISECONDS) - 1L + lastServiceState = + TimestampProcessor.updateTimestamp(serviceStateTimestamp, lastServiceState, TimeUnit.MILLISECONDS) + storeServiceState(unit, serviceType, lastServiceState) + } catch (ex: CouldNotPerformException) { + // we don't care if the last service state is not available + // which can be the case for an initial sync + // or any states which got only one state update since system startup. + } + + try { + storeServiceState(unit, serviceType, currentServiceState) + } catch (ex: CouldNotPerformException) { + // filter log if initial timestamps are missing + + if (initialSync) { + return + } + + ExceptionPrinter.printHistory( + "Could not store service state change into db! " + + "UnitType[" + unit.unitType + "] " + + "ServiceType[" + serviceType + "] " + + "CurrentServiceState[" + currentServiceState + "] " + + "LastServiceState[" + lastServiceState + "]", + ex, logger, LogLevel.DEBUG + ) + } + } + + @Throws(InvalidStateException::class) + private fun storeServiceState( + unit: org.openbase.bco.dal.lib.layer.unit.Unit<*>, + serviceType: ServiceTemplateType.ServiceTemplate.ServiceType, + serviceState: Message?, + ) { + val timestamp = TimestampProcessor.getTimestamp(serviceState, TimeUnit.MILLISECONDS) + try { + var initiator = try { + Services.getResponsibleAction(serviceState).getActionInitiator() + .getInitiatorType().name.lowercase( + Locale.getDefault() + ) + } catch (ex: NotAvailableException) { + // in this case we use the system as initiator because responsible actions are not available for pure provider services and those are always system generated. + "system" + } + val stateValuesMap = resolveStateValueToMap(serviceState) + val point = Point.measurement(serviceType.name.lowercase(Locale.getDefault())) + .addTag("alias", unit.config.getAlias(0)) + .addTag("initiator", initiator) + .addTag("unit_id", unit.id) + .addTag("unit_type", unit.unitType.name.lowercase(Locale.getDefault())) + .addTag("location_id", unit.parentLocationConfig.id) + .addTag("location_alias", unit.parentLocationConfig.getAlias(0)) + .time(timestamp, WritePrecision.MS) + + var values = 0 + for ((key, value) in stateValuesMap) { + // detect numbers with regex + if (value.matches("-?\\d+(\\.\\d+)?".toRegex())) { + values++ + point.addField(key, value.toDouble()) + } else { + point.addTag(key, value) + } + } + + val entryList = unit.config.label.entryList + for (entry in entryList) { + // skip entries that offer a language key but do not provide any label. + if (entry.valueList.isEmpty()) { + continue + } + point.addTag("label_" + entry.key, entry.getValue(0)) + } + + if (values > 0) { + writeApi!!.writePoint(bucketName!!, org!!, point) + } + } catch (ex: CouldNotPerformException) { + ExceptionPrinter.printHistory( + "Could not store service state " + serviceType.name + " of " + unit, + ex, + logger + ) + } + } + + + @Throws(CouldNotPerformException::class) + fun resolveStateValueToMap(serviceState: Message?): Map { + val stateValues: MutableMap = HashMap() + for (fieldDescriptor in serviceState!!.descriptorForType.fields) { + val stateName = fieldDescriptor.name + var stateType = fieldDescriptor.type.toString().lowercase(Locale.getDefault()) + + // filter invalid states + if (stateName == null) { + logger.warn("Could not detect datatype of $stateType") + } + + when (stateName) { + "aggregated_value_coverage", "last_value_occurrence", "timestamp", "responsible_action", "type", "rgb_color", "frame_id" -> continue + } + // filter data units + if (stateName!!.endsWith("data_unit")) { + continue + } + + var stateValue = serviceState.getField(fieldDescriptor).toString() + + try { + if (fieldDescriptor.type == Descriptors.FieldDescriptor.Type.MESSAGE) { + if (fieldDescriptor.isRepeated) { + val types: MutableList = ArrayList() + + for (i in 0 until serviceState.getRepeatedFieldCount(fieldDescriptor)) { + val repeatedFieldEntry = serviceState.getRepeatedField(fieldDescriptor, i) + if (repeatedFieldEntry is Message) { + types.add( + "[" + Services.resolveStateValue( + repeatedFieldEntry + ).toString() + "]" + ) + } + types.add(repeatedFieldEntry.toString()) + } + stateType = types.toString().lowercase(Locale.getDefault()) + } else { + stateValue = Services.resolveStateValue( + serviceState.getField(fieldDescriptor) as Message + ).toString() + } + } + } catch (ex: InvalidStateException) { + logger.warn("Could not process value of " + fieldDescriptor.name) + continue + } + + when (stateValue) { + "", "NaN" -> continue + else -> {} + } + if (fieldDescriptor.javaType == Descriptors.FieldDescriptor.JavaType.ENUM) { + val finalStateValue = stateValue + stateValue = fieldDescriptor.enumType.values.stream() + .filter { `val`: Descriptors.EnumValueDescriptor -> `val`.name == finalStateValue } + .findFirst().get().number.toString() + } + + stateValues[fieldDescriptor.name] = stateValue.lowercase(Locale.getDefault()) + } + return stateValues + } + + private val isConnected: Boolean + /** + * Method checks if the connection is established. + * + * @return true if the connection to influx db is established, otherwise false. + */ + get() { + try { + verifyConnection() + } catch (ex: VerificationFailedException) { + return false + } + return true + } + + /** + * Method verifies the connection state. + * + * @throws VerificationFailedException is thrown if the connection is not established. + */ + @Throws(VerificationFailedException::class) + private fun verifyConnection() { + if (influxDBClient == null) { + throw VerificationFailedException("Influx db connection has never been initiated.") + } + + if (influxDBClient!!.health().status.value !== "pass") { + throw VerificationFailedException("Could not connect to database server at $databaseUrl!") + } + + // initiate WriteApi + val writeoptions = WriteOptions.builder().batchSize(batchLimit!!).flushInterval(batchTime!!).build() + writeApi = influxDBClient!!.getWriteApi(writeoptions) + writeApi!!.listenEvents(WriteSuccessEvent::class.java) { event: WriteSuccessEvent? -> + logger.debug("Successfully wrote data into db") + } + writeApi!!.listenEvents(WriteErrorEvent::class.java) { event: WriteErrorEvent -> + val exception = event.throwable + logger.warn(exception.message) + } + logger.debug("Connected to Influxdb at $databaseUrl") + } + + private fun connectToDatabase() { + try { + influxDBClient?.close() + } catch (ex: Exception) { + ExceptionPrinter.printHistory("Could not shutdown database connection!", ex, logger) + } + logger.debug(" Try to connect to influxDB at $databaseUrl") + + + token?.let { + influxDBClient = InfluxDBClientFactory.create( + databaseUrl + "?readTimeout=" + InfluxDbProcessor.READ_TIMEOUT + "&connectTimeout=" + InfluxDbProcessor.CONNECT_TIMOUT + "&writeTimeout=" + InfluxDbProcessor.WRITE_TIMEOUT + "&logLevel=BASIC", + it + ) + } + } + + private fun disconnectDatabase() { + try { + if (influxDBClient != null) { + if (writeApi != null) { + writeApi!!.flush() + } + influxDBClient!!.close() + writeApi = null + } + } catch (ex: Exception) { + ExceptionPrinter.printHistory("Could not shutdown database connection!", ex, logger) + } + } + + @get:Throws(NotAvailableException::class) + private val databaseBucket: Unit + get() { + logger.debug("Get bucket $bucketName") + bucket = influxDBClient!!.bucketsApi.findBucketByName(bucketName!!) + if (bucket == null) { + throw NotAvailableException("bucket", bucketName) + } + } +} diff --git a/module/app/preset/src/main/java/org/openbase/bco/app/preset/NightLightApp.java b/module/app/preset/src/main/java/org/openbase/bco/app/preset/NightLightApp.java deleted file mode 100644 index cbd53b465a..0000000000 --- a/module/app/preset/src/main/java/org/openbase/bco/app/preset/NightLightApp.java +++ /dev/null @@ -1,360 +0,0 @@ -package org.openbase.bco.app.preset; - -/* - * #%L - * BCO App Preset - * %% - * Copyright (C) 2018 - 2021 openbase.org - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program. If not, see - * . - * #L% - */ - -import org.openbase.bco.dal.control.layer.unit.app.AbstractAppController; -import org.openbase.bco.dal.lib.layer.unit.Unit; -import org.openbase.bco.dal.remote.action.RemoteAction; -import org.openbase.bco.dal.remote.layer.unit.Units; -import org.openbase.bco.dal.remote.layer.unit.location.LocationRemote; -import org.openbase.bco.registry.remote.Registries; -import org.openbase.jul.exception.InstantiationException; -import org.openbase.jul.exception.*; -import org.openbase.jul.exception.printer.ExceptionPrinter; -import org.openbase.jul.iface.Activatable; -import org.openbase.jul.pattern.Observer; -import org.openbase.jul.pattern.provider.DataProvider; -import org.openbase.jul.schedule.CloseableWriteLockWrapper; -import org.openbase.jul.schedule.SyncObject; -import org.openbase.jul.schedule.Timeout; -import org.openbase.type.domotic.action.ActionDescriptionType.ActionDescription; -import org.openbase.type.domotic.service.ServiceTemplateType.ServiceTemplate.ServiceType; -import org.openbase.type.domotic.state.ActivationStateType.ActivationState; -import org.openbase.type.domotic.state.PowerStateType.PowerState.State; -import org.openbase.type.domotic.state.PresenceStateType.PresenceState; -import org.openbase.type.domotic.unit.UnitConfigType.UnitConfig; -import org.openbase.type.domotic.unit.UnitTemplateType.UnitTemplate.UnitType; -import org.openbase.type.domotic.unit.location.LocationConfigType.LocationConfig.LocationType; -import org.openbase.type.domotic.unit.location.LocationDataType.LocationData; -import org.openbase.type.vision.HSBColorType.HSBColor; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.*; -import java.util.concurrent.TimeUnit; - -/** - * UnitConfig - */ -public class NightLightApp extends AbstractAppController { - - public static final HSBColor COLOR_ORANGE = HSBColor.newBuilder().setHue(15d).setSaturation(1.0d).setBrightness(0.10d).build(); - private static final Logger LOGGER = LoggerFactory.getLogger(NightLightApp.class); - private static final String META_CONFIG_KEY_EXCLUDE_LOCATION = "EXCLUDE_LOCATION"; - - private SyncObject locationMapLock = new SyncObject("LocationMapLock"); - - private Map presentsActionLocationMap, absenceActionLocationMap; - private Map locationMap; - - public NightLightApp() throws InstantiationException { - this.locationMap = new HashMap<>(); - this.presentsActionLocationMap = new HashMap<>(); - this.absenceActionLocationMap = new HashMap<>(); - } - - /** - * @param location the location to process - * @param eventSource the source which has triggered the update: location / childlocation / timeout / init (null) - * @param timeout the timeout of the location - */ - private void update(final LocationRemote location, final Object eventSource, final Timeout timeout) { - try { - - // skip update when not active - if (getActivationState().getValue() != ActivationState.State.ACTIVE) { - - if (!executing) { - logger.warn("app inactive but still executing! Force stopp..."); - try { - stop(getActivationState()); - } catch (InterruptedException e) { - Thread.currentThread().interrupt(); - return; - } - } - logger.error("Update triggered even when not active!"); - StackTracePrinter.printStackTrace(logger); - return; - } - - // init present state with main location. - PresenceState.State presentState = location.getPresenceState().getValue(); - for (final LocationRemote neighbor : location.getNeighborLocationList(true)) { - - // break if any present person is detected. - if (presentState == PresenceState.State.PRESENT) { - break; - } - - // if not unknown apply state of neighbor - if (neighbor.getPresenceState().getValue() != PresenceState.State.UNKNOWN) { - presentState = neighbor.getPresenceState().getValue(); - } - } - - final RemoteAction absenceAction = absenceActionLocationMap.get(location); - final RemoteAction presentsAction = presentsActionLocationMap.get(location); - - switch (presentState) { - case PRESENT: - - if (eventSource == location) { - timeout.restart(10, TimeUnit.MINUTES); - } else { - timeout.restart(2, TimeUnit.MINUTES); - } - - // if ongoing action skip the update. - if (presentsAction != null && !presentsAction.isDone()) { - return; - } - - // System.out.println("Nightmode: switch location " + location.getLabel() + " to orange because of present state]."); - final Set availableServiceTypes = location.getAvailableServiceTypes(); - if (availableServiceTypes.contains(ServiceType.COLOR_STATE_SERVICE)) { - presentsActionLocationMap.put(location, observe(location.setColor(COLOR_ORANGE, getDefaultActionParameter()))); - } else if (availableServiceTypes.contains(ServiceType.BRIGHTNESS_STATE_SERVICE)) { - presentsActionLocationMap.put(location, observe(location.setBrightness(COLOR_ORANGE.getBrightness(), getDefaultActionParameter()))); - } else { - // location not supported for nightlight - } - - break; - case ABSENT: - - // if ongoing action skip the update. - if (absenceAction != null && !absenceAction.isDone()) { - return; - } - - if (timeout.isExpired() || !timeout.isActive()) { - // System.out.println("Nightmode: switch off " + location.getLabel() + " because of absent state."); - absenceActionLocationMap.put(location, observe(location.setPowerState(State.OFF, UnitType.LIGHT, getDefaultActionParameter()))); - - // cancel presents actions - if (presentsAction != null) { - presentsAction.cancel(); - presentsActionLocationMap.remove(location); - } - } - - break; - } - } catch (ShutdownInProgressException ex) { - // skip update when shutdown was initiated. - } catch (CouldNotPerformException ex) { - ExceptionPrinter.printHistory("Could not control light in " + location.getLabel("?") + " by night light!", ex, LOGGER); - } - } - - @Override - public UnitConfig applyConfigUpdate(UnitConfig config) throws CouldNotPerformException, InterruptedException { - try (final CloseableWriteLockWrapper ignored = getManageWriteLockInterruptible(this)) { - config = super.applyConfigUpdate(config); - updateLocationMap(); - return config; - } - } - - private void updateLocationMap() throws CouldNotPerformException { - try { - synchronized (locationMapLock) { - - // deregister all tile remotes - locationMap.forEach((remote, observer) -> { - observer.deactivate(); - }); - - // clear all tile remotes - locationMap.clear(); - - final Collection excludedLocations = new ArrayList<>(); - - // check location exclusion - try { - excludedLocations.addAll(generateVariablePool().getValues(META_CONFIG_KEY_EXCLUDE_LOCATION).values()); - } catch (final NotAvailableException ex) { - ExceptionPrinter.printHistory("Could not load variable pool!", ex, LOGGER); - // no locations excluded. - } - - // load parent location - final UnitConfig parentLocationConfig = Registries.getUnitRegistry().getUnitConfigById(getConfig().getPlacementConfig().getLocationId()); - - // load tile remotes - remoteLocationLoop: - for (String childLocationId : parentLocationConfig.getLocationConfig().getChildIdList()) { - - final UnitConfig locationUnitConfig = Registries.getUnitRegistry().getUnitConfigById(childLocationId); - - // let only tiles pass - if (locationUnitConfig.getLocationConfig().getLocationType() != LocationType.TILE) { - continue; - } - - // check if location was excluded by id - if (excludedLocations.contains(locationUnitConfig.getId())) { - // System.out.println("exclude locations: " + locationUnitConfig.getLabel()); - continue remoteLocationLoop; - } - - // check if location was excluded by alias - for (String alias : locationUnitConfig.getAliasList()) { - if (excludedLocations.contains(alias)) { - // System.out.println("exclude locations: " + locationUnitConfig.getLabel()); - continue remoteLocationLoop; - } - } - - final LocationRemote remote = Units.getUnit(locationUnitConfig, false, Units.LOCATION); - - // skip locations without colorable lights. - if (!remote.isServiceAvailable(ServiceType.COLOR_STATE_SERVICE)) { - continue remoteLocationLoop; - } - - locationMap.put(remote, new TimedObserver(remote)); - } - - if (getActivationState().getValue() == ActivationState.State.ACTIVE) { - locationMap.forEach((remote, observer) -> { - observer.activate(); - }); - } - } - } catch (final InterruptedException ex) { - Thread.currentThread().interrupt(); - } catch (final CouldNotPerformException ex) { - throw new CouldNotPerformException("Could not update location map", ex); - } - } - - @Override - public void shutdown() { - super.shutdown(); - synchronized (locationMapLock) { - locationMap.clear(); - } - } - - boolean executing = false; - - @Override - protected ActionDescription execute(final ActivationState activationState) throws CouldNotPerformException, InterruptedException { - executing = true; - synchronized (locationMapLock) { - locationMap.forEach((remote, observer) -> { - observer.activate(); - }); - } - return activationState.getResponsibleAction(); - } - - @Override - protected void stop(final ActivationState activationState) throws InterruptedException, CouldNotPerformException { - executing = false; - synchronized (locationMapLock) { - - // remove observer - locationMap.forEach((remote, observer) -> { - observer.deactivate(); - }); - - // clear actions list - presentsActionLocationMap.clear(); - absenceActionLocationMap.clear(); - } - super.stop(activationState); - } - - class TimedObserver implements Activatable { - - final LocationRemote remote; - final Timeout timeout; - final Observer, LocationData> internalObserver; - final List neighborLocationRemoteList; - - boolean active; - - public TimedObserver(LocationRemote remote) throws InstantiationException { - try { - this.remote = remote; - this.timeout = new Timeout(1, TimeUnit.MINUTES) { - @Override - public void expired() { - // skip update when not active - if (!active) { - logger.error("Update triggered even when not active!"); - StackTracePrinter.printStackTrace(logger); - return; - } - NightLightApp.this.update(remote, this, this); - } - }; - this.neighborLocationRemoteList = remote.getNeighborLocationList(false); - this.internalObserver = (source, data) -> { - // skip update when not active - if (!active) { - logger.error("Update triggered even when not active!"); - StackTracePrinter.printStackTrace(logger); - return; - } - NightLightApp.this.update(remote, source, timeout); - }; - } catch (CouldNotPerformException ex) { - throw new InstantiationException(this, ex); - } - } - - @Override - public synchronized void activate() { - active = true; - - // register observer - remote.addDataObserver(internalObserver); - for (LocationRemote neighbor : neighborLocationRemoteList) { - neighbor.addDataObserver(internalObserver); - } - - NightLightApp.this.update(remote, null, timeout); - } - - @Override - public synchronized void deactivate() { - active = false; - timeout.cancel(); - - // deregister observer - remote.removeDataObserver(internalObserver); - for (LocationRemote neighbor : neighborLocationRemoteList) { - neighbor.removeDataObserver(internalObserver); - } - } - - @Override - public boolean isActive() { - return active; - } - } -} diff --git a/module/app/preset/src/main/java/org/openbase/bco/app/preset/NightLightApp.kt b/module/app/preset/src/main/java/org/openbase/bco/app/preset/NightLightApp.kt new file mode 100644 index 0000000000..5337c3f317 --- /dev/null +++ b/module/app/preset/src/main/java/org/openbase/bco/app/preset/NightLightApp.kt @@ -0,0 +1,347 @@ +package org.openbase.bco.app.preset + +import org.openbase.bco.dal.control.layer.unit.app.AbstractAppController +import org.openbase.bco.dal.lib.layer.unit.Unit +import org.openbase.bco.dal.remote.action.RemoteAction +import org.openbase.bco.dal.remote.layer.unit.Units +import org.openbase.bco.dal.remote.layer.unit.location.LocationRemote +import org.openbase.bco.registry.remote.Registries +import org.openbase.jul.exception.CouldNotPerformException +import org.openbase.jul.exception.InstantiationException +import org.openbase.jul.exception.NotAvailableException +import org.openbase.jul.exception.ShutdownInProgressException +import org.openbase.jul.exception.StackTracePrinter.printStackTrace +import org.openbase.jul.exception.printer.ExceptionPrinter +import org.openbase.jul.iface.Activatable +import org.openbase.jul.pattern.Observer +import org.openbase.jul.pattern.provider.DataProvider +import org.openbase.jul.schedule.SyncObject +import org.openbase.jul.schedule.Timeout +import org.openbase.type.domotic.action.ActionDescriptionType +import org.openbase.type.domotic.service.ServiceTemplateType +import org.openbase.type.domotic.state.ActivationStateType +import org.openbase.type.domotic.state.PowerStateType +import org.openbase.type.domotic.state.PresenceStateType +import org.openbase.type.domotic.unit.UnitConfigType +import org.openbase.type.domotic.unit.UnitTemplateType +import org.openbase.type.domotic.unit.location.LocationConfigType +import org.openbase.type.domotic.unit.location.LocationDataType +import org.openbase.type.vision.HSBColorType +import org.slf4j.Logger +import org.slf4j.LoggerFactory +import java.util.concurrent.TimeUnit + +/** + * UnitConfig + */ +class NightLightApp : AbstractAppController() { + private val locationMapLock = SyncObject("LocationMapLock") + + private val presentsActionLocationMap: MutableMap?, RemoteAction> + private val absenceActionLocationMap: MutableMap?, RemoteAction> + private val locationMap: MutableMap + + /** + * @param location the location to process + * @param eventSource the source which has triggered the update: location / childlocation / timeout / init (null) + * @param timeout the timeout of the location + */ + private fun update(location: LocationRemote?, eventSource: Any?, timeout: Timeout?) { + try { + // skip update when not active + + if (activationState.value != ActivationStateType.ActivationState.State.ACTIVE) { + if (!executing) { + logger.warn("app inactive but still executing! Force stopp...") + try { + stop(activationState) + } catch (e: InterruptedException) { + Thread.currentThread().interrupt() + return + } + } + logger.error("Update triggered even when not active!") + printStackTrace(logger) + return + } + + // init present state with main location. + var presentState = location!!.presenceState.value + for (neighbor in location.getNeighborLocationList(true)) { + // break if any present person is detected. + + if (presentState == PresenceStateType.PresenceState.State.PRESENT) { + break + } + + // if not unknown apply state of neighbor + if (neighbor.presenceState.value != PresenceStateType.PresenceState.State.UNKNOWN) { + presentState = neighbor.presenceState.value + } + } + + val absenceAction = absenceActionLocationMap[location] + val presentsAction = presentsActionLocationMap[location] + + when (presentState) { + PresenceStateType.PresenceState.State.PRESENT -> { + if (eventSource === location) { + timeout!!.restart(10, TimeUnit.MINUTES) + } else { + timeout!!.restart(2, TimeUnit.MINUTES) + } + + // if ongoing action skip the update. + if (presentsAction != null && !presentsAction.isDone) { + return + } + + // System.out.println("Nightmode: switch location " + location.getLabel() + " to orange because of present state]."); + val availableServiceTypes = location.availableServiceTypes + if (availableServiceTypes.contains(ServiceTemplateType.ServiceTemplate.ServiceType.COLOR_STATE_SERVICE)) { + presentsActionLocationMap[location] = + observe(location.setColor(COLOR_ORANGE, defaultActionParameter)) + } else if (availableServiceTypes.contains(ServiceTemplateType.ServiceTemplate.ServiceType.BRIGHTNESS_STATE_SERVICE)) { + presentsActionLocationMap[location] = + observe(location.setBrightness(COLOR_ORANGE.brightness, defaultActionParameter)) + } else { + // location not supported for nightlight + } + } + + PresenceStateType.PresenceState.State.ABSENT -> { + // if ongoing action skip the update. + if (absenceAction != null && !absenceAction.isDone) { + return + } + + if (timeout!!.isExpired || !timeout.isActive) { + // System.out.println("Nightmode: switch off " + location.getLabel() + " because of absent state."); + absenceActionLocationMap[location] = observe( + location.setPowerState( + PowerStateType.PowerState.State.OFF, + UnitTemplateType.UnitTemplate.UnitType.LIGHT, + defaultActionParameter + ) + ) + + // cancel presents actions + if (presentsAction != null) { + presentsAction.cancel() + presentsActionLocationMap.remove(location) + } + } + } + + PresenceStateType.PresenceState.State.UNKNOWN -> TODO() + } + } catch (ex: ShutdownInProgressException) { + // skip update when shutdown was initiated. + } catch (ex: CouldNotPerformException) { + ExceptionPrinter.printHistory( + "Could not control light in " + location!!.getLabel("?") + " by night light!", + ex, + LOGGER + ) + } + } + + @Throws(CouldNotPerformException::class, InterruptedException::class) + override fun applyConfigUpdate(config: UnitConfigType.UnitConfig): UnitConfigType.UnitConfig { + var config: UnitConfigType.UnitConfig? = config + getManageWriteLockInterruptible(this).use { ignored -> + config = super.applyConfigUpdate(config!!) + updateLocationMap() + return config!! + } + } + + @Throws(CouldNotPerformException::class) + private fun updateLocationMap() { + try { + synchronized(locationMapLock) { + // deregister all tile remotes + locationMap.forEach { (remote: LocationRemote?, observer: TimedObserver) -> + observer.deactivate() + } + + // clear all tile remotes + locationMap.clear() + + val excludedLocations: MutableCollection = ArrayList() + + // check location exclusion + try { + excludedLocations.addAll(generateVariablePool().getValues(META_CONFIG_KEY_EXCLUDE_LOCATION).values) + } catch (ex: NotAvailableException) { + ExceptionPrinter.printHistory("Could not load variable pool!", ex, LOGGER) + // no locations excluded. + } + + // load parent location + val parentLocationConfig = + Registries.getUnitRegistry().getUnitConfigById(config.placementConfig.locationId) + + // load tile remotes + remoteLocationLoop@ for (childLocationId in parentLocationConfig.locationConfig.childIdList) { + val locationUnitConfig = Registries.getUnitRegistry().getUnitConfigById(childLocationId) + + // let only tiles pass + if (locationUnitConfig.locationConfig.locationType != LocationConfigType.LocationConfig.LocationType.TILE) { + continue + } + + // check if location was excluded by id + if (excludedLocations.contains(locationUnitConfig.id)) { + // System.out.println("exclude locations: " + locationUnitConfig.getLabel()); + continue@remoteLocationLoop + } + + // check if location was excluded by alias + for (alias in locationUnitConfig.aliasList) { + if (excludedLocations.contains(alias)) { + // System.out.println("exclude locations: " + locationUnitConfig.getLabel()); + continue@remoteLocationLoop + } + } + + val remote = Units.getUnit(locationUnitConfig, false, Units.LOCATION) + + // skip locations without colorable lights. + if (!remote.isServiceAvailable(ServiceTemplateType.ServiceTemplate.ServiceType.COLOR_STATE_SERVICE)) { + continue@remoteLocationLoop + } + + locationMap[remote] = TimedObserver(remote) + } + if (activationState.value == ActivationStateType.ActivationState.State.ACTIVE) { + locationMap.forEach { (remote: LocationRemote?, observer: TimedObserver) -> + observer.activate() + } + } + } + } catch (ex: InterruptedException) { + Thread.currentThread().interrupt() + } catch (ex: CouldNotPerformException) { + throw CouldNotPerformException("Could not update location map", ex) + } + } + + override fun shutdown() { + super.shutdown() + synchronized(locationMapLock) { + locationMap.clear() + } + } + + var executing: Boolean = false + + init { + this.locationMap = HashMap() + this.presentsActionLocationMap = HashMap() + this.absenceActionLocationMap = HashMap() + } + + @Throws(CouldNotPerformException::class, InterruptedException::class) + override fun execute(activationState: ActivationStateType.ActivationState): ActionDescriptionType.ActionDescription? { + executing = true + synchronized(locationMapLock) { + locationMap.forEach { (remote: LocationRemote?, observer: TimedObserver) -> + observer.activate() + } + } + return activationState.responsibleAction + } + + @Throws(InterruptedException::class, CouldNotPerformException::class) + override fun stop(activationState: ActivationStateType.ActivationState) { + executing = false + synchronized(locationMapLock) { + // remove observer + locationMap.forEach { (remote: LocationRemote?, observer: TimedObserver) -> + observer.deactivate() + } + + // clear actions list + presentsActionLocationMap.clear() + absenceActionLocationMap.clear() + } + super.stop(activationState) + } + + internal inner class TimedObserver(remote: LocationRemote) : Activatable { + var remote: LocationRemote? = null + var timeout: Timeout? = null + var internalObserver: Observer, LocationDataType.LocationData>? = + null + var neighborLocationRemoteList: List? = null + + var active: Boolean = false + + init { + try { + this.remote = remote + this.timeout = object : Timeout(1, TimeUnit.MINUTES) { + override fun expired() { + // skip update when not active + if (!active) { + logger.error("Update triggered even when not active!") + printStackTrace(logger) + return + } + this@NightLightApp.update(remote, this, this) + } + } + this.neighborLocationRemoteList = remote.getNeighborLocationList(false) + this.internalObserver = + Observer { source: DataProvider?, data: LocationDataType.LocationData? -> + // skip update when not active + if (!active) { + logger.error("Update triggered even when not active!") + printStackTrace(logger) + return@Observer + } + this@NightLightApp.update(remote, source, timeout) + } + } catch (ex: CouldNotPerformException) { + throw InstantiationException(this, ex) + } + } + + @Synchronized + override fun activate() { + active = true + + // register observer + remote!!.addDataObserver(internalObserver) + for (neighbor in neighborLocationRemoteList!!) { + neighbor.addDataObserver(internalObserver) + } + + this@NightLightApp.update(remote, null, timeout) + } + + @Synchronized + override fun deactivate() { + active = false + timeout!!.cancel() + + // deregister observer + remote!!.removeDataObserver(internalObserver) + for (neighbor in neighborLocationRemoteList!!) { + neighbor.removeDataObserver(internalObserver) + } + } + + override fun isActive(): Boolean { + return active + } + } + + companion object { + val COLOR_ORANGE: HSBColorType.HSBColor = + HSBColorType.HSBColor.newBuilder().setHue(15.0).setSaturation(1.0).setBrightness(0.10).build() + private val LOGGER: Logger = LoggerFactory.getLogger(NightLightApp::class.java) + private const val META_CONFIG_KEY_EXCLUDE_LOCATION = "EXCLUDE_LOCATION" + } +} diff --git a/module/app/preset/src/main/java/org/openbase/bco/app/preset/PartyLightTileFollowerApp.java b/module/app/preset/src/main/java/org/openbase/bco/app/preset/PartyLightTileFollowerApp.java deleted file mode 100644 index 04fe1f3817..0000000000 --- a/module/app/preset/src/main/java/org/openbase/bco/app/preset/PartyLightTileFollowerApp.java +++ /dev/null @@ -1,185 +0,0 @@ -package org.openbase.bco.app.preset; - -/* - * #%L - * BCO App Preset - * %% - * Copyright (C) 2018 - 2021 openbase.org - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program. If not, see - * . - * #L% - */ - -import org.openbase.bco.dal.lib.layer.unit.Unit; -import org.openbase.bco.dal.remote.action.RemoteAction; -import org.openbase.bco.dal.remote.layer.unit.Units; -import org.openbase.bco.dal.remote.layer.unit.location.LocationRemote; -import org.openbase.bco.dal.control.layer.unit.app.AbstractAppController; -import org.openbase.bco.registry.remote.Registries; -import org.openbase.jul.exception.CouldNotPerformException; -import org.openbase.jul.exception.ExceptionProcessor; -import org.openbase.jul.exception.InstantiationException; -import org.openbase.jul.exception.printer.ExceptionPrinter; -import org.openbase.jul.schedule.SyncObject; -import org.openbase.type.domotic.action.ActionDescriptionType.ActionDescription; -import org.openbase.type.domotic.state.ActivationStateType.ActivationState; -import org.openbase.type.domotic.unit.UnitConfigType.UnitConfig; -import org.openbase.type.domotic.unit.UnitTemplateType.UnitTemplate.UnitType; -import org.openbase.type.domotic.unit.location.LocationConfigType; -import org.openbase.type.vision.HSBColorType.HSBColor; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Map.Entry; -import java.util.concurrent.*; - -/** - * UnitConfig - */ -public class PartyLightTileFollowerApp extends AbstractAppController { - - private Map actionLocationMap; - private Map locationRemoteMap; - - private SyncObject taskLock = new SyncObject("TaskLock"); - - public PartyLightTileFollowerApp() throws InstantiationException, InterruptedException { - try { - Registries.waitForData(); - this.actionLocationMap = new HashMap<>(); - this.locationRemoteMap = new HashMap<>(); - } catch (CouldNotPerformException ex) { - throw new InstantiationException(this, ex); - } - } - - @Override - public void shutdown() { - locationRemoteMap.clear(); - super.shutdown(); - } - - private double brightness = 0.50d; - private HSBColor[] colors = { - HSBColor.newBuilder().setHue(0d).setSaturation(1.0d).setBrightness(brightness).build(), - HSBColor.newBuilder().setHue(290d).setSaturation(1.0d).setBrightness(brightness).build(), - HSBColor.newBuilder().setHue(30d).setSaturation(1.0d).setBrightness(brightness).build(),}; - - @Override - protected ActionDescription execute(final ActivationState activationState) throws CouldNotPerformException, InterruptedException { - logger.debug("Execute PartyLightTileFollowerApp[" + getLabel() + "]"); - - // init tile remotes - locationRemoteMap.clear(); - for (final UnitConfig locationUnitConfig : Registries.getUnitRegistry(true).getUnitConfigsByUnitType(UnitType.LOCATION)) { - if (!locationUnitConfig.getLocationConfig().getLocationType().equals(LocationConfigType.LocationConfig.LocationType.TILE)) { - continue; - } - locationRemoteMap.put(locationUnitConfig.getId(), Units.getUnit(locationUnitConfig, false, Units.LOCATION)); - } - - new TileFollower().call(); - return activationState.getResponsibleAction(); - } - - @Override - protected void stop(final ActivationState activationState) throws InterruptedException, CouldNotPerformException { - final ArrayList> cancelTaskList = new ArrayList<>(); - for (Entry unitActionEntry : actionLocationMap.entrySet()) { - cancelTaskList.add(unitActionEntry.getValue().cancel()); - } - - for (Future cancelTask : cancelTaskList) { - try { - cancelTask.get(10, TimeUnit.SECONDS); - } catch (ExecutionException | TimeoutException ex) { - if(!ExceptionProcessor.isCausedBySystemShutdown(ex)) { - ExceptionPrinter.printHistory("Could not cancel action!", ex, logger); - } - } - } - super.stop(activationState); - } - - public class TileFollower implements Callable { - - private final List processedLocations = new ArrayList<>(); - - @Override - public Void call() throws CouldNotPerformException, InterruptedException { - if (locationRemoteMap.isEmpty()) { - throw new CouldNotPerformException("No Locations found!"); - } - - LocationRemote locationRemote; - - int colorIndex = 0; - while (!Thread.currentThread().isInterrupted()) { - Thread.yield(); - try { - // apply updates for next iteration - colorIndex = ++colorIndex % colors.length; - processedLocations.clear(); - - // select initial room - locationRemote = locationRemoteMap.get(getConfig().getPlacementConfig().getLocationId()); - - processRoom(locationRemote, colors[colorIndex]); - - } catch (CouldNotPerformException ex) { - ExceptionPrinter.printHistory(new CouldNotPerformException("Skip animation run!", ExceptionProcessor.interruptOnShutdown(ex)), logger); - } - } - return null; - } - - private void processRoom(final LocationRemote locationRemote, final HSBColor color) throws CouldNotPerformException, InterruptedException { - logger.debug("Set " + locationRemote + " to " + color + "..."); - try { - - // skip if no colorable light is present - if (!Registries.getUnitRegistry().getUnitConfigsByLocationIdAndUnitType(locationRemote.getId(), UnitType.COLORABLE_LIGHT).isEmpty()) { - if (locationRemote.isConnected() && locationRemote.isDataAvailable()) { - final RemoteAction remoteAction = observe(locationRemote.setColor(color, getDefaultActionParameter())); - actionLocationMap.put(locationRemote, remoteAction); - remoteAction.waitForRegistration(); - } - Thread.sleep(1000); - } - - // mark as processed - processedLocations.add(locationRemote.getId()); - - // process neighbors - LocationRemote neighborRemote; - for (UnitConfig neighborConfig : Registries.getUnitRegistry().getNeighborLocationsByLocationId(locationRemote.getId())) { - // skip if already processed - if (processedLocations.contains(neighborConfig.getId())) { - continue; - } - - neighborRemote = locationRemoteMap.get(neighborConfig.getId()); - - // process remote - processRoom(neighborRemote, color); - } - } catch (CouldNotPerformException ex) { - throw new CouldNotPerformException("Could not process room of " + locationRemote, ex); - } - } - } -} diff --git a/module/app/preset/src/main/java/org/openbase/bco/app/preset/PartyLightTileFollowerApp.kt b/module/app/preset/src/main/java/org/openbase/bco/app/preset/PartyLightTileFollowerApp.kt new file mode 100644 index 0000000000..e89aa9a863 --- /dev/null +++ b/module/app/preset/src/main/java/org/openbase/bco/app/preset/PartyLightTileFollowerApp.kt @@ -0,0 +1,171 @@ +package org.openbase.bco.app.preset + +import org.openbase.bco.dal.control.layer.unit.app.AbstractAppController +import org.openbase.bco.dal.lib.layer.unit.Unit +import org.openbase.bco.dal.remote.action.RemoteAction +import org.openbase.bco.dal.remote.layer.unit.Units +import org.openbase.bco.dal.remote.layer.unit.location.LocationRemote +import org.openbase.bco.registry.remote.Registries +import org.openbase.jul.exception.CouldNotPerformException +import org.openbase.jul.exception.ExceptionProcessor.interruptOnShutdown +import org.openbase.jul.exception.ExceptionProcessor.isCausedBySystemShutdown +import org.openbase.jul.exception.InstantiationException +import org.openbase.jul.exception.printer.ExceptionPrinter +import org.openbase.jul.schedule.SyncObject +import org.openbase.type.domotic.action.ActionDescriptionType +import org.openbase.type.domotic.state.ActivationStateType +import org.openbase.type.domotic.unit.UnitTemplateType +import org.openbase.type.domotic.unit.location.LocationConfigType +import org.openbase.type.vision.HSBColorType +import java.util.concurrent.* + +/** + * UnitConfig + */ +class PartyLightTileFollowerApp : AbstractAppController() { + private var actionLocationMap: MutableMap?, RemoteAction>? = null + private var locationRemoteMap: MutableMap? = null + + private val taskLock = SyncObject("TaskLock") + + override fun shutdown() { + locationRemoteMap!!.clear() + super.shutdown() + } + + private val brightness = 0.50 + private val colors = arrayOf( + HSBColorType.HSBColor.newBuilder().setHue(0.0).setSaturation(1.0).setBrightness(brightness).build(), + HSBColorType.HSBColor.newBuilder().setHue(290.0).setSaturation(1.0).setBrightness(brightness).build(), + HSBColorType.HSBColor.newBuilder().setHue(30.0).setSaturation(1.0).setBrightness(brightness).build(), + ) + + init { + try { + Registries.waitForData() + this.actionLocationMap = HashMap() + this.locationRemoteMap = HashMap() + } catch (ex: CouldNotPerformException) { + throw InstantiationException(this, ex) + } + } + + @Throws(CouldNotPerformException::class, InterruptedException::class) + override fun execute(activationState: ActivationStateType.ActivationState): ActionDescriptionType.ActionDescription? { + logger.debug("Execute PartyLightTileFollowerApp[$label]") + + // init tile remotes + locationRemoteMap!!.clear() + for (locationUnitConfig in Registries.getUnitRegistry(true) + .getUnitConfigsByUnitType(UnitTemplateType.UnitTemplate.UnitType.LOCATION)) { + if (locationUnitConfig.locationConfig.locationType != LocationConfigType.LocationConfig.LocationType.TILE) { + continue + } + locationRemoteMap!![locationUnitConfig.id] = Units.getUnit(locationUnitConfig, false, Units.LOCATION) + } + + TileFollower().call() + return activationState.responsibleAction + } + + @Throws(InterruptedException::class, CouldNotPerformException::class) + override fun stop(activationState: ActivationStateType.ActivationState) { + val cancelTaskList = ArrayList>() + for ((_, value) in actionLocationMap!!) { + cancelTaskList.add(value.cancel()) + } + + for (cancelTask in cancelTaskList) { + try { + cancelTask[10, TimeUnit.SECONDS] + } catch (ex: ExecutionException) { + if (!isCausedBySystemShutdown(ex)) { + ExceptionPrinter.printHistory("Could not cancel action!", ex, logger) + } + } catch (ex: TimeoutException) { + if (!isCausedBySystemShutdown(ex)) { + ExceptionPrinter.printHistory("Could not cancel action!", ex, logger) + } + } + } + super.stop(activationState) + } + + inner class TileFollower : Callable { + private val processedLocations: MutableList = ArrayList() + + @Throws(CouldNotPerformException::class, InterruptedException::class) + override fun call(): Void? { + if (locationRemoteMap!!.isEmpty()) { + throw CouldNotPerformException("No Locations found!") + } + + var locationRemote: LocationRemote? + + var colorIndex = 0 + while (!Thread.currentThread().isInterrupted) { + Thread.yield() + try { + // apply updates for next iteration + colorIndex = ++colorIndex % colors.size + processedLocations.clear() + + // select initial room + locationRemote = locationRemoteMap!![config.placementConfig.locationId] + + processRoom(locationRemote, colors[colorIndex]) + } catch (ex: CouldNotPerformException) { + ExceptionPrinter.printHistory( + CouldNotPerformException( + "Skip animation run!", + interruptOnShutdown(ex) + ), logger + ) + } + } + return null + } + + @Throws(CouldNotPerformException::class, InterruptedException::class) + private fun processRoom(locationRemote: LocationRemote?, color: HSBColorType.HSBColor) { + logger.debug("Set $locationRemote to $color...") + try { + // skip if no colorable light is present + + if (Registries.getUnitRegistry().getUnitConfigsByLocationIdAndUnitType( + locationRemote!!.id, + UnitTemplateType.UnitTemplate.UnitType.COLORABLE_LIGHT + ).isNotEmpty() + ) { + if (locationRemote.isConnected && locationRemote.isDataAvailable) { + val remoteAction = observe(locationRemote.setColor(color, defaultActionParameter)) + actionLocationMap!![locationRemote] = remoteAction + remoteAction.waitForRegistration() + } + Thread.sleep(1000) + } + + // mark as processed + processedLocations.add(locationRemote.id) + + // process neighbors + var neighborRemote: LocationRemote? + for (neighborConfig in Registries.getUnitRegistry().getNeighborLocationsByLocationId( + locationRemote.id + )) { + // skip if already processed + if (processedLocations.contains(neighborConfig.id)) { + continue + } + + neighborRemote = locationRemoteMap!![neighborConfig.id] + + // process remote + processRoom(neighborRemote, color) + } + } catch (ex: CouldNotPerformException) { + throw CouldNotPerformException("Could not process room of $locationRemote", ex) + } + } + } +} diff --git a/module/app/util/build.gradle.kts b/module/app/util/build.gradle.kts index 8ebb23f953..67463c65a3 100644 --- a/module/app/util/build.gradle.kts +++ b/module/app/util/build.gradle.kts @@ -1,8 +1,20 @@ plugins { id("org.openbase.bco") + id("org.openjfx.javafxplugin") version "0.1.0" application } +javafx { + version = "21.0.1" + modules = listOf( + "javafx.base", + "javafx.graphics", + "javafx.media", + "javafx.controls", + "javafx.fxml" + ) +} + repositories { maven { url = uri("https://openhab.jfrog.io/openhab/libs-release") diff --git a/module/dal/control/src/main/java/org/openbase/bco/dal/control/layer/unit/AbstractExecutableBaseUnitController.java b/module/dal/control/src/main/java/org/openbase/bco/dal/control/layer/unit/AbstractExecutableBaseUnitController.java deleted file mode 100644 index 98d1d949ef..0000000000 --- a/module/dal/control/src/main/java/org/openbase/bco/dal/control/layer/unit/AbstractExecutableBaseUnitController.java +++ /dev/null @@ -1,144 +0,0 @@ -package org.openbase.bco.dal.control.layer.unit; - -/*- - * #%L - * BCO DAL Control - * %% - * Copyright (C) 2014 - 2021 openbase.org - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program. If not, see - * . - * #L% - */ - -import com.google.protobuf.AbstractMessage; -import org.openbase.bco.dal.lib.action.ActionDescriptionProcessor; -import org.openbase.bco.dal.lib.layer.service.ServiceProvider; -import org.openbase.bco.dal.lib.layer.service.operation.ActivationStateOperationService; -import org.openbase.bco.dal.lib.layer.service.provider.ActivationStateProviderService; -import org.openbase.bco.dal.lib.state.States; -import org.openbase.bco.dal.remote.action.RemoteAction; -import org.openbase.jul.exception.*; -import org.openbase.jul.exception.InstantiationException; -import org.openbase.jul.exception.printer.ExceptionPrinter; -import org.openbase.jul.exception.printer.LogLevel; -import org.openbase.jul.iface.TimedProcessable; -import org.openbase.jul.schedule.FutureProcessor; -import org.openbase.type.domotic.action.ActionDescriptionType.ActionDescription; -import org.openbase.type.domotic.action.ActionInitiatorType.ActionInitiator.InitiatorType; -import org.openbase.type.domotic.action.ActionParameterType.ActionParameter; -import org.openbase.type.domotic.action.ActionPriorityType.ActionPriority.Priority; -import org.openbase.type.domotic.service.ServiceTemplateType.ServiceTemplate.ServiceType; -import org.openbase.type.domotic.state.ActivationStateType.ActivationState; -import java.io.Serializable; -import java.util.concurrent.Future; -import java.util.concurrent.TimeUnit; -import java.util.concurrent.TimeoutException; - -/** - * @param the data type of this unit used for the state synchronization. - * @param the builder used to build the unit data instance. - * - * @author Divine Threepwood - */ -public abstract class AbstractExecutableBaseUnitController> extends AbstractBaseUnitController implements ActivationStateProviderService { - - public static final String FIELD_ACTIVATION_STATE = "activation_state"; - public static final String FIELD_AUTOSTART = "autostart"; - - public AbstractExecutableBaseUnitController(final DB builder) throws org.openbase.jul.exception.InstantiationException { - super(builder); - try { - registerOperationService(ServiceType.ACTIVATION_STATE_SERVICE, new ActivationStateOperationServiceImpl(this)); - } catch (CouldNotPerformException ex) { - throw new InstantiationException(this, ex); - } - } - - @Override - public void activate() throws CouldNotPerformException, InterruptedException { - super.activate(); - try { - // setup autostart - if (detectAutostart()) { - final ActionParameter.Builder actionParameter = ActionDescriptionProcessor.generateDefaultActionParameter(States.Activation.ACTIVE, ServiceType.ACTIVATION_STATE_SERVICE, this); - actionParameter.setInterruptible(true); - actionParameter.setSchedulable(true); - actionParameter.setPriority(Priority.NO); - actionParameter.getActionInitiatorBuilder().setInitiatorType(InitiatorType.SYSTEM); - actionParameter.setExecutionTimePeriod(TimeUnit.MILLISECONDS.toMicros(TimedProcessable.INFINITY_TIMEOUT)); - new RemoteAction(applyAction(actionParameter), this::isActive); - } - } catch (CouldNotPerformException ex) { - throw new CouldNotPerformException("Could not autostart " + this, ex); - } - } - - @Override - public void deactivate() throws CouldNotPerformException, InterruptedException { - cancelAllActions(); - super.deactivate(); - } - - private boolean detectAutostart() { - try { - return isAutostartEnabled(); - } catch (CouldNotPerformException ex) { - ExceptionPrinter.printHistory(new NotSupportedException("autostart", this, ex), logger, LogLevel.WARN); - return false; - } - } - - protected abstract boolean isAutostartEnabled() throws CouldNotPerformException; - - protected abstract ActionDescription execute(final ActivationState activationState) throws CouldNotPerformException, InterruptedException; - - protected abstract void stop(final ActivationState activationState) throws CouldNotPerformException, InterruptedException; - - public class ActivationStateOperationServiceImpl implements ActivationStateOperationService { - - private final ServiceProvider serviceProvider; - - public ActivationStateOperationServiceImpl(ServiceProvider serviceProvider) { - this.serviceProvider = serviceProvider; - } - - @Override - public Future setActivationState(final ActivationState activationState) { - try { - - switch (activationState.getValue()) { - case ACTIVE: - applyServiceState(activationState, ServiceType.ACTIVATION_STATE_SERVICE); - execute(activationState); - break; - case INACTIVE: - case UNKNOWN: - stop(activationState); - applyServiceState(activationState, ServiceType.ACTIVATION_STATE_SERVICE); - break; - } - - return FutureProcessor.completedFuture(activationState.getResponsibleAction()); - } catch (CouldNotPerformException | InterruptedException ex) { - return FutureProcessor.canceledFuture(ActionDescription.class, ex); - } - } - - @Override - public ServiceProvider getServiceProvider() { - return serviceProvider; - } - } -} diff --git a/module/dal/control/src/main/java/org/openbase/bco/dal/control/layer/unit/AbstractExecutableBaseUnitController.kt b/module/dal/control/src/main/java/org/openbase/bco/dal/control/layer/unit/AbstractExecutableBaseUnitController.kt new file mode 100644 index 0000000000..2141bb02e0 --- /dev/null +++ b/module/dal/control/src/main/java/org/openbase/bco/dal/control/layer/unit/AbstractExecutableBaseUnitController.kt @@ -0,0 +1,146 @@ +package org.openbase.bco.dal.control.layer.unit + +import com.google.protobuf.AbstractMessage +import org.openbase.bco.dal.lib.action.ActionDescriptionProcessor +import org.openbase.bco.dal.lib.layer.service.ServiceProvider +import org.openbase.bco.dal.lib.layer.service.operation.ActivationStateOperationService +import org.openbase.bco.dal.lib.layer.service.provider.ActivationStateProviderService +import org.openbase.bco.dal.lib.state.States +import org.openbase.bco.dal.remote.action.RemoteAction +import org.openbase.jul.exception.CouldNotPerformException +import org.openbase.jul.exception.InstantiationException +import org.openbase.jul.exception.printer.ExceptionPrinter +import org.openbase.jul.exception.printer.LogLevel +import org.openbase.jul.exception.tryOrNull +import org.openbase.jul.iface.TimedProcessable +import org.openbase.jul.schedule.FutureProcessor +import org.openbase.type.domotic.action.ActionDescriptionType.ActionDescription +import org.openbase.type.domotic.action.ActionInitiatorType.ActionInitiator.InitiatorType +import org.openbase.type.domotic.action.ActionPriorityType +import org.openbase.type.domotic.service.ServiceTemplateType +import org.openbase.type.domotic.state.ActivationStateType.ActivationState +import org.openbase.type.domotic.unit.UnitConfigType.UnitConfig +import java.io.Serializable +import java.util.concurrent.Future +import java.util.concurrent.TimeUnit + +/** + * @param the data type of this unit used for the state synchronization. + * @param the builder used to build the unit data instance. + * + * @author [Divine Threepwood](mailto:divine@openbase.org) + */ +abstract class AbstractExecutableBaseUnitController>(builder: DB) : + AbstractBaseUnitController(builder), + ActivationStateProviderService where D : AbstractMessage?, D : Serializable? { + init { + try { + registerOperationService( + ServiceTemplateType.ServiceTemplate.ServiceType.ACTIVATION_STATE_SERVICE, + ActivationStateOperationServiceImpl( + this + ) + ) + } catch (ex: CouldNotPerformException) { + throw InstantiationException(this, ex) + } + } + + @Throws(CouldNotPerformException::class, InterruptedException::class) + override fun activate() { + super.activate() + handleAutostart() + } + + @Throws(CouldNotPerformException::class, InterruptedException::class) + override fun deactivate() { + cancelAllActions() + super.deactivate() + } + + @Throws(CouldNotPerformException::class, InterruptedException::class) + override fun applyConfigUpdate(config: UnitConfig): UnitConfig { + getManageWriteLockInterruptible(this).use { _ -> + val originalConfig = tryOrNull { getConfig() } + return super.applyConfigUpdate(config).also { updatedConfig -> + originalConfig?.let { + if (isAutostartEnabled(it) != isAutostartEnabled(updatedConfig)) { + handleAutostart() + } + } + } + } + } + + private fun handleAutostart() { + if (!isAutostartEnabled()) { + return + } + + try { + val actionParameter = ActionDescriptionProcessor.generateDefaultActionParameter( + States.Activation.ACTIVE, + ServiceTemplateType.ServiceTemplate.ServiceType.ACTIVATION_STATE_SERVICE, + this + ) + actionParameter.setInterruptible(true) + actionParameter.setSchedulable(true) + actionParameter.setPriority(ActionPriorityType.ActionPriority.Priority.NO) + actionParameter.actionInitiatorBuilder.setInitiatorType(InitiatorType.SYSTEM) + actionParameter.setExecutionTimePeriod(TimeUnit.MILLISECONDS.toMicros(TimedProcessable.INFINITY_TIMEOUT)) + RemoteAction(applyAction(actionParameter)) { this.isActive } + } catch (ex: CouldNotPerformException) { + ExceptionPrinter.printHistory("Could not autostart $this", ex, logger, LogLevel.ERROR) + } + } + + protected abstract fun isAutostartEnabled(config: UnitConfig? = tryOrNull { getConfig() }): Boolean + + @Throws(CouldNotPerformException::class, InterruptedException::class) + protected abstract fun execute(activationState: ActivationState): ActionDescription? + + @Throws(CouldNotPerformException::class, InterruptedException::class) + protected abstract fun stop(activationState: ActivationState) + + inner class ActivationStateOperationServiceImpl(private val serviceProvider: ServiceProvider<*>) : + ActivationStateOperationService { + override fun setActivationState(activationState: ActivationState): Future { + try { + when (activationState.value) { + ActivationState.State.ACTIVE -> { + applyServiceState( + activationState, + ServiceTemplateType.ServiceTemplate.ServiceType.ACTIVATION_STATE_SERVICE + ) + execute(activationState) + } + + ActivationState.State.INACTIVE, ActivationState.State.UNKNOWN -> { + stop(activationState) + applyServiceState( + activationState, + ServiceTemplateType.ServiceTemplate.ServiceType.ACTIVATION_STATE_SERVICE + ) + } + + else -> { + throw CouldNotPerformException("Unsupported activation state: ${activationState.value}") + } + } + return FutureProcessor.completedFuture(activationState.responsibleAction) + } catch (ex: CouldNotPerformException) { + return FutureProcessor.canceledFuture( + ActionDescription::class.java, ex + ) + } catch (ex: InterruptedException) { + return FutureProcessor.canceledFuture( + ActionDescription::class.java, ex + ) + } + } + + override fun getServiceProvider(): ServiceProvider<*> { + return serviceProvider + } + } +} diff --git a/module/dal/control/src/main/java/org/openbase/bco/dal/control/layer/unit/AbstractUnitController.java b/module/dal/control/src/main/java/org/openbase/bco/dal/control/layer/unit/AbstractUnitController.java index 3164d573d3..dfb263371e 100644 --- a/module/dal/control/src/main/java/org/openbase/bco/dal/control/layer/unit/AbstractUnitController.java +++ b/module/dal/control/src/main/java/org/openbase/bco/dal/control/layer/unit/AbstractUnitController.java @@ -1935,7 +1935,7 @@ public void activate() throws InterruptedException, CouldNotPerformException { * * @throws CouldNotPerformException is thrown if the type of the service is already registered. */ - protected void registerOperationService(final ServiceType serviceType, final OperationService operationService) throws CouldNotPerformException { + final protected void registerOperationService(final ServiceType serviceType, final OperationService operationService) throws CouldNotPerformException { if (operationServiceMap.containsKey(serviceType)) { throw new VerificationFailedException("OperationService for Type[" + serviceType.name() + "] already registered!"); diff --git a/module/dal/control/src/main/java/org/openbase/bco/dal/control/layer/unit/agent/AbstractAgentController.java b/module/dal/control/src/main/java/org/openbase/bco/dal/control/layer/unit/agent/AbstractAgentController.java deleted file mode 100644 index 23cfead1de..0000000000 --- a/module/dal/control/src/main/java/org/openbase/bco/dal/control/layer/unit/agent/AbstractAgentController.java +++ /dev/null @@ -1,60 +0,0 @@ -package org.openbase.bco.dal.control.layer.unit.agent; - -/* - * #%L - * BCO DAL Control - * %% - * Copyright (C) 2014 - 2021 openbase.org - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program. If not, see - * . - * #L% - */ - -import org.openbase.bco.dal.control.layer.unit.AbstractAuthorizedBaseUnitController; -import org.openbase.bco.dal.lib.layer.unit.agent.AgentController; -import org.openbase.bco.registry.remote.Registries; -import org.openbase.jul.exception.CouldNotPerformException; -import org.openbase.jul.exception.InstantiationException; -import org.openbase.type.domotic.unit.agent.AgentDataType.AgentData.Builder; -import org.openbase.type.domotic.action.ActionParameterType.ActionParameter; -import org.openbase.type.domotic.unit.UnitConfigType.UnitConfig; -import org.openbase.type.domotic.unit.agent.AgentClassType.AgentClass; -import org.openbase.type.domotic.unit.agent.AgentDataType; -import org.openbase.type.domotic.unit.agent.AgentDataType.AgentData; - -/** - * @author Divine Threepwood - */ -public abstract class AbstractAgentController extends AbstractAuthorizedBaseUnitController implements AgentController { - - public AbstractAgentController() throws InstantiationException { - super(AgentDataType.AgentData.newBuilder()); - } - - @Override - protected ActionParameter.Builder getActionParameterTemplate(final UnitConfig config) throws InterruptedException, CouldNotPerformException { - final AgentClass agentClass = Registries.getClassRegistry(true).getAgentClassById(config.getAgentConfig().getAgentClassId()); - return ActionParameter.newBuilder() - .addAllCategory(agentClass.getCategoryList()) - .setPriority(agentClass.getPriority()) - .setSchedulable(agentClass.getSchedulable()) - .setInterruptible(agentClass.getInterruptible()); - } - - @Override - protected boolean isAutostartEnabled() throws CouldNotPerformException { - return getConfig().getAgentConfig().getAutostart(); - } -} diff --git a/module/dal/control/src/main/java/org/openbase/bco/dal/control/layer/unit/agent/AbstractAgentController.kt b/module/dal/control/src/main/java/org/openbase/bco/dal/control/layer/unit/agent/AbstractAgentController.kt new file mode 100644 index 0000000000..5ada887532 --- /dev/null +++ b/module/dal/control/src/main/java/org/openbase/bco/dal/control/layer/unit/agent/AbstractAgentController.kt @@ -0,0 +1,31 @@ +package org.openbase.bco.dal.control.layer.unit.agent + +import org.openbase.bco.dal.control.layer.unit.AbstractAuthorizedBaseUnitController +import org.openbase.bco.dal.lib.layer.unit.agent.AgentController +import org.openbase.bco.registry.remote.Registries +import org.openbase.jul.exception.CouldNotPerformException +import org.openbase.type.domotic.action.ActionParameterType +import org.openbase.type.domotic.unit.UnitConfigType +import org.openbase.type.domotic.unit.UnitConfigType.UnitConfig +import org.openbase.type.domotic.unit.agent.AgentDataType + +/** + * @author [Divine Threepwood](mailto:divine@openbase.org) + */ +abstract class AbstractAgentController : + AbstractAuthorizedBaseUnitController( + AgentDataType.AgentData.newBuilder() + ), AgentController { + @Throws(InterruptedException::class, CouldNotPerformException::class) + override fun getActionParameterTemplate(config: UnitConfigType.UnitConfig): ActionParameterType.ActionParameter.Builder { + val agentClass = Registries.getClassRegistry(true).getAgentClassById(config.agentConfig.agentClassId) + return ActionParameterType.ActionParameter.newBuilder() + .addAllCategory(agentClass.categoryList) + .setPriority(agentClass.priority) + .setSchedulable(agentClass.schedulable) + .setInterruptible(agentClass.interruptible) + } + + override fun isAutostartEnabled(config: UnitConfig?): Boolean = + config?.agentConfig?.autostart ?: false +} diff --git a/module/dal/control/src/main/java/org/openbase/bco/dal/control/layer/unit/agent/AgentControllerFactoryImpl.java b/module/dal/control/src/main/java/org/openbase/bco/dal/control/layer/unit/agent/AgentControllerFactoryImpl.java deleted file mode 100644 index bdace7f911..0000000000 --- a/module/dal/control/src/main/java/org/openbase/bco/dal/control/layer/unit/agent/AgentControllerFactoryImpl.java +++ /dev/null @@ -1,102 +0,0 @@ -package org.openbase.bco.dal.control.layer.unit.agent; - -/* - * #%L - * BCO DAL Control - * %% - * Copyright (C) 2014 - 2021 openbase.org - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program. If not, see - * . - * #L% - */ - -import org.openbase.bco.dal.lib.layer.unit.agent.Agent; -import org.openbase.bco.dal.lib.layer.unit.agent.AgentController; -import org.openbase.bco.dal.lib.layer.unit.agent.AgentControllerFactory; -import org.openbase.bco.registry.remote.Registries; -import org.openbase.jul.exception.CouldNotPerformException; -import org.openbase.jul.exception.NotAvailableException; -import org.openbase.jul.extension.type.processing.LabelProcessor; -import org.openbase.jul.extension.type.processing.MetaConfigVariableProvider; -import org.openbase.jul.processing.StringProcessor; -import org.openbase.type.domotic.unit.UnitConfigType.UnitConfig; -import org.openbase.type.domotic.unit.agent.AgentClassType.AgentClass; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.lang.reflect.InvocationTargetException; -import java.util.Locale; - -/** - * @author Divine Threepwood - */ -public class AgentControllerFactoryImpl implements AgentControllerFactory { - - protected final Logger logger = LoggerFactory.getLogger(AgentControllerFactoryImpl.class); - private static AgentControllerFactoryImpl instance; - - public static final String META_CONFIG_KEY_AGENT_CLASS_PREFIX = "AGENT_CLASS_PREFIX"; - - private static final String PRESET_AGENT_PACKAGE_PREFIX = "org.openbase.bco.app.preset"; - private static final String CUSTOM_AGENT_PACKAGE_PREFIX = "org.openbase.bco.app"; - - public synchronized static AgentControllerFactoryImpl getInstance() { - if (instance == null) { - instance = new AgentControllerFactoryImpl(); - } - return instance; - } - - private AgentControllerFactoryImpl() { - } - - @Override - public AgentController newInstance(final UnitConfig agentUnitConfig) throws org.openbase.jul.exception.InstantiationException { - AgentController agent; - try { - if (agentUnitConfig == null) { - throw new NotAvailableException("AgentConfig"); - } - - Registries.waitForData(); - final AgentClass agentClass = Registries.getClassRegistry().getAgentClassById(agentUnitConfig.getAgentConfig().getAgentClassId()); - final MetaConfigVariableProvider variableProvider = new MetaConfigVariableProvider("AgentClass", agentClass.getMetaConfig()); - - final String agentClassPrefix = variableProvider.getValue( - META_CONFIG_KEY_AGENT_CLASS_PREFIX, - StringProcessor.removeWhiteSpaces(LabelProcessor.getLabelByLanguage(Locale.ENGLISH, agentClass.getLabel()))); - - try { - // try to load preset agent - String className = PRESET_AGENT_PACKAGE_PREFIX - + ".agent" - + "." + agentClassPrefix + "Agent"; - agent = (AgentController) Thread.currentThread().getContextClassLoader().loadClass(className).getConstructor().newInstance(); - } catch (ClassNotFoundException | SecurityException | InstantiationException | IllegalAccessException | IllegalArgumentException | NoSuchMethodException | InvocationTargetException ex) { - // try to load custom agent - String className = CUSTOM_AGENT_PACKAGE_PREFIX - + "." + StringProcessor.removeWhiteSpaces(agentClassPrefix).toLowerCase() - + ".agent" - + "." + StringProcessor.transformToPascalCase(StringProcessor.removeWhiteSpaces(agentClassPrefix)) + "Agent"; - agent = (AgentController) Thread.currentThread().getContextClassLoader().loadClass(className).getConstructor().newInstance(); - } - logger.debug("Creating agent of type [" + LabelProcessor.getBestMatch(agentClass.getLabel()) + "]"); - agent.init(agentUnitConfig); - } catch (CouldNotPerformException | ClassNotFoundException | SecurityException | InstantiationException | IllegalAccessException | IllegalArgumentException | InterruptedException | NoSuchMethodException | InvocationTargetException ex) { - throw new org.openbase.jul.exception.InstantiationException(Agent.class, agentUnitConfig.getId(), ex); - } - return agent; - } -} diff --git a/module/dal/control/src/main/java/org/openbase/bco/dal/control/layer/unit/agent/AgentControllerFactoryImpl.kt b/module/dal/control/src/main/java/org/openbase/bco/dal/control/layer/unit/agent/AgentControllerFactoryImpl.kt new file mode 100644 index 0000000000..79bd946131 --- /dev/null +++ b/module/dal/control/src/main/java/org/openbase/bco/dal/control/layer/unit/agent/AgentControllerFactoryImpl.kt @@ -0,0 +1,135 @@ +package org.openbase.bco.dal.control.layer.unit.agent + +import org.openbase.bco.dal.lib.layer.unit.agent.Agent +import org.openbase.bco.dal.lib.layer.unit.agent.AgentController +import org.openbase.bco.dal.lib.layer.unit.agent.AgentControllerFactory +import org.openbase.bco.registry.remote.Registries +import org.openbase.jul.exception.CouldNotPerformException +import org.openbase.jul.exception.NotAvailableException +import org.openbase.jul.extension.type.processing.LabelProcessor.getBestMatch +import org.openbase.jul.extension.type.processing.LabelProcessor.getLabelByLanguage +import org.openbase.jul.extension.type.processing.MetaConfigVariableProvider +import org.openbase.jul.processing.StringProcessor +import org.openbase.type.domotic.unit.UnitConfigType +import org.slf4j.Logger +import org.slf4j.LoggerFactory +import java.lang.reflect.InvocationTargetException +import java.util.* + +/** + * @author [Divine Threepwood](mailto:divine@openbase.org) + */ +class AgentControllerFactoryImpl private constructor() : AgentControllerFactory { + protected val logger: Logger = LoggerFactory.getLogger(AgentControllerFactoryImpl::class.java) + + @Throws(org.openbase.jul.exception.InstantiationException::class) + override fun newInstance(agentUnitConfig: UnitConfigType.UnitConfig): AgentController { + var agent: AgentController + try { + if (agentUnitConfig == null) { + throw NotAvailableException("AgentConfig") + } + + Registries.waitForData() + val agentClass = Registries.getClassRegistry().getAgentClassById(agentUnitConfig.agentConfig.agentClassId) + val variableProvider = MetaConfigVariableProvider("AgentClass", agentClass.metaConfig) + + val agentClassPrefix = variableProvider.getValue( + META_CONFIG_KEY_AGENT_CLASS_PREFIX, + StringProcessor.removeWhiteSpaces(getLabelByLanguage(Locale.ENGLISH, agentClass.label)) + ) + + try { + // try to load preset agent + val className = (PRESET_AGENT_PACKAGE_PREFIX + + ".agent" + + "." + agentClassPrefix + "Agent") + agent = Thread.currentThread().contextClassLoader.loadClass(className).getConstructor() + .newInstance() as AgentController + } catch (ex: ClassNotFoundException) { + // try to load custom agent + val className = (CUSTOM_AGENT_PACKAGE_PREFIX + + "." + StringProcessor.removeWhiteSpaces(agentClassPrefix).lowercase(Locale.getDefault()) + + ".agent" + + "." + StringProcessor.transformToPascalCase(StringProcessor.removeWhiteSpaces(agentClassPrefix)) + "Agent") + agent = Thread.currentThread().contextClassLoader.loadClass(className).getConstructor() + .newInstance() as AgentController + } catch (ex: SecurityException) { + val className = (CUSTOM_AGENT_PACKAGE_PREFIX + + "." + StringProcessor.removeWhiteSpaces(agentClassPrefix).lowercase(Locale.getDefault()) + + ".agent" + + "." + StringProcessor.transformToPascalCase(StringProcessor.removeWhiteSpaces(agentClassPrefix)) + "Agent") + agent = Thread.currentThread().contextClassLoader.loadClass(className).getConstructor() + .newInstance() as AgentController + } catch (ex: InstantiationException) { + val className = (CUSTOM_AGENT_PACKAGE_PREFIX + + "." + StringProcessor.removeWhiteSpaces(agentClassPrefix).lowercase(Locale.getDefault()) + + ".agent" + + "." + StringProcessor.transformToPascalCase(StringProcessor.removeWhiteSpaces(agentClassPrefix)) + "Agent") + agent = Thread.currentThread().contextClassLoader.loadClass(className).getConstructor() + .newInstance() as AgentController + } catch (ex: IllegalAccessException) { + val className = (CUSTOM_AGENT_PACKAGE_PREFIX + + "." + StringProcessor.removeWhiteSpaces(agentClassPrefix).lowercase(Locale.getDefault()) + + ".agent" + + "." + StringProcessor.transformToPascalCase(StringProcessor.removeWhiteSpaces(agentClassPrefix)) + "Agent") + agent = Thread.currentThread().contextClassLoader.loadClass(className).getConstructor() + .newInstance() as AgentController + } catch (ex: IllegalArgumentException) { + val className = (CUSTOM_AGENT_PACKAGE_PREFIX + + "." + StringProcessor.removeWhiteSpaces(agentClassPrefix).lowercase(Locale.getDefault()) + + ".agent" + + "." + StringProcessor.transformToPascalCase(StringProcessor.removeWhiteSpaces(agentClassPrefix)) + "Agent") + agent = Thread.currentThread().contextClassLoader.loadClass(className).getConstructor() + .newInstance() as AgentController + } catch (ex: NoSuchMethodException) { + val className = (CUSTOM_AGENT_PACKAGE_PREFIX + + "." + StringProcessor.removeWhiteSpaces(agentClassPrefix).lowercase(Locale.getDefault()) + + ".agent" + + "." + StringProcessor.transformToPascalCase(StringProcessor.removeWhiteSpaces(agentClassPrefix)) + "Agent") + agent = Thread.currentThread().contextClassLoader.loadClass(className).getConstructor() + .newInstance() as AgentController + } catch (ex: InvocationTargetException) { + val className = (CUSTOM_AGENT_PACKAGE_PREFIX + + "." + StringProcessor.removeWhiteSpaces(agentClassPrefix).lowercase(Locale.getDefault()) + + ".agent" + + "." + StringProcessor.transformToPascalCase(StringProcessor.removeWhiteSpaces(agentClassPrefix)) + "Agent") + agent = Thread.currentThread().contextClassLoader.loadClass(className).getConstructor() + .newInstance() as AgentController + } + logger.debug("Creating agent of type [" + getBestMatch(agentClass.label) + "]") + agent.init(agentUnitConfig) + } catch (ex: CouldNotPerformException) { + throw org.openbase.jul.exception.InstantiationException(Agent::class.java, agentUnitConfig.id, ex) + } catch (ex: ClassNotFoundException) { + throw org.openbase.jul.exception.InstantiationException(Agent::class.java, agentUnitConfig.id, ex) + } catch (ex: SecurityException) { + throw org.openbase.jul.exception.InstantiationException(Agent::class.java, agentUnitConfig.id, ex) + } catch (ex: InstantiationException) { + throw org.openbase.jul.exception.InstantiationException(Agent::class.java, agentUnitConfig.id, ex) + } catch (ex: IllegalAccessException) { + throw org.openbase.jul.exception.InstantiationException(Agent::class.java, agentUnitConfig.id, ex) + } catch (ex: IllegalArgumentException) { + throw org.openbase.jul.exception.InstantiationException(Agent::class.java, agentUnitConfig.id, ex) + } catch (ex: InterruptedException) { + throw org.openbase.jul.exception.InstantiationException(Agent::class.java, agentUnitConfig.id, ex) + } catch (ex: NoSuchMethodException) { + throw org.openbase.jul.exception.InstantiationException(Agent::class.java, agentUnitConfig.id, ex) + } catch (ex: InvocationTargetException) { + throw org.openbase.jul.exception.InstantiationException(Agent::class.java, agentUnitConfig.id, ex) + } + return agent + } + + companion object { + @get:Synchronized + @JvmStatic + var instance: AgentControllerFactoryImpl = AgentControllerFactoryImpl() + private set + + const val META_CONFIG_KEY_AGENT_CLASS_PREFIX: String = "AGENT_CLASS_PREFIX" + + private const val PRESET_AGENT_PACKAGE_PREFIX = "org.openbase.bco.app.preset" + private const val CUSTOM_AGENT_PACKAGE_PREFIX = "org.openbase.bco.app" + } +} diff --git a/module/dal/control/src/main/java/org/openbase/bco/dal/control/layer/unit/agent/AgentManagerImpl.java b/module/dal/control/src/main/java/org/openbase/bco/dal/control/layer/unit/agent/AgentManagerImpl.java deleted file mode 100644 index 20e0e6536f..0000000000 --- a/module/dal/control/src/main/java/org/openbase/bco/dal/control/layer/unit/agent/AgentManagerImpl.java +++ /dev/null @@ -1,95 +0,0 @@ -package org.openbase.bco.dal.control.layer.unit.agent; - -/* - * #%L - * BCO DAL Control - * %% - * Copyright (C) 2014 - 2021 openbase.org - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program. If not, see - * . - * #L% - * - * @author Divine Threepwood - * - */ - -import org.openbase.bco.dal.control.layer.unit.UnitControllerRegistrySynchronizer; -import org.openbase.bco.dal.lib.layer.unit.UnitControllerRegistry; -import org.openbase.bco.dal.lib.layer.unit.UnitControllerRegistryImpl; -import org.openbase.bco.dal.lib.layer.unit.agent.AgentController; -import org.openbase.bco.dal.lib.layer.unit.agent.AgentControllerFactory; -import org.openbase.bco.dal.lib.layer.unit.agent.AgentManager; -import org.openbase.bco.registry.remote.login.BCOLogin; -import org.openbase.bco.registry.remote.Registries; -import org.openbase.jul.exception.CouldNotPerformException; -import org.openbase.jul.exception.InstantiationException; -import org.openbase.jul.iface.Launchable; -import org.openbase.jul.iface.VoidInitializable; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -public class AgentManagerImpl implements AgentManager, Launchable, VoidInitializable { - - protected static final Logger LOGGER = LoggerFactory.getLogger(AgentManagerImpl.class); - - private final AgentControllerFactory factory; - private final UnitControllerRegistry agentControllerRegistry; - private final UnitControllerRegistrySynchronizer agentRegistrySynchronizer; - - public AgentManagerImpl() throws InstantiationException { - try { - this.factory = AgentControllerFactoryImpl.getInstance(); - this.agentControllerRegistry = new UnitControllerRegistryImpl<>(); - this.agentRegistrySynchronizer = new UnitControllerRegistrySynchronizer<>(agentControllerRegistry, Registries.getUnitRegistry().getAgentUnitConfigRemoteRegistry(false), factory); - } catch (CouldNotPerformException ex) { - throw new org.openbase.jul.exception.InstantiationException(this, ex); - } - } - - @Override - public void init() { - // this has to stay, else do not implement VoidInitializable - } - - @Override - public void activate() throws CouldNotPerformException, InterruptedException { - BCOLogin.getSession().loginBCOUser(); - agentControllerRegistry.activate(); - agentRegistrySynchronizer.activate(); - } - - @Override - public boolean isActive() { - return agentRegistrySynchronizer.isActive() && - agentControllerRegistry.isActive(); - } - - @Override - public void deactivate() throws CouldNotPerformException, InterruptedException { - agentRegistrySynchronizer.deactivate(); - agentControllerRegistry.deactivate(); - } - - @Override - public void shutdown() { - agentRegistrySynchronizer.shutdown(); - agentControllerRegistry.shutdown(); - } - - @Override - public UnitControllerRegistry getAgentControllerRegistry() { - return agentControllerRegistry; - } -} diff --git a/module/dal/control/src/main/java/org/openbase/bco/dal/control/layer/unit/agent/AgentManagerImpl.kt b/module/dal/control/src/main/java/org/openbase/bco/dal/control/layer/unit/agent/AgentManagerImpl.kt new file mode 100644 index 0000000000..72f0ce2db8 --- /dev/null +++ b/module/dal/control/src/main/java/org/openbase/bco/dal/control/layer/unit/agent/AgentManagerImpl.kt @@ -0,0 +1,71 @@ +package org.openbase.bco.dal.control.layer.unit.agent + +import org.openbase.bco.dal.control.layer.unit.UnitControllerRegistrySynchronizer +import org.openbase.bco.dal.lib.layer.unit.UnitControllerRegistry +import org.openbase.bco.dal.lib.layer.unit.UnitControllerRegistryImpl +import org.openbase.bco.dal.lib.layer.unit.agent.AgentController +import org.openbase.bco.dal.lib.layer.unit.agent.AgentControllerFactory +import org.openbase.bco.dal.lib.layer.unit.agent.AgentManager +import org.openbase.bco.registry.remote.Registries +import org.openbase.bco.registry.remote.login.BCOLogin +import org.openbase.jul.exception.CouldNotPerformException +import org.openbase.jul.exception.InstantiationException +import org.openbase.jul.iface.Launchable +import org.openbase.jul.iface.VoidInitializable +import org.slf4j.Logger +import org.slf4j.LoggerFactory + +class AgentManagerImpl : AgentManager, Launchable, VoidInitializable { + private var factory: AgentControllerFactory + private var agentControllerRegistry: UnitControllerRegistry? = null + private var agentRegistrySynchronizer: UnitControllerRegistrySynchronizer? = null + + init { + try { + this.factory = AgentControllerFactoryImpl.instance + this.agentControllerRegistry = UnitControllerRegistryImpl() + this.agentRegistrySynchronizer = UnitControllerRegistrySynchronizer( + agentControllerRegistry, + Registries.getUnitRegistry().getAgentUnitConfigRemoteRegistry(false), + factory + ) + } catch (ex: CouldNotPerformException) { + throw InstantiationException(this, ex) + } + } + + override fun init() { + // this has to stay, else do not implement VoidInitializable + } + + @Throws(CouldNotPerformException::class, InterruptedException::class) + override fun activate() { + BCOLogin.getSession().loginBCOUser() + agentControllerRegistry!!.activate() + agentRegistrySynchronizer!!.activate() + } + + override fun isActive(): Boolean { + return agentRegistrySynchronizer!!.isActive && + agentControllerRegistry!!.isActive + } + + @Throws(CouldNotPerformException::class, InterruptedException::class) + override fun deactivate() { + agentRegistrySynchronizer!!.deactivate() + agentControllerRegistry!!.deactivate() + } + + override fun shutdown() { + agentRegistrySynchronizer!!.shutdown() + agentControllerRegistry!!.shutdown() + } + + override fun getAgentControllerRegistry(): UnitControllerRegistry { + return agentControllerRegistry!! + } + + companion object { + protected val LOGGER: Logger = LoggerFactory.getLogger(AgentManagerImpl::class.java) + } +} diff --git a/module/dal/control/src/main/java/org/openbase/bco/dal/control/layer/unit/agent/AgentManagerLauncher.java b/module/dal/control/src/main/java/org/openbase/bco/dal/control/layer/unit/agent/AgentManagerLauncher.java deleted file mode 100644 index 2d2487c50c..0000000000 --- a/module/dal/control/src/main/java/org/openbase/bco/dal/control/layer/unit/agent/AgentManagerLauncher.java +++ /dev/null @@ -1,49 +0,0 @@ -package org.openbase.bco.dal.control.layer.unit.agent; - -/* - * #%L - * BCO DAL Control - * %% - * Copyright (C) 2014 - 2021 openbase.org - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program. If not, see - * . - * #L% - * - * - * @author Divine Threepwood - */ -import org.openbase.bco.dal.lib.layer.unit.agent.AgentManager; -import org.openbase.bco.authentication.lib.BCO; -import org.openbase.jul.pattern.launch.AbstractLauncher; -import org.openbase.jul.exception.InstantiationException; - -public class AgentManagerLauncher extends AbstractLauncher { - - public AgentManagerLauncher() throws InstantiationException { - super(AgentManager.class, AgentManagerImpl.class); - } - - @Override - protected void loadProperties() { - } - - /** - * @param args the command line arguments - */ - public static void main(final String[] args) { - BCO.printLogo(); - AbstractLauncher.main(BCO.class, AgentManager.class, args, AgentManagerLauncher.class); - } -} diff --git a/module/dal/control/src/main/java/org/openbase/bco/dal/control/layer/unit/agent/AgentManagerLauncher.kt b/module/dal/control/src/main/java/org/openbase/bco/dal/control/layer/unit/agent/AgentManagerLauncher.kt new file mode 100644 index 0000000000..7e154aebd5 --- /dev/null +++ b/module/dal/control/src/main/java/org/openbase/bco/dal/control/layer/unit/agent/AgentManagerLauncher.kt @@ -0,0 +1,22 @@ +package org.openbase.bco.dal.control.layer.unit.agent + +import org.openbase.bco.authentication.lib.BCO +import org.openbase.bco.dal.lib.layer.unit.agent.AgentManager +import org.openbase.jul.pattern.launch.AbstractLauncher + +class AgentManagerLauncher : + AbstractLauncher(AgentManager::class.java, AgentManagerImpl::class.java) { + override fun loadProperties() { + } + + companion object { + /** + * @param args the command line arguments + */ + @JvmStatic + fun main(args: Array) { + BCO.printLogo() + main(BCO::class.java, AgentManager::class.java, args, AgentManagerLauncher::class.java) + } + } +} diff --git a/module/dal/control/src/main/java/org/openbase/bco/dal/control/layer/unit/app/AbstractAppController.java b/module/dal/control/src/main/java/org/openbase/bco/dal/control/layer/unit/app/AbstractAppController.java deleted file mode 100644 index 68782e8cf7..0000000000 --- a/module/dal/control/src/main/java/org/openbase/bco/dal/control/layer/unit/app/AbstractAppController.java +++ /dev/null @@ -1,107 +0,0 @@ -package org.openbase.bco.dal.control.layer.unit.app; - -/* - * #%L - * BCO DAL Control - * %% - * Copyright (C) 2014 - 2021 openbase.org - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program. If not, see - * . - * #L% - */ -import org.openbase.bco.dal.control.layer.unit.AbstractAuthorizedBaseUnitController; -import org.openbase.bco.dal.lib.layer.service.OperationServiceFactory; -import org.openbase.bco.dal.lib.layer.service.UnitDataSourceFactory; -import org.openbase.bco.dal.lib.layer.unit.UnitController; -import org.openbase.bco.dal.lib.layer.unit.app.AppController; -import org.openbase.bco.registry.remote.Registries; -import org.openbase.jul.exception.CouldNotPerformException; -import org.openbase.jul.exception.NotAvailableException; -import org.openbase.jul.exception.NotSupportedException; -import org.openbase.type.domotic.action.ActionParameterType.ActionParameter; -import org.openbase.type.domotic.unit.app.AppClassType.AppClass; -import org.openbase.type.domotic.unit.app.AppDataType.AppData.Builder; -import org.openbase.type.domotic.unit.UnitConfigType.UnitConfig; -import org.openbase.type.domotic.unit.app.AppDataType.AppData; - -import java.util.Collections; -import java.util.List; - -/** - * - * * @author Tamino Huxohl - */ -public abstract class AbstractAppController extends AbstractAuthorizedBaseUnitController implements AppController { - - private final OperationServiceFactory operationServiceFactory; - private final UnitDataSourceFactory unitDataSourceFactory; - - public AbstractAppController() throws org.openbase.jul.exception.InstantiationException { - this(null, null); - } - - public AbstractAppController(final OperationServiceFactory operationServiceFactory, final UnitDataSourceFactory unitDataSourceFactory) throws org.openbase.jul.exception.InstantiationException { - super(AppData.newBuilder()); - this.operationServiceFactory = operationServiceFactory; - this.unitDataSourceFactory = unitDataSourceFactory; - } - - @Override - public OperationServiceFactory getOperationServiceFactory() throws NotAvailableException { - if (operationServiceFactory == null) { - throw new NotAvailableException("ServiceFactory", new NotSupportedException("Unit hosting", this)); - } - return operationServiceFactory; - } - - @Override - public UnitDataSourceFactory getUnitDataSourceFactory() throws NotAvailableException { - if (unitDataSourceFactory == null) { - throw new NotAvailableException("UnitDataSourceFactory", new NotSupportedException("UnitDataSource", this)); - } - return unitDataSourceFactory; - } - - @Override - protected ActionParameter.Builder getActionParameterTemplate(final UnitConfig config) throws InterruptedException, CouldNotPerformException { - final AppClass appClass = Registries.getClassRegistry(true).getAppClassById(config.getAppConfig().getAppClassId()); - return ActionParameter.newBuilder() - .addAllCategory(appClass.getCategoryList()) - .setPriority(appClass.getPriority()); - } - - @Override - protected boolean isAutostartEnabled() throws CouldNotPerformException { - return getConfig().getAppConfig().getAutostart(); - } - - @Override - public List> getHostedUnitControllerList() { - // Method can be overwritten in case this app introduces further units. - return Collections.EMPTY_LIST; - } - - @Override - public UnitController getHostedUnitController(String id) throws NotAvailableException { - // Method can be overwritten in case this app introduces further units. - throw new NotAvailableException("UnitController", id); - } - - @Override - public List getHostedUnitConfigList() { - // Method can be overwritten in case this app introduces further units. - return Collections.EMPTY_LIST; - } -} diff --git a/module/dal/control/src/main/java/org/openbase/bco/dal/control/layer/unit/app/AbstractAppController.kt b/module/dal/control/src/main/java/org/openbase/bco/dal/control/layer/unit/app/AbstractAppController.kt new file mode 100644 index 0000000000..114446951c --- /dev/null +++ b/module/dal/control/src/main/java/org/openbase/bco/dal/control/layer/unit/app/AbstractAppController.kt @@ -0,0 +1,63 @@ +package org.openbase.bco.dal.control.layer.unit.app + +import org.openbase.bco.dal.control.layer.unit.AbstractAuthorizedBaseUnitController +import org.openbase.bco.dal.lib.layer.service.OperationServiceFactory +import org.openbase.bco.dal.lib.layer.service.UnitDataSourceFactory +import org.openbase.bco.dal.lib.layer.service.mock.OperationServiceFactoryMock +import org.openbase.bco.dal.lib.layer.unit.Unit +import org.openbase.bco.dal.lib.layer.unit.UnitController +import org.openbase.bco.dal.lib.layer.unit.app.AppController +import org.openbase.bco.registry.remote.Registries +import org.openbase.jul.exception.CouldNotPerformException +import org.openbase.jul.exception.NotAvailableException +import org.openbase.jul.iface.Activatable +import org.openbase.type.domotic.action.ActionParameterType +import org.openbase.type.domotic.unit.UnitConfigType +import org.openbase.type.domotic.unit.app.AppDataType.AppData +import java.util.* + +/** + * * @author [Tamino Huxohl](mailto:pleminoq@openbase.org) + */ +abstract class AbstractAppController( + private val operationServiceFactory: OperationServiceFactory = OperationServiceFactoryMock.getInstance(), + private val unitDataSourceFactory: UnitDataSourceFactory = object : UnitDataSourceFactory { + @Throws(InstantiationException::class) + override fun > newInstance(unit: UNIT): Activatable { + throw org.openbase.jul.exception.InstantiationException( + Unit::class.java, + UnsupportedOperationException("Not supported yet.") + ) + } + }, +) : AbstractAuthorizedBaseUnitController(AppData.newBuilder()), AppController { + + @Throws(NotAvailableException::class) + override fun getOperationServiceFactory(): OperationServiceFactory? = operationServiceFactory + + @Throws(NotAvailableException::class) + override fun getUnitDataSourceFactory(): UnitDataSourceFactory? = unitDataSourceFactory + + @Throws(InterruptedException::class, CouldNotPerformException::class) + override fun getActionParameterTemplate(config: UnitConfigType.UnitConfig): ActionParameterType.ActionParameter.Builder { + val appClass = Registries.getClassRegistry(true).getAppClassById(config.appConfig.appClassId) + return ActionParameterType.ActionParameter.newBuilder() + .addAllCategory(appClass.categoryList) + .setPriority(appClass.priority) + } + + override fun isAutostartEnabled(config: UnitConfigType.UnitConfig?): Boolean = + config?.appConfig?.autostart ?: false + + // Method can be overwritten in case this app introduces further units. + override fun getHostedUnitControllerList(): List?> = emptyList() + + @Throws(NotAvailableException::class) + override fun getHostedUnitController(id: String): UnitController<*, *> { + // Method can be overwritten in case this app introduces further units. + throw NotAvailableException("UnitController", id) + } + + // Method can be overwritten in case this app introduces further units. + override fun getHostedUnitConfigList(): List = emptyList() +} diff --git a/module/dal/control/src/main/java/org/openbase/bco/dal/control/layer/unit/app/AppControllerFactoryImpl.java b/module/dal/control/src/main/java/org/openbase/bco/dal/control/layer/unit/app/AppControllerFactoryImpl.java deleted file mode 100644 index 9c96835574..0000000000 --- a/module/dal/control/src/main/java/org/openbase/bco/dal/control/layer/unit/app/AppControllerFactoryImpl.java +++ /dev/null @@ -1,96 +0,0 @@ -package org.openbase.bco.dal.control.layer.unit.app; - -/* - * #%L - * BCO DAL Control - * %% - * Copyright (C) 2014 - 2021 openbase.org - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program. If not, see - * . - * #L% - */ - -import org.openbase.bco.dal.lib.layer.unit.app.App; -import org.openbase.bco.dal.lib.layer.unit.app.AppController; -import org.openbase.bco.dal.lib.layer.unit.app.AppControllerFactory; -import org.openbase.bco.registry.remote.Registries; -import org.openbase.jul.exception.CouldNotPerformException; -import org.openbase.jul.exception.NotAvailableException; -import org.openbase.jul.extension.type.processing.LabelProcessor; -import org.openbase.jul.processing.StringProcessor; -import org.openbase.type.domotic.unit.UnitConfigType.UnitConfig; -import org.openbase.type.domotic.unit.app.AppClassType.AppClass; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.lang.reflect.InvocationTargetException; -import java.util.Locale; - -/** - * @author Tamino Huxohl - */ -public class AppControllerFactoryImpl implements AppControllerFactory { - - protected final Logger logger = LoggerFactory.getLogger(AppControllerFactoryImpl.class); - private static AppControllerFactoryImpl instance; - - private static final String PRESET_APP_PACKAGE_PREFIX = "org.openbase.bco.app.preset"; - private static final String CUSTOM_APP_PACKAGE_PREFIX = "org.openbase.bco.app"; - - public synchronized static AppControllerFactoryImpl getInstance() { - if (instance == null) { - instance = new AppControllerFactoryImpl(); - } - return instance; - } - - private AppControllerFactoryImpl() { - } - - @Override - public AppController newInstance(final UnitConfig appUnitConfig) throws org.openbase.jul.exception.InstantiationException { - AppController app; - try { - if (appUnitConfig == null) { - throw new NotAvailableException("AppConfig"); - } - - Registries.waitForData(); - final AppClass appClass = Registries.getClassRegistry().getAppClassById(appUnitConfig.getAppConfig().getAppClassId()); - - try { - // try to load preset app - String className = PRESET_APP_PACKAGE_PREFIX - + "." + StringProcessor.removeWhiteSpaces(LabelProcessor.getLabelByLanguage(Locale.ENGLISH, appClass.getLabel())) + "App"; - app = (AppController) Thread.currentThread().getContextClassLoader().loadClass(className).getConstructor().newInstance(); - } catch (CouldNotPerformException | ClassNotFoundException | SecurityException | InstantiationException | - IllegalAccessException | IllegalArgumentException | NoSuchMethodException | - InvocationTargetException ex) { - // try to load custom app - String className = CUSTOM_APP_PACKAGE_PREFIX - + "." + StringProcessor.removeWhiteSpaces(LabelProcessor.getLabelByLanguage(Locale.ENGLISH, appClass.getLabel())).toLowerCase() - + "." + StringProcessor.transformToPascalCase(StringProcessor.removeWhiteSpaces(LabelProcessor.getLabelByLanguage(Locale.ENGLISH, appClass.getLabel()))) + "App"; - app = (AppController) Thread.currentThread().getContextClassLoader().loadClass(className).getConstructor().newInstance(); - } - logger.debug("Creating app of type [" + LabelProcessor.getBestMatch(appClass.getLabel()) + "]"); - app.init(appUnitConfig); - } catch (CouldNotPerformException | ClassNotFoundException | SecurityException | InstantiationException | - IllegalAccessException | IllegalArgumentException | InterruptedException | NoSuchMethodException | - InvocationTargetException ex) { - throw new org.openbase.jul.exception.InstantiationException(App.class, appUnitConfig.getId(), ex); - } - return app; - } -} diff --git a/module/dal/control/src/main/java/org/openbase/bco/dal/control/layer/unit/app/AppControllerFactoryImpl.kt b/module/dal/control/src/main/java/org/openbase/bco/dal/control/layer/unit/app/AppControllerFactoryImpl.kt new file mode 100644 index 0000000000..2cfe529745 --- /dev/null +++ b/module/dal/control/src/main/java/org/openbase/bco/dal/control/layer/unit/app/AppControllerFactoryImpl.kt @@ -0,0 +1,196 @@ +package org.openbase.bco.dal.control.layer.unit.app + +import org.openbase.bco.dal.lib.layer.unit.app.App +import org.openbase.bco.dal.lib.layer.unit.app.AppController +import org.openbase.bco.dal.lib.layer.unit.app.AppControllerFactory +import org.openbase.bco.registry.remote.Registries +import org.openbase.jul.exception.CouldNotPerformException +import org.openbase.jul.extension.type.processing.LabelProcessor.getBestMatch +import org.openbase.jul.extension.type.processing.LabelProcessor.getLabelByLanguage +import org.openbase.jul.processing.StringProcessor +import org.openbase.type.domotic.unit.UnitConfigType +import org.slf4j.Logger +import org.slf4j.LoggerFactory +import java.lang.reflect.InvocationTargetException +import java.util.* + +/** + * @author [Tamino Huxohl](mailto:pleminoq@openbase.org) + */ +class AppControllerFactoryImpl private constructor() : AppControllerFactory { + protected val logger: Logger = LoggerFactory.getLogger(AppControllerFactoryImpl::class.java) + + @Throws(org.openbase.jul.exception.InstantiationException::class) + override fun newInstance(appUnitConfig: UnitConfigType.UnitConfig): AppController { + var app: AppController + try { + + Registries.waitForData() + val appClass = Registries.getClassRegistry().getAppClassById(appUnitConfig.appConfig.appClassId) + + try { + // try to load preset app + val className = (PRESET_APP_PACKAGE_PREFIX + + "." + StringProcessor.removeWhiteSpaces( + getLabelByLanguage( + Locale.ENGLISH, + appClass.label + ) + ) + "App") + app = Thread.currentThread().contextClassLoader.loadClass(className).getConstructor() + .newInstance() as AppController + } catch (ex: CouldNotPerformException) { + // try to load custom app + val className = (CUSTOM_APP_PACKAGE_PREFIX + + "." + StringProcessor.removeWhiteSpaces(getLabelByLanguage(Locale.ENGLISH, appClass.label)) + .lowercase( + Locale.getDefault() + ) + + "." + StringProcessor.transformToPascalCase( + StringProcessor.removeWhiteSpaces( + getLabelByLanguage( + Locale.ENGLISH, appClass.label + ) + ) + ) + "App") + app = Thread.currentThread().contextClassLoader.loadClass(className).getConstructor() + .newInstance() as AppController + } catch (ex: ClassNotFoundException) { + val className = (CUSTOM_APP_PACKAGE_PREFIX + + "." + StringProcessor.removeWhiteSpaces(getLabelByLanguage(Locale.ENGLISH, appClass.label)) + .lowercase( + Locale.getDefault() + ) + + "." + StringProcessor.transformToPascalCase( + StringProcessor.removeWhiteSpaces( + getLabelByLanguage( + Locale.ENGLISH, appClass.label + ) + ) + ) + "App") + app = Thread.currentThread().contextClassLoader.loadClass(className).getConstructor() + .newInstance() as AppController + } catch (ex: SecurityException) { + val className = (CUSTOM_APP_PACKAGE_PREFIX + + "." + StringProcessor.removeWhiteSpaces(getLabelByLanguage(Locale.ENGLISH, appClass.label)) + .lowercase( + Locale.getDefault() + ) + + "." + StringProcessor.transformToPascalCase( + StringProcessor.removeWhiteSpaces( + getLabelByLanguage( + Locale.ENGLISH, appClass.label + ) + ) + ) + "App") + app = Thread.currentThread().contextClassLoader.loadClass(className).getConstructor() + .newInstance() as AppController + } catch (ex: InstantiationException) { + val className = (CUSTOM_APP_PACKAGE_PREFIX + + "." + StringProcessor.removeWhiteSpaces(getLabelByLanguage(Locale.ENGLISH, appClass.label)) + .lowercase( + Locale.getDefault() + ) + + "." + StringProcessor.transformToPascalCase( + StringProcessor.removeWhiteSpaces( + getLabelByLanguage( + Locale.ENGLISH, appClass.label + ) + ) + ) + "App") + app = Thread.currentThread().contextClassLoader.loadClass(className).getConstructor() + .newInstance() as AppController + } catch (ex: IllegalAccessException) { + val className = (CUSTOM_APP_PACKAGE_PREFIX + + "." + StringProcessor.removeWhiteSpaces(getLabelByLanguage(Locale.ENGLISH, appClass.label)) + .lowercase( + Locale.getDefault() + ) + + "." + StringProcessor.transformToPascalCase( + StringProcessor.removeWhiteSpaces( + getLabelByLanguage( + Locale.ENGLISH, appClass.label + ) + ) + ) + "App") + app = Thread.currentThread().contextClassLoader.loadClass(className).getConstructor() + .newInstance() as AppController + } catch (ex: IllegalArgumentException) { + val className = (CUSTOM_APP_PACKAGE_PREFIX + + "." + StringProcessor.removeWhiteSpaces(getLabelByLanguage(Locale.ENGLISH, appClass.label)) + .lowercase( + Locale.getDefault() + ) + + "." + StringProcessor.transformToPascalCase( + StringProcessor.removeWhiteSpaces( + getLabelByLanguage( + Locale.ENGLISH, appClass.label + ) + ) + ) + "App") + app = Thread.currentThread().contextClassLoader.loadClass(className).getConstructor() + .newInstance() as AppController + } catch (ex: NoSuchMethodException) { + val className = (CUSTOM_APP_PACKAGE_PREFIX + + "." + StringProcessor.removeWhiteSpaces(getLabelByLanguage(Locale.ENGLISH, appClass.label)) + .lowercase( + Locale.getDefault() + ) + + "." + StringProcessor.transformToPascalCase( + StringProcessor.removeWhiteSpaces( + getLabelByLanguage( + Locale.ENGLISH, appClass.label + ) + ) + ) + "App") + app = Thread.currentThread().contextClassLoader.loadClass(className).getConstructor() + .newInstance() as AppController + } catch (ex: InvocationTargetException) { + val className = (CUSTOM_APP_PACKAGE_PREFIX + + "." + StringProcessor.removeWhiteSpaces(getLabelByLanguage(Locale.ENGLISH, appClass.label)) + .lowercase( + Locale.getDefault() + ) + + "." + StringProcessor.transformToPascalCase( + StringProcessor.removeWhiteSpaces( + getLabelByLanguage( + Locale.ENGLISH, appClass.label + ) + ) + ) + "App") + app = Thread.currentThread().contextClassLoader.loadClass(className).getConstructor() + .newInstance() as AppController + } + logger.debug("Creating app of type [" + getBestMatch(appClass.label) + "]") + app.init(appUnitConfig) + } catch (ex: CouldNotPerformException) { + throw org.openbase.jul.exception.InstantiationException(App::class.java, appUnitConfig.id, ex) + } catch (ex: ClassNotFoundException) { + throw org.openbase.jul.exception.InstantiationException(App::class.java, appUnitConfig.id, ex) + } catch (ex: SecurityException) { + throw org.openbase.jul.exception.InstantiationException(App::class.java, appUnitConfig.id, ex) + } catch (ex: InstantiationException) { + throw org.openbase.jul.exception.InstantiationException(App::class.java, appUnitConfig.id, ex) + } catch (ex: IllegalAccessException) { + throw org.openbase.jul.exception.InstantiationException(App::class.java, appUnitConfig.id, ex) + } catch (ex: IllegalArgumentException) { + throw org.openbase.jul.exception.InstantiationException(App::class.java, appUnitConfig.id, ex) + } catch (ex: InterruptedException) { + throw org.openbase.jul.exception.InstantiationException(App::class.java, appUnitConfig.id, ex) + } catch (ex: NoSuchMethodException) { + throw org.openbase.jul.exception.InstantiationException(App::class.java, appUnitConfig.id, ex) + } catch (ex: InvocationTargetException) { + throw org.openbase.jul.exception.InstantiationException(App::class.java, appUnitConfig.id, ex) + } + return app + } + + companion object { + @get:Synchronized + var instance: AppControllerFactoryImpl = AppControllerFactoryImpl() + private set + + private const val PRESET_APP_PACKAGE_PREFIX = "org.openbase.bco.app.preset" + private const val CUSTOM_APP_PACKAGE_PREFIX = "org.openbase.bco.app" + } +} diff --git a/module/dal/control/src/main/java/org/openbase/bco/dal/control/layer/unit/app/AppManagerImpl.java b/module/dal/control/src/main/java/org/openbase/bco/dal/control/layer/unit/app/AppManagerImpl.java deleted file mode 100644 index de7e844f5b..0000000000 --- a/module/dal/control/src/main/java/org/openbase/bco/dal/control/layer/unit/app/AppManagerImpl.java +++ /dev/null @@ -1,111 +0,0 @@ -package org.openbase.bco.dal.control.layer.unit.app; - -/* - * #%L - * BCO DAL Control - * %% - * Copyright (C) 2014 - 2021 openbase.org - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program. If not, see - * . - * #L% - */ - -import org.openbase.bco.dal.control.layer.unit.UnitControllerRegistrySynchronizer; -import org.openbase.bco.dal.lib.layer.service.OperationServiceFactory; -import org.openbase.bco.dal.lib.layer.service.UnitDataSourceFactory; -import org.openbase.bco.dal.lib.layer.unit.UnitControllerRegistry; -import org.openbase.bco.dal.lib.layer.unit.UnitControllerRegistryImpl; -import org.openbase.bco.dal.lib.layer.unit.app.AppController; -import org.openbase.bco.dal.lib.layer.unit.app.AppControllerFactory; -import org.openbase.bco.dal.lib.layer.unit.app.AppManager; -import org.openbase.bco.registry.remote.login.BCOLogin; -import org.openbase.bco.registry.remote.Registries; -import org.openbase.jul.exception.CouldNotPerformException; -import org.openbase.jul.exception.InstantiationException; -import org.openbase.jul.exception.NotAvailableException; -import org.openbase.jul.exception.NotSupportedException; -import org.openbase.jul.iface.Launchable; -import org.openbase.jul.iface.VoidInitializable; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -/** - * - * @author Tamino Huxohl - */ -public class AppManagerImpl implements AppManager, Launchable, VoidInitializable { - - protected static final Logger LOGGER = LoggerFactory.getLogger(AppManagerImpl.class); - - private final AppControllerFactory factory; - private final UnitControllerRegistry appControllerRegistry; - private final UnitControllerRegistrySynchronizer appRegistrySynchronizer; - - public AppManagerImpl() throws InstantiationException { - try { - this.factory = AppControllerFactoryImpl.getInstance(); - this.appControllerRegistry = new UnitControllerRegistryImpl<>(); - this.appRegistrySynchronizer = new UnitControllerRegistrySynchronizer<>(appControllerRegistry, Registries.getUnitRegistry().getAppUnitConfigRemoteRegistry(false),factory); - } catch (CouldNotPerformException ex) { - throw new org.openbase.jul.exception.InstantiationException(this, ex); - } - } - - @Override - public void init() { - // this has to stay, else do not implement VoidInitializable - } - - @Override - public void activate() throws CouldNotPerformException, InterruptedException { - BCOLogin.getSession().loginBCOUser(); - appControllerRegistry.activate(); - appRegistrySynchronizer.activate(); - } - - @Override - public boolean isActive() { - return appRegistrySynchronizer.isActive() && - appControllerRegistry.isActive(); - } - - @Override - public void deactivate() throws CouldNotPerformException, InterruptedException { - appRegistrySynchronizer.deactivate(); - appControllerRegistry.deactivate(); - } - - @Override - public void shutdown() { - appRegistrySynchronizer.shutdown(); - appControllerRegistry.shutdown(); - } - - @Override - public OperationServiceFactory getOperationServiceFactory() throws NotAvailableException { - throw new NotAvailableException("OperationServiceFactory", new NotSupportedException("OperationServiceFactory", this)); - } - - @Override - public UnitDataSourceFactory getUnitDataSourceFactory() throws NotAvailableException { - throw new NotAvailableException("UnitDataSourceFactory", new NotSupportedException("UnitDataSourceFactory", this)); - } - - @Override - public UnitControllerRegistry getAppControllerRegistry() { - return appControllerRegistry; - } - -} diff --git a/module/dal/control/src/main/java/org/openbase/bco/dal/control/layer/unit/app/AppManagerImpl.kt b/module/dal/control/src/main/java/org/openbase/bco/dal/control/layer/unit/app/AppManagerImpl.kt new file mode 100644 index 0000000000..85e4ea24f3 --- /dev/null +++ b/module/dal/control/src/main/java/org/openbase/bco/dal/control/layer/unit/app/AppManagerImpl.kt @@ -0,0 +1,89 @@ +package org.openbase.bco.dal.control.layer.unit.app + +import org.openbase.bco.dal.control.layer.unit.UnitControllerRegistrySynchronizer +import org.openbase.bco.dal.lib.layer.service.OperationServiceFactory +import org.openbase.bco.dal.lib.layer.service.UnitDataSourceFactory +import org.openbase.bco.dal.lib.layer.unit.UnitControllerRegistry +import org.openbase.bco.dal.lib.layer.unit.UnitControllerRegistryImpl +import org.openbase.bco.dal.lib.layer.unit.app.AppController +import org.openbase.bco.dal.lib.layer.unit.app.AppControllerFactory +import org.openbase.bco.dal.lib.layer.unit.app.AppManager +import org.openbase.bco.registry.remote.Registries +import org.openbase.bco.registry.remote.login.BCOLogin +import org.openbase.jul.exception.CouldNotPerformException +import org.openbase.jul.exception.InstantiationException +import org.openbase.jul.exception.NotAvailableException +import org.openbase.jul.exception.NotSupportedException +import org.openbase.jul.iface.Launchable +import org.openbase.jul.iface.VoidInitializable +import org.slf4j.Logger +import org.slf4j.LoggerFactory + +/** + * + * @author [Tamino Huxohl](mailto:pleminoq@openbase.org) + */ +class AppManagerImpl : AppManager, Launchable, VoidInitializable { + private var factory: AppControllerFactory? = null + private var appControllerRegistry: UnitControllerRegistry + private var appRegistrySynchronizer: UnitControllerRegistrySynchronizer + + init { + try { + this.factory = AppControllerFactoryImpl.instance + this.appControllerRegistry = UnitControllerRegistryImpl() + this.appRegistrySynchronizer = UnitControllerRegistrySynchronizer( + appControllerRegistry, + Registries.getUnitRegistry().getAppUnitConfigRemoteRegistry(false), + factory + ) + } catch (ex: CouldNotPerformException) { + throw InstantiationException(this, ex) + } + } + + override fun init() { + // this has to stay, else do not implement VoidInitializable + } + + @Throws(CouldNotPerformException::class, InterruptedException::class) + override fun activate() { + BCOLogin.getSession().loginBCOUser() + appControllerRegistry.activate() + appRegistrySynchronizer.activate() + } + + override fun isActive(): Boolean { + return appRegistrySynchronizer.isActive && + appControllerRegistry.isActive + } + + @Throws(CouldNotPerformException::class, InterruptedException::class) + override fun deactivate() { + appRegistrySynchronizer.deactivate() + appControllerRegistry.deactivate() + } + + override fun shutdown() { + appRegistrySynchronizer.shutdown() + appControllerRegistry.shutdown() + } + + @Throws(NotAvailableException::class) + override fun getOperationServiceFactory(): OperationServiceFactory { + throw NotAvailableException("OperationServiceFactory", NotSupportedException("OperationServiceFactory", this)) + } + + @Throws(NotAvailableException::class) + override fun getUnitDataSourceFactory(): UnitDataSourceFactory { + throw NotAvailableException("UnitDataSourceFactory", NotSupportedException("UnitDataSourceFactory", this)) + } + + override fun getAppControllerRegistry(): UnitControllerRegistry { + return appControllerRegistry + } + + companion object { + protected val LOGGER: Logger = LoggerFactory.getLogger(AppManagerImpl::class.java) + } +} diff --git a/module/dal/control/src/main/java/org/openbase/bco/dal/control/layer/unit/app/AppManagerLauncher.java b/module/dal/control/src/main/java/org/openbase/bco/dal/control/layer/unit/app/AppManagerLauncher.java deleted file mode 100644 index 169b0f857c..0000000000 --- a/module/dal/control/src/main/java/org/openbase/bco/dal/control/layer/unit/app/AppManagerLauncher.java +++ /dev/null @@ -1,45 +0,0 @@ -package org.openbase.bco.dal.control.layer.unit.app; - -import org.openbase.bco.authentication.lib.BCO; -import org.openbase.bco.dal.lib.layer.unit.app.AppManager; -import org.openbase.jul.pattern.launch.AbstractLauncher; - -/* - * #%L - * BCO DAL Control - * %% - * Copyright (C) 2014 - 2021 openbase.org - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program. If not, see - * . - * #L% - * - * @author Divine Threepwood - * - */ -public class AppManagerLauncher extends AbstractLauncher { - - public AppManagerLauncher() throws org.openbase.jul.exception.InstantiationException { - super(AppManager.class, AppManagerImpl.class); - } - - @Override - public void loadProperties() { - } - - public static void main(String[] args) throws Throwable { - BCO.printLogo(); - main(BCO.class, AppManager.class, args, AppManagerLauncher.class); - } -} diff --git a/module/dal/control/src/main/java/org/openbase/bco/dal/control/layer/unit/app/AppManagerLauncher.kt b/module/dal/control/src/main/java/org/openbase/bco/dal/control/layer/unit/app/AppManagerLauncher.kt new file mode 100644 index 0000000000..6ce1870748 --- /dev/null +++ b/module/dal/control/src/main/java/org/openbase/bco/dal/control/layer/unit/app/AppManagerLauncher.kt @@ -0,0 +1,43 @@ +package org.openbase.bco.dal.control.layer.unit.app + +import org.openbase.bco.authentication.lib.BCO +import org.openbase.bco.dal.lib.layer.unit.app.AppManager +import org.openbase.jul.pattern.launch.AbstractLauncher + +/* +* #%L +* BCO DAL Control +* %% +* Copyright (C) 2014 - 2021 openbase.org +* %% +* This program is free software: you can redistribute it and/or modify +* it under the terms of the GNU General Public License as +* published by the Free Software Foundation, either version 3 of the +* License, or (at your option) any later version. +* +* This program is distributed in the hope that it will be useful, +* but WITHOUT ANY WARRANTY; without even the implied warranty of +* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +* GNU General Public License for more details. +* +* You should have received a copy of the GNU General Public +* License along with this program. If not, see +* . +* #L% +* +* @author Divine Threepwood +* +*/ +class AppManagerLauncher : AbstractLauncher(AppManager::class.java, AppManagerImpl::class.java) { + public override fun loadProperties() { + } + + companion object { + @JvmStatic + @Throws(Throwable::class) + fun main(args: Array) { + BCO.printLogo() + main(BCO::class.java, AppManager::class.java, args, AppManagerLauncher::class.java) + } + } +} diff --git a/module/dal/control/src/main/java/org/openbase/bco/dal/control/layer/unit/scene/SceneControllerImpl.java b/module/dal/control/src/main/java/org/openbase/bco/dal/control/layer/unit/scene/SceneControllerImpl.java index 817ddd693c..35ec94beeb 100644 --- a/module/dal/control/src/main/java/org/openbase/bco/dal/control/layer/unit/scene/SceneControllerImpl.java +++ b/module/dal/control/src/main/java/org/openbase/bco/dal/control/layer/unit/scene/SceneControllerImpl.java @@ -198,7 +198,7 @@ public UnitConfig applyConfigUpdate(UnitConfig config) throws CouldNotPerformExc .setInterruptible(true) .setSchedulable(true) .setPriority(Priority.HIGH) - .setExecutionTimePeriod(Duration.ofMinutes(30).toMillis()).build(); + .setExecutionTimePeriod(TimeUnit.MICROSECONDS.convert(Duration.ofMinutes(30))).build(); requiredActionPool.initViaServiceStateDescription(config.getSceneConfig().getRequiredServiceStateDescriptionList(), actionParameterPrototype, () -> getActivationState().getValue() == ActivationState.State.ACTIVE); optionalActionPool.initViaServiceStateDescription(config.getSceneConfig().getOptionalServiceStateDescriptionList(), actionParameterPrototype, () -> getActivationState().getValue() == ActivationState.State.ACTIVE); return config; @@ -209,7 +209,7 @@ public UnitConfig applyConfigUpdate(UnitConfig config) throws CouldNotPerformExc public void activate() throws InterruptedException, CouldNotPerformException { super.activate(); synchronized (buttonObserverLock) { - buttonRemoteSet.stream().forEach((button) -> { + buttonRemoteSet.forEach((button) -> { button.addDataObserver(buttonObserver); }); } @@ -221,7 +221,7 @@ public void activate() throws InterruptedException, CouldNotPerformException { @Override public void deactivate() throws InterruptedException, CouldNotPerformException { synchronized (buttonObserverLock) { - buttonRemoteSet.stream().forEach((button) -> { + buttonRemoteSet.forEach((button) -> { button.removeDataObserver(buttonObserver); }); } diff --git a/module/dal/control/src/main/java/org/openbase/bco/dal/control/message/MessageManager.kt b/module/dal/control/src/main/java/org/openbase/bco/dal/control/message/MessageManager.kt index 1b26e483d1..b0cd960f05 100644 --- a/module/dal/control/src/main/java/org/openbase/bco/dal/control/message/MessageManager.kt +++ b/module/dal/control/src/main/java/org/openbase/bco/dal/control/message/MessageManager.kt @@ -97,7 +97,7 @@ class MessageManager : Launchable, VoidInitializable { } override fun deactivate() { - Registries.getMessageRegistry().removeDataObserver(messageRegistryChangeObserver) + runCatching { Registries.getMessageRegistry() }.getOrNull()?.removeDataObserver(messageRegistryChangeObserver) unitsOfConditionsLock.write { unitsOfConditions?.forEach { it.removeDataObserver(conditionObserver) } unitsOfConditions = null diff --git a/module/device/openhab/src/main/java/org/openbase/bco/device/openhab/OpenHABDeviceManagerLauncher.java b/module/device/openhab/src/main/java/org/openbase/bco/device/openhab/OpenHABDeviceManagerLauncher.java index e4e56163c7..32bb4c924c 100644 --- a/module/device/openhab/src/main/java/org/openbase/bco/device/openhab/OpenHABDeviceManagerLauncher.java +++ b/module/device/openhab/src/main/java/org/openbase/bco/device/openhab/OpenHABDeviceManagerLauncher.java @@ -36,7 +36,7 @@ public class OpenHABDeviceManagerLauncher extends AbstractLauncher { - public OpenHABDeviceManagerLauncher() throws org.openbase.jul.exception.InstantiationException { + public OpenHABDeviceManagerLauncher() { super(OpenHABDeviceManagerLauncher.class, OpenHABDeviceManager.class); } @@ -45,9 +45,14 @@ public OpenHABDeviceManagerLauncher() throws org.openbase.jul.exception.Instanti */ public static void main(final String[] args) { BCO.printLogo(); - AbstractLauncher.main(BCO.class, OpenHABDeviceManagerLauncher.class, args, OpenHABDeviceManagerLauncher.class, + AbstractLauncher.main( + BCO.class, + OpenHABDeviceManagerLauncher.class, + args, + OpenHABDeviceManagerLauncher.class, OpenHABConfigSynchronizerLauncher.class, - OpenHABSitemapSynchronizerLauncher.class); + OpenHABSitemapSynchronizerLauncher.class + ); } @Override diff --git a/module/device/openhab/src/main/java/org/openbase/bco/device/openhab/communication/OpenHABRestCommunicator.java b/module/device/openhab/src/main/java/org/openbase/bco/device/openhab/communication/OpenHABRestCommunicator.java deleted file mode 100644 index 97618bfd04..0000000000 --- a/module/device/openhab/src/main/java/org/openbase/bco/device/openhab/communication/OpenHABRestCommunicator.java +++ /dev/null @@ -1,287 +0,0 @@ -package org.openbase.bco.device.openhab.communication; - -/*- - * #%L - * BCO Openhab Device Manager - * %% - * Copyright (C) 2015 - 2021 openbase.org - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program. If not, see - * . - * #L% - */ - -import com.google.gson.JsonArray; -import com.google.gson.JsonElement; -import com.google.gson.JsonParser; -import com.google.gson.JsonSyntaxException; -import jakarta.ws.rs.core.MediaType; -import org.openbase.jul.exception.CouldNotPerformException; -import org.openbase.jul.exception.InitializationException; -import org.openbase.jul.exception.InstantiationException; -import org.openbase.jul.exception.NotAvailableException; -import org.openbase.jul.exception.printer.ExceptionPrinter; -import org.openbase.jul.iface.Shutdownable; -import org.openhab.core.config.discovery.dto.DiscoveryResultDTO; -import org.openhab.core.io.rest.core.item.EnrichedItemDTO; -import org.openhab.core.io.rest.core.thing.EnrichedThingDTO; -import org.openhab.core.items.dto.ItemDTO; -import org.openhab.core.thing.dto.ThingDTO; -import org.openhab.core.thing.link.dto.ItemChannelLinkDTO; -import org.openhab.core.types.Command; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.ArrayList; -import java.util.HashMap; -import java.util.List; - -public class OpenHABRestCommunicator extends OpenHABRestConnection { - - - public static final String ITEMS_TARGET = "items"; - public static final String LINKS_TARGET = "links"; - public static final String THINGS_TARGET = "things"; - public static final String INBOX_TARGET = "inbox"; - public static final String DISCOVERY_TARGET = "discovery"; - public static final String ADDONS_TARGET = "addons"; - public static final String ADDONS_BINDING_PREFIX = "binding-"; - public static final String INSTALL_TARGET = "install"; - public static final String UNINSTALL_TARGET = "uninstall"; - public static final String BINDINGS_TARGET = "bindings"; - public static final String CONFIG_TARGET = "config"; - public static final String SCAN_TARGET = "scan"; - - private static final Logger LOGGER = LoggerFactory.getLogger(OpenHABRestCommunicator.class); - - private static OpenHABRestCommunicator instance = null; - - public synchronized static OpenHABRestCommunicator getInstance() { - if (instance == null) { - try { - instance = new OpenHABRestCommunicator(); - Shutdownable.registerShutdownHook(instance); - } catch (InitializationException ex) { - ExceptionPrinter.printHistory("Could not create OpenHABRestCommunicator", ex, LOGGER); - } catch (CouldNotPerformException ex) { - // only thrown if instance would be null - } - } - - return instance; - } - - private OpenHABRestCommunicator() throws InstantiationException { - super(); - } - - // ========================================================================================================================================== - // THINGS - // ========================================================================================================================================== - - public EnrichedThingDTO registerThing(final ThingDTO thingDTO) throws CouldNotPerformException { - return jsonToClass(JsonParser.parseString(postJson(THINGS_TARGET, thingDTO)), EnrichedThingDTO.class); - } - - public EnrichedThingDTO updateThing(final EnrichedThingDTO enrichedThingDTO) throws CouldNotPerformException { - return jsonToClass(JsonParser.parseString(putJson(THINGS_TARGET + SEPARATOR + enrichedThingDTO.UID, enrichedThingDTO)), EnrichedThingDTO.class); - } - - public EnrichedThingDTO deleteThing(final EnrichedThingDTO enrichedThingDTO) throws CouldNotPerformException { - return deleteThing(enrichedThingDTO.UID); - } - - public EnrichedThingDTO deleteThing(final String thingUID) throws CouldNotPerformException { - return jsonToClass(JsonParser.parseString(delete(THINGS_TARGET + SEPARATOR + thingUID)), EnrichedThingDTO.class); - } - - public EnrichedThingDTO getThing(final String thingUID) throws NotAvailableException { - try { - return jsonToClass(JsonParser.parseString(get(THINGS_TARGET + SEPARATOR + thingUID)), EnrichedThingDTO.class); - } catch (CouldNotPerformException ex) { - throw new NotAvailableException("Thing[" + thingUID + "]"); - } - } - - public List getThings() throws CouldNotPerformException { - return jsonElementToTypedList(JsonParser.parseString(get(THINGS_TARGET)), EnrichedThingDTO.class); - } - - // ========================================================================================================================================== - // ITEMS - // ========================================================================================================================================== - - public ItemDTO registerItem(final ItemDTO itemDTO) throws CouldNotPerformException { - final List itemDTOList = new ArrayList<>(); - itemDTOList.add(itemDTO); - return registerItems(itemDTOList).get(0); - } - - public List registerItems(final List itemDTOList) throws CouldNotPerformException { - return jsonElementToTypedList(JsonParser.parseString(putJson(ITEMS_TARGET, itemDTOList)), ItemDTO.class); - } - - public ItemDTO updateItem(final ItemDTO itemDTO) throws CouldNotPerformException { - return jsonToClass(JsonParser.parseString(putJson(ITEMS_TARGET + SEPARATOR + itemDTO.name, itemDTO)), ItemDTO.class); - } - - public ItemDTO deleteItem(final ItemDTO itemDTO) throws CouldNotPerformException { - return deleteItem(itemDTO.name); - } - - public ItemDTO deleteItem(final String itemName) throws CouldNotPerformException { - LOGGER.warn("Delete item {}", itemName); - return jsonToClass(JsonParser.parseString(delete(ITEMS_TARGET + SEPARATOR + itemName)), ItemDTO.class); - } - - public List getItems() throws CouldNotPerformException { - return jsonElementToTypedList(JsonParser.parseString(get(ITEMS_TARGET)), EnrichedItemDTO.class); - } - - public EnrichedItemDTO getItem(final String itemName) throws NotAvailableException { - try { - return jsonToClass(JsonParser.parseString(get(ITEMS_TARGET + SEPARATOR + itemName)), EnrichedItemDTO.class); - } catch (CouldNotPerformException ex) { - throw new NotAvailableException("Item with name[" + itemName + "]"); - } - } - - public boolean hasItem(final String itemName) { - try { - getItem(itemName); - return true; - } catch (NotAvailableException ex) { - return false; - } - } - - public void postCommand(final String itemName, final Command command) throws CouldNotPerformException { - postCommand(itemName, command.toString()); - } - - public void postCommand(final String itemName, final String command) throws CouldNotPerformException { - post(ITEMS_TARGET + SEPARATOR + itemName, command, MediaType.TEXT_PLAIN_TYPE); - } - - // ========================================================================================================================================== - // ITEM_CHANNEL_LINK - // ========================================================================================================================================== - - public void registerItemChannelLink(final String itemName, final String channelUID) throws CouldNotPerformException { - registerItemChannelLink(new ItemChannelLinkDTO(itemName, channelUID, new HashMap<>())); - } - - public void registerItemChannelLink(final ItemChannelLinkDTO itemChannelLinkDTO) throws CouldNotPerformException { - putJson(LINKS_TARGET + SEPARATOR + itemChannelLinkDTO.itemName + SEPARATOR + itemChannelLinkDTO.channelUID, itemChannelLinkDTO); - } - - public void deleteItemChannelLink(final ItemChannelLinkDTO itemChannelLinkDTO) throws CouldNotPerformException { - deleteItemChannelLink(itemChannelLinkDTO.itemName, itemChannelLinkDTO.channelUID); - } - - public void deleteItemChannelLink(final String itemName, final String channelUID) throws CouldNotPerformException { - delete(LINKS_TARGET + SEPARATOR + itemName + SEPARATOR + channelUID); - } - - public List getItemChannelLinks() throws CouldNotPerformException { - return jsonElementToTypedList(JsonParser.parseString(get(LINKS_TARGET)), ItemChannelLinkDTO.class); - } - - // ========================================================================================================================================== - // DISCOVERY - // ========================================================================================================================================== - - /** - * @param bindingId - * @return the discovery timeout in seconds - * @throws CouldNotPerformException - */ - public Integer startDiscovery(final String bindingId) throws CouldNotPerformException { - final String response = post(DISCOVERY_TARGET + SEPARATOR + BINDINGS_TARGET + SEPARATOR + bindingId + SCAN_TARGET, "", MediaType.APPLICATION_JSON_TYPE); - int discoveryTimeout = Integer.parseInt(response); - - if (discoveryTimeout <= 0) { - throw new CouldNotPerformException("Invalid discovery timeout. Maybe binding " + bindingId + " is not available"); - } - - return discoveryTimeout; - } - - public void approve(final String thingUID, final String label) throws CouldNotPerformException { - post(INBOX_TARGET + SEPARATOR + thingUID + SEPARATOR + APPROVE_TARGET, label, MediaType.TEXT_PLAIN_TYPE); - } - - public List getDiscoveryResults() throws CouldNotPerformException { - return jsonElementToTypedList(JsonParser.parseString(get(INBOX_TARGET)), DiscoveryResultDTO.class); - } - - // ========================================================================================================================================== - // Extensions - // ========================================================================================================================================== - - public void installBinding(final String bindingId) throws CouldNotPerformException { - LOGGER.debug("Install Binding[" + bindingId + "]"); - post(ADDONS_TARGET + SEPARATOR + ADDONS_BINDING_PREFIX + bindingId + SEPARATOR + INSTALL_TARGET, "", MediaType.APPLICATION_JSON_TYPE); - } - - public boolean isBindingInstalled(final String bindingId) { - try { - get(BINDINGS_TARGET + SEPARATOR + bindingId + SEPARATOR + CONFIG_TARGET); - LOGGER.debug("Binding[" + bindingId + "] currently not installed!"); - return true; - } catch (CouldNotPerformException ex) { - LOGGER.debug("Binding[" + bindingId + "] is already installed."); - return false; - } - } - - public void uninstallBindings(final String bindingId) throws CouldNotPerformException { - post(ADDONS_TARGET + SEPARATOR + bindingId + SEPARATOR + UNINSTALL_TARGET, "", MediaType.APPLICATION_JSON_TYPE); - } - - // ========================================================================================================================================== - // UTIL - // ========================================================================================================================================== - - private List jsonElementToTypedList(final JsonElement jsonElement, final Class clazz) throws CouldNotPerformException { - if (jsonElement.isJsonArray()) { - return jsonArrayToTypedList(jsonElement.getAsJsonArray(), clazz); - } else { - throw new CouldNotPerformException("JsonElement is not a JsonArray and thus cannot be converted to a list"); - } - } - - private List jsonArrayToTypedList(final JsonArray jsonArray, final Class clazz) throws CouldNotPerformException { - final List result = new ArrayList(); - - for (final JsonElement jsonElement : jsonArray) { - result.add(jsonToClass(jsonElement, clazz)); - } - - return result; - } - - private T jsonToClass(final JsonElement jsonElement, final Class clazz) throws CouldNotPerformException { - try { - return gson.fromJson(jsonElement, clazz); - } catch (JsonSyntaxException ex) { - throw new CouldNotPerformException("Could not parse jsonElement into object of class[" + clazz.getSimpleName() + "]", ex); - } - } - - @Override - protected void testConnection() throws CouldNotPerformException { - get(INBOX_TARGET, true); - } -} diff --git a/module/device/openhab/src/main/java/org/openbase/bco/device/openhab/communication/OpenHABRestCommunicator.kt b/module/device/openhab/src/main/java/org/openbase/bco/device/openhab/communication/OpenHABRestCommunicator.kt new file mode 100644 index 0000000000..dd79838c2a --- /dev/null +++ b/module/device/openhab/src/main/java/org/openbase/bco/device/openhab/communication/OpenHABRestCommunicator.kt @@ -0,0 +1,308 @@ +package org.openbase.bco.device.openhab.communication + +import com.google.gson.JsonArray +import com.google.gson.JsonElement +import com.google.gson.JsonParser +import com.google.gson.JsonSyntaxException +import jakarta.ws.rs.core.MediaType +import org.openbase.jul.exception.CouldNotPerformException +import org.openbase.jul.exception.InitializationException +import org.openbase.jul.exception.NotAvailableException +import org.openbase.jul.exception.printer.ExceptionPrinter +import org.openbase.jul.iface.Shutdownable +import org.openhab.core.config.discovery.dto.DiscoveryResultDTO +import org.openhab.core.io.rest.core.item.EnrichedItemDTO +import org.openhab.core.io.rest.core.thing.EnrichedThingDTO +import org.openhab.core.items.dto.ItemDTO +import org.openhab.core.thing.dto.ThingDTO +import org.openhab.core.thing.link.dto.ItemChannelLinkDTO +import org.openhab.core.types.Command +import org.slf4j.Logger +import org.slf4j.LoggerFactory + +class OpenHABRestCommunicator private constructor() : OpenHABRestConnection() { + // ========================================================================================================================================== + // THINGS + // ========================================================================================================================================== + @Throws(CouldNotPerformException::class) + fun registerThing(thingDTO: ThingDTO?): EnrichedThingDTO { + return jsonToClass(JsonParser.parseString(postJson(THINGS_TARGET, thingDTO)), EnrichedThingDTO::class.java) + } + + @Throws(CouldNotPerformException::class) + fun updateThing(enrichedThingDTO: EnrichedThingDTO): EnrichedThingDTO { + return jsonToClass( + JsonParser.parseString( + putJson( + THINGS_TARGET + SEPARATOR + enrichedThingDTO.UID, + enrichedThingDTO + ) + ), EnrichedThingDTO::class.java + ) + } + + @Throws(CouldNotPerformException::class) + fun deleteThing(enrichedThingDTO: EnrichedThingDTO): EnrichedThingDTO { + return deleteThing(enrichedThingDTO.UID) + } + + @Throws(CouldNotPerformException::class) + fun deleteThing(thingUID: String): EnrichedThingDTO { + return jsonToClass( + JsonParser.parseString(delete(THINGS_TARGET + SEPARATOR + thingUID)), + EnrichedThingDTO::class.java + ) + } + + @Throws(NotAvailableException::class) + fun getThing(thingUID: String): EnrichedThingDTO { + try { + return jsonToClass( + JsonParser.parseString(get(THINGS_TARGET + SEPARATOR + thingUID)), + EnrichedThingDTO::class.java + ) + } catch (ex: CouldNotPerformException) { + throw NotAvailableException("Thing[$thingUID]") + } + } + + @get:Throws(CouldNotPerformException::class) + val things: List + get() = jsonElementToTypedList(JsonParser.parseString(get(THINGS_TARGET)), EnrichedThingDTO::class.java) + + // ========================================================================================================================================== + // ITEMS + // ========================================================================================================================================== + @Throws(CouldNotPerformException::class) + fun registerItem(itemDTO: ItemDTO): ItemDTO { + val itemDTOList: MutableList = ArrayList() + itemDTOList.add(itemDTO) + return registerItems(itemDTOList)[0] + } + + @Throws(CouldNotPerformException::class) + fun registerItems(itemDTOList: List?): List { + return jsonElementToTypedList(JsonParser.parseString(putJson(ITEMS_TARGET, itemDTOList)), ItemDTO::class.java) + } + + @Throws(CouldNotPerformException::class) + fun updateItem(itemDTO: ItemDTO): ItemDTO { + return jsonToClass( + JsonParser.parseString(putJson(ITEMS_TARGET + SEPARATOR + itemDTO.name, itemDTO)), + ItemDTO::class.java + ) + } + + @Throws(CouldNotPerformException::class) + fun deleteItem(itemDTO: ItemDTO): ItemDTO = deleteItem(itemDTO.name) + + @Throws(CouldNotPerformException::class) + fun deleteItem(itemName: String): ItemDTO { + LOGGER.warn("Delete item {}", itemName) + return jsonToClass(JsonParser.parseString(delete(ITEMS_TARGET + SEPARATOR + itemName)), ItemDTO::class.java) + } + + @get:Throws(CouldNotPerformException::class) + val items: List + get() = jsonElementToTypedList(JsonParser.parseString(get(ITEMS_TARGET)), EnrichedItemDTO::class.java) + + @Throws(NotAvailableException::class) + fun getItem(itemName: String): EnrichedItemDTO = + try { + jsonToClass( + JsonParser.parseString(get(ITEMS_TARGET + SEPARATOR + itemName)), + EnrichedItemDTO::class.java + ) + } catch (ex: CouldNotPerformException) { + throw NotAvailableException("Item with name[$itemName]") + } + + fun hasItem(itemName: String): Boolean { + try { + getItem(itemName) + return true + } catch (ex: NotAvailableException) { + return false + } + } + + @Throws(CouldNotPerformException::class) + fun postCommand(itemName: String, command: Command) { + postCommand(itemName, command.toString()) + } + + @Throws(CouldNotPerformException::class) + fun postCommand(itemName: String, command: String?) { + post(ITEMS_TARGET + SEPARATOR + itemName, command!!, MediaType.TEXT_PLAIN_TYPE) + } + + // ========================================================================================================================================== + // ITEM_CHANNEL_LINK + // ========================================================================================================================================== + @Throws(CouldNotPerformException::class) + fun registerItemChannelLink(itemName: String?, channelUID: String?) { + registerItemChannelLink(ItemChannelLinkDTO(itemName, channelUID, HashMap())) + } + + @Throws(CouldNotPerformException::class) + fun registerItemChannelLink(itemChannelLinkDTO: ItemChannelLinkDTO) { + putJson( + LINKS_TARGET + SEPARATOR + itemChannelLinkDTO.itemName + SEPARATOR + itemChannelLinkDTO.channelUID, + itemChannelLinkDTO + ) + } + + @Throws(CouldNotPerformException::class) + fun deleteItemChannelLink(itemChannelLinkDTO: ItemChannelLinkDTO) { + deleteItemChannelLink(itemChannelLinkDTO.itemName, itemChannelLinkDTO.channelUID) + } + + @Throws(CouldNotPerformException::class) + fun deleteItemChannelLink(itemName: String, channelUID: String) { + delete(LINKS_TARGET + SEPARATOR + itemName + SEPARATOR + channelUID) + } + + @get:Throws(CouldNotPerformException::class) + val itemChannelLinks: List + get() = jsonElementToTypedList(JsonParser.parseString(get(LINKS_TARGET)), ItemChannelLinkDTO::class.java) + + // ========================================================================================================================================== + // DISCOVERY + // ========================================================================================================================================== + /** + * @param bindingId + * + * @return the discovery timeout in seconds + * + * @throws CouldNotPerformException + */ + @Throws(CouldNotPerformException::class) + fun startDiscovery(bindingId: String): Int { + val response = post( + DISCOVERY_TARGET + SEPARATOR + BINDINGS_TARGET + SEPARATOR + bindingId + SCAN_TARGET, + "", + MediaType.APPLICATION_JSON_TYPE + ) + val discoveryTimeout = response.toInt() + + if (discoveryTimeout <= 0) { + throw CouldNotPerformException("Invalid discovery timeout. Maybe binding $bindingId is not available") + } + + return discoveryTimeout + } + + @Throws(CouldNotPerformException::class) + fun approve(thingUID: String, label: String?) { + post(INBOX_TARGET + SEPARATOR + thingUID + SEPARATOR + APPROVE_TARGET, label!!, MediaType.TEXT_PLAIN_TYPE) + } + + @get:Throws(CouldNotPerformException::class) + val discoveryResults: List + get() = jsonElementToTypedList(JsonParser.parseString(get(INBOX_TARGET)), DiscoveryResultDTO::class.java) + + // ========================================================================================================================================== + // Extensions + // ========================================================================================================================================== + @Throws(CouldNotPerformException::class) + fun installBinding(bindingId: String) { + LOGGER.debug("Install Binding[$bindingId]") + post( + ADDONS_TARGET + SEPARATOR + ADDONS_BINDING_PREFIX + bindingId + SEPARATOR + INSTALL_TARGET, + "", + MediaType.APPLICATION_JSON_TYPE + ) + } + + fun isBindingInstalled(bindingId: String): Boolean { + try { + get(BINDINGS_TARGET + SEPARATOR + bindingId + SEPARATOR + CONFIG_TARGET) + LOGGER.debug("Binding[$bindingId] currently not installed!") + return true + } catch (ex: CouldNotPerformException) { + LOGGER.debug("Binding[$bindingId] is already installed.") + return false + } + } + + @Throws(CouldNotPerformException::class) + fun uninstallBindings(bindingId: String) { + post(ADDONS_TARGET + SEPARATOR + bindingId + SEPARATOR + UNINSTALL_TARGET, "", MediaType.APPLICATION_JSON_TYPE) + } + + // ========================================================================================================================================== + // UTIL + // ========================================================================================================================================== + @Throws(CouldNotPerformException::class) + private fun jsonElementToTypedList(jsonElement: JsonElement, clazz: Class): List { + if (jsonElement.isJsonArray) { + return jsonArrayToTypedList(jsonElement.asJsonArray, clazz) + } else { + throw CouldNotPerformException("JsonElement is not a JsonArray and thus cannot be converted to a list") + } + } + + @Throws(CouldNotPerformException::class) + private fun jsonArrayToTypedList(jsonArray: JsonArray, clazz: Class): List { + val result: MutableList = ArrayList() + + for (jsonElement in jsonArray) { + result.add(jsonToClass(jsonElement, clazz)) + } + + return result + } + + @Throws(CouldNotPerformException::class) + private fun jsonToClass(jsonElement: JsonElement, clazz: Class): T { + try { + return gson.fromJson(jsonElement, clazz) + } catch (ex: JsonSyntaxException) { + throw CouldNotPerformException( + "Could not parse jsonElement into object of class[" + clazz.simpleName + "]", + ex + ) + } + } + + @Throws(CouldNotPerformException::class) + override fun testConnection() { + get(INBOX_TARGET, true) + } + + companion object { + const val ITEMS_TARGET: String = "items" + const val LINKS_TARGET: String = "links" + const val THINGS_TARGET: String = "things" + const val INBOX_TARGET: String = "inbox" + const val DISCOVERY_TARGET: String = "discovery" + const val ADDONS_TARGET: String = "addons" + const val ADDONS_BINDING_PREFIX: String = "binding-" + const val INSTALL_TARGET: String = "install" + const val UNINSTALL_TARGET: String = "uninstall" + const val BINDINGS_TARGET: String = "bindings" + const val CONFIG_TARGET: String = "config" + const val SCAN_TARGET: String = "scan" + + private val LOGGER: Logger = LoggerFactory.getLogger(OpenHABRestCommunicator::class.java) + + @JvmStatic + @get:Synchronized + var instance: OpenHABRestCommunicator? = null + get() { + if (field == null) { + try { + field = OpenHABRestCommunicator() + Shutdownable.registerShutdownHook(field) + } catch (ex: InitializationException) { + ExceptionPrinter.printHistory("Could not create OpenHABRestCommunicator", ex, LOGGER) + } catch (ex: CouldNotPerformException) { + // only thrown if instance would be null + } + } + + return field + } + private set + } +} diff --git a/module/device/openhab/src/main/java/org/openbase/bco/device/openhab/communication/OpenHABRestConnection.java b/module/device/openhab/src/main/java/org/openbase/bco/device/openhab/communication/OpenHABRestConnection.java deleted file mode 100644 index 16ef2ccd5d..0000000000 --- a/module/device/openhab/src/main/java/org/openbase/bco/device/openhab/communication/OpenHABRestConnection.java +++ /dev/null @@ -1,479 +0,0 @@ -package org.openbase.bco.device.openhab.communication; - -/*- - * #%L - * BCO Openhab Device Manager - * %% - * Copyright (C) 2015 - 2021 openbase.org - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program. If not, see - * . - * #L% - */ - -import com.google.gson.*; -import jakarta.ws.rs.ProcessingException; -import jakarta.ws.rs.client.Client; -import jakarta.ws.rs.client.ClientBuilder; -import jakarta.ws.rs.client.Entity; -import jakarta.ws.rs.client.WebTarget; -import jakarta.ws.rs.core.MediaType; -import jakarta.ws.rs.core.Response; -import jakarta.ws.rs.sse.InboundSseEvent; -import jakarta.ws.rs.sse.SseEventSource; -import org.glassfish.jersey.client.oauth2.OAuth2ClientSupport; -import org.openbase.bco.device.openhab.jp.JPOpenHABURI; -import org.openbase.bco.registry.remote.Registries; -import org.openbase.jps.core.JPService; -import org.openbase.jps.exception.JPNotAvailableException; -import org.openbase.jul.exception.InstantiationException; -import org.openbase.jul.exception.*; -import org.openbase.jul.exception.printer.ExceptionPrinter; -import org.openbase.jul.exception.printer.LogLevel; -import org.openbase.jul.extension.type.processing.LabelProcessor; -import org.openbase.jul.extension.type.processing.MetaConfigProcessor; -import org.openbase.jul.iface.Shutdownable; -import org.openbase.jul.pattern.Observable; -import org.openbase.jul.pattern.ObservableImpl; -import org.openbase.jul.pattern.Observer; -import org.openbase.jul.schedule.GlobalScheduledExecutorService; -import org.openbase.jul.schedule.SyncObject; -import org.openbase.type.domotic.state.ConnectionStateType.ConnectionState; -import org.openbase.type.domotic.state.ConnectionStateType.ConnectionState.State; -import org.openbase.type.domotic.unit.UnitConfigType; -import org.openbase.type.domotic.unit.UnitTemplateType; -import org.openbase.type.domotic.unit.gateway.GatewayClassType; -import org.openhab.core.types.CommandDescription; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; -import java.util.HashMap; -import java.util.Map; -import java.util.Map.Entry; -import java.util.concurrent.RejectedExecutionException; -import java.util.concurrent.ScheduledFuture; -import java.util.concurrent.TimeUnit; -import java.util.function.Consumer; - -public abstract class OpenHABRestConnection implements Shutdownable { - - public static final String SEPARATOR = "/"; - public static final String REST_TARGET = "rest"; - - public static final String APPROVE_TARGET = "approve"; - public static final String EVENTS_TARGET = "events"; - - public static final String TOPIC_KEY = "topic"; - public static final String TOPIC_SEPARATOR = SEPARATOR; - - private static final Logger LOGGER = LoggerFactory.getLogger(OpenHABRestConnection.class); - - private final SyncObject topicObservableMapLock = new SyncObject("topicObservableMapLock"); - private final SyncObject connectionStateSyncLock = new SyncObject("connectionStateSyncLock"); - private final Map> topicObservableMap; - - private final Client restClient; - private final WebTarget restTarget; - private SseEventSource sseSource; - - private boolean shutdownInitiated = false; - - protected final Gson gson; - - private ScheduledFuture connectionTask; - - protected ConnectionState.State openhabConnectionState = State.DISCONNECTED; - - public OpenHABRestConnection() throws InstantiationException { - try { - this.topicObservableMap = new HashMap<>(); - this.gson = new GsonBuilder().setExclusionStrategies(new ExclusionStrategy() { - @Override - public boolean shouldSkipField(FieldAttributes fieldAttributes) { - return false; - } - - @Override - public boolean shouldSkipClass(Class aClass) { - // ignore Command Description because its an interface and can not be serialized without any instance creator. - if (aClass.equals(CommandDescription.class)) { - return true; - } - return false; - } - }).create(); - - this.restClient = ClientBuilder.newClient(); - try { - restClient.register(OAuth2ClientSupport.feature(getToken())); - } catch (NotAvailableException ex) { - LOGGER.warn("Could not retrieve OpenHAB token from gateway config!", ex); - } - this.restTarget = restClient.target(JPService.getProperty(JPOpenHABURI.class).getValue().resolve(SEPARATOR + REST_TARGET)); - this.setConnectState(State.CONNECTING); - } catch (JPNotAvailableException | CouldNotPerformException ex) { - throw new InstantiationException(this, ex); - } - } - - private boolean isTargetReachable() { - try { - testConnection(); - } catch (CouldNotPerformException e) { - if (e.getCause() instanceof ProcessingException) { - return false; - } - } - return true; - } - - protected abstract void testConnection() throws CouldNotPerformException; - - public void waitForConnectionState(final ConnectionState.State connectionState, final long timeout, final TimeUnit timeUnit) throws InterruptedException { - synchronized (connectionStateSyncLock) { - while (getOpenhabConnectionState() != connectionState) { - connectionStateSyncLock.wait(timeUnit.toMillis(timeout)); - } - } - } - - public void waitForConnectionState(final ConnectionState.State connectionState) throws InterruptedException { - synchronized (connectionStateSyncLock) { - while (getOpenhabConnectionState() != connectionState) { - connectionStateSyncLock.wait(); - } - } - } - - private void setConnectState(final ConnectionState.State connectState) { - synchronized (connectionStateSyncLock) { - - // filter non changing states - if (connectState == this.openhabConnectionState) { - return; - } - LOGGER.trace("Openhab Connection State changed to: " + connectState); - - // update state - this.openhabConnectionState = connectState; - - // handle state change - switch (connectState) { - case CONNECTING: - LOGGER.info("Wait for openHAB..."); - try { - connectionTask = GlobalScheduledExecutorService.scheduleWithFixedDelay(() -> { - if (isTargetReachable()) { - // set connected - setConnectState(State.CONNECTED); - - // cleanup own task - connectionTask.cancel(false); - } - }, 0, 15, TimeUnit.SECONDS); - } catch (NotAvailableException | RejectedExecutionException ex) { - // if global executor service is not available we have no chance to connect. - LOGGER.warn("Wait for openHAB...", ex); - setConnectState(State.DISCONNECTED); - } - break; - case CONNECTED: - LOGGER.info("Connection to OpenHAB established."); - initSSE(); - break; - case RECONNECTING: - LOGGER.warn("Connection to OpenHAB lost!"); - resetConnection(); - setConnectState(State.CONNECTING); - break; - case DISCONNECTED: - LOGGER.info("Connection to OpenHAB closed."); - resetConnection(); - break; - } - - // notify state change - connectionStateSyncLock.notifyAll(); - - // apply next state if required - switch (connectState) { - case RECONNECTING: - setConnectState(State.CONNECTING); - break; - } - } - } - - private void initSSE() { - // activate sse source if not already done - if (sseSource != null) { - LOGGER.warn("SSE already initialized!"); - return; - } - - final WebTarget webTarget = restTarget.path(EVENTS_TARGET); - sseSource = SseEventSource.target(webTarget).reconnectingEvery(15, TimeUnit.SECONDS).build(); - sseSource.open(); - - final Consumer evenConsumer = inboundSseEvent -> { - // dispatch event - try { - final JsonObject payload = JsonParser.parseString(inboundSseEvent.readData()).getAsJsonObject(); - for (Entry> topicObserverEntry : topicObservableMap.entrySet()) { - try { - if (payload.get(TOPIC_KEY).getAsString().matches(topicObserverEntry.getKey())) { - topicObserverEntry.getValue().notifyObservers(payload); - } - } catch (Exception ex) { - ExceptionPrinter.printHistory(new CouldNotPerformException("Could not notify listeners on topic[" + topicObserverEntry.getKey() + "]", ex), LOGGER); - } - } - } catch (Exception ex) { - ExceptionPrinter.printHistory(new CouldNotPerformException("Could not handle SSE payload!", ex), LOGGER); - } - }; - - final Consumer errorHandler = ex -> { - ExceptionPrinter.printHistory("Openhab connection error detected!", ex, LOGGER, LogLevel.DEBUG); - checkConnectionState(); - }; - - final Runnable reconnectHandler = () -> { - setConnectState(State.RECONNECTING); - }; - - sseSource.register(evenConsumer, errorHandler, reconnectHandler); - } - - public State getOpenhabConnectionState() { - return openhabConnectionState; - } - - public void checkConnectionState() { - synchronized (connectionStateSyncLock) { - // only validate if connected - if (!isConnected()) { - return; - } - - // if not reachable init a reconnect - if (!isTargetReachable()) { - setConnectState(State.RECONNECTING); - } - } - } - - public boolean isConnected() { - return getOpenhabConnectionState() == State.CONNECTED; - } - - public void addSSEObserver(Observer observer) { - addSSEObserver(observer, ""); - } - - public void addSSEObserver(final Observer observer, final String topicRegex) { - synchronized (topicObservableMapLock) { - if (topicObservableMap.containsKey(topicRegex)) { - topicObservableMap.get(topicRegex).addObserver(observer); - return; - } - - final ObservableImpl observable = new ObservableImpl<>(this); - observable.addObserver(observer); - topicObservableMap.put(topicRegex, observable); - } - } - - public void removeSSEObserver(Observer observer) { - removeSSEObserver(observer, ""); - } - - public void removeSSEObserver(Observer observer, final String topicFilter) { - synchronized (topicObservableMapLock) { - if (topicObservableMap.containsKey(topicFilter)) { - topicObservableMap.get(topicFilter).removeObserver(observer); - } - } - } - - private void resetConnection() { - // cancel ongoing connection task - if (!connectionTask.isDone()) { - connectionTask.cancel(false); - } - - // close sse - if (sseSource != null) { - sseSource.close(); - sseSource = null; - } - } - - public void validateConnection() throws CouldNotPerformException { - if (!isConnected()) { - throw new InvalidStateException("Openhab not reachable yet!"); - } - } - - private String validateResponse(final Response response) throws CouldNotPerformException, ProcessingException { - return validateResponse(response, false); - } - - private String validateResponse(final Response response, final boolean skipConnectionValidation) throws CouldNotPerformException, ProcessingException { - final String result = response.readEntity(String.class); - - if (response.getStatus() == 200 || response.getStatus() == 201 || response.getStatus() == 202) { - return result; - } else if (response.getStatus() == 404) { - if (!skipConnectionValidation) { - checkConnectionState(); - } - throw new NotAvailableException("URL"); - } else if (response.getStatus() == 503) { - if (!skipConnectionValidation) { - checkConnectionState(); - } - // throw a processing exception to indicate that openHAB is still not fully started, this is used to wait for openHAB - throw new ProcessingException("OpenHAB server not ready"); - } else { - throw new CouldNotPerformException("Response returned with ErrorCode[" + response.getStatus() + "], Result[" + result + "] and ErrorMessage[" + response.getStatusInfo().getReasonPhrase() + "]"); - } - } - - protected String get(final String target) throws CouldNotPerformException { - return get(target, false); - } - - protected String get(final String target, final boolean skipValidation) throws CouldNotPerformException { - try { - - // handle validation - if (!skipValidation) { - validateConnection(); - } - - final WebTarget webTarget = restTarget.path(target); - final Response response = webTarget.request().get(); - - return validateResponse(response, skipValidation); - } catch (CouldNotPerformException | ProcessingException ex) { - if (isShutdownInitiated()) { - ExceptionProcessor.setInitialCause(ex, new ShutdownInProgressException(this)); - } - throw new CouldNotPerformException("Could not get sub-URL[" + target + "]", ex); - } - } - - protected String delete(final String target) throws CouldNotPerformException { - try { - validateConnection(); - final WebTarget webTarget = restTarget.path(target); - final Response response = webTarget.request().delete(); - - return validateResponse(response); - } catch (CouldNotPerformException | ProcessingException ex) { - if (isShutdownInitiated()) { - ExceptionProcessor.setInitialCause(ex, new ShutdownInProgressException(this)); - } - throw new CouldNotPerformException("Could not delete sub-URL[" + target + "]", ex); - } - } - - protected String putJson(final String target, final Object value) throws CouldNotPerformException { - return put(target, gson.toJson(value), MediaType.APPLICATION_JSON_TYPE); - } - - protected String put(final String target, final String value, final MediaType mediaType) throws CouldNotPerformException { - try { - validateConnection(); - final WebTarget webTarget = restTarget.path(target); - final Response response = webTarget.request().put(Entity.entity(value, mediaType)); - - return validateResponse(response); - } catch (CouldNotPerformException | ProcessingException ex) { - if (isShutdownInitiated()) { - ExceptionProcessor.setInitialCause(ex, new ShutdownInProgressException(this)); - } - throw new CouldNotPerformException("Could not put value[" + value + "] on sub-URL[" + target + "]", ex); - } - } - - protected String postJson(final String target, final Object value) throws CouldNotPerformException { - return post(target, gson.toJson(value), MediaType.APPLICATION_JSON_TYPE); - } - - protected String post(final String target, final String value, final MediaType mediaType) throws CouldNotPerformException { - try { - validateConnection(); - final WebTarget webTarget = restTarget.path(target); - final Response response = webTarget.request().post(Entity.entity(value, mediaType)); - - return validateResponse(response); - } catch (CouldNotPerformException | ProcessingException ex) { - if (isShutdownInitiated()) { - ExceptionProcessor.setInitialCause(ex, new ShutdownInProgressException(this)); - } - throw new CouldNotPerformException("Could not post Value[" + value + "] of MediaType[" + mediaType + "] on sub-URL[" + target + "]", ex); - } - } - - public boolean isShutdownInitiated() { - return shutdownInitiated; - } - - @Override - public void shutdown() { - - // prepare shutdown - shutdownInitiated = true; - setConnectState(State.DISCONNECTED); - - // stop rest service - restClient.close(); - - // stop sse service - synchronized (topicObservableMapLock) { - for (final Observable jsonObjectObservable : topicObservableMap.values()) { - jsonObjectObservable.shutdown(); - } - - topicObservableMap.clear(); - resetConnection(); - } - } - - - private final String OPENHAB_GATEWAY_CLASS_LABEL = "OpenHAB"; - private final String META_CONFIG_TOKEN_KEY = "TOKEN"; - - private final GatewayClassType.GatewayClass findOpenHABGatewayClass() throws CouldNotPerformException { - for (GatewayClassType.GatewayClass gatewayClass : Registries.getClassRegistry().getGatewayClasses()) { - if (LabelProcessor.contains(gatewayClass.getLabel(), OPENHAB_GATEWAY_CLASS_LABEL)) { - return gatewayClass; - } - } - - throw new NotAvailableException("OpenHAB Gateway Class"); - } - - private String getToken() throws CouldNotPerformException { - final GatewayClassType.GatewayClass openHABGatewayClass = findOpenHABGatewayClass(); - - for (UnitConfigType.UnitConfig unitConfig : Registries.getUnitRegistry().getUnitConfigsByUnitType(UnitTemplateType.UnitTemplate.UnitType.GATEWAY)) { - if (unitConfig.getGatewayConfig().getGatewayClassId().equals(openHABGatewayClass.getId())) { - return MetaConfigProcessor.getValue(unitConfig.getMetaConfig(), META_CONFIG_TOKEN_KEY); - } - } - throw new NotAvailableException("token"); - } -} diff --git a/module/device/openhab/src/main/java/org/openbase/bco/device/openhab/communication/OpenHABRestConnection.kt b/module/device/openhab/src/main/java/org/openbase/bco/device/openhab/communication/OpenHABRestConnection.kt new file mode 100644 index 0000000000..4cd02a14b1 --- /dev/null +++ b/module/device/openhab/src/main/java/org/openbase/bco/device/openhab/communication/OpenHABRestConnection.kt @@ -0,0 +1,473 @@ +package org.openbase.bco.device.openhab.communication + +import com.google.gson.* +import jakarta.ws.rs.ProcessingException +import jakarta.ws.rs.client.Client +import jakarta.ws.rs.client.ClientBuilder +import jakarta.ws.rs.client.Entity +import jakarta.ws.rs.client.WebTarget +import jakarta.ws.rs.core.MediaType +import jakarta.ws.rs.core.Response +import jakarta.ws.rs.sse.InboundSseEvent +import jakarta.ws.rs.sse.SseEventSource +import org.glassfish.jersey.client.oauth2.OAuth2ClientSupport +import org.openbase.bco.device.openhab.jp.JPOpenHABURI +import org.openbase.bco.registry.remote.Registries +import org.openbase.jps.core.JPService +import org.openbase.jps.exception.JPNotAvailableException +import org.openbase.jul.exception.* +import org.openbase.jul.exception.ExceptionProcessor.setInitialCause +import org.openbase.jul.exception.printer.ExceptionPrinter +import org.openbase.jul.exception.printer.LogLevel +import org.openbase.jul.extension.type.processing.LabelProcessor.contains +import org.openbase.jul.extension.type.processing.MetaConfigProcessor +import org.openbase.jul.iface.Shutdownable +import org.openbase.jul.pattern.ObservableImpl +import org.openbase.jul.pattern.Observer +import org.openbase.jul.schedule.GlobalScheduledExecutorService +import org.openbase.type.domotic.state.ConnectionStateType +import org.openbase.type.domotic.unit.UnitTemplateType.UnitTemplate.UnitType +import org.openbase.type.domotic.unit.gateway.GatewayClassType +import org.openhab.core.types.CommandDescription +import org.slf4j.Logger +import org.slf4j.LoggerFactory +import java.net.ConnectException +import java.util.concurrent.RejectedExecutionException +import java.util.concurrent.ScheduledFuture +import java.util.concurrent.TimeUnit +import java.util.concurrent.locks.ReentrantLock +import java.util.function.Consumer +import kotlin.concurrent.withLock + +abstract class OpenHABRestConnection : Shutdownable { + private val topicObservableMapLock = ReentrantLock() + private val connectionStateLock = ReentrantLock() + private val connectionStateCondition = connectionStateLock.newCondition() + private var topicObservableMap: MutableMap> + + private var restClient: Client + private var restTarget: WebTarget + private var sseSource: SseEventSource? = null + + var isShutdownInitiated: Boolean = false + private set + + @JvmField + protected var gson: Gson + + private var connectionTask: ScheduledFuture<*>? = null + + var openhabConnectionState: ConnectionStateType.ConnectionState.State = + ConnectionStateType.ConnectionState.State.DISCONNECTED + protected set + + init { + try { + this.topicObservableMap = HashMap() + this.gson = GsonBuilder().setExclusionStrategies(object : ExclusionStrategy { + override fun shouldSkipField(fieldAttributes: FieldAttributes): Boolean { + return false + } + + override fun shouldSkipClass(aClass: Class<*>): Boolean { + // ignore Command Description because its an interface and can not be serialized without any instance creator. + return aClass == CommandDescription::class.java + } + }).create() + + this.restClient = ClientBuilder.newClient() + try { + restClient.register(OAuth2ClientSupport.feature(token)) + } catch (ex: NotAvailableException) { + LOGGER.warn("Could not retrieve OpenHAB token from gateway config!", ex) + } + this.restTarget = + restClient.target(JPService.getProperty(JPOpenHABURI::class.java).value.resolve(SEPARATOR + REST_TARGET)) + this.setConnectState(ConnectionStateType.ConnectionState.State.CONNECTING) + } catch (ex: JPNotAvailableException) { + throw InstantiationException(this, ex) + } catch (ex: CouldNotPerformException) { + throw InstantiationException(this, ex) + } + } + + private val isTargetReachable: Boolean + get() = runCatching { testConnection() }.isSuccess + + @Throws(CouldNotPerformException::class) + protected abstract fun testConnection() + + @Throws(InterruptedException::class) + fun waitForConnectionState( + connectionState: ConnectionStateType.ConnectionState.State, + timeout: Long, + timeUnit: TimeUnit, + ) { + connectionStateLock.withLock { + while (openhabConnectionState != connectionState) { + connectionStateCondition.await(timeout, timeUnit) + } + } + } + + @Throws(InterruptedException::class) + fun waitForConnectionState(connectionState: ConnectionStateType.ConnectionState.State) { + connectionStateLock.withLock { + while (openhabConnectionState != connectionState) { + connectionStateCondition.await() + } + } + } + + private fun setConnectState(connectState: ConnectionStateType.ConnectionState.State) { + connectionStateLock.withLock { + // filter non changing states + if (connectState == this.openhabConnectionState) { + return + } + LOGGER.trace("Openhab Connection State changed to: {}", connectState) + + // update state + this.openhabConnectionState = connectState + + when (connectState) { + ConnectionStateType.ConnectionState.State.CONNECTING -> { + LOGGER.info("Wait for openHAB...") + try { + connectionTask?.cancel(true) + connectionTask = GlobalScheduledExecutorService.scheduleWithFixedDelay({ + if (isTargetReachable) { + // set connected + setConnectState(ConnectionStateType.ConnectionState.State.CONNECTED) + + // cleanup own task + connectionTask?.cancel(false) + } + }, 0, 15, TimeUnit.SECONDS) + } catch (ex: NotAvailableException) { + // if global executor service is not available we have no chance to connect. + LOGGER.warn("Wait for openHAB...", ex) + setConnectState(ConnectionStateType.ConnectionState.State.DISCONNECTED) + } catch (ex: RejectedExecutionException) { + LOGGER.warn("Wait for openHAB...", ex) + setConnectState(ConnectionStateType.ConnectionState.State.DISCONNECTED) + } + } + + ConnectionStateType.ConnectionState.State.CONNECTED -> { + LOGGER.info("Connection to OpenHAB established.") + initSSE() + } + + ConnectionStateType.ConnectionState.State.RECONNECTING -> { + LOGGER.warn("Connection to OpenHAB lost!") + resetConnection() + setConnectState(ConnectionStateType.ConnectionState.State.CONNECTING) + } + + ConnectionStateType.ConnectionState.State.DISCONNECTED -> { + LOGGER.info("Connection to OpenHAB closed.") + resetConnection() + } + + else -> { + LOGGER.warn("Unknown connection state: $connectState") + } + } + // notify state change + connectionStateCondition.signalAll() + if (connectState == ConnectionStateType.ConnectionState.State.RECONNECTING) { + setConnectState(ConnectionStateType.ConnectionState.State.CONNECTING) + } + } + } + + private fun initSSE() { + // activate sse source if not already done + if (sseSource != null) { + LOGGER.warn("SSE already initialized!") + return + } + + sseSource = SseEventSource + .target(restTarget.path(EVENTS_TARGET)) + .reconnectingEvery(15, TimeUnit.SECONDS) + .build() + .also { it.open() } + + + val evenConsumer = Consumer { inboundSseEvent: InboundSseEvent -> + // dispatch event + try { + val payload = JsonParser.parseString(inboundSseEvent.readData()).asJsonObject + for ((key, value) in topicObservableMap) { + try { + payload[TOPIC_KEY] + ?.asString + ?.takeIf { it.matches(key.toRegex()) } + ?.run { value.notifyObservers(payload) } + } catch (ex: Exception) { + ExceptionPrinter.printHistory( + CouldNotPerformException( + "Could not notify listeners on topic[$key]", + ex + ), LOGGER + ) + } + } + } catch (ex: Exception) { + ExceptionPrinter.printHistory(CouldNotPerformException("Could not handle SSE payload!", ex), LOGGER) + } + } + + val errorHandler = Consumer { ex: Throwable -> + ExceptionPrinter.printHistory("Openhab connection error detected!", ex, LOGGER, LogLevel.DEBUG) + checkConnectionState() + } + + val reconnectHandler = Runnable { + setConnectState(ConnectionStateType.ConnectionState.State.RECONNECTING) + } + + sseSource?.register(evenConsumer, errorHandler, reconnectHandler) + } + + private fun checkConnectionState() { + connectionStateLock.withLock { + // only validate if connected + if (!isConnected) { + return + } + + // if not reachable init a reconnect + if (!isTargetReachable) { + setConnectState(ConnectionStateType.ConnectionState.State.RECONNECTING) + } + } + } + + val isConnected: Boolean + get() = openhabConnectionState == ConnectionStateType.ConnectionState.State.CONNECTED + + @JvmOverloads + fun addSSEObserver(observer: Observer, topicRegex: String = "") { + topicObservableMapLock.withLock { + topicObservableMap + .getOrPut(topicRegex) { ObservableImpl(this) } + .addObserver(observer) + } + } + + @JvmOverloads + fun removeSSEObserver(observer: Observer, topicFilter: String = "") { + topicObservableMapLock.withLock { + topicObservableMap[topicFilter]?.removeObserver(observer) + } + } + + private fun resetConnection() { + // cancel ongoing connection task + connectionTask + ?.takeIf { !it.isDone } + ?.cancel(false) + + // close sse + sseSource + ?.close() + ?.also { sseSource = null } + } + + @Throws(CouldNotPerformException::class) + fun validateConnection() { + if (!isConnected) { + throw InvalidStateException("Openhab not reachable yet!") + } + } + + @Throws(CouldNotPerformException::class, ProcessingException::class) + private fun validateResponse(response: Response, skipConnectionValidation: Boolean = false): String = + response.readEntity(String::class.java).let { result -> + when (response.status) { + 200, 201, 202 -> { + result + } + + 404 -> { + if (!skipConnectionValidation) { + checkConnectionState() + } + throw NotAvailableException("URL") + } + + 503 -> { + if (!skipConnectionValidation) { + checkConnectionState() + } + // throw a processing exception to indicate that openHAB is still not fully started, this is used to wait for openHAB + throw ProcessingException("OpenHAB server not ready") + } + + else -> { + throw CouldNotPerformException("Response returned with ErrorCode[" + response.status + "], Result[" + result + "] and ErrorMessage[" + response.statusInfo.reasonPhrase + "]") + } + } + } + + @Throws(CouldNotPerformException::class) + protected fun get(target: String, skipValidation: Boolean = false): String { + try { + // handle validation + + if (!skipValidation) { + validateConnection() + } + + val webTarget = restTarget.path(target) + val response = webTarget.request().get() + + return validateResponse(response, skipValidation) + } catch (ex: CouldNotPerformException) { + if (isShutdownInitiated) { + setInitialCause(ex, ShutdownInProgressException(this)) + } + throw CouldNotPerformException("Could not get sub-URL[$target]", ex) + } catch (ex: ProcessingException) { + if (isShutdownInitiated) { + setInitialCause(ex, ShutdownInProgressException(this)) + } + throw CouldNotPerformException("Could not get sub-URL[$target]", ex) + } + } + + @Throws(CouldNotPerformException::class) + protected fun delete(target: String): String { + try { + validateConnection() + val webTarget = restTarget.path(target) + val response = webTarget.request().delete() + + return validateResponse(response) + } catch (ex: CouldNotPerformException) { + if (isShutdownInitiated) { + setInitialCause(ex, ShutdownInProgressException(this)) + } + throw CouldNotPerformException("Could not delete sub-URL[$target]", ex) + } catch (ex: ProcessingException) { + if (isShutdownInitiated) { + setInitialCause(ex, ShutdownInProgressException(this)) + } + throw CouldNotPerformException("Could not delete sub-URL[$target]", ex) + } + } + + @Throws(CouldNotPerformException::class) + protected fun putJson(target: String, value: Any?): String { + return put(target, gson.toJson(value), MediaType.APPLICATION_JSON_TYPE) + } + + @Throws(CouldNotPerformException::class) + protected fun put(target: String, value: String, mediaType: MediaType?): String { + try { + validateConnection() + val webTarget = restTarget.path(target) + val response = webTarget.request().put(Entity.entity(value, mediaType)) + + return validateResponse(response) + } catch (ex: CouldNotPerformException) { + if (isShutdownInitiated) { + setInitialCause(ex, ShutdownInProgressException(this)) + } + throw CouldNotPerformException("Could not put value[$value] on sub-URL[$target]", ex) + } catch (ex: ProcessingException) { + if (isShutdownInitiated) { + setInitialCause(ex, ShutdownInProgressException(this)) + } + throw CouldNotPerformException("Could not put value[$value] on sub-URL[$target]", ex) + } catch (ex: ConnectException) { + if (isShutdownInitiated) { + setInitialCause(ex, ShutdownInProgressException(this)) + } + throw CouldNotPerformException("Could not put value[$value] on sub-URL[$target]", ex) + } + } + + @Throws(CouldNotPerformException::class) + protected fun postJson(target: String, value: Any?): String { + return post(target, gson.toJson(value), MediaType.APPLICATION_JSON_TYPE) + } + + @Throws(CouldNotPerformException::class) + protected fun post(target: String, value: String, mediaType: MediaType): String { + try { + validateConnection() + val webTarget = restTarget.path(target) + val response = webTarget.request().post(Entity.entity(value, mediaType)) + + return validateResponse(response) + } catch (ex: CouldNotPerformException) { + if (isShutdownInitiated) { + setInitialCause(ex, ShutdownInProgressException(this)) + } + throw CouldNotPerformException( + "Could not post Value[$value] of MediaType[$mediaType] on sub-URL[$target]", + ex + ) + } catch (ex: ProcessingException) { + if (isShutdownInitiated) { + setInitialCause(ex, ShutdownInProgressException(this)) + } + throw CouldNotPerformException( + "Could not post Value[$value] of MediaType[$mediaType] on sub-URL[$target]", + ex + ) + } + } + + override fun shutdown() { + // prepare shutdown + + isShutdownInitiated = true + setConnectState(ConnectionStateType.ConnectionState.State.DISCONNECTED) + + // stop rest service + restClient.close() + + // stop sse service + topicObservableMapLock.withLock { + topicObservableMap.values.forEach { jsonObjectObservable -> + jsonObjectObservable.shutdown() + } + topicObservableMap.clear() + resetConnection() + } + } + + @Throws(CouldNotPerformException::class) + private fun findOpenHABGatewayClass(): GatewayClassType.GatewayClass? = + Registries.getClassRegistry().gatewayClasses.find { contains(it.label, OPENHAB_GATEWAY_CLASS_LABEL) } + + private val token: String? + get() = findOpenHABGatewayClass()?.let { openHABGatewayClass -> + Registries.getUnitRegistry() + .getUnitConfigsByUnitType(UnitType.GATEWAY) + .find { it.gatewayConfig.gatewayClassId == openHABGatewayClass.id } + ?.let { MetaConfigProcessor.getValue(it.metaConfig, META_CONFIG_TOKEN_KEY) } + } + + companion object { + + private const val OPENHAB_GATEWAY_CLASS_LABEL = "OpenHAB" + private const val META_CONFIG_TOKEN_KEY = "TOKEN" + + const val SEPARATOR: String = "/" + const val REST_TARGET: String = "rest" + + const val APPROVE_TARGET: String = "approve" + const val EVENTS_TARGET: String = "events" + + const val TOPIC_KEY: String = "topic" + const val TOPIC_SEPARATOR: String = SEPARATOR + + private val LOGGER: Logger = LoggerFactory.getLogger(OpenHABRestConnection::class.java) + } +} diff --git a/module/device/openhab/src/main/java/org/openbase/bco/device/openhab/jp/JPOpenHABConfiguration.java b/module/device/openhab/src/main/java/org/openbase/bco/device/openhab/jp/JPOpenHABConfiguration.java deleted file mode 100644 index 4340dc83ae..0000000000 --- a/module/device/openhab/src/main/java/org/openbase/bco/device/openhab/jp/JPOpenHABConfiguration.java +++ /dev/null @@ -1,62 +0,0 @@ -package org.openbase.bco.device.openhab.jp; - -/*- - * #%L - * BCO Openhab Device Manager - * %% - * Copyright (C) 2015 - 2021 openbase.org - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program. If not, see - * . - * #L% - */ - -import org.openbase.jps.core.JPService; -import org.openbase.jps.exception.JPNotAvailableException; -import org.openbase.jps.preset.AbstractJPDirectory; -import org.openbase.jps.tools.FileHandler; - -import java.io.File; - -/** - * @author Divine Threepwood - */ -public class JPOpenHABConfiguration extends AbstractJPDirectory { - - public static final String[] COMMAND_IDENTIFIERS = {"--openhab-config"}; - public static final String SYSTEM_VARIABLE_OPENHAB_CONF = "OPENHAB_CONF"; - public static final String DEFAULT_PATH = "/etc/openhab2"; - - public JPOpenHABConfiguration() { - super(COMMAND_IDENTIFIERS, FileHandler.ExistenceHandling.Must, FileHandler.AutoMode.Off); - } - - @Override - protected File getPropertyDefaultValue() throws JPNotAvailableException { - - // use system variable if defined - String systemDefinedPath = System.getenv(SYSTEM_VARIABLE_OPENHAB_CONF); - if (systemDefinedPath != null) { - return new File(systemDefinedPath); - } - - return new File(DEFAULT_PATH); - } - - @Override - public String getDescription() { - return "Defines the openhab configuration directory. This property is based on the system variable " + SYSTEM_VARIABLE_OPENHAB_CONF; - } - -} diff --git a/module/device/openhab/src/main/java/org/openbase/bco/device/openhab/jp/JPOpenHABConfiguration.kt b/module/device/openhab/src/main/java/org/openbase/bco/device/openhab/jp/JPOpenHABConfiguration.kt new file mode 100644 index 0000000000..5678799ec6 --- /dev/null +++ b/module/device/openhab/src/main/java/org/openbase/bco/device/openhab/jp/JPOpenHABConfiguration.kt @@ -0,0 +1,34 @@ +package org.openbase.bco.device.openhab.jp + +import org.openbase.jps.exception.JPNotAvailableException +import org.openbase.jps.preset.AbstractJPDirectory +import org.openbase.jps.tools.FileHandler +import java.io.File + +/** + * @author [Divine Threepwood](mailto:divine@openbase.org) + */ +class JPOpenHABConfiguration : + AbstractJPDirectory(COMMAND_IDENTIFIERS, FileHandler.ExistenceHandling.Must, FileHandler.AutoMode.Off) { + @Throws(JPNotAvailableException::class) + override fun getPropertyDefaultValue(): File { + // use system variable if defined + + val systemDefinedPath = System.getenv(SYSTEM_VARIABLE_OPENHAB_CONF) + if (systemDefinedPath != null) { + return File(systemDefinedPath) + } + + return File(DEFAULT_PATH) + } + + override fun getDescription(): String { + return "Defines the openhab configuration directory. This property is based on the system variable " + SYSTEM_VARIABLE_OPENHAB_CONF + } + + companion object { + val COMMAND_IDENTIFIERS: Array = arrayOf("--openhab-config") + const val SYSTEM_VARIABLE_OPENHAB_CONF: String = "OPENHAB_CONF" + const val DEFAULT_PATH: String = "/etc/openhab2" + } +} diff --git a/module/device/openhab/src/main/java/org/openbase/bco/device/openhab/jp/JPOpenHABSitemap.java b/module/device/openhab/src/main/java/org/openbase/bco/device/openhab/jp/JPOpenHABSitemap.java deleted file mode 100644 index add2497857..0000000000 --- a/module/device/openhab/src/main/java/org/openbase/bco/device/openhab/jp/JPOpenHABSitemap.java +++ /dev/null @@ -1,51 +0,0 @@ -package org.openbase.bco.device.openhab.jp; - -/*- - * #%L - * BCO Openhab Device Manager - * %% - * Copyright (C) 2015 - 2021 openbase.org - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program. If not, see - * . - * #L% - */ - -import org.openbase.jps.core.JPService; -import org.openbase.jps.exception.JPNotAvailableException; -import org.openbase.jps.preset.AbstractJPDirectory; -import org.openbase.jps.preset.AbstractJPFile; -import org.openbase.jps.tools.FileHandler; - -import java.io.File; - -public class JPOpenHABSitemap extends AbstractJPDirectory { - private static final String[] COMMAND_IDENTIFIERS = {"--sitemap"}; - - public JPOpenHABSitemap() { - super(COMMAND_IDENTIFIERS, FileHandler.ExistenceHandling.Must, FileHandler.AutoMode.Off); - registerDependingProperty(JPOpenHABConfiguration.class); - } - - @Override - protected File getPropertyDefaultValue() throws JPNotAvailableException { - return new File(JPService.getProperty(JPOpenHABConfiguration.class).getValue(), "sitemaps"); - } - - @Override - public String getDescription() { - return "Defines the path to the openhab sitemap directory."; - } - -} diff --git a/module/device/openhab/src/main/java/org/openbase/bco/device/openhab/jp/JPOpenHABSitemap.kt b/module/device/openhab/src/main/java/org/openbase/bco/device/openhab/jp/JPOpenHABSitemap.kt new file mode 100644 index 0000000000..8683203b59 --- /dev/null +++ b/module/device/openhab/src/main/java/org/openbase/bco/device/openhab/jp/JPOpenHABSitemap.kt @@ -0,0 +1,27 @@ +package org.openbase.bco.device.openhab.jp + +import org.openbase.jps.core.JPService +import org.openbase.jps.exception.JPNotAvailableException +import org.openbase.jps.preset.AbstractJPDirectory +import org.openbase.jps.tools.FileHandler +import java.io.File + +class JPOpenHABSitemap : + AbstractJPDirectory(COMMAND_IDENTIFIERS, FileHandler.ExistenceHandling.Must, FileHandler.AutoMode.Off) { + init { + registerDependingProperty(JPOpenHABConfiguration::class.java) + } + + @Throws(JPNotAvailableException::class) + override fun getPropertyDefaultValue(): File { + return File(JPService.getProperty(JPOpenHABConfiguration::class.java).value, "sitemaps") + } + + override fun getDescription(): String { + return "Defines the path to the openhab sitemap directory." + } + + companion object { + private val COMMAND_IDENTIFIERS = arrayOf("--sitemap") + } +} diff --git a/module/device/openhab/src/main/java/org/openbase/bco/device/openhab/jp/JPOpenHABURI.java b/module/device/openhab/src/main/java/org/openbase/bco/device/openhab/jp/JPOpenHABURI.java deleted file mode 100644 index f579407fe0..0000000000 --- a/module/device/openhab/src/main/java/org/openbase/bco/device/openhab/jp/JPOpenHABURI.java +++ /dev/null @@ -1,79 +0,0 @@ -package org.openbase.bco.device.openhab.jp; - -/*- - * #%L - * BCO Openhab Device Manager - * %% - * Copyright (C) 2015 - 2021 openbase.org - * %% - * This program is free software: you can redistribute it and/or modify - * it under the terms of the GNU General Public License as - * published by the Free Software Foundation, either version 3 of the - * License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public - * License along with this program. If not, see - * . - * #L% - */ - -import org.openbase.jps.core.AbstractJavaProperty; - -import java.net.URI; -import java.util.List; - -/** - * @author Tamino Huxohl - */ -public class JPOpenHABURI extends AbstractJavaProperty { - - private static final String[] ARGUMENT_IDENTIFIERS = {"URI"}; - private static final String[] COMMAND_IDENTIFIERS = {"--openhab-url", "--openhab-uri", "--uri"}; - - private static final String DEFAULT_URI = "http://openhab:8080"; - - public static final String SYSTEM_VARIABLE_OPENHAB_PORT = "OPENHAB_HTTP_PORT"; - - public JPOpenHABURI() { - super(COMMAND_IDENTIFIERS); - } - - @Override - protected String[] generateArgumentIdentifiers() { - return ARGUMENT_IDENTIFIERS; - } - - @Override - protected URI getPropertyDefaultValue() { - // URI.create does not throw an exception which is fine for the default value - - // use system variable if defined - String systemDefinedPort = System.getenv(SYSTEM_VARIABLE_OPENHAB_PORT); - if (systemDefinedPort != null) { - return URI.create("http://localhost:" + systemDefinedPort); - } - - return URI.create(DEFAULT_URI); - } - - @Override - protected URI parse(final List list) throws Exception { - String uri = getOneArgumentResult(); - // make sure that the uri always starts with http ot https - if (!uri.startsWith("http")) { - uri = "http://" + uri; - } - // create a new uri, this will throw an exception if the uri is not valid - return new URI(uri); - } - - @Override - public String getDescription() { - return "Define the URI of the OpenHAB 2 instance this app should connect to."; - } -} diff --git a/module/device/openhab/src/main/java/org/openbase/bco/device/openhab/jp/JPOpenHABURI.kt b/module/device/openhab/src/main/java/org/openbase/bco/device/openhab/jp/JPOpenHABURI.kt new file mode 100644 index 0000000000..762ecb0e34 --- /dev/null +++ b/module/device/openhab/src/main/java/org/openbase/bco/device/openhab/jp/JPOpenHABURI.kt @@ -0,0 +1,50 @@ +package org.openbase.bco.device.openhab.jp + +import org.openbase.jps.core.AbstractJavaProperty +import java.net.URI + +/** + * @author [Tamino Huxohl](mailto:pleminoq@openbase.org) + */ +class JPOpenHABURI : AbstractJavaProperty(COMMAND_IDENTIFIERS) { + override fun generateArgumentIdentifiers(): Array { + return ARGUMENT_IDENTIFIERS + } + + override fun getPropertyDefaultValue(): URI { + // URI.create does not throw an exception which is fine for the default value + + // use system variable if defined + + val systemDefinedPort = System.getenv(SYSTEM_VARIABLE_OPENHAB_PORT) + if (systemDefinedPort != null) { + return URI.create("http://localhost:$systemDefinedPort") + } + + return URI.create(DEFAULT_URI) + } + + @Throws(Exception::class) + override fun parse(list: List): URI { + var uri = oneArgumentResult + // make sure that the uri always starts with http ot https + if (!uri.startsWith("http")) { + uri = "http://$uri" + } + // create a new uri, this will throw an exception if the uri is not valid + return URI(uri) + } + + override fun getDescription(): String { + return "Define the URI of the OpenHAB 2 instance this app should connect to." + } + + companion object { + private val ARGUMENT_IDENTIFIERS = arrayOf("URI") + private val COMMAND_IDENTIFIERS = arrayOf("--openhab-url", "--openhab-uri", "--uri") + + private const val DEFAULT_URI = "http://openhab:8080" + + const val SYSTEM_VARIABLE_OPENHAB_PORT: String = "OPENHAB_HTTP_PORT" + } +} diff --git a/module/device/openhab/src/main/java/org/openbase/bco/device/openhab/manager/service/BlindStateServiceImpl.java b/module/device/openhab/src/main/java/org/openbase/bco/device/openhab/manager/service/BlindStateServiceImpl.java index 09c6e05659..bedc53054b 100644 --- a/module/device/openhab/src/main/java/org/openbase/bco/device/openhab/manager/service/BlindStateServiceImpl.java +++ b/module/device/openhab/src/main/java/org/openbase/bco/device/openhab/manager/service/BlindStateServiceImpl.java @@ -10,12 +10,12 @@ * it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public * License along with this program. If not, see * . @@ -24,7 +24,6 @@ import org.openbase.bco.dal.lib.layer.service.operation.BlindStateOperationService; import org.openbase.bco.dal.lib.layer.unit.Unit; -import org.openbase.jul.exception.CouldNotPerformException; import org.openbase.jul.exception.InstantiationException; import org.openbase.jul.exception.NotAvailableException; import org.openbase.type.domotic.action.ActionDescriptionType.ActionDescription; @@ -32,8 +31,6 @@ import java.util.concurrent.Future; -// todo: class possibly not used anymore, please validate and cleanup. -@Deprecated public class BlindStateServiceImpl> extends OpenHABService implements BlindStateOperationService { public BlindStateServiceImpl(ST unit) throws InstantiationException { diff --git a/module/device/openhab/src/main/java/org/openbase/bco/device/openhab/manager/service/BrightnessStateServiceImpl.java b/module/device/openhab/src/main/java/org/openbase/bco/device/openhab/manager/service/BrightnessStateServiceImpl.java index f12773be1b..55f323b12b 100644 --- a/module/device/openhab/src/main/java/org/openbase/bco/device/openhab/manager/service/BrightnessStateServiceImpl.java +++ b/module/device/openhab/src/main/java/org/openbase/bco/device/openhab/manager/service/BrightnessStateServiceImpl.java @@ -10,12 +10,12 @@ * it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public * License along with this program. If not, see * . @@ -24,7 +24,6 @@ import org.openbase.bco.dal.lib.layer.service.operation.BrightnessStateOperationService; import org.openbase.bco.dal.lib.layer.unit.Unit; -import org.openbase.jul.exception.CouldNotPerformException; import org.openbase.jul.exception.InstantiationException; import org.openbase.jul.exception.NotAvailableException; import org.openbase.type.domotic.action.ActionDescriptionType.ActionDescription; @@ -32,8 +31,6 @@ import java.util.concurrent.Future; -// todo: class possibly not used anymore, please validate and cleanup. -@Deprecated public class BrightnessStateServiceImpl> extends OpenHABService implements BrightnessStateOperationService { public BrightnessStateServiceImpl(final ST unit) throws InstantiationException { diff --git a/module/device/openhab/src/main/java/org/openbase/bco/device/openhab/manager/service/ColorStateServiceImpl.java b/module/device/openhab/src/main/java/org/openbase/bco/device/openhab/manager/service/ColorStateServiceImpl.java index 3debef69b3..42a932d213 100644 --- a/module/device/openhab/src/main/java/org/openbase/bco/device/openhab/manager/service/ColorStateServiceImpl.java +++ b/module/device/openhab/src/main/java/org/openbase/bco/device/openhab/manager/service/ColorStateServiceImpl.java @@ -10,12 +10,12 @@ * it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public * License along with this program. If not, see * . @@ -24,19 +24,16 @@ import org.openbase.bco.dal.lib.layer.service.operation.ColorStateOperationService; import org.openbase.bco.dal.lib.layer.unit.Unit; -import org.openbase.jul.exception.CouldNotPerformException; import org.openbase.jul.exception.InstantiationException; import org.openbase.jul.exception.NotAvailableException; +import org.openbase.type.domotic.action.ActionDescriptionType.ActionDescription; +import org.openbase.type.domotic.state.ColorStateType.ColorState; import org.openbase.type.vision.ColorType.Color; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import org.openbase.type.domotic.action.ActionDescriptionType.ActionDescription; -import org.openbase.type.domotic.state.ColorStateType.ColorState; import java.util.concurrent.Future; -// todo: class possibly not used anymore, please validate and cleanup. -@Deprecated public class ColorStateServiceImpl> extends OpenHABService implements ColorStateOperationService { private static final Logger LOGGER = LoggerFactory.getLogger(ColorStateServiceImpl.class); diff --git a/module/device/openhab/src/main/java/org/openbase/bco/device/openhab/manager/service/PowerStateServiceImpl.java b/module/device/openhab/src/main/java/org/openbase/bco/device/openhab/manager/service/PowerStateServiceImpl.java index f636448083..68e5e85668 100644 --- a/module/device/openhab/src/main/java/org/openbase/bco/device/openhab/manager/service/PowerStateServiceImpl.java +++ b/module/device/openhab/src/main/java/org/openbase/bco/device/openhab/manager/service/PowerStateServiceImpl.java @@ -10,12 +10,12 @@ * it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public * License along with this program. If not, see * . @@ -24,7 +24,6 @@ import org.openbase.bco.dal.lib.layer.service.operation.PowerStateOperationService; import org.openbase.bco.dal.lib.layer.unit.Unit; -import org.openbase.jul.exception.CouldNotPerformException; import org.openbase.jul.exception.InstantiationException; import org.openbase.jul.exception.NotAvailableException; import org.openbase.type.domotic.action.ActionDescriptionType.ActionDescription; @@ -32,9 +31,6 @@ import java.util.concurrent.Future; -// todo: class possibly not used anymore, please validate and cleanup. -// otherwise, implement CustomOpenhabService and handle more generic and check why activation state was not required? -@Deprecated public class PowerStateServiceImpl> extends OpenHABService implements PowerStateOperationService { public PowerStateServiceImpl(final ST unit) throws InstantiationException { diff --git a/module/device/openhab/src/main/java/org/openbase/bco/device/openhab/manager/service/StandbyStateServiceImpl.java b/module/device/openhab/src/main/java/org/openbase/bco/device/openhab/manager/service/StandbyStateServiceImpl.java index e1d11ce227..22e10e6c81 100644 --- a/module/device/openhab/src/main/java/org/openbase/bco/device/openhab/manager/service/StandbyStateServiceImpl.java +++ b/module/device/openhab/src/main/java/org/openbase/bco/device/openhab/manager/service/StandbyStateServiceImpl.java @@ -10,12 +10,12 @@ * it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public * License along with this program. If not, see * . @@ -24,7 +24,6 @@ import org.openbase.bco.dal.lib.layer.service.operation.StandbyStateOperationService; import org.openbase.bco.dal.lib.layer.unit.Unit; -import org.openbase.jul.exception.CouldNotPerformException; import org.openbase.jul.exception.InstantiationException; import org.openbase.jul.exception.NotAvailableException; import org.openbase.type.domotic.action.ActionDescriptionType.ActionDescription; @@ -32,8 +31,6 @@ import java.util.concurrent.Future; -// todo: class possibly not used anymore, please validate and cleanup. -@Deprecated public class StandbyStateServiceImpl> extends OpenHABService implements StandbyStateOperationService { public StandbyStateServiceImpl(ST unit) throws InstantiationException { diff --git a/module/device/openhab/src/main/java/org/openbase/bco/device/openhab/manager/service/TargetTemperatureStateServiceImpl.java b/module/device/openhab/src/main/java/org/openbase/bco/device/openhab/manager/service/TargetTemperatureStateServiceImpl.java index e8dbe54f42..5fa8fccc47 100644 --- a/module/device/openhab/src/main/java/org/openbase/bco/device/openhab/manager/service/TargetTemperatureStateServiceImpl.java +++ b/module/device/openhab/src/main/java/org/openbase/bco/device/openhab/manager/service/TargetTemperatureStateServiceImpl.java @@ -10,12 +10,12 @@ * it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public * License along with this program. If not, see * . @@ -24,7 +24,6 @@ import org.openbase.bco.dal.lib.layer.service.operation.TargetTemperatureStateOperationService; import org.openbase.bco.dal.lib.layer.unit.Unit; -import org.openbase.jul.exception.CouldNotPerformException; import org.openbase.jul.exception.InstantiationException; import org.openbase.jul.exception.NotAvailableException; import org.openbase.type.domotic.action.ActionDescriptionType.ActionDescription; @@ -32,8 +31,6 @@ import java.util.concurrent.Future; -// todo: class possibly not used anymore, please validate and cleanup. -@Deprecated public class TargetTemperatureStateServiceImpl> extends OpenHABService implements TargetTemperatureStateOperationService { public TargetTemperatureStateServiceImpl(ST unit) throws InstantiationException { diff --git a/module/device/openhab/src/main/java/org/openbase/bco/device/openhab/registry/OpenHABConfigSynchronizer.java b/module/device/openhab/src/main/java/org/openbase/bco/device/openhab/registry/OpenHABConfigSynchronizer.java index 21b6c0de08..bce68b50bc 100644 --- a/module/device/openhab/src/main/java/org/openbase/bco/device/openhab/registry/OpenHABConfigSynchronizer.java +++ b/module/device/openhab/src/main/java/org/openbase/bco/device/openhab/registry/OpenHABConfigSynchronizer.java @@ -10,12 +10,12 @@ * it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public * License along with this program. If not, see * . @@ -39,7 +39,7 @@ public class OpenHABConfigSynchronizer implements Launchable, VoidInitiali private static final Logger LOGGER = LoggerFactory.getLogger(OpenHABConfigSynchronizer.class); - private final SyncObject synchronizationLock = new SyncObject("SyncLock"); + private final static SyncObject synchronizationLock = new SyncObject("SyncLock"); private final InboxApprover inboxApprover; diff --git a/module/device/openhab/src/main/java/org/openbase/bco/device/openhab/registry/synchronizer/InboxApprover.java b/module/device/openhab/src/main/java/org/openbase/bco/device/openhab/registry/synchronizer/InboxApprover.java index 8bb65f4e8d..fcfc78b2b0 100644 --- a/module/device/openhab/src/main/java/org/openbase/bco/device/openhab/registry/synchronizer/InboxApprover.java +++ b/module/device/openhab/src/main/java/org/openbase/bco/device/openhab/registry/synchronizer/InboxApprover.java @@ -84,7 +84,7 @@ public InboxApprover() { // ignore not supported things } catch (NotAvailableException ex) { // no matching gateway or device class found so ignore it for now - ExceptionPrinter.printHistory("Ignore discovered thing[" + discoveryResultDTO.thingUID + "].", ex, LOGGER, LogLevel.WARN); + ExceptionPrinter.printHistory("Ignore discovered thing[" + discoveryResultDTO.thingUID + "].", ex, LOGGER, LogLevel.INFO); } }; } diff --git a/module/device/openhab/src/main/java/org/openbase/bco/device/openhab/registry/synchronizer/ItemUnitSynchronization.java b/module/device/openhab/src/main/java/org/openbase/bco/device/openhab/registry/synchronizer/ItemUnitSynchronization.java index 9ee6ebd6f1..c648aef2aa 100644 --- a/module/device/openhab/src/main/java/org/openbase/bco/device/openhab/registry/synchronizer/ItemUnitSynchronization.java +++ b/module/device/openhab/src/main/java/org/openbase/bco/device/openhab/registry/synchronizer/ItemUnitSynchronization.java @@ -39,6 +39,7 @@ import java.util.ArrayList; import java.util.List; +import java.util.Objects; /** * @author Tamino Huxohl @@ -51,7 +52,7 @@ public ItemUnitSynchronization(final SyncObject synchronizationLock) throws Inst @Override public void activate() throws CouldNotPerformException, InterruptedException { - OpenHABRestCommunicator.getInstance().waitForConnectionState(ConnectionState.State.CONNECTED); + Objects.requireNonNull(OpenHABRestCommunicator.getInstance()).waitForConnectionState(ConnectionState.State.CONNECTED); super.activate(); } diff --git a/module/device/openhab/src/main/java/org/openbase/bco/device/openhab/registry/synchronizer/ThingUnitSynchronization.java b/module/device/openhab/src/main/java/org/openbase/bco/device/openhab/registry/synchronizer/ThingUnitSynchronization.java index 2d0a0cb97c..af04fe1491 100644 --- a/module/device/openhab/src/main/java/org/openbase/bco/device/openhab/registry/synchronizer/ThingUnitSynchronization.java +++ b/module/device/openhab/src/main/java/org/openbase/bco/device/openhab/registry/synchronizer/ThingUnitSynchronization.java @@ -38,11 +38,11 @@ import org.openhab.core.io.rest.core.thing.EnrichedThingDTO; import org.openhab.core.items.dto.ItemDTO; import org.openhab.core.thing.dto.ChannelDTO; -import org.openhab.core.thing.dto.ThingDTO; import org.openhab.core.thing.link.dto.ItemChannelLinkDTO; import java.util.ArrayList; import java.util.List; +import java.util.Objects; import java.util.concurrent.ExecutionException; /** @@ -63,7 +63,7 @@ public ThingUnitSynchronization(final SyncObject synchronizationLock) throws Ins @Override public void activate() throws CouldNotPerformException, InterruptedException { - OpenHABRestCommunicator.getInstance().waitForConnectionState(ConnectionState.State.CONNECTED); + Objects.requireNonNull(OpenHABRestCommunicator.getInstance()).waitForConnectionState(ConnectionState.State.CONNECTED); super.activate(); } diff --git a/module/registry/lib/src/main/java/org/openbase/bco/registry/lib/util/UnitConfigProcessor.java b/module/registry/lib/src/main/java/org/openbase/bco/registry/lib/util/UnitConfigProcessor.java index 2afb05b2d0..019a930879 100644 --- a/module/registry/lib/src/main/java/org/openbase/bco/registry/lib/util/UnitConfigProcessor.java +++ b/module/registry/lib/src/main/java/org/openbase/bco/registry/lib/util/UnitConfigProcessor.java @@ -10,12 +10,12 @@ * it under the terms of the GNU General Public License as * published by the Free Software Foundation, either version 3 of the * License, or (at your option) any later version. - * + * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. - * + * * You should have received a copy of the GNU General Public * License along with this program. If not, see * . @@ -30,17 +30,19 @@ import org.openbase.jul.exception.printer.ExceptionPrinter; import org.openbase.jul.exception.printer.LogLevel; import org.openbase.jul.extension.protobuf.processing.ProtoBufFieldProcessor; -import org.openbase.jul.extension.type.processing.ScopeProcessor; import org.openbase.jul.extension.type.processing.LabelProcessor; import org.openbase.jul.extension.type.processing.ScopeProcessor; import org.openbase.jul.processing.StringProcessor; -import org.slf4j.LoggerFactory; import org.openbase.type.domotic.state.EnablingStateType; import org.openbase.type.domotic.unit.UnitConfigType.UnitConfig; import org.openbase.type.domotic.unit.UnitConfigType.UnitConfigOrBuilder; import org.openbase.type.domotic.unit.UnitTemplateType.UnitTemplate.UnitType; +import org.slf4j.LoggerFactory; -import java.util.*; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.List; /** * @author Tamino Huxohl @@ -295,6 +297,11 @@ public static FieldDescriptor getUnitTypeFieldDescriptor(final UnitType unitType * @return the default alias as string. */ public static String getDefaultAlias(final UnitConfigOrBuilder unitConfig, final String alternative) { + + if (unitConfig == null) { + return alternative; + } + try { return getDefaultAlias(unitConfig); } catch (NotAvailableException e) { diff --git a/module/registry/unit-registry/lib/src/main/java/org/openbase/bco/registry/unit/lib/auth/AuthorizationWithTokenHelper.kt b/module/registry/unit-registry/lib/src/main/java/org/openbase/bco/registry/unit/lib/auth/AuthorizationWithTokenHelper.kt index 4a9221328e..52a7b39247 100644 --- a/module/registry/unit-registry/lib/src/main/java/org/openbase/bco/registry/unit/lib/auth/AuthorizationWithTokenHelper.kt +++ b/module/registry/unit-registry/lib/src/main/java/org/openbase/bco/registry/unit/lib/auth/AuthorizationWithTokenHelper.kt @@ -250,24 +250,24 @@ object AuthorizationWithTokenHelper { // check if authenticated user has needed permissions if (AuthorizationHelper.canDo( unitConfig, - userClientPair.getUserId(), + userClientPair.userId, unitRegistry.getAuthorizationGroupMap(), unitRegistry.getLocationMap(), permissionType ) ) { - return AuthPair(userClientPair, userClientPair.getUserId()) + return AuthPair(userClientPair, userClientPair.userId) } if (AuthorizationHelper.canDo( unitConfig, - userClientPair.getClientId(), + userClientPair.clientId, unitRegistry.getAuthorizationGroupMap(), unitRegistry.getLocationMap(), permissionType ) ) { - return AuthPair(userClientPair, userClientPair.getClientId()) + return AuthPair(userClientPair, userClientPair.clientId) } // authenticated user does not have permissions so check if the authorization token grants them @@ -290,11 +290,11 @@ object AuthorizationWithTokenHelper { ) } } - var userRepresentation = userClientPair.getUserId() + var userRepresentation = userClientPair.userId if (userRepresentation.isNotEmpty()) { userRepresentation += "@" } - userRepresentation += userClientPair.getClientId() + userRepresentation += userClientPair.clientId if (userRepresentation.isEmpty()) { userRepresentation = "Other" }