From e429e1ddeaf2bc78a415022d9151912b08310834 Mon Sep 17 00:00:00 2001 From: Javier Guerra Melgares Date: Fri, 13 Dec 2019 11:37:38 +0100 Subject: [PATCH 1/6] Update end-entity certificate --- src/main/resources/data/kyrio-ee-cert.pem | 18 +++++++++--------- src/main/resources/data/kyrio-ee-key.pem | 6 +++--- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/src/main/resources/data/kyrio-ee-cert.pem b/src/main/resources/data/kyrio-ee-cert.pem index 3ee52a3..9dcb5b9 100644 --- a/src/main/resources/data/kyrio-ee-cert.pem +++ b/src/main/resources/data/kyrio-ee-cert.pem @@ -1,14 +1,14 @@ -----BEGIN CERTIFICATE----- -MIIEEzCCA7mgAwIBAgIJAI0K+3tTsk0AMAoGCCqGSM49BAMCMFsxDDAKBgNVBAoM +MIIEEzCCA7mgAwIBAgIJAI0K+3tTsk07MAoGCCqGSM49BAMCMFsxDDAKBgNVBAoM A09DRjEiMCAGA1UECwwZS3lyaW8gVGVzdCBJbmZyYXN0cnVjdHVyZTEnMCUGA1UE -AwweS3lyaW8gVEVTVCBJbnRlcm1lZGlhdGUgQ0EwMDAyMB4XDTE5MTAyNDA5NDg1 -NFoXDTE5MTEyMzA5NDg1NFowYTEMMAoGA1UECgwDT0NGMSIwIAYDVQQLDBlLeXJp +AwweS3lyaW8gVEVTVCBJbnRlcm1lZGlhdGUgQ0EwMDAyMB4XDTE5MTEyODEzMzYw +OVoXDTE5MTIyODEzMzYwOVowYTEMMAoGA1UECgwDT0NGMSIwIAYDVQQLDBlLeXJp byBUZXN0IEluZnJhc3RydWN0dXJlMS0wKwYDVQQDDCQxZTFiZWJmYi04ZjAzLTQ3 -ODUtNWZhNy0xYjcwNGU2NTQzNjAwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAATW -d0t/5GahEMUSb8dhaOIZdTDHDTelbWWfjSxA6OhcMy1uKGewCg7e2R2ZTK7ZM/th -KSXuMywN0JXA6BoW9on8o4ICXjCCAlowCQYDVR0TBAIwADAOBgNVHQ8BAf8EBAMC +ODUtNWZhNy0xYjcwNGU2NTQzNjAwWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQS +rNS0ha8XBiRD+Q7nL+R3uX7f5FPgQO75Wh9PqaiVLhMFewF/Yrbr+KhCdj8e6MNz +WGDbVtMVc59RBHyvgzbho4ICXjCCAlowCQYDVR0TBAIwADAOBgNVHQ8BAf8EBAMC A4gwKQYDVR0lBCIwIAYIKwYBBQUHAwIGCCsGAQUFBwMBBgorBgEEAYLefAEGMB0G -A1UdDgQWBBS+4P5iaPJfppBg66266sma6Ffe9jAfBgNVHSMEGDAWgBQZc2oEGgsH +A1UdDgQWBBR1GbdeJoLZj6iMx9ZDNEv+aoECrjAfBgNVHSMEGDAWgBQZc2oEGgsH cE9TeVM2h/wMunyuCzCBlgYIKwYBBQUHAQEEgYkwgYYwXQYIKwYBBQUHMAKGUWh0 dHA6Ly90ZXN0cGtpLmt5cmlvLmNvbS9vY2YvY2FjZXJ0cy9CQkU2NEY5QTdFRTM3 RDI5QTA1RTRCQjc3NTk1RjMwOEJFNDFFQjA3LmNydDAlBggrBgEFBQcwAYYZaHR0 @@ -19,6 +19,6 @@ AjBgBgorBgEEAYORVgEABFIwUDAJAgECAgEAAgEAMDYMGTEuMy42LjEuNC4xLjUx NDE0LjAuMC4xLjAMGTEuMy42LjEuNC4xLjUxNDE0LjAuMC4yLjAMBE9UR0MMBURF S1JBMCoGCisGAQQBg5FWAQEEHDAaBgsrBgEEAYORVgEBAAYLKwYBBAGDkVYBAQEw MAYKKwYBBAGDkVYBAgQiMCAMDjEuMy42LjEuNC4xLjcxDAlEaXNjb3ZlcnkMAzEu -MDAKBggqhkjOPQQDAgNIADBFAiEA3Ay4oPSGwARJWub9/k58xiqARpRKjCDaGGZi -mHTurqYCIC/e7Y9NAMiweZZ2JaGAYXC7T8YTqAFneT9jaq2o3c9m +MDAKBggqhkjOPQQDAgNIADBFAiAP9ttApmZfcFoipNra7ZqFa1kdD7JxmD84fuMH +XXyTBgIhAIIrpiVkOxAQqTlfDpJZk3F8byz/x2c9xpNeQEZTllMc -----END CERTIFICATE----- diff --git a/src/main/resources/data/kyrio-ee-key.pem b/src/main/resources/data/kyrio-ee-key.pem index eb4fad6..80c8b7a 100644 --- a/src/main/resources/data/kyrio-ee-key.pem +++ b/src/main/resources/data/kyrio-ee-key.pem @@ -2,7 +2,7 @@ BggqhkjOPQMBBw== -----END EC PARAMETERS----- -----BEGIN EC PRIVATE KEY----- -MHcCAQEEIDUCAKRYHFbz7MVYj4LASsOxX54sYcVNbE4MLwIa/0j/oAoGCCqGSM49 -AwEHoUQDQgAE1ndLf+RmoRDFEm/HYWjiGXUwxw03pW1ln40sQOjoXDMtbihnsAoO -3tkdmUyu2TP7YSkl7jMsDdCVwOgaFvaJ/A== +MHcCAQEEIDFeXNSayEnCQIlEjbV+4vGKeqRAmjnspnA8ICW0FnAwoAoGCCqGSM49 +AwEHoUQDQgAEEqzUtIWvFwYkQ/kO5y/kd7l+3+RT4EDu+VofT6molS4TBXsBf2K2 +6/ioQnY/HujDc1hg21bTFXOfUQR8r4M24Q== -----END EC PRIVATE KEY----- From 46b19a196b20c0c40331ed0ab4ec5c0fc80b61ef Mon Sep 17 00:00:00 2001 From: Javier Guerra Melgares Date: Fri, 13 Dec 2019 11:39:23 +0100 Subject: [PATCH 2/6] Fix duplicate devices during scanning --- .../otgc/data/repository/IotivityRepository.java | 10 ++++++++-- .../otgc/domain/model/devicelist/Device.java | 10 ++++++++++ 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/src/main/java/org/openconnectivity/otgc/data/repository/IotivityRepository.java b/src/main/java/org/openconnectivity/otgc/data/repository/IotivityRepository.java index 7b293f5..fb4eaa9 100644 --- a/src/main/java/org/openconnectivity/otgc/data/repository/IotivityRepository.java +++ b/src/main/java/org/openconnectivity/otgc/data/repository/IotivityRepository.java @@ -162,7 +162,10 @@ public Observable scanUnownedDevices() { deviceDao.insert(new DeviceEntity(deviceId, device.getName(), endpoints, DeviceType.UNOWNED, Device.NOTHING_PERMITS)); } - unownedDevices.add(new Device(DeviceType.UNOWNED, deviceId, new OcDeviceInfo(), endpoints, Device.NOTHING_PERMITS)); + Device device1 = new Device(DeviceType.UNOWNED, deviceId, new OcDeviceInfo(), endpoints, Device.NOTHING_PERMITS); + if (!unownedDevices.contains(device1)) { + unownedDevices.add(device1); + } }; int ret; @@ -202,7 +205,10 @@ public Observable scanOwnedDevices() { deviceDao.insert(new DeviceEntity(deviceId, device.getName(), endpoints, DeviceType.OWNED_BY_SELF, Device.FULL_PERMITS)); } - ownedDevices.add(new Device(DeviceType.OWNED_BY_SELF, deviceId, new OcDeviceInfo(), endpoints, Device.FULL_PERMITS)); + Device device1 = new Device(DeviceType.OWNED_BY_SELF, deviceId, new OcDeviceInfo(), endpoints, Device.FULL_PERMITS); + if (!ownedDevices.contains(device1)) { + ownedDevices.add(device1); + } }; int ret; diff --git a/src/main/java/org/openconnectivity/otgc/domain/model/devicelist/Device.java b/src/main/java/org/openconnectivity/otgc/domain/model/devicelist/Device.java index c655496..45533b1 100644 --- a/src/main/java/org/openconnectivity/otgc/domain/model/devicelist/Device.java +++ b/src/main/java/org/openconnectivity/otgc/domain/model/devicelist/Device.java @@ -233,4 +233,14 @@ public int compareTo(Device device) { return res; } + + @Override + public boolean equals(Object device) { + boolean same = false; + + if (device != null && device instanceof Device) { + same = this.deviceId.equals(((Device)device).getDeviceId()); + } + return same; + } } From cd279d82493e0b066481ef13e6a486cb4e3c726e Mon Sep 17 00:00:00 2001 From: Javier Guerra Melgares Date: Fri, 13 Dec 2019 11:41:26 +0100 Subject: [PATCH 3/6] Fix discover button in menu --- .../java/org/openconnectivity/otgc/view/menu/MenuView.java | 6 ++---- .../otgc/viewmodel/DeviceListViewModel.java | 6 ++++++ .../org/openconnectivity/otgc/viewmodel/MenuViewModel.java | 5 +++++ 3 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/main/java/org/openconnectivity/otgc/view/menu/MenuView.java b/src/main/java/org/openconnectivity/otgc/view/menu/MenuView.java index 537511a..2e3f4ef 100644 --- a/src/main/java/org/openconnectivity/otgc/view/menu/MenuView.java +++ b/src/main/java/org/openconnectivity/otgc/view/menu/MenuView.java @@ -20,9 +20,7 @@ package org.openconnectivity.otgc.view.menu; import com.google.inject.Inject; -import de.saxsys.mvvmfx.FluentViewLoader; -import de.saxsys.mvvmfx.FxmlView; -import de.saxsys.mvvmfx.InjectViewModel; +import de.saxsys.mvvmfx.*; import javafx.fxml.FXML; import javafx.fxml.Initializable; import javafx.scene.Parent; @@ -57,7 +55,7 @@ public void initialize(URL url, ResourceBundle resourceBundle) { @FXML public void discover() { - // TODO + viewModel.discover(); } @FXML diff --git a/src/main/java/org/openconnectivity/otgc/viewmodel/DeviceListViewModel.java b/src/main/java/org/openconnectivity/otgc/viewmodel/DeviceListViewModel.java index 0355009..41050b1 100644 --- a/src/main/java/org/openconnectivity/otgc/viewmodel/DeviceListViewModel.java +++ b/src/main/java/org/openconnectivity/otgc/viewmodel/DeviceListViewModel.java @@ -86,6 +86,12 @@ public void initialize() { onDiscoverRequest(); }) ); + notificationCenter.subscribe(NotificationKey.SCAN_DEVICES, + ((key, payload) -> { + notificationCenter.publish(NotificationKey.REFRESH_ID); + onDiscoverRequest(); + }) + ); deviceListToolbarDetailScope.subscribe(NotificationKey.UPDATE_DEVICE, (key, payload) -> updateItem((int) payload[0], (Device) payload[1])); deviceListToolbarDetailScope.subscribe(NotificationKey.UPDATE_DEVICE_TYPE, (key, payload) -> updateDevice((Device)payload[0])); } diff --git a/src/main/java/org/openconnectivity/otgc/viewmodel/MenuViewModel.java b/src/main/java/org/openconnectivity/otgc/viewmodel/MenuViewModel.java index 542e55f..f9372cd 100644 --- a/src/main/java/org/openconnectivity/otgc/viewmodel/MenuViewModel.java +++ b/src/main/java/org/openconnectivity/otgc/viewmodel/MenuViewModel.java @@ -58,7 +58,12 @@ public void initialize() { (key, payload) -> deviceUuid.setValue(getDeviceIdUseCase.execute().blockingGet())); } + public void discover() { + notificationCenter.publish(NotificationKey.SCAN_DEVICES); + } + public void closeAction() { closeIotivityUseCase.execute(); + System.exit(1); } } From 1688ffad70c59fbe4747485f9284de3415a7f48e Mon Sep 17 00:00:00 2001 From: Javier Guerra Melgares Date: Fri, 13 Dec 2019 11:45:49 +0100 Subject: [PATCH 4/6] Work item 13 - Onboarding multiple devices in a batch --- .../otgc/data/repository/DoxsRepository.java | 5 +- .../domain/usecase/OnboardDevicesUseCase.java | 83 ++++++++++ .../utils/handler/OCSetRandomPinHandler.java | 2 +- .../scopes/DeviceListToolbarDetailScope.java | 10 +- .../otgc/view/devicelist/DeviceListView.java | 17 +- .../otgc/view/main/MainView.java | 6 +- .../otgc/view/toolbar/ToolbarView.java | 134 +++++++++++++-- .../viewmodel/AccessControlViewModel.java | 98 +++++------ .../otgc/viewmodel/ClientViewModel.java | 85 ++++++---- .../otgc/viewmodel/CredentialViewModel.java | 75 +++++---- .../otgc/viewmodel/DeviceListViewModel.java | 64 ++++---- .../otgc/viewmodel/LinkDevicesViewModel.java | 146 +++++++++-------- .../otgc/viewmodel/ToolbarViewModel.java | 153 +++++++++++++++++- 13 files changed, 631 insertions(+), 247 deletions(-) create mode 100644 src/main/java/org/openconnectivity/otgc/domain/usecase/OnboardDevicesUseCase.java diff --git a/src/main/java/org/openconnectivity/otgc/data/repository/DoxsRepository.java b/src/main/java/org/openconnectivity/otgc/data/repository/DoxsRepository.java index 89cb247..c23375b 100644 --- a/src/main/java/org/openconnectivity/otgc/data/repository/DoxsRepository.java +++ b/src/main/java/org/openconnectivity/otgc/data/repository/DoxsRepository.java @@ -62,8 +62,9 @@ public Completable doOwnershipTransfer(String deviceId, OcfOxmType oxm) { } else if (oxm == OcfOxmType.OC_OXMTYPE_RDP) { ret = OCObt.requestRandomPin(uuid, (OCUuid ocUuid, int status) -> { if (status >= 0) { - LOG.debug("Successfully request Random PIN " + OCUuidUtil.uuidToString(ocUuid)); - String pin = randomPinHandler.handler(); + String id = OCUuidUtil.uuidToString(ocUuid); + LOG.debug("Successfully request Random PIN " + id); + String pin = randomPinHandler.handler(id); if (OCObt.performRandomPinOtm(uuid, pin, handler) != -1){ emitter.onComplete(); } else { diff --git a/src/main/java/org/openconnectivity/otgc/domain/usecase/OnboardDevicesUseCase.java b/src/main/java/org/openconnectivity/otgc/domain/usecase/OnboardDevicesUseCase.java new file mode 100644 index 0000000..5c41ebd --- /dev/null +++ b/src/main/java/org/openconnectivity/otgc/domain/usecase/OnboardDevicesUseCase.java @@ -0,0 +1,83 @@ +package org.openconnectivity.otgc.domain.usecase; + +import io.reactivex.Single; +import org.openconnectivity.otgc.data.repository.DoxsRepository; +import org.openconnectivity.otgc.data.repository.IotivityRepository; +import org.openconnectivity.otgc.data.repository.SettingRepository; +import org.openconnectivity.otgc.domain.model.devicelist.Device; +import org.openconnectivity.otgc.utils.constant.OcfOxmType; +import org.openconnectivity.otgc.utils.rx.SchedulersFacade; + +import javax.inject.Inject; +import java.util.List; +import java.util.concurrent.TimeUnit; + +public class OnboardDevicesUseCase { + + /* Repositories */ + private final IotivityRepository iotivityRepository; + private final DoxsRepository doxsRepository; + private final SettingRepository settingRepository; + /* Scheduler */ + private final SchedulersFacade schedulersFacade; + + @Inject + public OnboardDevicesUseCase(IotivityRepository iotivityRepository, + DoxsRepository doxsRepository, + SettingRepository settingRepository, + SchedulersFacade schedulersFacade) { + this.iotivityRepository = iotivityRepository; + this.doxsRepository = doxsRepository; + this.settingRepository = settingRepository; + + this.schedulersFacade = schedulersFacade; + } + + public Single execute(Device device, List oxms) { + int it1 = oxms.size() - 1; + if (it1 < 0) { + return null; + } + + return executeOnboard(device, oxms.get(it1)) + .onErrorResumeNext(error1 -> { + int it2 = it1 - 1; + if (it2 < 0) { + return null; + } + return iotivityRepository.scanUnownedDevices() + .filter(device1 -> device.getDeviceId().equals(device1.getDeviceId())) + .firstOrError() + .flatMap(device1 -> + executeOnboard(device1, oxms.get(it2)) + .onErrorResumeNext(error -> { + int it3 = it1 - 2; + if (it3 < 0) { + return null; + } + return iotivityRepository.scanUnownedDevices() + .filter(device2 -> device.getDeviceId().equals(device2.getDeviceId())) + .firstOrError() + .flatMap(device2 -> executeOnboard(device2, oxms.get(it3))); + }) + ); + }); + } + + private Single executeOnboard(Device deviceToOnboard, OcfOxmType oxm) { + int delay = Integer.parseInt(settingRepository.get(SettingRepository.REQUESTS_DELAY_KEY, SettingRepository.REQUESTS_DELAY_DEFAULT_VALUE)); + + final Single getUpdatedOcSecureResource = iotivityRepository.scanOwnedDevices() + .filter(device -> deviceToOnboard.getDeviceId().equals(device.getDeviceId()) + || deviceToOnboard.equalsHosts(device)) + .singleOrError(); + + return doxsRepository.doOwnershipTransfer(deviceToOnboard.getDeviceId(), oxm) + .delay(2 * delay, TimeUnit.SECONDS, schedulersFacade.ui()) + .andThen(getUpdatedOcSecureResource + .onErrorResumeNext(error -> getUpdatedOcSecureResource + .retry(2) + .onErrorResumeNext(Single.error(error))) + ); + } +} diff --git a/src/main/java/org/openconnectivity/otgc/utils/handler/OCSetRandomPinHandler.java b/src/main/java/org/openconnectivity/otgc/utils/handler/OCSetRandomPinHandler.java index d3399a5..aa0765b 100644 --- a/src/main/java/org/openconnectivity/otgc/utils/handler/OCSetRandomPinHandler.java +++ b/src/main/java/org/openconnectivity/otgc/utils/handler/OCSetRandomPinHandler.java @@ -1,5 +1,5 @@ package org.openconnectivity.otgc.utils.handler; public interface OCSetRandomPinHandler { - public String handler(); + public String handler(String deviceId); } diff --git a/src/main/java/org/openconnectivity/otgc/utils/scopes/DeviceListToolbarDetailScope.java b/src/main/java/org/openconnectivity/otgc/utils/scopes/DeviceListToolbarDetailScope.java index 10470bf..6d88ff7 100644 --- a/src/main/java/org/openconnectivity/otgc/utils/scopes/DeviceListToolbarDetailScope.java +++ b/src/main/java/org/openconnectivity/otgc/utils/scopes/DeviceListToolbarDetailScope.java @@ -23,10 +23,12 @@ import javafx.beans.property.*; import org.openconnectivity.otgc.domain.model.devicelist.Device; +import java.util.List; + public class DeviceListToolbarDetailScope implements Scope { - private final ObjectProperty selectedDevice = new SimpleObjectProperty<>(this, "selectedDevice"); - public ObjectProperty selectedDeviceProperty() { + private final ObjectProperty> selectedDevice = new SimpleObjectProperty<>(this, "selectedDevice"); + public ObjectProperty> selectedDeviceProperty() { return this.selectedDevice; } @@ -43,7 +45,7 @@ public StringProperty selectedTabProperty() { return this.selectedTab; } - public final Device getSelectedDevice() { + /*public final Device getSelectedDevice() { return this.selectedDeviceProperty().get(); } public final void setSelectedDevice(final Device selectedDevice) { @@ -55,5 +57,5 @@ public final int getPositionSelectedDevice() { } public final void setPositionSelectedDevice(final int position) { this.positionSelectedDeviceProperty().set(position); - } + }*/ } diff --git a/src/main/java/org/openconnectivity/otgc/view/devicelist/DeviceListView.java b/src/main/java/org/openconnectivity/otgc/view/devicelist/DeviceListView.java index ca956cf..2017668 100644 --- a/src/main/java/org/openconnectivity/otgc/view/devicelist/DeviceListView.java +++ b/src/main/java/org/openconnectivity/otgc/view/devicelist/DeviceListView.java @@ -23,9 +23,11 @@ import de.saxsys.mvvmfx.InjectViewModel; import de.saxsys.mvvmfx.utils.notifications.NotificationCenter; import javafx.beans.value.ObservableValue; +import javafx.collections.ObservableList; import javafx.fxml.FXML; import javafx.fxml.Initializable; import javafx.scene.control.ListView; +import javafx.scene.control.SelectionMode; import javafx.stage.Stage; import org.apache.log4j.Logger; import org.openconnectivity.otgc.utils.constant.NotificationKey; @@ -36,7 +38,8 @@ import javax.inject.Inject; import java.net.URL; -import java.util.ResourceBundle; +import java.util.*; +import java.util.stream.Collectors; public class DeviceListView implements FxmlView, Initializable { @@ -64,10 +67,14 @@ public void initialize(URL url, ResourceBundle resourceBundle) { listView.itemsProperty().bind(viewModel.devicesListProperty()); listView.setCellFactory(deviceListView -> new DeviceListViewCell()); - listView.getSelectionModel().selectedItemProperty().addListener(((observable, oldValue, newValue) -> { - viewModel.selectedDeviceProperty().setValue(newValue); - viewModel.positionSelectedDeviceProperty().setValue(viewModel.devicesListProperty().indexOf(newValue)); - })); + listView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE); + listView.getSelectionModel().selectedItemProperty().addListener((observable, oldValue, newValue) -> { + ObservableList devices = listView.getSelectionModel().getSelectedItems(); + viewModel.selectedDeviceProperty().setValue(devices.stream().collect(Collectors.toList())); + if (devices.size() == 1) { + viewModel.positionSelectedDeviceProperty().setValue(viewModel.devicesListProperty().indexOf(devices.get(0))); + } + }); viewModel.scanResponseProperty().addListener(this::processScanResponse); viewModel.updateDeviceResponseProperty().addListener(this::processUpdateDeviceResponse); diff --git a/src/main/java/org/openconnectivity/otgc/view/main/MainView.java b/src/main/java/org/openconnectivity/otgc/view/main/MainView.java index 10dc9f4..b93be25 100644 --- a/src/main/java/org/openconnectivity/otgc/view/main/MainView.java +++ b/src/main/java/org/openconnectivity/otgc/view/main/MainView.java @@ -77,15 +77,15 @@ public void initialize(URL url, ResourceBundle resourceBundle) { } private String verifyPin = ""; - OCSetRandomPinHandler randomPinCallbackListener = () -> { + OCSetRandomPinHandler randomPinCallbackListener = (String uuid) -> { LOG.debug("Inside randomPinListener"); final Object lock = new Object(); Platform.runLater(() -> { ButtonType yesButton = new ButtonType("Yes", ButtonBar.ButtonData.OK_DONE); Alert alertDialog = new Alert(Alert.AlertType.CONFIRMATION); - alertDialog.setTitle("Insert random PIN"); - alertDialog.setHeaderText("PIN: "); + alertDialog.setTitle(uuid); + alertDialog.setHeaderText("Insert random PIN: "); final JFXTextField input = new JFXTextField(); alertDialog.getDialogPane().setGraphic(input); alertDialog.getButtonTypes().clear(); diff --git a/src/main/java/org/openconnectivity/otgc/view/toolbar/ToolbarView.java b/src/main/java/org/openconnectivity/otgc/view/toolbar/ToolbarView.java index c040dca..e37543b 100644 --- a/src/main/java/org/openconnectivity/otgc/view/toolbar/ToolbarView.java +++ b/src/main/java/org/openconnectivity/otgc/view/toolbar/ToolbarView.java @@ -29,9 +29,14 @@ import javafx.beans.value.ObservableValue; import javafx.fxml.FXML; import javafx.fxml.Initializable; +import javafx.geometry.Pos; import javafx.scene.Parent; +import javafx.scene.Scene; import javafx.scene.control.*; +import javafx.scene.layout.VBox; +import javafx.stage.Modality; import javafx.stage.Stage; +import javafx.stage.StageStyle; import org.apache.log4j.Logger; import org.openconnectivity.otgc.domain.model.devicelist.DeviceType; import org.openconnectivity.otgc.utils.constant.NotificationKey; @@ -89,6 +94,11 @@ public void initialize(URL url, ResourceBundle resourceBundle) { viewModel.deviceInfoProperty().addListener(this::processDeviceInfoResponse); viewModel.deviceRoleProperty().addListener(this::processDeviceRoleResponse); viewModel.provisionAceOtmProperty().addListener(this::processProvisionAceOtmResponse); + viewModel.onboardWaitingProperty().addListener(this::processOnboardWaitingResponse); + viewModel.otmMultiResponseProperty().addListener(this::processOtmMultiResponse); + viewModel.deviceInfoMultiProperty().addListener(this::processDeviceInfoMultiResponse); + viewModel.deviceRoleMultiProperty().addListener(this::processDeviceRoleMultiResponse); + viewModel.provisionAceOtmMultiProperty().addListener(this::processProvisionAceOtmMultiResponse); viewModel.offboardResponseProperty().addListener(this::processOffboardResponse); viewModel.clientModeResponseProperty().addListener(this::processClientModeResponse); viewModel.obtModeResponseProperty().addListener(this::processObtModeResponse); @@ -154,23 +164,20 @@ public void handleDiscoverButton() { @FXML public void handleOnboardButton() { - switch(viewModel.deviceProperty.get().getDeviceType()) { - case UNOWNED: - positionBeingUpdated = viewModel.positionDeviceProperty().get(); - viewModel.doOwnershipTransfer(viewModel.deviceProperty.get()); - break; - case OWNED_BY_SELF: - case OWNED_BY_OTHER: - default: - break; + if (viewModel.deviceProperty.get().size() > 1) { + viewModel.onboardAllDevices(viewModel.deviceProperty.get()); + } else { + positionBeingUpdated = viewModel.positionDeviceProperty().get(); + viewModel.doOwnershipTransfer(viewModel.deviceProperty.get().get(0)); } } @FXML public void handleOffboardButton() { - positionBeingUpdated = viewModel.positionDeviceProperty().get(); - - viewModel.offboard(viewModel.deviceProperty.get()); + if (viewModel.deviceProperty.get().size() == 1) { + positionBeingUpdated = viewModel.positionDeviceProperty().get(); + viewModel.offboard(viewModel.deviceProperty.get().get(0)); + } } @FXML @@ -273,6 +280,109 @@ private void processProvisionAceOtmResponse(ObservableValue> observableValue, Response oldValue, Response newValue) { + switch (newValue.status) { + case SUCCESS: + if (newValue.data) { + if (waitingModal == null) { + waitingModal = new Stage(); + waitingModal.initModality(Modality.APPLICATION_MODAL); + waitingModal.initStyle(StageStyle.UTILITY); + //waitingModal.setAlwaysOnTop(true); + waitingModal.setTitle("Waiting"); + waitingModal.setOnCloseRequest(event -> { + event.consume(); + }); + VBox vBox = new VBox(new Label("Please, wait while selected devices are onboarded.")); + vBox.setAlignment(Pos.CENTER); + Scene scene = new Scene(vBox, 400, 100); + waitingModal.setScene(scene); + waitingModal.initOwner(primaryStage); + waitingModal.show(); + + notificationCenter.publish(NotificationKey.SET_PROGRESS_STATUS, true); + Toast.show(primaryStage, resourceBundle.getString("toolbar.otm.load")); + } + } else { + if (waitingModal != null && waitingModal.isShowing()) { + waitingModal.close(); + waitingModal = null; + + notificationCenter.publish(NotificationKey.SET_PROGRESS_STATUS, false); + viewModel.onScanPressed(); + } + } + break; + default: + break; + } + } + + private void processOtmMultiResponse(ObservableValue> observableValue, Response oldValue, Response newValue) { + switch (newValue.status) { + case SUCCESS: + break; + case ERROR: + LOG.debug(newValue.message); + Toast.show(primaryStage, resourceBundle.getString("toolbar.otm.error")); + break; + } + } + + private void processDeviceInfoMultiResponse(ObservableValue> observableValue, Response oldValue, Response newValue) { + switch (newValue.status) { + case LOADING: + break; + case SUCCESS: + break; + case ERROR: + LOG.debug(newValue.message); + Toast.show(primaryStage, resourceBundle.getString("toolbar.get_device_info.error")); + break; + default: + break; + } + } + + private void processDeviceRoleMultiResponse(ObservableValue> observableValue, Response oldValue, Response newValue) { + switch (newValue.status) { + case LOADING: + break; + case SUCCESS: + /*if (newValue.data != null) { + if (newValue.data.getDeviceType() == DeviceType.OWNED_BY_SELF) { + showSetDeviceNameDialog(positionBeingUpdated, newValue.data, newValue.data.getDeviceId(), newValue.data.getDeviceInfo().getName()); + } else { + viewModel.updateItem(positionBeingUpdated, newValue.data); + } + positionBeingUpdated = 0; + }*/ + break; + case ERROR: + LOG.debug(newValue.message); + Toast.show(primaryStage, resourceBundle.getString("toolbar.get_device_role.error")); + break; + default: + break; + } + } + + private void processProvisionAceOtmMultiResponse(ObservableValue> observableValue, Response oldValue, Response newValue) { + switch (newValue.status) { + case LOADING: + break; + case SUCCESS: + break; + case ERROR: + Toast.show(primaryStage, resourceBundle.getString("toolbar.provision_ace_otm.error")); + break; + default: + break; + } + } + private void processOffboardResponse(ObservableValue> observableValue, Response oldValue, Response newValue) { switch (newValue.status) { case LOADING: diff --git a/src/main/java/org/openconnectivity/otgc/viewmodel/AccessControlViewModel.java b/src/main/java/org/openconnectivity/otgc/viewmodel/AccessControlViewModel.java index b5b7280..9fa7177 100644 --- a/src/main/java/org/openconnectivity/otgc/viewmodel/AccessControlViewModel.java +++ b/src/main/java/org/openconnectivity/otgc/viewmodel/AccessControlViewModel.java @@ -52,7 +52,7 @@ public class AccessControlViewModel implements ViewModel { private List selectedVerticalResource = new ArrayList<>(); private List wildcardList = new ArrayList<>(); - public ObjectProperty deviceProperty; + public ObjectProperty> deviceProperty; @InjectScope private DeviceListToolbarDetailScope deviceListToolbarDetailScope; @@ -110,8 +110,8 @@ public void initialize() { } public ObservableBooleanValue amsVisibleProperty() { - return Bindings.createBooleanBinding(() -> deviceProperty.get() != null - && deviceProperty.get().getDeviceType() != DeviceType.UNOWNED, deviceProperty); + return Bindings.createBooleanBinding(() -> deviceProperty.get() != null && deviceProperty.get().size() == 1 + && deviceProperty.get().get(0).getDeviceType() != DeviceType.UNOWNED, deviceProperty); } public ObjectProperty> retrieveAclResponseProperty() { @@ -135,16 +135,16 @@ public void setWildcardSelectedVerticalResource(String wildcard) { wildcardList.add(wildcard); } - public void loadAccessControl(ObservableValue observable, Device oldValue, Device newValue) { + public void loadAccessControl(ObservableValue> observable, List oldValue, List newValue) { // Clean Info aceListProperty().clear(); verticalResourceListProperty().clear(); selectedVerticalResource.clear(); if (selectedTabProperty().get() != null && selectedTabProperty().get().equals(resourceBundle.getString("client.tab.ams")) - && newValue != null && newValue.getDeviceType() != DeviceType.UNOWNED) { - retrieveAcl(newValue); - retrieveVerticalResources(newValue); + && newValue != null && newValue.size() == 1 && newValue.get(0).getDeviceType() != DeviceType.UNOWNED) { + retrieveAcl(newValue.get(0)); + retrieveVerticalResources(newValue.get(0)); } } @@ -155,9 +155,9 @@ public void loadAccessControl(ObservableValue observable, Stri selectedVerticalResource.clear(); if (newValue != null && newValue.equals(resourceBundle.getString("client.tab.ams")) && deviceProperty.get() != null - && deviceProperty.get().getDeviceType() != DeviceType.UNOWNED) { - retrieveAcl(deviceProperty.get()); - retrieveVerticalResources(deviceProperty.get()); + && deviceProperty.get().size() == 1 && deviceProperty.get().get(0).getDeviceType() != DeviceType.UNOWNED) { + retrieveAcl(deviceProperty.get().get(0)); + retrieveVerticalResources(deviceProperty.get().get(0)); } } @@ -259,15 +259,17 @@ public void createAce(String subjectId, long permission, boolean isWildcard) { resources = selectedVerticalResource; } - disposable.add(createAclUseCase.execute(deviceProperty.get(), subjectId, resources, permission) - .subscribeOn(schedulersFacade.io()) - .observeOn(schedulersFacade.ui()) - .doOnSubscribe(__ -> createAclResponse.setValue(Response.loading())) - .subscribe( - () -> createAclResponse.setValue(Response.success(true)), - throwable -> createAclResponse.setValue(Response.error(throwable)) - ) - ); + if (deviceProperty.get().size() == 1) { + disposable.add(createAclUseCase.execute(deviceProperty.get().get(0), subjectId, resources, permission) + .subscribeOn(schedulersFacade.io()) + .observeOn(schedulersFacade.ui()) + .doOnSubscribe(__ -> createAclResponse.setValue(Response.loading())) + .subscribe( + () -> createAclResponse.setValue(Response.success(true)), + throwable -> createAclResponse.setValue(Response.error(throwable)) + ) + ); + } } public void createAce(String roleId, String roleAuthority, long permission, boolean isWildcard) { @@ -278,15 +280,17 @@ public void createAce(String roleId, String roleAuthority, long permission, bool resources = selectedVerticalResource; } - disposable.add(createAclUseCase.execute(deviceProperty.get(), roleId, roleAuthority, resources, permission) - .subscribeOn(schedulersFacade.io()) - .observeOn(schedulersFacade.ui()) - .doOnSubscribe(__ -> createAclResponse.setValue(Response.loading())) - .subscribe( - () -> createAclResponse.setValue(Response.success(true)), - throwable -> createAclResponse.setValue(Response.error(throwable)) - ) - ); + if (deviceProperty.get().size() == 1) { + disposable.add(createAclUseCase.execute(deviceProperty.get().get(0), roleId, roleAuthority, resources, permission) + .subscribeOn(schedulersFacade.io()) + .observeOn(schedulersFacade.ui()) + .doOnSubscribe(__ -> createAclResponse.setValue(Response.loading())) + .subscribe( + () -> createAclResponse.setValue(Response.success(true)), + throwable -> createAclResponse.setValue(Response.error(throwable)) + ) + ); + } } public void createAce(boolean isAuth, long permission, boolean isWildcard) { @@ -297,25 +301,29 @@ public void createAce(boolean isAuth, long permission, boolean isWildcard) { resources = selectedVerticalResource; } - disposable.add(createAclUseCase.execute(deviceProperty.get(), isAuth, resources, permission) - .subscribeOn(schedulersFacade.io()) - .observeOn(schedulersFacade.ui()) - .doOnSubscribe(__ -> createAclResponse.setValue(Response.loading())) - .subscribe( - () -> createAclResponse.setValue(Response.success(true)), - throwable -> createAclResponse.setValue(Response.error(throwable)) - ) - ); + if (deviceProperty.get().size() == 1) { + disposable.add(createAclUseCase.execute(deviceProperty.get().get(0), isAuth, resources, permission) + .subscribeOn(schedulersFacade.io()) + .observeOn(schedulersFacade.ui()) + .doOnSubscribe(__ -> createAclResponse.setValue(Response.loading())) + .subscribe( + () -> createAclResponse.setValue(Response.success(true)), + throwable -> createAclResponse.setValue(Response.error(throwable)) + ) + ); + } } public void deleteACL(long aceId) { - disposable.add(deleteAclUseCase.execute(deviceProperty.get(), aceId) - .subscribeOn(schedulersFacade.io()) - .observeOn(schedulersFacade.ui()) - .doOnSubscribe(__ -> deleteAclResponse.setValue(Response.loading())) - .subscribe( - () -> deleteAclResponse.setValue(Response.success(aceId)), - throwable -> deleteAclResponse.setValue(Response.error(throwable)) - )); + if (deviceProperty.get().size() == 1) { + disposable.add(deleteAclUseCase.execute(deviceProperty.get().get(0), aceId) + .subscribeOn(schedulersFacade.io()) + .observeOn(schedulersFacade.ui()) + .doOnSubscribe(__ -> deleteAclResponse.setValue(Response.loading())) + .subscribe( + () -> deleteAclResponse.setValue(Response.success(aceId)), + throwable -> deleteAclResponse.setValue(Response.error(throwable)) + )); + } } } diff --git a/src/main/java/org/openconnectivity/otgc/viewmodel/ClientViewModel.java b/src/main/java/org/openconnectivity/otgc/viewmodel/ClientViewModel.java index 9ddbd97..f4a5957 100644 --- a/src/main/java/org/openconnectivity/otgc/viewmodel/ClientViewModel.java +++ b/src/main/java/org/openconnectivity/otgc/viewmodel/ClientViewModel.java @@ -52,7 +52,7 @@ public class ClientViewModel implements ViewModel, SceneLifecycle { - public ObjectProperty deviceProperty; + public ObjectProperty> deviceProperty; @InjectScope private DeviceListToolbarDetailScope deviceListToolbarDetailScope; @@ -170,32 +170,34 @@ public ObjectProperty> observeResourceResponsePro public ObservableBooleanValue clientVisibleProperty() { return Bindings.createBooleanBinding(() -> deviceProperty.get() != null - && deviceProperty.get().getDeviceType() != DeviceType.UNOWNED, deviceProperty); + && deviceProperty.get().size() == 1 && deviceProperty.get().get(0).getDeviceType() != DeviceType.UNOWNED, deviceProperty); } - public void loadInfoDevice(ObservableValue observable, Device oldValue, Device newValue) { + public void loadInfoDevice(ObservableValue> observable, List oldValue, List newValue) { // Clean Info infoListProperty().clear(); - if (newValue == null || (oldValue != null && !newValue.getDeviceId().equals(oldValue.getDeviceId()))) { + if (newValue == null || (oldValue != null + && newValue.size() == 1 && oldValue.size() == 1 + && !newValue.get(0).getDeviceId().equals(oldValue.get(0).getDeviceId()))) { cancellAllObserveResource(); } - if ((newValue != null) && newValue.getDeviceType() != DeviceType.UNOWNED) { + if ((newValue != null) && newValue.size() == 1 && newValue.get(0).getDeviceType() != DeviceType.UNOWNED) { // Load Info - loadDeviceInfo(newValue); - loadPlatformInfo(newValue); + loadDeviceInfo(newValue.get(0)); + loadPlatformInfo(newValue.get(0)); if (selectedTabProperty().get() != null && selectedTabProperty().get().equals(resourceBundle.getString("client.tab.generic_client"))) { - introspect(newValue); + introspect(newValue.get(0)); } } } public void loadGenericClient(ObservableValue observable, String oldValue, String newValue) { if (newValue != null && newValue.equals(resourceBundle.getString("client.tab.generic_client")) && deviceProperty.get() != null - && deviceProperty.get().getDeviceType() != DeviceType.UNOWNED){ - introspect(deviceProperty.get()); + && deviceProperty.get().size() == 1 && deviceProperty.get().get(0).getDeviceType() != DeviceType.UNOWNED){ + introspect(deviceProperty.get().get(0)); } } @@ -286,25 +288,31 @@ public void buildUiForIntrospect(List resources) { serializableResource.setResourceTypes(resource.getResourceTypes()); serializableResource.setResourceInterfaces(resource.getInterfaces()); - getRequest(deviceProperty.get(), serializableResource); + if (deviceProperty.get().size() == 1) { + getRequest(deviceProperty.get().get(0), serializableResource); + } } } } public void findResources() { - disposables.add(getResourcesUseCase.execute(deviceProperty.get()) - .subscribeOn(schedulersFacade.io()) - .observeOn(schedulersFacade.ui()) - .doOnSubscribe(__ -> getResourcesResponse.setValue(Response.loading())) - .subscribe( - serializableResources -> getResourcesResponse.setValue(Response.success(serializableResources)), - throwable -> getResourcesResponse.setValue(Response.error(throwable)) - )); + if (deviceProperty.get().size() == 1) { + disposables.add(getResourcesUseCase.execute(deviceProperty.get().get(0)) + .subscribeOn(schedulersFacade.io()) + .observeOn(schedulersFacade.ui()) + .doOnSubscribe(__ -> getResourcesResponse.setValue(Response.loading())) + .subscribe( + serializableResources -> getResourcesResponse.setValue(Response.success(serializableResources)), + throwable -> getResourcesResponse.setValue(Response.error(throwable)) + )); + } } public void buildUiForRetrieveResources(List resources) { - for(SerializableResource resource : resources) { - getRequest(deviceProperty.get(), resource); + if (deviceProperty.get().size() == 1) { + for(SerializableResource resource : resources) { + getRequest(deviceProperty.get().get(0), resource); + } } } @@ -350,23 +358,30 @@ private void getRequest(Device device, SerializableResource resource) { } public void postRequest(SerializableResource resource, OCRepresentation rep, Object valueArray) { - disposables.add(postRequestUseCase.execute(deviceProperty.get(), resource, rep, valueArray) - .subscribeOn(schedulersFacade.io()) - .observeOn(schedulersFacade.ui()) - .subscribe( - () -> postRequestResponse.setValue(Response.success(true)), - throwable -> postRequestResponse.setValue(Response.error(throwable)) - )); + if (deviceProperty.get().size() == 1) { + disposables.add(postRequestUseCase.execute(deviceProperty.get().get(0), resource, rep, valueArray) + .subscribeOn(schedulersFacade.io()) + .observeOn(schedulersFacade.ui()) + .subscribe( + () -> postRequestResponse.setValue(Response.success(true)), + throwable -> { + postRequestResponse.setValue(Response.error(throwable)); + observeResourceResponse.setValue(Response.success(resource)); + } + )); + } } public void registerResourceObserve(SerializableResource resource) { - disposables.add(observeResourceUseCase.execute(deviceProperty.get(), resource) - .subscribeOn(schedulersFacade.io()) - .observeOn(schedulersFacade.ui()) - .subscribe( - serializableResource -> observeResourceResponse.setValue(Response.success(serializableResource)), - throwable -> observeResourceResponse.setValue(Response.error(throwable)) - )); + if (deviceProperty.get().size() == 1) { + disposables.add(observeResourceUseCase.execute(deviceProperty.get().get(0), resource) + .subscribeOn(schedulersFacade.io()) + .observeOn(schedulersFacade.ui()) + .subscribe( + serializableResource -> observeResourceResponse.setValue(Response.success(serializableResource)), + throwable -> observeResourceResponse.setValue(Response.error(throwable)) + )); + } } public void cancelResourceObserve(SerializableResource resource) { diff --git a/src/main/java/org/openconnectivity/otgc/viewmodel/CredentialViewModel.java b/src/main/java/org/openconnectivity/otgc/viewmodel/CredentialViewModel.java index df72ae1..ea413cb 100644 --- a/src/main/java/org/openconnectivity/otgc/viewmodel/CredentialViewModel.java +++ b/src/main/java/org/openconnectivity/otgc/viewmodel/CredentialViewModel.java @@ -49,7 +49,7 @@ import java.util.ResourceBundle; public class CredentialViewModel implements ViewModel { - public ObjectProperty deviceProperty; + public ObjectProperty> deviceProperty; @InjectScope private DeviceListToolbarDetailScope deviceListToolbarDetailScope; @@ -101,8 +101,8 @@ public void initialize() { } public ObservableBooleanValue cmsVisibleProperty() { - return Bindings.createBooleanBinding(() -> deviceProperty.get() != null - && (deviceProperty.get().getDeviceType() != DeviceType.UNOWNED), deviceProperty); + return Bindings.createBooleanBinding(() -> deviceProperty.get() != null && deviceProperty.get().size() == 1 + && (deviceProperty.get().get(0).getDeviceType() != DeviceType.UNOWNED), deviceProperty); } public ObjectProperty> createCredResponseProperty() { @@ -122,18 +122,18 @@ public void loadCredentials(ObservableValue observable, String credListProperty().clear(); if ((newValue != null) && newValue.equals(resourceBundle.getString("client.tab.cms")) && deviceProperty.get() != null - && (deviceProperty.get().getDeviceType() != DeviceType.UNOWNED)) { - retrieveCreds(deviceProperty.get()); + && deviceProperty.get().size() == 1 && (deviceProperty.get().get(0).getDeviceType() != DeviceType.UNOWNED)) { + retrieveCreds(deviceProperty.get().get(0)); } } - public void loadCredentials(ObservableValue observable, Device oldValue, Device newValue) { + public void loadCredentials(ObservableValue> observable, List oldValue, List newValue) { // Clean Info credListProperty().clear(); if (selectedTabProperty().get() != null && selectedTabProperty().get().equals(resourceBundle.getString("client.tab.cms")) && (newValue != null) - &&(newValue.getDeviceType() != DeviceType.UNOWNED)) { - retrieveCreds(newValue); + && newValue.size() == 1 && (newValue.get(0).getDeviceType() != DeviceType.UNOWNED)) { + retrieveCreds(newValue.get(0)); } } @@ -194,38 +194,43 @@ public void setCred(OcCredentials credential) { } public void provisionIdentityCertificate() { - disposable.add(provisionIdentityCertificateUseCase.execute(deviceProperty.get()) - .subscribeOn(schedulersFacade.io()) - .observeOn(schedulersFacade.ui()) - .doOnSubscribe(__ -> createCredResponse.setValue(Response.loading())) - .subscribe( - () -> createCredResponse.setValue(Response.success(true)), - throwable -> createCredResponse.setValue(Response.error(throwable)) - ) - ); + if (deviceProperty.get().size() == 1){ + disposable.add(provisionIdentityCertificateUseCase.execute(deviceProperty.get().get(0)) + .subscribeOn(schedulersFacade.io()) + .observeOn(schedulersFacade.ui()) + .doOnSubscribe(__ -> createCredResponse.setValue(Response.loading())) + .subscribe( + () -> createCredResponse.setValue(Response.success(true)), + throwable -> createCredResponse.setValue(Response.error(throwable)) + ) + ); + } } public void provisionRoleCertificate(String roleId, String roleAuthority) { - disposable.add(provisionRoleCertificateUseCase.execute(deviceProperty.get(), roleId, roleAuthority) - .subscribeOn(schedulersFacade.io()) - .observeOn(schedulersFacade.ui()) - .doOnSubscribe(__ -> createCredResponse.setValue(Response.loading())) - .subscribe( - () -> createCredResponse.setValue(Response.success(true)), - throwable -> createCredResponse.setValue(Response.error(throwable)) - ) - ); + if (deviceProperty.get().size() == 1){ + disposable.add(provisionRoleCertificateUseCase.execute(deviceProperty.get().get(0), roleId, roleAuthority) + .subscribeOn(schedulersFacade.io()) + .observeOn(schedulersFacade.ui()) + .doOnSubscribe(__ -> createCredResponse.setValue(Response.loading())) + .subscribe( + () -> createCredResponse.setValue(Response.success(true)), + throwable -> createCredResponse.setValue(Response.error(throwable)) + ) + ); + } } public void deleteCred(long credId) { - disposable.add(deleteCredentialUseCase.execute(deviceProperty.get(), credId) - .subscribeOn(schedulersFacade.io()) - .observeOn(schedulersFacade.ui()) - .doOnSubscribe(__ -> deleteCredResponse.setValue(Response.loading())) - .subscribe( - () -> deleteCredResponse.setValue(Response.success(true)), - throwable -> deleteCredResponse.setValue(Response.error(throwable)) - )); - + if (deviceProperty.get().size() == 1) { + disposable.add(deleteCredentialUseCase.execute(deviceProperty.get().get(0), credId) + .subscribeOn(schedulersFacade.io()) + .observeOn(schedulersFacade.ui()) + .doOnSubscribe(__ -> deleteCredResponse.setValue(Response.loading())) + .subscribe( + () -> deleteCredResponse.setValue(Response.success(true)), + throwable -> deleteCredResponse.setValue(Response.error(throwable)) + )); + } } } diff --git a/src/main/java/org/openconnectivity/otgc/viewmodel/DeviceListViewModel.java b/src/main/java/org/openconnectivity/otgc/viewmodel/DeviceListViewModel.java index 41050b1..917bed7 100644 --- a/src/main/java/org/openconnectivity/otgc/viewmodel/DeviceListViewModel.java +++ b/src/main/java/org/openconnectivity/otgc/viewmodel/DeviceListViewModel.java @@ -59,8 +59,8 @@ public class DeviceListViewModel implements ViewModel { private ListProperty devicesList = new SimpleListProperty<>(); public ListProperty devicesListProperty() { return devicesList; } - private final ObjectProperty selectedDevice = new SimpleObjectProperty<>(); - public final ObjectProperty selectedDeviceProperty() { + private final ObjectProperty> selectedDevice = new SimpleObjectProperty<>(); + public final ObjectProperty> selectedDeviceProperty() { return selectedDevice; } private final IntegerProperty positionSelectedDevice = new SimpleIntegerProperty(); @@ -144,41 +144,41 @@ public void onDiscoverRequest() { devicesList.clear(); disposables.add(scanDevicesUseCase.execute() - .map(device -> { - device.setDeviceInfo(getDeviceInfoUseCase.execute(device).blockingGet()); - return device; - }) - .map(device -> { - device.setDeviceRole(getDeviceRoleUseCase.execute(device).blockingGet()); - return device; - }) - .map(device -> { - if (device.getDeviceType().equals(DeviceType.OWNED_BY_SELF)) { - String storedDeviceName = getDeviceNameUseCase.execute(device.getDeviceId()).blockingGet(); - if (storedDeviceName != null && !storedDeviceName.isEmpty()) { - device.getDeviceInfo().setName(storedDeviceName); + .map(device -> { + device.setDeviceInfo(getDeviceInfoUseCase.execute(device).blockingGet()); + return device; + }) + .map(device -> { + device.setDeviceRole(getDeviceRoleUseCase.execute(device).blockingGet()); + return device; + }) + .map(device -> { + if (device.getDeviceType().equals(DeviceType.OWNED_BY_SELF)) { + String storedDeviceName = getDeviceNameUseCase.execute(device.getDeviceId()).blockingGet(); + if (storedDeviceName != null && !storedDeviceName.isEmpty()) { + device.getDeviceInfo().setName(storedDeviceName); + } } - } - return device; - }) - .subscribeOn(schedulersFacade.io()) - .observeOn(schedulersFacade.ui()) - .doOnSubscribe(__ -> scanResponse.setValue(Response.loading())) - .doOnComplete(() -> scanResponse.setValue(Response.complete())) - .subscribe( - device -> scanResponse.setValue(Response.success(device)), - throwable -> scanResponse.setValue(Response.error(throwable)) - )); + return device; + }) + .subscribeOn(schedulersFacade.io()) + .observeOn(schedulersFacade.ui()) + .doOnSubscribe(__ -> scanResponse.setValue(Response.loading())) + .doOnComplete(() -> scanResponse.setValue(Response.complete())) + .subscribe( + device -> scanResponse.setValue(Response.success(device)), + throwable -> scanResponse.setValue(Response.error(throwable)) + )); } public void updateDevice(Device device) { disposables.add(getDeviceDatabaseUseCase.execute(device) - .subscribeOn(schedulersFacade.io()) - .observeOn(schedulersFacade.ui()) - .subscribe( - device1 -> updateDeviceResponse.setValue(Response.success(device1)), - throwable -> {} - )); + .subscribeOn(schedulersFacade.io()) + .observeOn(schedulersFacade.ui()) + .subscribe( + device1 -> updateDeviceResponse.setValue(Response.success(device1)), + throwable -> {} + )); } private void updateItem(int positionToUpdate, Device deviceToUpdate) { diff --git a/src/main/java/org/openconnectivity/otgc/viewmodel/LinkDevicesViewModel.java b/src/main/java/org/openconnectivity/otgc/viewmodel/LinkDevicesViewModel.java index e99ee96..e92bbea 100644 --- a/src/main/java/org/openconnectivity/otgc/viewmodel/LinkDevicesViewModel.java +++ b/src/main/java/org/openconnectivity/otgc/viewmodel/LinkDevicesViewModel.java @@ -54,8 +54,8 @@ public class LinkDevicesViewModel implements ViewModel { private ListProperty ownedDevices = new SimpleListProperty<>(); public ListProperty ownedDevicesProperty() { return ownedDevices; } - private ObjectProperty device = new SimpleObjectProperty<>(); - public ObjectProperty deviceProperty() { + private ObjectProperty> device = new SimpleObjectProperty<>(); + public ObjectProperty> deviceProperty() { return device; } private StringProperty selectedTab = new SimpleStringProperty(); @@ -135,8 +135,8 @@ public ObjectProperty>> retrieveLinkedRolesResponsePropert } public ObservableBooleanValue linkedDevicesVisibleProperty() { - return Bindings.createBooleanBinding(() -> deviceProperty().get() != null - && (deviceProperty().get().getDeviceType() == DeviceType.OWNED_BY_SELF), device); + return Bindings.createBooleanBinding(() -> deviceProperty().get() != null && deviceProperty().get().size() == 1 + && (deviceProperty().get().get(0).getDeviceType() == DeviceType.OWNED_BY_SELF), device); } public void ownedDeviceListProperty() { @@ -148,7 +148,7 @@ public void ownedDeviceListProperty() { } for (Device device : devicesListProperty().filtered(device -> (device.getDeviceType() == DeviceType.OWNED_BY_SELF - && device.getDeviceRole() != deviceProperty().get().getDeviceRole()))) { + && device.getDeviceRole() != deviceProperty().get().get(0).getDeviceRole()))) { if (!tmp.contains(device.getDeviceId())) { tmp.add(device.getDeviceId()); } @@ -156,26 +156,26 @@ public void ownedDeviceListProperty() { ownedDevicesProperty().setValue(FXCollections.observableArrayList(tmp)); } - public void loadLinked(ObservableValue observable, Device oldValue, Device newValue) { + public void loadLinked(ObservableValue> observable, List oldValue, List newValue) { if (selectedTabProperty().get() != null && selectedTabProperty().get().equals(resourceBundle.getString("client.tab.linkeddevices")) - && newValue != null && newValue.getDeviceType() == DeviceType.OWNED_BY_SELF) { + && newValue != null && newValue.size() == 1 && newValue.get(0).getDeviceType() == DeviceType.OWNED_BY_SELF) { // Load linked devices - loadLinkedDevices(newValue); + loadLinkedDevices(newValue.get(0)); // Load linked roles - loadLinkedRoles(newValue); + loadLinkedRoles(newValue.get(0)); } } public void loadLinked(ObservableValue observable, String oldValue, String newValue) { if (newValue != null && newValue.equals(resourceBundle.getString("client.tab.linkeddevices")) - && deviceProperty().get() != null && deviceProperty().get().getDeviceType() == DeviceType.OWNED_BY_SELF) + && deviceProperty().get() != null && deviceProperty().get().size() == 1 && deviceProperty().get().get(0).getDeviceType() == DeviceType.OWNED_BY_SELF) { // Load linked devices - loadLinkedDevices(deviceProperty().get()); + loadLinkedDevices(deviceProperty().get().get(0)); // Load linked roles - loadLinkedRoles(deviceProperty().get()); + loadLinkedRoles(deviceProperty().get().get(0)); } } @@ -210,7 +210,7 @@ public void retrieveLinkedDevices(Device device) { public void retrieveLinkedRoles(Device device) { Single> useCase; - if (deviceProperty().get().getDeviceRole().equals(DeviceRole.CLIENT)) { + if (device.getDeviceRole().equals(DeviceRole.CLIENT)) { useCase = retrieveLinkedRolesForClientUseCase.execute(device); } else { useCase = retrieveLinkedRolesForServerUseCase.execute(device); @@ -244,24 +244,26 @@ public void linkDevices(String deviceId) { Device client; Device server; - if (deviceProperty().get().getDeviceRole().equals(DeviceRole.SERVER)) { - server = deviceProperty().get(); - client = devicesList.get().filtered(d -> d.getDeviceId().equals(deviceId)).get(0); - } else { - client = deviceProperty().get(); - server = devicesList.get().filtered(d -> d.getDeviceId().equals(deviceId)).get(0); - } + if (deviceProperty().get().size() == 1) { + if (deviceProperty().get().get(0).getDeviceRole().equals(DeviceRole.SERVER)) { + server = deviceProperty().get().get(0); + client = devicesList.get().filtered(d -> d.getDeviceId().equals(deviceId)).get(0); + } else { + client = deviceProperty().get().get(0); + server = devicesList.get().filtered(d -> d.getDeviceId().equals(deviceId)).get(0); + } - disposables.add(linkDevicesUseCase.execute(client, server) - .subscribeOn(schedulersFacade.io()) - .observeOn(schedulersFacade.ui()) - .subscribe( - ()-> { - LOG.debug("LinkDevices has been completed"); - loadLinkedDevices(deviceProperty().get()); - }, - throwable -> LOG.error("LinkDevices has failed") - )); + disposables.add(linkDevicesUseCase.execute(client, server) + .subscribeOn(schedulersFacade.io()) + .observeOn(schedulersFacade.ui()) + .subscribe( + ()-> { + LOG.debug("LinkDevices has been completed"); + loadLinkedDevices(deviceProperty().get().get(0)); + }, + throwable -> LOG.error("LinkDevices has failed") + )); + } } public void setLinkedRoles(List linkedRoles) { @@ -281,57 +283,65 @@ public void setLinkedRoles(List linkedRoles) { public void linkRoleCertificate(String roleId, String roleAuthority) { Completable useCase; - if (deviceProperty().get().getDeviceRole().equals(DeviceRole.CLIENT)) { - useCase = linkRoleForClientUseCase.execute(deviceProperty().get(), roleId, roleAuthority); - } else { - useCase = linkRoleForServerUseCase.execute(deviceProperty().get(), roleId, roleAuthority); + if (deviceProperty().get().size() == 1) { + if (deviceProperty().get().get(0).getDeviceRole().equals(DeviceRole.CLIENT)) { + useCase = linkRoleForClientUseCase.execute(deviceProperty().get().get(0), roleId, roleAuthority); + } else { + useCase = linkRoleForServerUseCase.execute(deviceProperty().get().get(0), roleId, roleAuthority); + } + + disposables.add(useCase + .subscribeOn(schedulersFacade.io()) + .observeOn(schedulersFacade.ui()) + .subscribe( + ()-> { + LOG.debug("LinkRole has been completed"); + loadLinkedRoles(deviceProperty().get().get(0)); + }, + throwable -> LOG.error("LinkRole has failed") + )); } - disposables.add(useCase - .subscribeOn(schedulersFacade.io()) - .observeOn(schedulersFacade.ui()) - .subscribe( - ()-> { - LOG.debug("LinkRole has been completed"); - loadLinkedRoles(deviceProperty().get()); - }, - throwable -> LOG.error("LinkRole has failed") - )); } public void unlinkDevices(String serverId) { Device server = devicesList.get().filtered(d -> d.getDeviceId().equals(serverId)).get(0); - disposables.add(unlinkDevicesUseCase.execute(deviceProperty().get(), server) - .subscribeOn(schedulersFacade.io()) - .observeOn(schedulersFacade.ui()) - .subscribe( - ()-> { - LOG.debug("UnlinkDevices has been completed"); - loadLinkedDevices(deviceProperty().get()); - }, - throwable -> LOG.error("UnlinkDevices has failed") - )); + if (deviceProperty().get().size() == 1) { + disposables.add(unlinkDevicesUseCase.execute(deviceProperty().get().get(0), server) + .subscribeOn(schedulersFacade.io()) + .observeOn(schedulersFacade.ui()) + .subscribe( + ()-> { + LOG.debug("UnlinkDevices has been completed"); + loadLinkedDevices(deviceProperty().get().get(0)); + }, + throwable -> LOG.error("UnlinkDevices has failed") + )); + } } public void unlinkRole(String roleId) { Completable useCase; - if (deviceProperty().get().getDeviceRole().equals(DeviceRole.CLIENT)) { - useCase = unlinkRoleForClientUseCase.execute(deviceProperty().get(), roleId); - } else { - useCase = unlinkRoleForServerUseCase.execute(deviceProperty().get(), roleId); + if (deviceProperty().get().size() == 1) { + if (deviceProperty().get().get(0).getDeviceRole().equals(DeviceRole.CLIENT)) { + useCase = unlinkRoleForClientUseCase.execute(deviceProperty().get().get(0), roleId); + } else { + useCase = unlinkRoleForServerUseCase.execute(deviceProperty().get().get(0), roleId); + } + + disposables.add(useCase + .subscribeOn(schedulersFacade.io()) + .observeOn(schedulersFacade.ui()) + .subscribe( + ()-> { + LOG.debug("UnlinkRole has been completed"); + loadLinkedRoles(deviceProperty().get().get(0)); + }, + throwable -> LOG.error("UnlinkRole has failed") + )); } - disposables.add(useCase - .subscribeOn(schedulersFacade.io()) - .observeOn(schedulersFacade.ui()) - .subscribe( - ()-> { - LOG.debug("UnlinkRole has been completed"); - loadLinkedRoles(deviceProperty().get()); - }, - throwable -> LOG.error("UnlinkRole has failed") - )); } } diff --git a/src/main/java/org/openconnectivity/otgc/viewmodel/ToolbarViewModel.java b/src/main/java/org/openconnectivity/otgc/viewmodel/ToolbarViewModel.java index a6ca99e..3e8d6a1 100644 --- a/src/main/java/org/openconnectivity/otgc/viewmodel/ToolbarViewModel.java +++ b/src/main/java/org/openconnectivity/otgc/viewmodel/ToolbarViewModel.java @@ -47,7 +47,7 @@ public class ToolbarViewModel implements ViewModel { private final Logger LOG = Logger.getLogger(ToolbarViewModel.class); - public ObjectProperty deviceProperty; + public ObjectProperty> deviceProperty; private IntegerProperty positionDevice; public IntegerProperty positionDeviceProperty() { return this.positionDevice; @@ -61,6 +61,7 @@ public IntegerProperty positionDeviceProperty() { private final SchedulersFacade schedulersFacade; private final GetOTMethodsUseCase getOTMethodsUseCase; private final OnboardUseCase onboardUseCase; + private final OnboardDevicesUseCase onboardDevicesUseCase; private final CreateAclUseCase createAclUseCase; private final GetDeviceInfoUseCase getDeviceInfoUseCase; private final GetDeviceNameUseCase getDeviceNameUseCase; @@ -84,6 +85,13 @@ public IntegerProperty positionDeviceProperty() { private final ObjectProperty> obtModeResponse = new SimpleObjectProperty<>(); private final ObjectProperty> modeProperty = new SimpleObjectProperty<>(); + // Onboard selected devices responses + private final ObjectProperty> onboardWaiting = new SimpleObjectProperty<>(); + private final ObjectProperty> otmMultiResponse = new SimpleObjectProperty<>(); + private final ObjectProperty> deviceInfoMultiResponse = new SimpleObjectProperty<>(); + private final ObjectProperty> deviceRoleMultiResponse = new SimpleObjectProperty<>(); + private final ObjectProperty> provisionAceOtmMultiResponse = new SimpleObjectProperty<>(); + private SelectOxMListener oxmListener; public void initialize() { @@ -95,6 +103,7 @@ public void initialize() { public ToolbarViewModel(SchedulersFacade schedulersFacade, GetOTMethodsUseCase getOTMethodsUseCase, OnboardUseCase onboardUseCase, + OnboardDevicesUseCase onboardDevicesUseCase, CreateAclUseCase createAclUseCase, GetDeviceInfoUseCase getDeviceInfoUseCase, GetDeviceNameUseCase getDeviceNameUseCase, @@ -110,6 +119,7 @@ public ToolbarViewModel(SchedulersFacade schedulersFacade, this.schedulersFacade = schedulersFacade; this.getOTMethodsUseCase = getOTMethodsUseCase; this.onboardUseCase = onboardUseCase; + this.onboardDevicesUseCase = onboardDevicesUseCase; this.createAclUseCase = createAclUseCase; this.getDeviceInfoUseCase = getDeviceInfoUseCase; this.getDeviceNameUseCase = getDeviceNameUseCase; @@ -125,13 +135,26 @@ public ToolbarViewModel(SchedulersFacade schedulersFacade, } public ObservableBooleanValue onboardButtonDisabled() { - return Bindings.createBooleanBinding(() -> deviceProperty.get() == null - || deviceProperty.get().getDeviceType() != DeviceType.UNOWNED, deviceProperty); + return Bindings.createBooleanBinding(() -> { + boolean disabled = false; + if (deviceProperty.get() == null || deviceProperty.get().isEmpty()) { + disabled = true; + } else { + for (Device device : deviceProperty.get()) { + if (device.getDeviceType() != DeviceType.UNOWNED) { + disabled = true; + } + } + } + + return disabled; + }, deviceProperty); } public ObservableBooleanValue offboardButtonDisabled() { - return Bindings.createBooleanBinding(() -> deviceProperty.get() == null - || deviceProperty.get().getDeviceType() != DeviceType.OWNED_BY_SELF, deviceProperty); + return Bindings.createBooleanBinding(() -> deviceProperty.get() == null || deviceProperty.get().isEmpty() + || (deviceProperty.get().size() == 1 && deviceProperty.get().get(0).getDeviceType() != DeviceType.OWNED_BY_SELF) + || deviceProperty.get().size() > 1, deviceProperty); } public void setOxmListener(SelectOxMListener listener) { @@ -170,6 +193,26 @@ public ObjectProperty> modeResponseProperty() { return modeProperty; } + public ObjectProperty> onboardWaitingProperty() { + return onboardWaiting; + } + + public ObjectProperty> otmMultiResponseProperty() { + return otmMultiResponse; + } + + public ObjectProperty> deviceInfoMultiProperty() { + return deviceInfoMultiResponse; + } + + public ObjectProperty> deviceRoleMultiProperty() { + return deviceRoleMultiResponse; + } + + public ObjectProperty> provisionAceOtmMultiProperty() { + return provisionAceOtmMultiResponse; + } + public void doOwnershipTransfer(Device deviceToOnboard) { disposables.add(getModeUseCase.execute() .subscribeOn(schedulersFacade.io()) @@ -388,6 +431,106 @@ public void getMode() { )); } + public void onboardAllDevices(List devices) { + disposables.add(getModeUseCase.execute() + .subscribeOn(schedulersFacade.io()) + .observeOn(schedulersFacade.ui()) + .subscribe( + mode -> { + if (mode.equals(OtgcMode.OBT)) { + int countOnboards = devices.size(); + if (countOnboards > 0) { + onboardWaiting.setValue(Response.success(true)); + + final Device device = devices.get(0); + disposables.add( + getOTMethodsUseCase.execute(device) + .filter(oxms -> oxms != null) + .subscribeOn(schedulersFacade.io()) + .observeOn(schedulersFacade.ui()) + .subscribe( + oxms -> { + onboardDevicesUseCase.execute(device, oxms) + .subscribeOn(schedulersFacade.io()) + .observeOn(schedulersFacade.ui()) + .subscribe( + ownedDevice -> getDeviceInfoUseCase.execute(ownedDevice) + .subscribeOn(schedulersFacade.io()) + .observeOn(schedulersFacade.ui()) + .subscribe( + deviceInfo -> { + ownedDevice.setDeviceInfo(deviceInfo); + getDeviceRoleUseCase.execute(ownedDevice) + .subscribeOn(schedulersFacade.io()) + .observeOn(schedulersFacade.ui()) + .subscribe( + deviceRole -> { + ownedDevice.setDeviceRole(deviceRole); + String deviceName = ownedDevice.getDeviceRole().toString() + ownedDevice.getDeviceId().substring(0, 5); + ownedDevice.getDeviceInfo().setName(deviceName); + setDeviceName(ownedDevice.getDeviceId(), deviceName); + deviceRoleMultiResponse.setValue(Response.success(ownedDevice)); + String deviceId = getDeviceIdUseCase.execute().blockingGet(); + createAclUseCase.execute(ownedDevice, deviceId, Arrays.asList("*"), 6) + .subscribeOn(schedulersFacade.io()) + .observeOn(schedulersFacade.ui()) + .subscribe( + () -> { + provisionAceOtmMultiResponse.setValue(Response.success(ownedDevice)); + + devices.remove(device); + onboardAllDevices(devices); + }, + throwable -> { + devices.remove(device); + onboardAllDevices(devices); + + provisionAceOtmMultiResponse.setValue(Response.error(throwable)); + } + ); + }, + throwable -> { + devices.remove(device); + onboardAllDevices(devices); + + deviceRoleMultiResponse.setValue(Response.error(throwable)); + } + ); + }, + throwable -> { + devices.remove(device); + onboardAllDevices(devices); + + deviceInfoMultiResponse.setValue(Response.error(throwable)); + } + ), + throwable -> { + devices.remove(device); + onboardAllDevices(devices); + + otmMultiResponse.setValue(Response.error(throwable)); + } + ); + }, + throwable -> { + devices.remove(device); + onboardAllDevices(devices); + + otmMultiResponse.setValue(Response.error(throwable)); + } + ) + ); + } else { + onboardWaiting.setValue(Response.success(false)); + } + } else { + otmResponse.setValue(Response.error(new Exception())); + } + }, + throwable -> otmResponse.setValue(Response.error(throwable)) + )); + } + public interface SelectOxMListener { OcfOxmType onGetOxM(List supportedOxm); } From 2478f401e159df4ba3a5f831163b6dc62f8f25cf Mon Sep 17 00:00:00 2001 From: Javier Guerra Melgares Date: Fri, 13 Dec 2019 11:47:03 +0100 Subject: [PATCH 5/6] Work item 11 - Complete JSON Objects w/ Arrays --- .../data/repository/IotivityRepository.java | 75 ++++ .../model/client/SerializableResource.java | 14 + .../usecase/client/PostRequestUseCase.java | 6 + .../usecase/client/UiFromSwaggerUseCase.java | 19 +- .../otgc/view/client/ClientView.java | 351 ++++++++++++++++-- .../otgc/viewmodel/ClientViewModel.java | 20 +- 6 files changed, 445 insertions(+), 40 deletions(-) diff --git a/src/main/java/org/openconnectivity/otgc/data/repository/IotivityRepository.java b/src/main/java/org/openconnectivity/otgc/data/repository/IotivityRepository.java index fb4eaa9..1c625f1 100644 --- a/src/main/java/org/openconnectivity/otgc/data/repository/IotivityRepository.java +++ b/src/main/java/org/openconnectivity/otgc/data/repository/IotivityRepository.java @@ -574,6 +574,38 @@ public Completable post(String host, String uri, String deviceId, OCRepresentati }); } + public Completable post(String host, String uri, String deviceId, Map values) { + return Completable.create(emitter -> { + OCEndpoint ep = OCEndpointUtil.stringToEndpoint(host, new String[1]); + OCUuid uuid = OCUuidUtil.stringToUuid(deviceId); + OCEndpointUtil.setDi(ep, uuid); + + OCResponseHandler handler = (OCClientResponse response) -> { + OCStatus code = response.getCode(); + if (code == OCStatus.OC_STATUS_OK + || code == OCStatus.OC_STATUS_CHANGED) { + emitter.onComplete(); + } else { + emitter.onError(new Exception("POST " + uri + " error - code: " + code)); + } + }; + + if (OCMain.initPost(uri, ep, null, handler, OCQos.HIGH_QOS)) { + CborEncoder root = OCRep.beginRootObject(); + parseOCRepresentionToCbor(root, values); + OCRep.endRootObject(); + + if (!OCMain.doPost()) { + emitter.onError(new Exception("Do POST " + uri + " error")); + } + } else { + emitter.onError(new Exception("Init POST " + uri + " error")); + } + + OCEndpointUtil.freeEndpoint(ep); + }); + } + private void parseOCRepresentionToCbor(CborEncoder parent, OCRepresentation rep, Object valueArray) { while (rep != null) { switch (rep.getType()) { @@ -598,6 +630,9 @@ private void parseOCRepresentionToCbor(CborEncoder parent, OCRepresentation rep, case OC_REP_STRING_ARRAY: OCRep.setStringArray(parent, rep.getName(), (String[])valueArray); break; + case OC_REP_BOOL_ARRAY: + OCRep.setBooleanArray(parent, rep.getName(), (boolean[])valueArray); + break; default: break; } @@ -606,6 +641,46 @@ private void parseOCRepresentionToCbor(CborEncoder parent, OCRepresentation rep, } } + private void parseOCRepresentionToCbor(CborEncoder parent, Map values) { + for (String key : values.keySet()) { + if (values.get(key) instanceof Boolean) { + OCRep.setBoolean(parent, key, (boolean)values.get(key)); + } else if (values.get(key) instanceof Integer) { + OCRep.setLong(parent, key, (Integer)values.get(key)); + } else if (values.get(key) instanceof Double) { + OCRep.setDouble(parent, key, (Double)values.get(key)); + } else if (values.get(key) instanceof String) { + OCRep.setTextString(parent, key, (String)values.get(key)); + } else if (values.get(key) instanceof List) { + if (((List) values.get(key)).get(0) instanceof String) { + String[] ret = new String[((List)values.get(key)).size()]; + for (int i=0; i< ((List)values.get(key)).size(); i++) { + ret[i] = ((List)values.get(key)).get(i); + } + OCRep.setStringArray(parent, key, ret); + } else if (((List) values.get(key)).get(0) instanceof Integer) { + long[] ret = new long[((List)values.get(key)).size()]; + for (int i=0; i< ((List)values.get(key)).size(); i++) { + ret[i] = ((List)values.get(key)).get(i); + } + OCRep.setLongArray(parent, key, ret); + } else if (((List) values.get(key)).get(0) instanceof Double) { + double[] ret = new double[((List)values.get(key)).size()]; + for (int i=0; i< ((List)values.get(key)).size(); i++) { + ret[i] = ((List)values.get(key)).get(i); + } + OCRep.setDoubleArray(parent, key, ret); + } else if (((List) values.get(key)).get(0) instanceof Boolean) { + boolean[] ret = new boolean[((List)values.get(key)).size()]; + for (int i=0; i< ((List)values.get(key)).size(); i++) { + ret[i] = ((List)values.get(key)).get(i); + } + OCRep.setBooleanArray(parent, key, ret); + } + } + } + } + public void close() { LOG.debug("Calling OCMain.mainShutdown()"); OCMain.mainShutdown(); diff --git a/src/main/java/org/openconnectivity/otgc/domain/model/client/SerializableResource.java b/src/main/java/org/openconnectivity/otgc/domain/model/client/SerializableResource.java index 9b1120d..948838a 100644 --- a/src/main/java/org/openconnectivity/otgc/domain/model/client/SerializableResource.java +++ b/src/main/java/org/openconnectivity/otgc/domain/model/client/SerializableResource.java @@ -35,6 +35,7 @@ public class SerializableResource implements Serializable { private List types; private List interfaces; Map properties = new HashMap<>(); + Map propertiesAccess = new HashMap<>(); private boolean observing = false; private boolean observable = true; @@ -95,6 +96,9 @@ public void setProperties(OCRepresentation ocRepresentation) { case OC_REP_BOOL: properties.put(ocRepresentation.getName(), ocRepresentation.getValue().getBool()); break; + case OC_REP_BOOL_ARRAY: + properties.put(ocRepresentation.getName(), OCRep.ocArrayToBooleanArray(ocRepresentation.getValue().getArray())); + break; case OC_REP_STRING: properties.put(ocRepresentation.getName(), ocRepresentation.getValue().getString()); break; @@ -121,6 +125,16 @@ public void setProperties(OCRepresentation ocRepresentation) { } } + public Map getPropertiesAccess() { + return this.propertiesAccess; + } + + public void setPropertiesAccess(List properties) { + for (DynamicUiProperty property : properties) { + propertiesAccess.put(property.getName(), property.isReadOnly()); + } + } + public boolean isObserving() { return this.observing; } diff --git a/src/main/java/org/openconnectivity/otgc/domain/usecase/client/PostRequestUseCase.java b/src/main/java/org/openconnectivity/otgc/domain/usecase/client/PostRequestUseCase.java index be34b4c..b25c395 100644 --- a/src/main/java/org/openconnectivity/otgc/domain/usecase/client/PostRequestUseCase.java +++ b/src/main/java/org/openconnectivity/otgc/domain/usecase/client/PostRequestUseCase.java @@ -26,6 +26,7 @@ import org.openconnectivity.otgc.domain.model.devicelist.Device; import javax.inject.Inject; +import java.util.Map; public class PostRequestUseCase { private final IotivityRepository iotivityRepository; @@ -39,4 +40,9 @@ public Completable execute(Device device, SerializableResource resource, OCRepre return iotivityRepository.getSecureEndpoint(device) .flatMapCompletable(endpoint -> iotivityRepository.post(endpoint, resource.getUri(), device.getDeviceId(), rep, valueArray)); } + + public Completable execute(Device device, SerializableResource resource, Map values) { + return iotivityRepository.getSecureEndpoint(device) + .flatMapCompletable(endpoint -> iotivityRepository.post(endpoint, resource.getUri(), device.getDeviceId(), values)); + } } diff --git a/src/main/java/org/openconnectivity/otgc/domain/usecase/client/UiFromSwaggerUseCase.java b/src/main/java/org/openconnectivity/otgc/domain/usecase/client/UiFromSwaggerUseCase.java index 91cf9fa..f7c6415 100644 --- a/src/main/java/org/openconnectivity/otgc/domain/usecase/client/UiFromSwaggerUseCase.java +++ b/src/main/java/org/openconnectivity/otgc/domain/usecase/client/UiFromSwaggerUseCase.java @@ -71,7 +71,7 @@ private List jsonSwaggerToUi(@NonNull JSONObject jsonSwagger) uiElement.setPath(pathEntry.getKey()); String definitionName = getSchemaTitle(pathEntry.getValue()); if (definitionName != null && !definitionName.isEmpty()) { - uiElement.setResourceTypes(getResourceTypes(jsonSwagger, definitionName)); + uiElement.setResourceTypes(getResourceTypes(swagger, definitionName)); uiElement.setInterfaces(getInterfaces(swagger, definitionName)); uiElement.setProperties(getProperties(swagger, definitionName)); uiElement.setSupportedOperations(getSupportedOperations(pathEntry.getValue())); @@ -94,20 +94,11 @@ private String getSchemaTitle(Path path) { return schemaTitle; } - private List getResourceTypes(JSONObject jsonSwagger, String definitionName) throws JSONException { - List resourceTypes = new ArrayList<>(); + private List getResourceTypes(Swagger swagger, String definitionName) throws JSONException { + ArrayProperty interfaces = (ArrayProperty) swagger.getDefinitions().get(definitionName).getProperties().get("rt"); + StringProperty rtItems = (StringProperty) interfaces.getItems(); - JSONArray jsonRt = jsonSwagger.getJSONObject("definitions") - .getJSONObject(definitionName) - .getJSONObject("properties") - .getJSONObject("rt") - .getJSONArray("default"); - - for (int i = 0; i < jsonRt.length(); i++) { - resourceTypes.add(jsonRt.getString(i)); - } - - return resourceTypes; + return rtItems.getEnum(); } private List getInterfaces(Swagger swagger, String definitionName) { diff --git a/src/main/java/org/openconnectivity/otgc/view/client/ClientView.java b/src/main/java/org/openconnectivity/otgc/view/client/ClientView.java index 95963dc..cb980d8 100644 --- a/src/main/java/org/openconnectivity/otgc/view/client/ClientView.java +++ b/src/main/java/org/openconnectivity/otgc/view/client/ClientView.java @@ -38,6 +38,8 @@ import org.apache.log4j.Logger; import org.controlsfx.control.ToggleSwitch; import org.iotivity.*; +import org.openconnectivity.otgc.utils.constant.OcfResourceAttributeKey; +import org.openconnectivity.otgc.utils.constant.OcfResourceType; import org.openconnectivity.otgc.viewmodel.ClientViewModel; import org.openconnectivity.otgc.domain.model.client.DynamicUiElement; import org.openconnectivity.otgc.domain.model.client.SerializableResource; @@ -50,9 +52,7 @@ import javax.inject.Inject; import java.net.URL; -import java.util.List; -import java.util.Map; -import java.util.ResourceBundle; +import java.util.*; public class ClientView implements FxmlView, Initializable { @@ -268,7 +268,11 @@ private void createResource(VBox container, SerializableResource resource) { anchorPane.setPrefWidth(Control.USE_COMPUTED_SIZE); paneResource.setContent(anchorPane); - createUI(anchorPane, resource, resourceProperties); + if (resource.getPropertiesAccess().isEmpty()) { + createUI(anchorPane, resource, resourceProperties); + } else { + createUIForIntrospection(anchorPane, resource, resourceProperties); + } } private void updateResource(VBox container, SerializableResource resource) { @@ -368,18 +372,20 @@ private void createUI(AnchorPane anchorPane, SerializableResource resource, Map< Integer number; try { number = Integer.valueOf(integerText.getText()); - } catch (NumberFormatException ex) { - return; - } - OCValue value = new OCValue(); - value.setInteger(number); - OCRepresentation rep = new OCRepresentation(); - rep.setName(key); - rep.setType(OCType.OC_REP_INT); - rep.setValue(value); + OCValue value = new OCValue(); + value.setInteger(number); - viewModel.postRequest(resource, rep, null); + OCRepresentation rep = new OCRepresentation(); + rep.setName(key); + rep.setType(OCType.OC_REP_INT); + rep.setValue(value); + + viewModel.postRequest(resource, rep, null); + } catch (NumberFormatException ex) { + integerText.requestFocus(); + Toast.show(primaryStage, "The value of the " + key + " property has to be an integer"); + } } })); } else { @@ -398,19 +404,20 @@ private void createUI(AnchorPane anchorPane, SerializableResource resource, Map< Double number; try { number = Double.valueOf(doubleText.getText()); - } catch (NumberFormatException ex) { - return; - } - OCValue value = new OCValue(); - value.setDouble(number); + OCValue value = new OCValue(); + value.setDouble(number); - OCRepresentation rep = new OCRepresentation(); - rep.setName(key); - rep.setType(OCType.OC_REP_DOUBLE); - rep.setValue(value); + OCRepresentation rep = new OCRepresentation(); + rep.setName(key); + rep.setType(OCType.OC_REP_DOUBLE); + rep.setValue(value); - viewModel.postRequest(resource, rep, null); + viewModel.postRequest(resource, rep, null); + } catch (NumberFormatException ex) { + doubleText.requestFocus(); + Toast.show(primaryStage, "The value of the " + key + " property has to be a double"); + } } })); } else { @@ -503,6 +510,33 @@ private void createUI(AnchorPane anchorPane, SerializableResource resource, Map< stringArrayComboBox.getSelectionModel().selectFirst(); vbox.getChildren().add(stringArrayLabel); vbox.getChildren().add(stringArrayComboBox); + } else if(resourceProperties.get(key) instanceof boolean[]) { + Label booleanArrayLabel = new Label(key); + booleanArrayLabel.setPadding(new Insets(0, 20, 0, 20)); + HBox booleanArrBox = new HBox(); + booleanArrBox.setPadding(new Insets(0, 10, 0, 10)); + booleanArrBox.setSpacing(10); + for (boolean v : (boolean[])resourceProperties.get(key)) { + ToggleSwitch boolResource = new ToggleSwitch(); + boolResource.setSelected(v); + boolResource.selectedProperty().addListener((observable, oldValue, newValue) -> { + boolean[] ret = new boolean[booleanArrBox.getChildren().size()]; + for (int i=0; i resourceProperties) { + HBox hbox = new HBox(); + hbox.setPrefHeight(Control.USE_COMPUTED_SIZE); + hbox.setPrefWidth(Control.USE_COMPUTED_SIZE); + hbox.setPadding(new Insets(5, 10, 5, 10)); + hbox.setSpacing(5.0); + anchorPane.getChildren().add(hbox); + + // Observable property + VBox vboxObservable = new VBox(); + vboxObservable.setPrefHeight(Control.USE_COMPUTED_SIZE); + vboxObservable.setPrefWidth(Control.USE_COMPUTED_SIZE); + vboxObservable.setSpacing(5.0); + Label labelObservable = new Label("Observe"); + labelObservable.setPadding(new Insets(0, 0, 0, 20)); + ToggleSwitch toggleSwitchObservable = new ToggleSwitch(); + toggleSwitchObservable.setSelected(resource.isObserving()); + vboxObservable.getChildren().add(labelObservable); + vboxObservable.getChildren().add(toggleSwitchObservable); + if (resource.isObservable()) { + toggleSwitchObservable.selectedProperty().addListener(((observable, oldValue, newValue) -> { + resource.setObserving(newValue); + if (newValue) { + viewModel.registerResourceObserve(resource); + } else { + viewModel.cancelResourceObserve(resource); + } + })); + } else { + vboxObservable.disableProperty().setValue(true); + } + hbox.getChildren().add(vboxObservable); + + for (String key : resourceProperties.keySet()) { + VBox vbox = new VBox(); + vbox.setPrefHeight(Control.USE_COMPUTED_SIZE); + vbox.setPrefWidth(Control.USE_COMPUTED_SIZE); + vbox.setSpacing(5.0); + + if (resourceProperties.get(key) instanceof Boolean) { + Label boolLabel = new Label(key); + boolLabel.setPadding(new Insets(0, 0, 0, 20)); + ToggleSwitch toggleSwitch = new ToggleSwitch(); + toggleSwitch.setSelected((boolean)resourceProperties.get(key)); + vbox.getChildren().add(boolLabel); + vbox.getChildren().add(toggleSwitch); + if (viewModel.isViewEnabled(resource.getResourceInterfaces())) { + toggleSwitch.selectedProperty().addListener(((observable, oldValue, newValue) -> sendResourceValues(resource, hbox))); + } else { + vbox.disableProperty().setValue(true); + } + } else if (resourceProperties.get(key) instanceof Integer) { + Label integerLabel = new Label(key); + TextField integerText = new TextField(String.valueOf((int)resourceProperties.get(key))); + // TODO: TextField with integer format + integerText.setMaxWidth(50.0); + vbox.getChildren().add(integerLabel); + vbox.getChildren().add(integerText); + if (viewModel.isViewEnabled(resource.getResourceInterfaces())) { + integerText.focusedProperty().addListener(((observable, oldValue, newValue) -> { + if (oldValue == true && newValue == false) { + String value = integerText.getText(); + if (!value.matches("-?\\d+")) { + integerText.requestFocus(); + Toast.show(primaryStage, "The value of the " + key + " property has to be an integer"); + } else { + sendResourceValues(resource, hbox); + } + } + })); + } else { + vbox.disableProperty().setValue(true); + } + } else if (resourceProperties.get(key) instanceof Double) { + Label doubleLabel = new Label(key); + TextField doubleText = new TextField(String.valueOf((double)resourceProperties.get(key))); + // TODO: TextField with decimal format + doubleText.setMaxWidth(50.0); + vbox.getChildren().add(doubleLabel); + vbox.getChildren().add(doubleText); + if (viewModel.isViewEnabled(resource.getResourceInterfaces())) { + doubleText.focusedProperty().addListener(((observable, oldValue, newValue) -> { + if (oldValue == true && newValue == false) { + String value = doubleText.getText(); + if (!value.matches("-?\\d+\\.\\d+")) { + doubleText.requestFocus(); + Toast.show(primaryStage, "The value of the " + key + " property has to be a double"); + } else { + sendResourceValues(resource, hbox); + } + } + })); + } else { + vbox.disableProperty().setValue(true); + } + } else if (resourceProperties.get(key) instanceof String) { + Label stringLabel = new Label(key); + TextField stringText = new TextField((String)resourceProperties.get(key)); + stringText.setMaxWidth(150.0); + vbox.getChildren().add(stringLabel); + vbox.getChildren().add(stringText); + if (viewModel.isViewEnabled(resource.getResourceInterfaces())) { + stringText.focusedProperty().addListener(((observable, oldValue, newValue) -> { + if (oldValue == true && newValue == false) { + sendResourceValues(resource, hbox); + } + })); + } + } else if (resourceProperties.get(key) instanceof int[]) { + Label integerArrayLabel = new Label(key); + integerArrayLabel.setPadding(new Insets(0, 20, 0, 20)); + HBox intArrBox = new HBox(); + intArrBox.setPadding(new Insets(0, 10, 0, 10)); + intArrBox.setSpacing(10); + intArrBox.setAlignment(Pos.CENTER); + for (int v : (int[])resourceProperties.get(key)) { + TextField textResource = new TextField(String.valueOf(v)); + textResource.setMaxWidth(50.0); + textResource.focusedProperty().addListener((observable, oldValue, newValue) -> { + if (oldValue == true && newValue == false) { + for (int i=0; i { + if (oldValue == true && newValue == false) { + for (int i=0; i stringArrayComboBox = new ComboBox<>(); + if (viewModel.isViewEnabled(resource.getResourceInterfaces())) { + stringArrayComboBox.focusedProperty().addListener(((observable, oldValue, newValue) -> { + if (oldValue == true && newValue == false) { + sendResourceValues(resource, hbox); + } + })); + } + stringArrayComboBox.getItems().addAll((String[])resourceProperties.get(key)); + stringArrayComboBox.getSelectionModel().selectFirst(); + vbox.getChildren().add(stringArrayLabel); + vbox.getChildren().add(stringArrayComboBox); + } else if (resourceProperties.get(key) instanceof boolean[]) { + Label booleanArrayLabel = new Label(key); + booleanArrayLabel.setPadding(new Insets(0, 20, 0, 20)); + HBox booleanArrBox = new HBox(); + booleanArrBox.setPadding(new Insets(0, 10, 0, 10)); + booleanArrBox.setSpacing(10); + booleanArrBox.setAlignment(Pos.CENTER); + for (boolean v : (boolean[])resourceProperties.get(key)) { + ToggleSwitch boolResource = new ToggleSwitch(); + boolResource.setSelected(v); + boolResource.selectedProperty().addListener((observable, oldValue, newValue) -> { + sendResourceValues(resource, hbox); + }); + + booleanArrBox.getChildren().add(boolResource); + } + vbox.getChildren().add(booleanArrayLabel); + vbox.getChildren().add(booleanArrBox); + } + + if (resource.getPropertiesAccess().containsKey(key)) { + ToggleSwitch readOnly = new ToggleSwitch(); + readOnly.setSelected(resource.getPropertiesAccess().get(key)); + readOnly.setVisible(false); + vbox.getChildren().add(readOnly); + } + + if (vbox != null) { + hbox.getChildren().add(vbox); + } + } + } + + private void sendResourceValues(SerializableResource resource, HBox parent) { + Map values = new HashMap<>(); + + for (Node properties : parent.getChildren()) { + String key = ""; + Object value = null; + boolean readOnly = false; + for (Node node : ((VBox)properties).getChildren()) { + if (node instanceof Label) { + key = ((Label)node).getText(); + } else if (node instanceof ToggleSwitch) { + if (node.isVisible()) { + value = ((ToggleSwitch)node).isSelected(); + } else { + readOnly = ((ToggleSwitch)node).isSelected(); + } + } else if (node instanceof TextField) { + String tmp = ((TextField)node).getText(); + if (tmp.matches("-?\\d+")) { + value = Integer.valueOf(tmp); + } else if (tmp.matches("-?\\d+\\.\\d+")) { + value = Double.valueOf(tmp); + } else { + value = tmp; + } + } else if (node instanceof ComboBox) { + value = ((ComboBox)node).getItems(); + } else if (node instanceof HBox) { + List children = ((HBox)node).getChildren(); + value = new ArrayList<>(); + for (Node child : children) { + if (child instanceof TextField) { + String tmp = ((TextField)child).getText(); + if (tmp.matches("-?\\d+")) { + ((List)value).add(Integer.valueOf(tmp)); + } else if (tmp.matches("-?\\d+\\.\\d+")) { + ((List)value).add(Double.valueOf(tmp)); + } else { + ((List)value).add(tmp); + } + } else if (child instanceof ToggleSwitch) { + ((List)value).add(((ToggleSwitch)child).isSelected()); + } + } + } + } + + if (!key.equals("Observe") && value != null && !readOnly + && !key.equals(OcfResourceAttributeKey.RESOURCE_TYPES_KEY) + && !key.equals(OcfResourceAttributeKey.INTERFACES_KEY)) { + values.put(key, value); + } + } + + viewModel.postRequest(resource, values); + } } diff --git a/src/main/java/org/openconnectivity/otgc/viewmodel/ClientViewModel.java b/src/main/java/org/openconnectivity/otgc/viewmodel/ClientViewModel.java index f4a5957..29bc5e2 100644 --- a/src/main/java/org/openconnectivity/otgc/viewmodel/ClientViewModel.java +++ b/src/main/java/org/openconnectivity/otgc/viewmodel/ClientViewModel.java @@ -170,7 +170,7 @@ public ObjectProperty> observeResourceResponsePro public ObservableBooleanValue clientVisibleProperty() { return Bindings.createBooleanBinding(() -> deviceProperty.get() != null - && deviceProperty.get().size() == 1 && deviceProperty.get().get(0).getDeviceType() != DeviceType.UNOWNED, deviceProperty); + && deviceProperty.get().size() == 1 && deviceProperty.get().get(0).getDeviceType() != DeviceType.UNOWNED, deviceProperty); } public void loadInfoDevice(ObservableValue> observable, List oldValue, List newValue) { @@ -196,7 +196,7 @@ public void loadInfoDevice(ObservableValue> observable, L public void loadGenericClient(ObservableValue observable, String oldValue, String newValue) { if (newValue != null && newValue.equals(resourceBundle.getString("client.tab.generic_client")) && deviceProperty.get() != null - && deviceProperty.get().size() == 1 && deviceProperty.get().get(0).getDeviceType() != DeviceType.UNOWNED){ + && deviceProperty.get().size() == 1 && deviceProperty.get().get(0).getDeviceType() != DeviceType.UNOWNED){ introspect(deviceProperty.get().get(0)); } } @@ -285,6 +285,7 @@ public void buildUiForIntrospect(List resources) { if (resource.getSupportedOperations().contains("get")) { SerializableResource serializableResource = new SerializableResource(); serializableResource.setUri(resource.getPath()); + serializableResource.setPropertiesAccess(resource.getProperties()); serializableResource.setResourceTypes(resource.getResourceTypes()); serializableResource.setResourceInterfaces(resource.getInterfaces()); @@ -372,6 +373,21 @@ public void postRequest(SerializableResource resource, OCRepresentation rep, Obj } } + public void postRequest(SerializableResource resource, Map values) { + if (deviceProperty.get().size() == 1) { + disposables.add(postRequestUseCase.execute(deviceProperty.get().get(0), resource, values) + .subscribeOn(schedulersFacade.io()) + .observeOn(schedulersFacade.ui()) + .subscribe( + () -> postRequestResponse.setValue(Response.success(true)), + throwable -> { + postRequestResponse.setValue(Response.error(throwable)); + observeResourceResponse.setValue(Response.success(resource)); + } + )); + } + } + public void registerResourceObserve(SerializableResource resource) { if (deviceProperty.get().size() == 1) { disposables.add(observeResourceUseCase.execute(deviceProperty.get().get(0), resource) From 2db78a883d7503f257da5bee23a8ca163299f5da Mon Sep 17 00:00:00 2001 From: Javier Guerra Melgares Date: Fri, 13 Dec 2019 11:47:31 +0100 Subject: [PATCH 6/6] Update version to 2.8.0 --- build/debian/otgc_native.sh | 2 +- pom.xml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/build/debian/otgc_native.sh b/build/debian/otgc_native.sh index 8a993d9..a0a7bbd 100755 --- a/build/debian/otgc_native.sh +++ b/build/debian/otgc_native.sh @@ -11,7 +11,7 @@ # Constants PROJECT_NAME="otgc" -VERSION="2.7.0" +VERSION="2.8.0" program=$0 diff --git a/pom.xml b/pom.xml index 6f9b58f..8eb1b3d 100644 --- a/pom.xml +++ b/pom.xml @@ -6,7 +6,7 @@ otgc otgc - 2.7.0 + 2.8.0 UTF-8